Changeset 77d0cd for src/Dynamics
- Timestamp:
- Apr 10, 2018, 6:43:30 AM (7 years ago)
- Branches:
- AutomationFragmentation_failures, Candidate_v1.6.1, ChemicalSpaceEvaluator, Exclude_Hydrogens_annealWithBondGraph, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_contraction-expansion, Gui_displays_atomic_force_velocity, PythonUI_with_named_parameters, StoppableMakroAction, TremoloParser_IncreasedPrecision
- Children:
- 6458e7
- Parents:
- d51e62
- git-author:
- Frederik Heber <frederik.heber@…> (06/13/17 22:46:53)
- git-committer:
- Frederik Heber <frederik.heber@…> (04/10/18 06:43:30)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Dynamics/ForceAnnealing.hpp
rd51e62 r77d0cd 15 15 16 16 #include <algorithm> 17 #include <functional> 17 18 #include <iterator> 18 19 … … 27 28 #include "Descriptors/AtomIdDescriptor.hpp" 28 29 #include "Dynamics/AtomicForceManipulator.hpp" 30 #include "Dynamics/BondVectors.hpp" 29 31 #include "Fragmentation/ForceMatrix.hpp" 30 32 #include "Graph/BoostGraphCreator.hpp" … … 100 102 { 101 103 // make sum of forces equal zero 102 AtomicForceManipulator<T>::correctForceMatrixForFixedCenterOfMass(_offset, _CurrentTimeStep); 104 AtomicForceManipulator<T>::correctForceMatrixForFixedCenterOfMass( 105 _offset, 106 _CurrentTimeStep-1>=0 ? _CurrentTimeStep - 1 : 0); 103 107 104 108 // are we in initial step? Then set static entities … … 225 229 { 226 230 // get nodes on either side of selected bond via BFS discovery 227 // std::vector<atomId_t> atomids;228 // for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();229 // iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {230 // atomids.push_back((*iter)->getId());231 // }232 // ASSERT( atomids.size() == AtomicForceManipulator<T>::atoms.size(),233 // "ForceAnnealing() - could not gather all atomic ids?");234 231 BoostGraphCreator BGcreator; 235 232 BGcreator.createFromRange( … … 247 244 /// PositionUpdate. This is almost what we are going to do. 248 245 249 /// One moreissue is: If we need to shorten bond, then we use the PositionUpdate246 /// One issue is: If we need to shorten bond, then we use the PositionUpdate 250 247 /// also on the the other bond partner already. This is because it is in the 251 248 /// direction of the bond. Therefore, the update is actually performed twice on … … 257 254 /// check whether each gradient points inwards out or outwards with respect 258 255 /// to the bond and then shift accordingly. 256 259 257 /// One more issue is that the projection onto the bond directions does not 260 258 /// recover the gradient but may be larger as the bond directions are a … … 263 261 /// overestimation and obtain a weighting for each bond. 264 262 265 // gather weights 263 // initialize helper class for bond vectors using bonds from range of atoms 264 BondVectors bv; 265 bv.setFromAtomRange< T >( 266 AtomicForceManipulator<T>::atoms.begin(), 267 AtomicForceManipulator<T>::atoms.end(), 268 CurrentTimeStep); 269 const BondVectors::container_t &sorted_bonds = bv.getSorted(); 270 271 // knowing the number of bonds in total, we can setup the storage for the 272 // projected forces 273 enum whichatom_t { 274 leftside=0, 275 rightside=1, 276 MAX_sides 277 }; 278 std::vector< // time step 279 std::vector< // which bond side 280 std::vector<double> > // over all bonds 281 > projected_forces(2); // one for leftatoms, one for rightatoms (and for both time steps) 282 for (size_t i=0;i<2;++i) { 283 projected_forces[i].resize(MAX_sides); 284 for (size_t j=0;j<MAX_sides;++j) 285 projected_forces[i][j].resize(sorted_bonds.size(), 0.); 286 } 287 288 // for each atom we need to gather weights and then project the gradient 266 289 typedef std::deque<double> weights_t; 267 290 typedef std::map<atomId_t, weights_t > weights_per_atom_t; 268 291 std::vector<weights_per_atom_t> weights_per_atom(2); 269 292 for (size_t timestep = 0; timestep <= 1; ++timestep) { 270 const size_t CurrentStep = CurrentTimeStep- 2*timestep >= 0 ? CurrentTimeStep - 2*timestep: 0;293 const size_t CurrentStep = CurrentTimeStep-timestep-1 >= 0 ? CurrentTimeStep-timestep-1 : 0; 271 294 LOG(2, "DEBUG: CurrentTimeStep is " << CurrentTimeStep 272 295 << ", timestep is " << timestep 273 296 << ", and CurrentStep is " << CurrentStep); 297 298 // get all bond vectors for this time step (from the perspective of the 299 // bonds taken from the currentStep) 300 const BondVectors::mapped_t bondvectors = bv.getBondVectorsAtStep(CurrentStep); 274 301 275 302 for(typename AtomSetMixin<T>::const_iterator iter = AtomicForceManipulator<T>::atoms.begin(); … … 277 304 const atom &walker = *(*iter); 278 305 const Vector &walkerGradient = walker.getAtomicForceAtStep(CurrentStep); 279 306 LOG(3, "DEBUG: Gradient of atom #" << walker.getId() << ", namely " 307 << walker << " is " << walkerGradient << " with magnitude of " 308 << walkerGradient.Norm()); 309 310 const BondList& ListOfBonds = walker.getListOfBonds(); 280 311 if (walkerGradient.Norm() > MYEPSILON) { 281 312 282 // gather BondVector and projected gradient over all bonds 283 const BondList& ListOfBonds = walker.getListOfBondsAtStep(CurrentStep); 284 std::vector<double> projected_forces; 313 // gather subset of BondVectors for the current atom 285 314 std::vector<Vector> BondVectors; 286 projected_forces.reserve(ListOfBonds.size());287 315 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 288 316 bonditer != ListOfBonds.end(); ++bonditer) { 289 317 const bond::ptr ¤t_bond = *bonditer; 290 BondVectors.push_back( 291 current_bond->leftatom->getPositionAtStep(CurrentStep) 292 - current_bond->rightatom->getPositionAtStep(CurrentStep)); 293 Vector &BondVector = BondVectors.back(); 294 BondVector.Normalize(); 295 projected_forces.push_back( walkerGradient.ScalarProduct(BondVector) ); 318 const BondVectors::mapped_t::const_iterator bviter = 319 bondvectors.find(current_bond); 320 ASSERT( bviter != bondvectors.end(), 321 "ForceAnnealing() - cannot find current_bond ?"); 322 ASSERT( bviter != bondvectors.end(), 323 "ForceAnnealing - cannot find current bond "+toString(*current_bond) 324 +" in bonds."); 325 BondVectors.push_back(bviter->second); 296 326 } 297 298 // go through all bonds and check what magnitude is represented by the others 299 // i.e. sum of scalar products against other bonds 327 LOG(4, "DEBUG: BondVectors for atom #" << walker.getId() << ": " << BondVectors); 328 329 // go through all its bonds and calculate what magnitude is represented 330 // by the others i.e. sum of scalar products against other bonds 300 331 std::pair<weights_per_atom_t::iterator, bool> inserter = 301 weights_per_atom[timestep -1].insert(332 weights_per_atom[timestep].insert( 302 333 std::make_pair(walker.getId(), weights_t()) ); 303 334 ASSERT( inserter.second, 304 335 "ForceAnnealing::operator() - weight map for atom "+toString(walker) 305 +" and time step "+toString(timestep -1)+" already filled?");336 +" and time step "+toString(timestep)+" already filled?"); 306 337 weights_t &weights = inserter.first->second; 307 338 for (std::vector<Vector>::const_iterator iter = BondVectors.begin(); 308 339 iter != BondVectors.end(); ++iter) { 309 340 std::vector<double> scps; 341 scps.reserve(BondVectors.size()); 310 342 std::transform( 311 343 BondVectors.begin(), BondVectors.end(), 312 344 std::back_inserter(scps), 313 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1) 345 boost::bind(static_cast< double (*)(double) >(&fabs), 346 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1)) 314 347 ); 315 348 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.); 349 ASSERT( (scp_sum-1.) > -MYEPSILON, 350 "ForceAnnealing() - sum of weights must be equal or larger one but is " 351 +toString(scp_sum)); 316 352 weights.push_back( 1./scp_sum ); 317 353 } 354 LOG(4, "DEBUG: Weights for atom #" << walker.getId() << ": " << weights); 355 318 356 // for testing we check whether all weighted scalar products now come out as 1. 319 357 #ifndef NDEBUG 320 358 for (std::vector<Vector>::const_iterator iter = BondVectors.begin(); 321 359 iter != BondVectors.end(); ++iter) { 322 double scp_sum = 0.; 323 weights_t::const_iterator weightiter = weights.begin(); 324 for (std::vector<Vector>::const_iterator otheriter = BondVectors.begin(); 325 otheriter != BondVectors.end(); ++otheriter, ++weightiter) { 326 scp_sum += (*weightiter)*(*iter).ScalarProduct(*otheriter); 327 } 360 std::vector<double> scps; 361 scps.reserve(BondVectors.size()); 362 std::transform( 363 BondVectors.begin(), BondVectors.end(), 364 weights.begin(), 365 std::back_inserter(scps), 366 boost::bind(static_cast< double (*)(double) >(&fabs), 367 boost::bind(std::multiplies<double>(), 368 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1), 369 _2)) 370 ); 371 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.); 328 372 ASSERT( fabs(scp_sum - 1.) < MYEPSILON, 329 373 "ForceAnnealing::operator() - for BondVector "+toString(*iter) … … 331 375 } 332 376 #endif 377 378 // projected gradient over all bonds and place in one of projected_forces 379 // using the obtained weights 380 { 381 weights_t::const_iterator weightiter = weights.begin(); 382 std::vector<Vector>::const_iterator vectoriter = BondVectors.begin(); 383 Vector forcesum_check; 384 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 385 bonditer != ListOfBonds.end(); ++bonditer, ++weightiter, ++vectoriter) { 386 const bond::ptr ¤t_bond = *bonditer; 387 const Vector &BondVector = *vectoriter; 388 389 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ? 390 projected_forces[timestep][leftside] : projected_forces[timestep][rightside]; 391 const size_t index = bv.getIndexForBond(current_bond); 392 ASSERT( index != (size_t)-1, 393 "ForceAnnealing() - could not find bond "+toString(*current_bond) 394 +" in bondvectors"); 395 forcelist[index] = (*weightiter)*walkerGradient.ScalarProduct(BondVector); 396 LOG(4, "DEBUG: BondVector " << BondVector << " receives projected force of " 397 << forcelist[index]); 398 forcesum_check += forcelist[index] * BondVector; 399 } 400 ASSERT( weightiter == weights.end(), 401 "ForceAnnealing - weightiter is not at end when it should be."); 402 ASSERT( vectoriter == BondVectors.end(), 403 "ForceAnnealing - vectoriter is not at end when it should be."); 404 LOG(3, "DEBUG: sum of projected forces is " << forcesum_check); 405 } 406 333 407 } else { 334 408 LOG(2, "DEBUG: Gradient is " << walkerGradient << " less than " 335 409 << MYEPSILON << " for atom " << walker); 410 // note that projected_forces is initialized to full length and filled 411 // with zeros. Hence, nothing to do here 336 412 } 337 413 } … … 340 416 // step through each bond and shift the atoms 341 417 std::map<atomId_t, Vector> GatheredUpdates; //!< gathers all updates which are applied at the end 342 // for (size_t i = 0;i<bondvector.size();++i) { 343 // const atom* bondatom[2] = { 344 // bondvector[i]->leftatom, 345 // bondvector[i]->rightatom}; 346 // const double &bondforce = bondforces[i]; 347 // const double &oldbondforce = oldbondforces[i]; 348 // const double bondforcedifference = (bondforce - oldbondforce); 349 // Vector BondVector = (bondatom[0]->getPosition() - bondatom[1]->getPosition()); 350 // BondVector.Normalize(); 351 // double stepwidth = 0.; 352 // for (size_t n=0;n<2;++n) { 353 // const Vector oldPosition = bondatom[n]->getPositionAtStep(CurrentTimeStep-2 >= 0 ? CurrentTimeStep - 2 : 0); 354 // const Vector currentPosition = bondatom[n]->getPosition(); 355 // stepwidth += fabs((currentPosition - oldPosition).ScalarProduct(BondVector))/bondforcedifference; 356 // } 357 // stepwidth = stepwidth/2; 358 // Vector PositionUpdate = stepwidth * BondVector; 359 // if (fabs(stepwidth) < 1e-10) { 360 // // dont' warn in first step, deltat usage normal 361 // if (currentStep != 1) 362 // ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead."); 363 // PositionUpdate = currentDeltat * BondVector; 364 // } 365 // LOG(3, "DEBUG: Update would be " << PositionUpdate); 366 // 367 // // remove the edge 368 //#ifndef NDEBUG 369 // const bool status = 370 //#endif 371 // BGcreator.removeEdge(bondatom[0]->getId(), bondatom[1]->getId()); 372 // ASSERT( status, "ForceAnnealing() - edge to found bond is not present?"); 373 // 374 // // gather nodes for either atom 375 // BoostGraphHelpers::Nodeset_t bondside_set[2]; 376 // BreadthFirstSearchGatherer::distance_map_t distance_map[2]; 377 // for (size_t n=0;n<2;++n) { 378 // bondside_set[n] = NodeGatherer(bondatom[n]->getId(), max_distance); 379 // distance_map[n] = NodeGatherer.getDistances(); 380 // std::sort(bondside_set[n].begin(), bondside_set[n].end()); 381 // } 382 // 383 // // re-add edge 384 // BGcreator.addEdge(bondatom[0]->getId(), bondatom[1]->getId()); 385 // 386 // // add PositionUpdate for all nodes in the bondside_set 387 // for (size_t n=0;n<2;++n) { 388 // for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set[n].begin(); 389 // setiter != bondside_set[n].end(); ++setiter) { 390 // const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter 391 // = distance_map[n].find(*setiter); 392 // ASSERT( diter != distance_map[n].end(), 393 // "ForceAnnealing() - could not find distance to an atom."); 394 // const double factor = pow(damping_factor, diter->second); 395 // LOG(3, "DEBUG: Update for atom #" << *setiter << " will be " 396 // << factor << "*" << PositionUpdate); 397 // if (GatheredUpdates.count((*setiter))) { 398 // GatheredUpdates[(*setiter)] += factor*PositionUpdate; 399 // } else { 400 // GatheredUpdates.insert( 401 // std::make_pair( 402 // (*setiter), 403 // factor*PositionUpdate) ); 404 // } 405 // } 406 // // invert for other atom 407 // PositionUpdate *= -1; 408 // } 409 // } 410 // delete[] bondforces; 411 // delete[] oldbondforces; 418 419 LOG(3, "DEBUG: current step is " << currentStep << ", given time step is " << CurrentTimeStep); 420 const BondVectors::mapped_t bondvectors = bv.getBondVectorsAtStep(CurrentTimeStep); 421 422 for (BondVectors::container_t::const_iterator bondsiter = sorted_bonds.begin(); 423 bondsiter != sorted_bonds.end(); ++bondsiter) { 424 const bond::ptr ¤t_bond = *bondsiter; 425 const size_t index = bv.getIndexForBond(current_bond); 426 const atom* bondatom[MAX_sides] = { 427 current_bond->leftatom, 428 current_bond->rightatom 429 }; 430 431 // remove the edge 432 #ifndef NDEBUG 433 const bool status = 434 #endif 435 BGcreator.removeEdge(bondatom[leftside]->getId(), bondatom[rightside]->getId()); 436 ASSERT( status, "ForceAnnealing() - edge to found bond is not present?"); 437 438 // gather nodes for either atom 439 BoostGraphHelpers::Nodeset_t bondside_set[MAX_sides]; 440 BreadthFirstSearchGatherer::distance_map_t distance_map[MAX_sides]; 441 for (size_t side=leftside;side<MAX_sides;++side) { 442 bondside_set[side] = NodeGatherer(bondatom[side]->getId(), max_distance); 443 distance_map[side] = NodeGatherer.getDistances(); 444 std::sort(bondside_set[side].begin(), bondside_set[side].end()); 445 } 446 447 // re-add edge 448 BGcreator.addEdge(bondatom[leftside]->getId(), bondatom[rightside]->getId()); 449 450 // do for both leftatom and rightatom of bond 451 for (size_t side = leftside; side < MAX_sides; ++side) { 452 const double &bondforce = projected_forces[0][side][index]; 453 const double &oldbondforce = projected_forces[1][side][index]; 454 const double bondforcedifference = (bondforce - oldbondforce); 455 // if difference or bondforce itself is zero, do nothing 456 if ((fabs(bondforce) < MYEPSILON) || (fabs(bondforcedifference) < MYEPSILON)) 457 continue; 458 const BondVectors::mapped_t::const_iterator bviter = 459 bondvectors.find(current_bond); 460 ASSERT( bviter != bondvectors.end(), 461 "ForceAnnealing() - cannot find current_bond ?"); 462 const Vector &BondVector = bviter->second; 463 464 // calculate gradient and position differences for stepwidth 465 const Vector currentGradient = bondforce * BondVector; 466 LOG(4, "DEBUG: current projected gradient for " 467 << (side == leftside ? "left" : "right") << " side of bond is " << currentGradient); 468 const Vector &oldPosition = bondatom[side]->getPositionAtStep(CurrentTimeStep-2 >= 0 ? CurrentTimeStep - 2 : 0); 469 const Vector ¤tPosition = bondatom[side]->getPositionAtStep(CurrentTimeStep-1>=0 ? CurrentTimeStep - 1 : 0); 470 const Vector PositionDifference = currentPosition - oldPosition; 471 LOG(4, "DEBUG: old position is " << oldPosition); 472 LOG(4, "DEBUG: current position is " << currentPosition); 473 LOG(4, "DEBUG: difference in position is " << PositionDifference); 474 LOG(4, "DEBUG: bondvector is " << BondVector); 475 const double projected_PositionDifference = PositionDifference.ScalarProduct(BondVector); 476 LOG(4, "DEBUG: difference in position projected onto bondvector is " 477 << projected_PositionDifference); 478 LOG(4, "DEBUG: abs. difference in forces is " << bondforcedifference); 479 480 // calculate step width 481 Vector PositionUpdate; 482 double stepwidth = 483 fabs(projected_PositionDifference)/bondforcedifference; 484 if (fabs(stepwidth) < 1e-10) { 485 // dont' warn in first step, deltat usage normal 486 if (currentStep != 1) 487 ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead."); 488 PositionUpdate = currentDeltat * BondVector; 489 } 490 LOG(3, "DEBUG: Update would be " << PositionUpdate); 491 492 // add PositionUpdate for all nodes in the bondside_set 493 for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set[side].begin(); 494 setiter != bondside_set[side].end(); ++setiter) { 495 const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter 496 = distance_map[side].find(*setiter); 497 ASSERT( diter != distance_map[side].end(), 498 "ForceAnnealing() - could not find distance to an atom."); 499 const double factor = pow(damping_factor, diter->second); 500 LOG(3, "DEBUG: Update for atom #" << *setiter << " will be " 501 << factor << "*" << PositionUpdate); 502 if (GatheredUpdates.count((*setiter))) { 503 GatheredUpdates[(*setiter)] += factor*PositionUpdate; 504 } else { 505 GatheredUpdates.insert( 506 std::make_pair( 507 (*setiter), 508 factor*PositionUpdate) ); 509 } 510 } 511 } 512 } 412 513 413 514 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin(); … … 415 516 atom &walker = *(*iter); 416 517 // extract largest components for showing progress of annealing 417 const Vector currentGradient = walker.getAtomicForce ();518 const Vector currentGradient = walker.getAtomicForceAtStep(CurrentTimeStep-1>=0 ? CurrentTimeStep-1 : 0); 418 519 for(size_t i=0;i<NDIM;++i) 419 520 maxComponents[i] = std::max(maxComponents[i], fabs(currentGradient[i])); … … 434 535 LOG(3, "DEBUG: Applying update " << update << " to atom #" << atomid 435 536 << ", namely " << *walker); 436 walker->setPosition( walker->getPosition() + update ); 537 walker->setPosition( 538 walker->getPositionAtStep(CurrentTimeStep-1>=0 ? CurrentTimeStep - 1 : 0) 539 + update); 540 // walker->setAtomicForce( RemnantGradient_per_atom[walker->getId()] ); 437 541 } 438 542 }
Note:
See TracChangeset
for help on using the changeset viewer.