- Timestamp:
- Jul 20, 2017, 9:38:37 AM (8 years ago)
- Branches:
- ForceAnnealing_with_BondGraph_continued
- Children:
- 6d360a
- Parents:
- cc3964
- git-author:
- Frederik Heber <frederik.heber@…> (06/13/17 22:46:53)
- git-committer:
- Frederik Heber <frederik.heber@…> (07/20/17 09:38:37)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Dynamics/ForceAnnealing.hpp
rcc3964 r4cd46b 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" … … 92 94 * \todo This is not yet checked if it is correctly working with DoConstrainedMD set >0. 93 95 */ 94 void operator()(const int NextStep, const size_t offset)96 void operator()(const int CurrentTimeStep, const size_t offset) 95 97 { 96 98 // make sum of forces equal zero 97 AtomicForceManipulator<T>::correctForceMatrixForFixedCenterOfMass(offset, NextStep);99 AtomicForceManipulator<T>::correctForceMatrixForFixedCenterOfMass(offset,CurrentTimeStep); 98 100 99 101 // are we in initial step? Then set static entities … … 108 110 109 111 // get nodes on either side of selected bond via BFS discovery 110 // std::vector<atomId_t> atomids;111 // for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();112 // iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {113 // atomids.push_back((*iter)->getId());114 // }115 // ASSERT( atomids.size() == AtomicForceManipulator<T>::atoms.size(),116 // "ForceAnnealing() - could not gather all atomic ids?");117 112 BoostGraphCreator BGcreator; 118 113 BGcreator.createFromRange( … … 130 125 /// PositionUpdate. This is almost what we are going to do. 131 126 132 /// One moreissue is: If we need to shorten bond, then we use the PositionUpdate127 /// One issue is: If we need to shorten bond, then we use the PositionUpdate 133 128 /// also on the the other bond partner already. This is because it is in the 134 129 /// direction of the bond. Therefore, the update is actually performed twice on … … 140 135 /// check whether each gradient points inwards out or outwards with respect 141 136 /// to the bond and then shift accordingly. 137 142 138 /// One more issue is that the projection onto the bond directions does not 143 139 /// recover the gradient but may be larger as the bond directions are a … … 146 142 /// overestimation and obtain a weighting for each bond. 147 143 148 // gather weights 144 // initialize helper class for bond vectors using bonds from range of atoms 145 BondVectors bv; 146 bv.setFromAtomRange< T >( 147 AtomicForceManipulator<T>::atoms.begin(), 148 AtomicForceManipulator<T>::atoms.end(), 149 currentStep); 150 const BondVectors::container_t &sorted_bonds = bv.getSorted(); 151 152 // knowing the number of bonds in total, we can setup the storage for the 153 // projected forces 154 enum whichatom_t { 155 leftside=0, 156 rightside=1, 157 MAX_sides 158 }; 159 std::vector< // time step 160 std::vector< // which bond side 161 std::vector<double> > // over all bonds 162 > projected_forces(2); // one for leftatoms, one for rightatoms (and for both time steps) 163 for (size_t i=0;i<2;++i) { 164 projected_forces[i].resize(MAX_sides); 165 for (size_t j=0;j<MAX_sides;++j) 166 projected_forces[i][j].resize(sorted_bonds.size(), 0.); 167 } 168 169 // for each atom we need to gather weights and then project the gradient 149 170 typedef std::deque<double> weights_t; 150 171 typedef std::map<atomId_t, weights_t > weights_per_atom_t; 151 172 std::vector<weights_per_atom_t> weights_per_atom(2); 152 for (size_t timestep = 1; timestep <= 2; ++timestep) { 153 const size_t CurrentStep = NextStep-timestep >= 0 ? NextStep - timestep : 0; 173 for (size_t timestep = 0; timestep <= 1; ++timestep) { 174 // TODO: We have this extra step in between because of DoOutput copying 175 // change this making the code easier to understand 176 const size_t CurrentStep = CurrentTimeStep-2*timestep >= 0 ? CurrentTimeStep - 2*timestep : 0; 177 178 // get all bond vectors for this time step (from the perspective of the 179 // bonds taken from the currentStep) 180 const BondVectors::mapped_t bondvectors = bv.getBondVectorsAtStep(CurrentStep); 181 154 182 for(typename AtomSetMixin<T>::const_iterator iter = AtomicForceManipulator<T>::atoms.begin(); 155 183 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) { 156 184 const atom &walker = *(*iter); 157 185 const Vector &walkerGradient = walker.getAtomicForceAtStep(CurrentStep); 158 186 LOG(3, "DEBUG: Gradient of atom #" << walker.getId() << ", namely " 187 << walker << " is " << walkerGradient); 188 189 const BondList& ListOfBonds = walker.getListOfBonds(); 159 190 if (walkerGradient.Norm() > MYEPSILON) { 160 191 161 // gather BondVector and projected gradient over all bonds 162 const BondList& ListOfBonds = walker.getListOfBondsAtStep(CurrentStep); 163 std::vector<double> projected_forces; 192 // gather subset of BondVectors for the current atom 164 193 std::vector<Vector> BondVectors; 165 projected_forces.reserve(ListOfBonds.size());166 194 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 167 195 bonditer != ListOfBonds.end(); ++bonditer) { 168 196 const bond::ptr ¤t_bond = *bonditer; 169 BondVectors.push_back( 170 current_bond->leftatom->getPositionAtStep(CurrentStep) 171 - current_bond->rightatom->getPositionAtStep(CurrentStep)); 172 Vector &BondVector = BondVectors.back(); 173 BondVector.Normalize(); 174 projected_forces.push_back( walkerGradient.ScalarProduct(BondVector) ); 197 const BondVectors::mapped_t::const_iterator bviter = 198 bondvectors.find(current_bond); 199 ASSERT( bviter != bondvectors.end(), 200 "ForceAnnealing() - cannot find current_bond ?"); 201 ASSERT( bviter != bondvectors.end(), 202 "ForceAnnealing - cannot find current bond "+toString(*current_bond) 203 +" in bonds."); 204 BondVectors.push_back(bviter->second); 175 205 } 176 177 // go through all bonds and check what magnitude is represented by the others 178 // i.e. sum of scalar products against other bonds 206 LOG(4, "DEBUG: BondVectors for atom #" << walker.getId() << ": " << BondVectors); 207 208 // go through all its bonds and calculate what magnitude is represented 209 // by the others i.e. sum of scalar products against other bonds 179 210 std::pair<weights_per_atom_t::iterator, bool> inserter = 180 weights_per_atom[timestep -1].insert(211 weights_per_atom[timestep].insert( 181 212 std::make_pair(walker.getId(), weights_t()) ); 182 213 ASSERT( inserter.second, 183 214 "ForceAnnealing::operator() - weight map for atom "+toString(walker) 184 +" and time step "+toString(timestep -1)+" already filled?");215 +" and time step "+toString(timestep)+" already filled?"); 185 216 weights_t &weights = inserter.first->second; 186 217 for (std::vector<Vector>::const_iterator iter = BondVectors.begin(); 187 218 iter != BondVectors.end(); ++iter) { 188 219 std::vector<double> scps; 220 scps.reserve(BondVectors.size()); 189 221 std::transform( 190 222 BondVectors.begin(), BondVectors.end(), 191 223 std::back_inserter(scps), 192 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1) 224 boost::bind(static_cast< double (*)(double) >(&fabs), 225 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1)) 193 226 ); 194 227 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.); 228 ASSERT( (scp_sum-1.) > -MYEPSILON, 229 "ForceAnnealing() - sum of weights must be equal or larger one but is " 230 +toString(scp_sum)); 195 231 weights.push_back( 1./scp_sum ); 196 232 } 233 LOG(4, "DEBUG: Weights for atom #" << walker.getId() << ": " << weights); 234 197 235 // for testing we check whether all weighted scalar products now come out as 1. 198 236 #ifndef NDEBUG 199 237 for (std::vector<Vector>::const_iterator iter = BondVectors.begin(); 200 238 iter != BondVectors.end(); ++iter) { 201 double scp_sum = 0.; 202 weights_t::const_iterator weightiter = weights.begin(); 203 for (std::vector<Vector>::const_iterator otheriter = BondVectors.begin(); 204 otheriter != BondVectors.end(); ++otheriter, ++weightiter) { 205 scp_sum += (*weightiter)*(*iter).ScalarProduct(*otheriter); 206 } 239 std::vector<double> scps; 240 scps.reserve(BondVectors.size()); 241 std::transform( 242 BondVectors.begin(), BondVectors.end(), 243 weights.begin(), 244 std::back_inserter(scps), 245 boost::bind(static_cast< double (*)(double) >(&fabs), 246 boost::bind(std::multiplies<double>(), 247 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1), 248 _2)) 249 ); 250 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.); 207 251 ASSERT( fabs(scp_sum - 1.) < MYEPSILON, 208 252 "ForceAnnealing::operator() - for BondVector "+toString(*iter) … … 210 254 } 211 255 #endif 256 257 // projected gradient over all bonds and place in one of projected_forces 258 // using the obtained weights 259 { 260 weights_t::const_iterator weightiter = weights.begin(); 261 std::vector<Vector>::const_iterator vectoriter = BondVectors.begin(); 262 Vector forcesum_check; 263 for(BondList::const_iterator bonditer = ListOfBonds.begin(); 264 bonditer != ListOfBonds.end(); ++bonditer, ++weightiter, ++vectoriter) { 265 const bond::ptr ¤t_bond = *bonditer; 266 const Vector &BondVector = *vectoriter; 267 268 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ? 269 projected_forces[timestep][leftside] : projected_forces[timestep][rightside]; 270 const size_t index = bv.getIndexForBond(current_bond); 271 ASSERT( index != (size_t)-1, 272 "ForceAnnealing() - could not find bond "+toString(*current_bond) 273 +" in bondvectors"); 274 forcelist[index] = (*weightiter)*walkerGradient.ScalarProduct(BondVector); 275 LOG(4, "DEBUG: BondVector " << BondVector << " receives projected force of " 276 << forcelist[index]); 277 forcesum_check += forcelist[index] * BondVector; 278 } 279 ASSERT( weightiter == weights.end(), 280 "ForceAnnealing - weightiter is not at end when it should be."); 281 ASSERT( vectoriter == BondVectors.end(), 282 "ForceAnnealing - vectoriter is not at end when it should be."); 283 LOG(3, "DEBUG: sum of projected forces is " << forcesum_check); 284 } 285 212 286 } else { 213 287 LOG(2, "DEBUG: Gradient is " << walkerGradient << " less than " 214 288 << MYEPSILON << " for atom " << walker); 289 // note that projected_forces is initialized to full length and filled 290 // with zeros. Hence, nothing to do here 215 291 } 216 292 } … … 219 295 // step through each bond and shift the atoms 220 296 std::map<atomId_t, Vector> GatheredUpdates; //!< gathers all updates which are applied at the end 221 // for (size_t i = 0;i<bondvector.size();++i) { 222 // const atom* bondatom[2] = { 223 // bondvector[i]->leftatom, 224 // bondvector[i]->rightatom}; 225 // const double &bondforce = bondforces[i]; 226 // const double &oldbondforce = oldbondforces[i]; 227 // const double bondforcedifference = (bondforce - oldbondforce); 228 // Vector BondVector = (bondatom[0]->getPosition() - bondatom[1]->getPosition()); 229 // BondVector.Normalize(); 230 // double stepwidth = 0.; 231 // for (size_t n=0;n<2;++n) { 232 // const Vector oldPosition = bondatom[n]->getPositionAtStep(NextStep-2 >= 0 ? NextStep - 2 : 0); 233 // const Vector currentPosition = bondatom[n]->getPosition(); 234 // stepwidth += fabs((currentPosition - oldPosition).ScalarProduct(BondVector))/bondforcedifference; 235 // } 236 // stepwidth = stepwidth/2; 237 // Vector PositionUpdate = stepwidth * BondVector; 238 // if (fabs(stepwidth) < 1e-10) { 239 // // dont' warn in first step, deltat usage normal 240 // if (currentStep != 1) 241 // ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead."); 242 // PositionUpdate = currentDeltat * BondVector; 243 // } 244 // LOG(3, "DEBUG: Update would be " << PositionUpdate); 245 // 246 // // remove the edge 247 //#ifndef NDEBUG 248 // const bool status = 249 //#endif 250 // BGcreator.removeEdge(bondatom[0]->getId(), bondatom[1]->getId()); 251 // ASSERT( status, "ForceAnnealing() - edge to found bond is not present?"); 252 // 253 // // gather nodes for either atom 254 // BoostGraphHelpers::Nodeset_t bondside_set[2]; 255 // BreadthFirstSearchGatherer::distance_map_t distance_map[2]; 256 // for (size_t n=0;n<2;++n) { 257 // bondside_set[n] = NodeGatherer(bondatom[n]->getId(), max_distance); 258 // distance_map[n] = NodeGatherer.getDistances(); 259 // std::sort(bondside_set[n].begin(), bondside_set[n].end()); 260 // } 261 // 262 // // re-add edge 263 // BGcreator.addEdge(bondatom[0]->getId(), bondatom[1]->getId()); 264 // 265 // // add PositionUpdate for all nodes in the bondside_set 266 // for (size_t n=0;n<2;++n) { 267 // for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set[n].begin(); 268 // setiter != bondside_set[n].end(); ++setiter) { 269 // const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter 270 // = distance_map[n].find(*setiter); 271 // ASSERT( diter != distance_map[n].end(), 272 // "ForceAnnealing() - could not find distance to an atom."); 273 // const double factor = pow(damping_factor, diter->second); 274 // LOG(3, "DEBUG: Update for atom #" << *setiter << " will be " 275 // << factor << "*" << PositionUpdate); 276 // if (GatheredUpdates.count((*setiter))) { 277 // GatheredUpdates[(*setiter)] += factor*PositionUpdate; 278 // } else { 279 // GatheredUpdates.insert( 280 // std::make_pair( 281 // (*setiter), 282 // factor*PositionUpdate) ); 283 // } 284 // } 285 // // invert for other atom 286 // PositionUpdate *= -1; 287 // } 288 // } 289 // delete[] bondforces; 290 // delete[] oldbondforces; 297 298 LOG(3, "DEBUG: current step is " << currentStep << ", given time step is " << CurrentTimeStep); 299 const BondVectors::mapped_t bondvectors = bv.getBondVectorsAtStep(currentStep); 300 301 for (BondVectors::container_t::const_iterator bondsiter = sorted_bonds.begin(); 302 bondsiter != sorted_bonds.end(); ++bondsiter) { 303 const bond::ptr ¤t_bond = *bondsiter; 304 const size_t index = bv.getIndexForBond(current_bond); 305 const atom* bondatom[MAX_sides] = { 306 current_bond->leftatom, 307 current_bond->rightatom 308 }; 309 310 // remove the edge 311 #ifndef NDEBUG 312 const bool status = 313 #endif 314 BGcreator.removeEdge(bondatom[leftside]->getId(), bondatom[rightside]->getId()); 315 ASSERT( status, "ForceAnnealing() - edge to found bond is not present?"); 316 317 // gather nodes for either atom 318 BoostGraphHelpers::Nodeset_t bondside_set[MAX_sides]; 319 BreadthFirstSearchGatherer::distance_map_t distance_map[MAX_sides]; 320 for (size_t side=leftside;side<MAX_sides;++side) { 321 bondside_set[side] = NodeGatherer(bondatom[side]->getId(), max_distance); 322 distance_map[side] = NodeGatherer.getDistances(); 323 std::sort(bondside_set[side].begin(), bondside_set[side].end()); 324 } 325 326 // re-add edge 327 BGcreator.addEdge(bondatom[leftside]->getId(), bondatom[rightside]->getId()); 328 329 // do for both leftatom and rightatom of bond 330 for (size_t side = leftside; side < MAX_sides; ++side) { 331 const double &bondforce = projected_forces[0][side][index]; 332 const double &oldbondforce = projected_forces[1][side][index]; 333 const double bondforcedifference = (bondforce - oldbondforce); 334 // if difference or bondforce itself is zero, do nothing 335 if ((fabs(bondforce) < MYEPSILON) || (fabs(bondforcedifference) < MYEPSILON)) 336 continue; 337 const BondVectors::mapped_t::const_iterator bviter = 338 bondvectors.find(current_bond); 339 ASSERT( bviter != bondvectors.end(), 340 "ForceAnnealing() - cannot find current_bond ?"); 341 const Vector &BondVector = bviter->second; 342 const Vector &oldPosition = bondatom[side]->getPositionAtStep(CurrentTimeStep-1 >= 0 ? CurrentTimeStep - 1 : 0); 343 const Vector ¤tPosition = bondatom[side]->getPosition(); 344 const double stepwidth = 345 fabs((currentPosition - oldPosition).ScalarProduct(BondVector))/bondforcedifference; 346 Vector PositionUpdate = stepwidth * BondVector; 347 if (fabs(stepwidth) < 1e-10) { 348 // dont' warn in first step, deltat usage normal 349 if (currentStep != 1) 350 ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead."); 351 PositionUpdate = currentDeltat * BondVector; 352 } 353 LOG(3, "DEBUG: Update would be " << PositionUpdate); 354 355 // add PositionUpdate for all nodes in the bondside_set 356 for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set[side].begin(); 357 setiter != bondside_set[side].end(); ++setiter) { 358 const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter 359 = distance_map[side].find(*setiter); 360 ASSERT( diter != distance_map[side].end(), 361 "ForceAnnealing() - could not find distance to an atom."); 362 const double factor = pow(damping_factor, diter->second); 363 LOG(3, "DEBUG: Update for atom #" << *setiter << " will be " 364 << factor << "*" << PositionUpdate); 365 if (GatheredUpdates.count((*setiter))) { 366 GatheredUpdates[(*setiter)] += factor*PositionUpdate; 367 } else { 368 GatheredUpdates.insert( 369 std::make_pair( 370 (*setiter), 371 factor*PositionUpdate) ); 372 } 373 } 374 } 375 } 291 376 292 377 Vector maxComponents(zeroVec);
Note:
See TracChangeset
for help on using the changeset viewer.