Changeset 0682c2
- Timestamp:
- Jun 20, 2018, 8:21:41 AM (7 years ago)
- Branches:
- Candidate_v1.6.1, ChemicalSpaceEvaluator, Exclude_Hydrogens_annealWithBondGraph
- Children:
- 3183f5
- Parents:
- bd19c1
- git-author:
- Frederik Heber <frederik.heber@…> (06/16/18 00:03:03)
- git-committer:
- Frederik Heber <frederik.heber@…> (06/20/18 08:21:41)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Dynamics/ForceAnnealing.hpp
rbd19c1 r0682c2 322 322 } 323 323 324 /** Helper function to insert \a PositionUpdate into a map for every atom. 325 * 326 * \param _GatheredUpdates map of updates per atom 327 * \param _LargestUpdate_per_Atom map with the largest update per atom for checking 328 * \param _atomno key for map 329 * \param _PositionUpdate update to add 330 * \param _factor optional dampening factor 331 */ 332 void updateInserter( 333 std::map<atomId_t, Vector> &_GatheredUpdates, 334 std::map<atomId_t, double> &_LargestUpdate_per_Atom, 335 const atomId_t _atomno, 336 const Vector &_PositionUpdate, 337 const double _factor = 1. 338 ) 339 { 340 if (_GatheredUpdates.count(_atomno)) { 341 _GatheredUpdates[_atomno] += _factor*_PositionUpdate; 342 _LargestUpdate_per_Atom[_atomno] = 343 std::max(_LargestUpdate_per_Atom[_atomno], _factor*_PositionUpdate.Norm()); 344 } else { 345 _GatheredUpdates.insert( 346 std::make_pair( 347 _atomno, 348 _factor*_PositionUpdate) ); 349 _LargestUpdate_per_Atom.insert( 350 std::make_pair( 351 _atomno, 352 _PositionUpdate.Norm()) ); 353 } 354 } 355 324 356 /** Performs Gradient optimization on the bonds with BarzilaiBorwein stepwdith. 325 357 * … … 445 477 LOG(3, "DEBUG: Update would be " << stepwidth << "*" << currentGradient << " = " << PositionUpdate); 446 478 447 /** for each atom, we imagine a plane at the position of the atom with 448 * its atomic gradient as the normal vector. We go through all its bonds 449 * and check on which side of the plane the bond is. This defines whether 450 * the bond is contracting (+) or expanding (-) with respect to this atom. 451 * 452 * A bond has two atoms, however. Hence, we do this for either atom and 453 * look at the combination: Is it in sum contracting or expanding given 454 * both projected_forces? 455 */ 456 457 /** go through all bonds and check projected_forces and side of plane 458 * the idea is that if all bonds on one side are contracting ones or expanding, 459 * respectively, then we may shift not only the atom with respect to its 460 * gradient but also its neighbors (towards contraction or towards 461 * expansion depending on direction of gradient). 462 * if they are mixed on both sides of the plane, then we simply shift 463 * only the atom itself. 464 * if they are not mixed on either side, then we also only shift the 465 * atom, namely away from expanding and towards contracting bonds. 466 * 467 * We may get this information right away by looking at the projected_forces. 468 * They give the atomic gradient of either atom projected onto the BondVector 469 * with an additional weight in [0,1]. 470 */ 471 472 // sign encodes side of plane and also encodes contracting(-) or expanding(+) 473 typedef std::vector<int> sides_t; 474 typedef std::vector<int> types_t; 475 sides_t sides; 476 types_t types; 477 const BondList& ListOfBonds = walker.getListOfBonds(); 478 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 479 bonditer != ListOfBonds.end(); ++bonditer) { 480 const bond::ptr ¤t_bond = *bonditer; 481 482 // BondVector goes from bond::rightatom to bond::leftatom 483 const size_t index = bv.getIndexForBond(current_bond); 484 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ? 485 projected_forces[BondVectors::leftside] : projected_forces[BondVectors::rightside]; 486 // note that projected_forces has sign such as to indicate whether 487 // atomic gradient wants bond to contract (-) or expand (+). 488 // This goes into sides: Minus side points away from gradient, plus side point 489 // towards gradient. 490 // 491 // the sum of both bond sides goes into types, depending on which is 492 // stronger if either wants a different thing 493 const double &temp = forcelist[index]; 494 if (fabs(temp) < MYEPSILON) 495 sides.push_back(1); 496 else 497 sides.push_back( -1.*temp/fabs(temp) ); // BondVectors has exactly opposite sign for sides decision 498 ASSERT( (sides.back() == 1) || (sides.back() == -1), 499 "ForceAnnealing() - sides is not in {-1,1}."); 500 const double sum = 501 projected_forces[BondVectors::leftside][index]+projected_forces[BondVectors::rightside][index]; 502 types.push_back( sum/fabs(sum) ); 503 LOG(4, "DEBUG: Bond " << *current_bond << " is on side " << sides.back() 504 << " and has type " << types.back()); 505 } 506 // /// check whether both conditions are compatible: 507 // // i.e. either we have ++/-- for all entries in sides and types 508 // // or we have +-/-+ for all entries 509 // // hence, multiplying and taking the sum and its absolute value 510 // // should be equal to the maximum number of entries 511 // sides_t results; 512 // std::transform( 513 // sides.begin(), sides.end(), 514 // types.begin(), 515 // std::back_inserter(results), 516 // std::multiplies<int>); 517 // int result = abs(std::accumulate(results.begin(), results.end(), 0, std::plus<int>)); 518 519 std::vector<size_t> first_per_side(2, (size_t)-1); //!< mark down one representative from either side 520 std::vector< std::vector<int> > types_per_side(2); //!< gather all types on each side 521 types_t::const_iterator typesiter = types.begin(); 522 for (sides_t::const_iterator sidesiter = sides.begin(); 523 sidesiter != sides.end(); ++sidesiter, ++typesiter) { 524 const size_t index = (*sidesiter+1)/2; 525 types_per_side[index].push_back(*typesiter); 526 if (first_per_side[index] == (size_t)-1) 527 first_per_side[index] = std::distance(const_cast<const sides_t &>(sides).begin(), sidesiter); 528 } 529 LOG(4, "DEBUG: First on side minus is " << first_per_side[0] << ", and first on side plus is " 530 << first_per_side[1]); 531 //!> enumerate types per side with a little witching with the numbers to allow easy setting from types 532 enum whichtypes_t { 533 contracting=0, 534 unset=1, 535 expanding=2, 536 mixed 537 }; 538 std::vector<int> typeside(2, unset); 539 for(size_t i=0;i<2;++i) { 540 for (std::vector<int>::const_iterator tpsiter = types_per_side[i].begin(); 541 tpsiter != types_per_side[i].end(); ++tpsiter) { 542 if (typeside[i] == unset) { 543 typeside[i] = *tpsiter+1; //contracting(0) or expanding(2) 544 } else { 545 if (typeside[i] != (*tpsiter+1)) // no longer he same type 546 typeside[i] = mixed; 479 if (walker.getElementNo() != 1) { 480 /** for each atom, we imagine a plane at the position of the atom with 481 * its atomic gradient as the normal vector. We go through all its bonds 482 * and check on which side of the plane the bond is. This defines whether 483 * the bond is contracting (+) or expanding (-) with respect to this atom. 484 * 485 * A bond has two atoms, however. Hence, we do this for either atom and 486 * look at the combination: Is it in sum contracting or expanding given 487 * both projected_forces? 488 */ 489 490 /** go through all bonds and check projected_forces and side of plane 491 * the idea is that if all bonds on one side are contracting ones or expanding, 492 * respectively, then we may shift not only the atom with respect to its 493 * gradient but also its neighbors (towards contraction or towards 494 * expansion depending on direction of gradient). 495 * if they are mixed on both sides of the plane, then we simply shift 496 * only the atom itself. 497 * if they are not mixed on either side, then we also only shift the 498 * atom, namely away from expanding and towards contracting bonds. 499 * 500 * We may get this information right away by looking at the projected_forces. 501 * They give the atomic gradient of either atom projected onto the BondVector 502 * with an additional weight in [0,1]. 503 */ 504 505 // sign encodes side of plane and also encodes contracting(-) or expanding(+) 506 typedef std::vector<int> sides_t; 507 typedef std::vector<int> types_t; 508 sides_t sides; 509 types_t types; 510 const BondList& ListOfBonds = walker.getListOfBonds(); 511 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 512 bonditer != ListOfBonds.end(); ++bonditer) { 513 const bond::ptr ¤t_bond = *bonditer; 514 515 // BondVector goes from bond::rightatom to bond::leftatom 516 const size_t index = bv.getIndexForBond(current_bond); 517 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ? 518 projected_forces[BondVectors::leftside] : projected_forces[BondVectors::rightside]; 519 // note that projected_forces has sign such as to indicate whether 520 // atomic gradient wants bond to contract (-) or expand (+). 521 // This goes into sides: Minus side points away from gradient, plus side point 522 // towards gradient. 523 // 524 // the sum of both bond sides goes into types, depending on which is 525 // stronger if either wants a different thing 526 const double &temp = forcelist[index]; 527 if (fabs(temp) < MYEPSILON) 528 sides.push_back(1); 529 else 530 sides.push_back( -1.*temp/fabs(temp) ); // BondVectors has exactly opposite sign for sides decision 531 ASSERT( (sides.back() == 1) || (sides.back() == -1), 532 "ForceAnnealing() - sides is not in {-1,1}."); 533 const double sum = 534 projected_forces[BondVectors::leftside][index]+projected_forces[BondVectors::rightside][index]; 535 types.push_back( sum/fabs(sum) ); 536 LOG(4, "DEBUG: Bond " << *current_bond << " is on side " << sides.back() 537 << " and has type " << types.back()); 538 } 539 // /// check whether both conditions are compatible: 540 // // i.e. either we have ++/-- for all entries in sides and types 541 // // or we have +-/-+ for all entries 542 // // hence, multiplying and taking the sum and its absolute value 543 // // should be equal to the maximum number of entries 544 // sides_t results; 545 // std::transform( 546 // sides.begin(), sides.end(), 547 // types.begin(), 548 // std::back_inserter(results), 549 // std::multiplies<int>); 550 // int result = abs(std::accumulate(results.begin(), results.end(), 0, std::plus<int>)); 551 552 std::vector<size_t> first_per_side(2, (size_t)-1); //!< mark down one representative from either side 553 std::vector< std::vector<int> > types_per_side(2); //!< gather all types on each side 554 types_t::const_iterator typesiter = types.begin(); 555 for (sides_t::const_iterator sidesiter = sides.begin(); 556 sidesiter != sides.end(); ++sidesiter, ++typesiter) { 557 const size_t index = (*sidesiter+1)/2; 558 types_per_side[index].push_back(*typesiter); 559 if (first_per_side[index] == (size_t)-1) 560 first_per_side[index] = std::distance(const_cast<const sides_t &>(sides).begin(), sidesiter); 561 } 562 LOG(4, "DEBUG: First on side minus is " << first_per_side[0] << ", and first on side plus is " 563 << first_per_side[1]); 564 //!> enumerate types per side with a little witching with the numbers to allow easy setting from types 565 enum whichtypes_t { 566 contracting=0, 567 unset=1, 568 expanding=2, 569 mixed 570 }; 571 std::vector<int> typeside(2, unset); 572 for(size_t i=0;i<2;++i) { 573 for (std::vector<int>::const_iterator tpsiter = types_per_side[i].begin(); 574 tpsiter != types_per_side[i].end(); ++tpsiter) { 575 if (typeside[i] == unset) { 576 typeside[i] = *tpsiter+1; //contracting(0) or expanding(2) 577 } else { 578 if (typeside[i] != (*tpsiter+1)) // no longer he same type 579 typeside[i] = mixed; 580 } 547 581 } 548 582 } 549 }550 LOG(4, "DEBUG: Minus side is " << typeside[0] << " and plus side is " << typeside[1]); 551 552 typedef std::vector< std::pair<atomId_t, atomId_t> > RemovedEdges_t;553 if ((typeside[0] != mixed) || (typeside[1] != mixed)) {554 const size_t sideno = ((typeside[0] != mixed) && (typeside[0] != unset)) ? 0 : 1;555 LOG(4, "DEBUG: Chosen side is " << sideno << " with type " << typeside[sideno]);556 ASSERT( (typeside[sideno] == contracting) || (typeside[sideno] == expanding),557 "annealWithBondGraph_BB() - chosen side is neither expanding nor contracting.");558 // one side is not mixed, all bonds on one side are of same type559 // hence, find out which bonds to exclude560 const BondList& ListOfBonds = walker.getListOfBonds(); 561 562 // sideno is away (0) or in direction (1) of gradient563 // tpyes[first_per_side[sideno]] is either contracting (-1) or expanding (+1)564 // : side (i), where (i) means which bonds we keep for the BFS, bonds565 // on side (-i) are removed566 // If all bonds on side away (0) want expansion (+1), move towards side with atom: side1567 // if all bonds side towards (1) want contraction (-1), move away side with atom : side -1 568 569 // unsure whether this or do nothing in the remaining cases:570 // If all bonds on side toward (1) want expansion (+1), move away side with atom : side -1571 // (the reasoning is that the bond's other atom must have a stronger572 // gradient in the same direction and they push along atoms in573 // gradient direction: we don't want to interface with those.574 // Hence, move atoms along on away side575 // if all bonds side away (0) want contraction (-1), move towards side with atom: side 1576 // (the reasoning is the same, don't interfere with update from577 // stronger gradient)578 // hence, the decision is only based on sides once we have picked a side579 // depending on all bonds associated with have same good type. 580 581 // away from gradient (minus) and contracting582 // or towards gradient (plus) and expanding583 // gather all on same side and remove584 const double sign =585 (sides[first_per_side[sideno]] == types[first_per_side[sideno]])586 ? sides[first_per_side[sideno]] : -1.*sides[first_per_side[sideno]]; 587 588 LOG(4, "DEBUG: Removing edges from side with sign " << sign);589 BondList::const_iterator bonditer = ListOfBonds.begin();590 RemovedEdges_t RemovedEdges;591 for (sides_t::const_iterator sidesiter = sides.begin();592 sidesiter != sides.end(); ++sidesiter, ++bonditer) {593 if (*sidesiter == sign) {594 // remove the edge595 const bond::ptr ¤t_bond = *bonditer;596 LOG(5, "DEBUG: Removing edge " << *current_bond);597 RemovedEdges.push_back( std::make_pair(598 current_bond->leftatom->getId(),599 current_bond->rightatom->getId())600 );601 #ifndef NDEBUG 602 const bool status =603 #endif 604 BGcreator.removeEdge(RemovedEdges.back());605 ASSERT( status, "ForceAnnealing() - edge to found bond is not present?");583 LOG(4, "DEBUG: Minus side is " << typeside[0] << " and plus side is " << typeside[1]); 584 585 typedef std::vector< std::pair<atomId_t, atomId_t> > RemovedEdges_t; 586 if ((typeside[0] != mixed) || (typeside[1] != mixed)) { 587 const size_t sideno = ((typeside[0] != mixed) && (typeside[0] != unset)) ? 0 : 1; 588 LOG(4, "DEBUG: Chosen side is " << sideno << " with type " << typeside[sideno]); 589 ASSERT( (typeside[sideno] == contracting) || (typeside[sideno] == expanding), 590 "annealWithBondGraph_BB() - chosen side is neither expanding nor contracting."); 591 // one side is not mixed, all bonds on one side are of same type 592 // hence, find out which bonds to exclude 593 const BondList& ListOfBonds = walker.getListOfBonds(); 594 595 // sideno is away (0) or in direction (1) of gradient 596 // tpyes[first_per_side[sideno]] is either contracting (-1) or expanding (+1) 597 // : side (i), where (i) means which bonds we keep for the BFS, bonds 598 // on side (-i) are removed 599 // If all bonds on side away (0) want expansion (+1), move towards side with atom: side 1 600 // if all bonds side towards (1) want contraction (-1), move away side with atom : side -1 601 602 // unsure whether this or do nothing in the remaining cases: 603 // If all bonds on side toward (1) want expansion (+1), move away side with atom : side -1 604 // (the reasoning is that the bond's other atom must have a stronger 605 // gradient in the same direction and they push along atoms in 606 // gradient direction: we don't want to interface with those. 607 // Hence, move atoms along on away side 608 // if all bonds side away (0) want contraction (-1), move towards side with atom: side 1 609 // (the reasoning is the same, don't interfere with update from 610 // stronger gradient) 611 // hence, the decision is only based on sides once we have picked a side 612 // depending on all bonds associated with have same good type. 613 614 // away from gradient (minus) and contracting 615 // or towards gradient (plus) and expanding 616 // gather all on same side and remove 617 const double sign = 618 (sides[first_per_side[sideno]] == types[first_per_side[sideno]]) 619 ? sides[first_per_side[sideno]] : -1.*sides[first_per_side[sideno]]; 620 621 LOG(4, "DEBUG: Removing edges from side with sign " << sign); 622 BondList::const_iterator bonditer = ListOfBonds.begin(); 623 RemovedEdges_t RemovedEdges; 624 for (sides_t::const_iterator sidesiter = sides.begin(); 625 sidesiter != sides.end(); ++sidesiter, ++bonditer) { 626 if (*sidesiter == sign) { 627 // remove the edge 628 const bond::ptr ¤t_bond = *bonditer; 629 LOG(5, "DEBUG: Removing edge " << *current_bond); 630 RemovedEdges.push_back( std::make_pair( 631 current_bond->leftatom->getId(), 632 current_bond->rightatom->getId()) 633 ); 634 #ifndef NDEBUG 635 const bool status = 636 #endif 637 BGcreator.removeEdge(RemovedEdges.back()); 638 ASSERT( status, "ForceAnnealing() - edge to found bond is not present?"); 639 } 606 640 } 607 } 608 // perform limited-horizon BFS 609 BoostGraphHelpers::Nodeset_t bondside_set; 610 BreadthFirstSearchGatherer::distance_map_t distance_map; 611 bondside_set = NodeGatherer(walker.getId(), max_distance); 612 distance_map = NodeGatherer.getDistances(); 613 std::sort(bondside_set.begin(), bondside_set.end()); 614 615 // re-add edge 616 for (RemovedEdges_t::const_iterator edgeiter = RemovedEdges.begin(); 617 edgeiter != RemovedEdges.end(); ++edgeiter) 618 BGcreator.addEdge(edgeiter->first, edgeiter->second); 619 620 // update position with dampening factor on the discovered bonds 621 for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set.begin(); 622 setiter != bondside_set.end(); ++setiter) { 623 const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter 624 = distance_map.find(*setiter); 625 ASSERT( diter != distance_map.end(), 626 "ForceAnnealing() - could not find distance to an atom."); 627 const double factor = pow(damping_factor, diter->second+1); 628 LOG(3, "DEBUG: Update for atom #" << *setiter << " will be " 629 << factor << "*" << PositionUpdate); 630 if (GatheredUpdates.count((*setiter))) { 631 GatheredUpdates[(*setiter)] += factor*PositionUpdate; 632 LargestUpdate_per_Atom[(*setiter)] = 633 std::max(LargestUpdate_per_Atom[(*setiter)], factor*PositionUpdate.Norm()); 634 } else { 635 GatheredUpdates.insert( 636 std::make_pair( 637 (*setiter), 638 factor*PositionUpdate) ); 639 LargestUpdate_per_Atom.insert( 640 std::make_pair( 641 (*setiter), 642 factor*PositionUpdate.Norm()) ); 641 // perform limited-horizon BFS 642 BoostGraphHelpers::Nodeset_t bondside_set; 643 BreadthFirstSearchGatherer::distance_map_t distance_map; 644 bondside_set = NodeGatherer(walker.getId(), max_distance); 645 distance_map = NodeGatherer.getDistances(); 646 std::sort(bondside_set.begin(), bondside_set.end()); 647 648 // re-add edge 649 for (RemovedEdges_t::const_iterator edgeiter = RemovedEdges.begin(); 650 edgeiter != RemovedEdges.end(); ++edgeiter) 651 BGcreator.addEdge(edgeiter->first, edgeiter->second); 652 653 // update position with dampening factor on the discovered bonds 654 for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set.begin(); 655 setiter != bondside_set.end(); ++setiter) { 656 const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter 657 = distance_map.find(*setiter); 658 ASSERT( diter != distance_map.end(), 659 "ForceAnnealing() - could not find distance to an atom."); 660 const double factor = pow(damping_factor, diter->second+1); 661 LOG(3, "DEBUG: Update for atom #" << *setiter << " will be " 662 << factor << "*" << PositionUpdate); 663 updateInserter(GatheredUpdates, LargestUpdate_per_Atom, *setiter, PositionUpdate, factor); 643 664 } 665 } else { 666 // simple atomic annealing, i.e. damping factor of 1 667 updateInserter(GatheredUpdates, LargestUpdate_per_Atom, walker.getId(), PositionUpdate); 644 668 } 645 669 } else { 646 // simple atomic annealing, i.e. damping factor of 1 647 LOG(3, "DEBUG: Update for atom #" << walker.getId() << " will be " << PositionUpdate); 648 GatheredUpdates.insert( 649 std::make_pair( 650 walker.getId(), 651 PositionUpdate) ); 652 LargestUpdate_per_Atom.insert( 653 std::make_pair( 654 walker.getId(), 655 PositionUpdate.Norm()) ); 670 // hydrogens (are light-weighted and therefore) are always updated normally 671 LOG(3, "DEBUG: Update for hydrogen #" << walker.getId() << " will be " << PositionUpdate); 672 updateInserter(GatheredUpdates, LargestUpdate_per_Atom, walker.getId(), PositionUpdate); 656 673 } 657 674 }
Note:
See TracChangeset
for help on using the changeset viewer.