source: src/Dynamics/ForceAnnealing.hpp@ 6458e7

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
Last change on this file since 6458e7 was 6458e7, checked in by Frederik Heber <frederik.heber@…>, 7 years ago

ForceAnnealing can now be used either atom- or bond-centered.

  • atom is old annealing method, bond graph is new annealing method where the bond neighborhood is shifted as well to anneal to force projected onto the BondVector.
  • In the first step we always use atom-centered annealing where we use the given deltat step width. Afterwards Barzilai-Borwein may then proceed.
  • Property mode set to 100644
File size: 25.4 KB
Line 
1/*
2 * ForceAnnealing.hpp
3 *
4 * Created on: Aug 02, 2014
5 * Author: heber
6 */
7
8#ifndef FORCEANNEALING_HPP_
9#define FORCEANNEALING_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <algorithm>
17#include <functional>
18#include <iterator>
19
20#include <boost/bind.hpp>
21
22#include "Atom/atom.hpp"
23#include "Atom/AtomSet.hpp"
24#include "CodePatterns/Assert.hpp"
25#include "CodePatterns/Info.hpp"
26#include "CodePatterns/Log.hpp"
27#include "CodePatterns/Verbose.hpp"
28#include "Descriptors/AtomIdDescriptor.hpp"
29#include "Dynamics/AtomicForceManipulator.hpp"
30#include "Dynamics/BondVectors.hpp"
31#include "Fragmentation/ForceMatrix.hpp"
32#include "Graph/BoostGraphCreator.hpp"
33#include "Graph/BoostGraphHelpers.hpp"
34#include "Graph/BreadthFirstSearchGatherer.hpp"
35#include "Helpers/helpers.hpp"
36#include "Helpers/defs.hpp"
37#include "LinearAlgebra/LinearSystemOfEquations.hpp"
38#include "LinearAlgebra/MatrixContent.hpp"
39#include "LinearAlgebra/Vector.hpp"
40#include "LinearAlgebra/VectorContent.hpp"
41#include "Thermostats/ThermoStatContainer.hpp"
42#include "Thermostats/Thermostat.hpp"
43#include "World.hpp"
44
45/** This class is the essential build block for performing structural optimization.
46 *
47 * Sadly, we have to use some static instances as so far values cannot be passed
48 * between actions. Hence, we need to store the current step and the adaptive-
49 * step width (we cannot perform a line search, as we have no control over the
50 * calculation of the forces).
51 *
52 * However, we do use the bond graph, i.e. if a single atom needs to be shifted
53 * to the left, then the whole molecule left of it is shifted, too. This is
54 * controlled by the \a max_distance parameter.
55 */
56template <class T>
57class ForceAnnealing : public AtomicForceManipulator<T>
58{
59public:
60 /** Constructor of class ForceAnnealing.
61 *
62 * \note We use a fixed delta t of 1.
63 *
64 * \param _atoms set of atoms to integrate
65 * \param _Deltat time step width in atomic units
66 * \param _IsAngstroem whether length units are in angstroem or bohr radii
67 * \param _maxSteps number of optimization steps to perform
68 * \param _max_distance up to this bond order is bond graph taken into account.
69 */
70 ForceAnnealing(
71 AtomSetMixin<T> &_atoms,
72 const double _Deltat,
73 bool _IsAngstroem,
74 const size_t _maxSteps,
75 const int _max_distance,
76 const double _damping_factor) :
77 AtomicForceManipulator<T>(_atoms, _Deltat, _IsAngstroem),
78 maxSteps(_maxSteps),
79 max_distance(_max_distance),
80 damping_factor(_damping_factor)
81 {}
82
83 /** Destructor of class ForceAnnealing.
84 *
85 */
86 ~ForceAnnealing()
87 {}
88
89 /** Performs Gradient optimization.
90 *
91 * We assume that forces have just been calculated.
92 *
93 *
94 * \param CurrentTimeStep current time step (i.e. \f$ t + \Delta t \f$ in the sense of the velocity verlet)
95 * \param offset offset in matrix file to the first force component
96 * \todo This is not yet checked if it is correctly working with DoConstrainedMD set >0.
97 */
98 void operator()(
99 const int _CurrentTimeStep,
100 const size_t _offset,
101 const bool _UseBondgraph)
102 {
103 // make sum of forces equal zero
104 AtomicForceManipulator<T>::correctForceMatrixForFixedCenterOfMass(
105 _offset,
106 _CurrentTimeStep-1>=0 ? _CurrentTimeStep - 1 : 0);
107
108 // are we in initial step? Then set static entities
109 Vector maxComponents(zeroVec);
110 if (currentStep == 0) {
111 currentDeltat = AtomicForceManipulator<T>::Deltat;
112 currentStep = 1;
113 LOG(2, "DEBUG: Initial step, setting values, current step is #" << currentStep);
114
115 // always use atomic annealing on first step
116 anneal(_CurrentTimeStep, _offset, maxComponents);
117 } else {
118 ++currentStep;
119 LOG(2, "DEBUG: current step is #" << currentStep);
120
121 if (_UseBondgraph)
122 annealWithBondGraph(_CurrentTimeStep, _offset, maxComponents);
123 else
124 anneal(_CurrentTimeStep, _offset, maxComponents);
125 }
126
127
128 LOG(1, "STATUS: Largest remaining force components at step #"
129 << currentStep << " are " << maxComponents);
130
131 // are we in final step? Remember to reset static entities
132 if (currentStep == maxSteps) {
133 LOG(2, "DEBUG: Final step, resetting values");
134 reset();
135 }
136 }
137
138 /** Helper function to calculate the Barzilai-Borwein stepwidth.
139 *
140 * \param _PositionDifference difference in position between current and last step
141 * \param _GradientDifference difference in gradient between current and last step
142 * \return step width according to Barzilai-Borwein
143 */
144 double getBarzilaiBorweinStepwidth(const Vector &_PositionDifference, const Vector &_GradientDifference)
145 {
146 double stepwidth = 0.;
147 if (_GradientDifference.NormSquared() > MYEPSILON)
148 stepwidth = fabs(_PositionDifference.ScalarProduct(_GradientDifference))/
149 _GradientDifference.NormSquared();
150 if (fabs(stepwidth) < 1e-10) {
151 // dont' warn in first step, deltat usage normal
152 if (currentStep != 1)
153 ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead.");
154 stepwidth = currentDeltat;
155 }
156 return stepwidth;
157 }
158
159 /** Performs Gradient optimization on the atoms.
160 *
161 * We assume that forces have just been calculated.
162 *
163 * \param CurrentTimeStep current time step (i.e. \f$ t + \Delta t \f$ in the sense of the velocity verlet)
164 * \param offset offset in matrix file to the first force component
165 * \param maxComponents to be filled with maximum force component over all atoms
166 */
167 void anneal(
168 const int CurrentTimeStep,
169 const size_t offset,
170 Vector &maxComponents)
171 {
172 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();
173 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
174 // atom's force vector gives steepest descent direction
175 const Vector oldPosition = (*iter)->getPositionAtStep(CurrentTimeStep-1 >= 0 ? CurrentTimeStep - 1 : 0);
176 const Vector currentPosition = (*iter)->getPositionAtStep(CurrentTimeStep);
177 const Vector oldGradient = (*iter)->getAtomicForceAtStep(CurrentTimeStep-1 >= 0 ? CurrentTimeStep - 1 : 0);
178 const Vector currentGradient = (*iter)->getAtomicForceAtStep(CurrentTimeStep);
179 LOG(4, "DEBUG: oldPosition for atom " << **iter << " is " << oldPosition);
180 LOG(4, "DEBUG: currentPosition for atom " << **iter << " is " << currentPosition);
181 LOG(4, "DEBUG: oldGradient for atom " << **iter << " is " << oldGradient);
182 LOG(4, "DEBUG: currentGradient for atom " << **iter << " is " << currentGradient);
183// LOG(4, "DEBUG: Force for atom " << **iter << " is " << currentGradient);
184
185 // we use Barzilai-Borwein update with position reversed to get descent
186 const double stepwidth = getBarzilaiBorweinStepwidth(
187 currentPosition - oldPosition, currentGradient - oldGradient);
188 Vector PositionUpdate = stepwidth * currentGradient;
189 LOG(3, "DEBUG: Update would be " << stepwidth << "*" << currentGradient << " = " << PositionUpdate);
190
191 // extract largest components for showing progress of annealing
192 for(size_t i=0;i<NDIM;++i)
193 maxComponents[i] = std::max(maxComponents[i], fabs(currentGradient[i]));
194
195 // are we in initial step? Then don't check against velocity
196 if ((currentStep > 1) && (!(*iter)->getAtomicVelocity().IsZero()))
197 // update with currentDelta tells us how the current gradient relates to
198 // the last one: If it has become larger, reduce currentDelta
199 if ((PositionUpdate.ScalarProduct((*iter)->getAtomicVelocity()) < 0)
200 && (currentDeltat > MinimumDeltat)) {
201 currentDeltat = .5*currentDeltat;
202 LOG(2, "DEBUG: Upgrade in other direction: " << PositionUpdate.NormSquared()
203 << " > " << (*iter)->getAtomicVelocity().NormSquared()
204 << ", decreasing deltat: " << currentDeltat);
205 PositionUpdate = currentDeltat * currentGradient;
206 }
207 // finally set new values
208 (*iter)->setPosition(currentPosition + PositionUpdate);
209 (*iter)->setAtomicVelocity(PositionUpdate);
210 //std::cout << "Id of atom is " << (*iter)->getId() << std::endl;
211// (*iter)->VelocityVerletUpdateU((*iter)->getId(), CurrentTimeStep-1, Deltat, IsAngstroem);
212 }
213 }
214
215 /** Performs Gradient optimization on the bonds.
216 *
217 * We assume that forces have just been calculated. These forces are projected
218 * onto the bonds and these are annealed subsequently by moving atoms in the
219 * bond neighborhood on either side conjunctively.
220 *
221 *
222 * \param CurrentTimeStep current time step (i.e. \f$ t + \Delta t \f$ in the sense of the velocity verlet)
223 * \param offset offset in matrix file to the first force component
224 * \param maxComponents to be filled with maximum force component over all atoms
225 */
226 void annealWithBondGraph(
227 const int CurrentTimeStep,
228 const size_t offset,
229 Vector &maxComponents)
230 {
231 // get nodes on either side of selected bond via BFS discovery
232 BoostGraphCreator BGcreator;
233 BGcreator.createFromRange(
234 AtomicForceManipulator<T>::atoms.begin(),
235 AtomicForceManipulator<T>::atoms.end(),
236 AtomicForceManipulator<T>::atoms.size(),
237 BreadthFirstSearchGatherer::AlwaysTruePredicate);
238 BreadthFirstSearchGatherer NodeGatherer(BGcreator);
239
240 /// We assume that a force is local, i.e. a bond is too short yet and hence
241 /// the atom needs to be moved. However, all the adjacent (bound) atoms might
242 /// already be at the perfect distance. If we just move the atom alone, we ruin
243 /// all the other bonds. Hence, it would be sensible to move every atom found
244 /// through the bond graph in the direction of the force as well by the same
245 /// PositionUpdate. This is almost what we are going to do.
246
247 /// One issue is: If we need to shorten bond, then we use the PositionUpdate
248 /// also on the the other bond partner already. This is because it is in the
249 /// direction of the bond. Therefore, the update is actually performed twice on
250 /// each bond partner, i.e. the step size is twice as large as it should be.
251 /// This problem only occurs when bonds need to be shortened, not when they
252 /// need to be made longer (then the force vector is facing the other
253 /// direction than the bond vector).
254 /// As a remedy we need to average the force on either end of the bond and
255 /// check whether each gradient points inwards out or outwards with respect
256 /// to the bond and then shift accordingly.
257
258 /// One more issue is that the projection onto the bond directions does not
259 /// recover the gradient but may be larger as the bond directions are a
260 /// generating system and not a basis (e.g. 3 bonds on a plane where 2 would
261 /// suffice to span the plane). To this end, we need to account for the
262 /// overestimation and obtain a weighting for each bond.
263
264 // initialize helper class for bond vectors using bonds from range of atoms
265 BondVectors bv;
266 bv.setFromAtomRange< T >(
267 AtomicForceManipulator<T>::atoms.begin(),
268 AtomicForceManipulator<T>::atoms.end(),
269 CurrentTimeStep);
270 const BondVectors::container_t &sorted_bonds = bv.getSorted();
271
272 // knowing the number of bonds in total, we can setup the storage for the
273 // projected forces
274 enum whichatom_t {
275 leftside=0,
276 rightside=1,
277 MAX_sides
278 };
279 std::vector< // time step
280 std::vector< // which bond side
281 std::vector<double> > // over all bonds
282 > projected_forces(2); // one for leftatoms, one for rightatoms (and for both time steps)
283 for (size_t i=0;i<2;++i) {
284 projected_forces[i].resize(MAX_sides);
285 for (size_t j=0;j<MAX_sides;++j)
286 projected_forces[i][j].resize(sorted_bonds.size(), 0.);
287 }
288
289 // for each atom we need to gather weights and then project the gradient
290 typedef std::deque<double> weights_t;
291 typedef std::map<atomId_t, weights_t > weights_per_atom_t;
292 std::vector<weights_per_atom_t> weights_per_atom(2);
293 for (size_t timestep = 0; timestep <= 1; ++timestep) {
294 const size_t CurrentStep = CurrentTimeStep-timestep-1 >= 0 ? CurrentTimeStep-timestep-1 : 0;
295 LOG(2, "DEBUG: CurrentTimeStep is " << CurrentTimeStep
296 << ", timestep is " << timestep
297 << ", and CurrentStep is " << CurrentStep);
298
299 // get all bond vectors for this time step (from the perspective of the
300 // bonds taken from the currentStep)
301 const BondVectors::mapped_t bondvectors = bv.getBondVectorsAtStep(CurrentStep);
302
303 for(typename AtomSetMixin<T>::const_iterator iter = AtomicForceManipulator<T>::atoms.begin();
304 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
305 const atom &walker = *(*iter);
306 const Vector &walkerGradient = walker.getAtomicForceAtStep(CurrentStep);
307 LOG(3, "DEBUG: Gradient of atom #" << walker.getId() << ", namely "
308 << walker << " is " << walkerGradient << " with magnitude of "
309 << walkerGradient.Norm());
310
311 const BondList& ListOfBonds = walker.getListOfBonds();
312 if (walkerGradient.Norm() > MYEPSILON) {
313
314 // gather subset of BondVectors for the current atom
315 std::vector<Vector> BondVectors;
316 for(BondList::const_iterator bonditer = ListOfBonds.begin();
317 bonditer != ListOfBonds.end(); ++bonditer) {
318 const bond::ptr &current_bond = *bonditer;
319 const BondVectors::mapped_t::const_iterator bviter =
320 bondvectors.find(current_bond);
321 ASSERT( bviter != bondvectors.end(),
322 "ForceAnnealing() - cannot find current_bond ?");
323 ASSERT( bviter != bondvectors.end(),
324 "ForceAnnealing - cannot find current bond "+toString(*current_bond)
325 +" in bonds.");
326 BondVectors.push_back(bviter->second);
327 }
328 LOG(4, "DEBUG: BondVectors for atom #" << walker.getId() << ": " << BondVectors);
329
330 // go through all its bonds and calculate what magnitude is represented
331 // by the others i.e. sum of scalar products against other bonds
332 std::pair<weights_per_atom_t::iterator, bool> inserter =
333 weights_per_atom[timestep].insert(
334 std::make_pair(walker.getId(), weights_t()) );
335 ASSERT( inserter.second,
336 "ForceAnnealing::operator() - weight map for atom "+toString(walker)
337 +" and time step "+toString(timestep)+" already filled?");
338 weights_t &weights = inserter.first->second;
339 for (std::vector<Vector>::const_iterator iter = BondVectors.begin();
340 iter != BondVectors.end(); ++iter) {
341 std::vector<double> scps;
342 scps.reserve(BondVectors.size());
343 std::transform(
344 BondVectors.begin(), BondVectors.end(),
345 std::back_inserter(scps),
346 boost::bind(static_cast< double (*)(double) >(&fabs),
347 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1))
348 );
349 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.);
350 ASSERT( (scp_sum-1.) > -MYEPSILON,
351 "ForceAnnealing() - sum of weights must be equal or larger one but is "
352 +toString(scp_sum));
353 weights.push_back( 1./scp_sum );
354 }
355 LOG(4, "DEBUG: Weights for atom #" << walker.getId() << ": " << weights);
356
357 // for testing we check whether all weighted scalar products now come out as 1.
358#ifndef NDEBUG
359 for (std::vector<Vector>::const_iterator iter = BondVectors.begin();
360 iter != BondVectors.end(); ++iter) {
361 std::vector<double> scps;
362 scps.reserve(BondVectors.size());
363 std::transform(
364 BondVectors.begin(), BondVectors.end(),
365 weights.begin(),
366 std::back_inserter(scps),
367 boost::bind(static_cast< double (*)(double) >(&fabs),
368 boost::bind(std::multiplies<double>(),
369 boost::bind(&Vector::ScalarProduct, boost::cref(*iter), _1),
370 _2))
371 );
372 const double scp_sum = std::accumulate(scps.begin(), scps.end(), 0.);
373 ASSERT( fabs(scp_sum - 1.) < MYEPSILON,
374 "ForceAnnealing::operator() - for BondVector "+toString(*iter)
375 +" we have weighted scalar product of "+toString(scp_sum)+" != 1.");
376 }
377#endif
378
379 // projected gradient over all bonds and place in one of projected_forces
380 // using the obtained weights
381 {
382 weights_t::const_iterator weightiter = weights.begin();
383 std::vector<Vector>::const_iterator vectoriter = BondVectors.begin();
384 Vector forcesum_check;
385 for(BondList::const_iterator bonditer = ListOfBonds.begin();
386 bonditer != ListOfBonds.end(); ++bonditer, ++weightiter, ++vectoriter) {
387 const bond::ptr &current_bond = *bonditer;
388 const Vector &BondVector = *vectoriter;
389
390 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ?
391 projected_forces[timestep][leftside] : projected_forces[timestep][rightside];
392 const size_t index = bv.getIndexForBond(current_bond);
393 ASSERT( index != (size_t)-1,
394 "ForceAnnealing() - could not find bond "+toString(*current_bond)
395 +" in bondvectors");
396 forcelist[index] = (*weightiter)*walkerGradient.ScalarProduct(BondVector);
397 LOG(4, "DEBUG: BondVector " << BondVector << " receives projected force of "
398 << forcelist[index]);
399 forcesum_check += forcelist[index] * BondVector;
400 }
401 ASSERT( weightiter == weights.end(),
402 "ForceAnnealing - weightiter is not at end when it should be.");
403 ASSERT( vectoriter == BondVectors.end(),
404 "ForceAnnealing - vectoriter is not at end when it should be.");
405 LOG(3, "DEBUG: sum of projected forces is " << forcesum_check);
406 }
407
408 } else {
409 LOG(2, "DEBUG: Gradient is " << walkerGradient << " less than "
410 << MYEPSILON << " for atom " << walker);
411 // note that projected_forces is initialized to full length and filled
412 // with zeros. Hence, nothing to do here
413 }
414 }
415 }
416
417 // step through each bond and shift the atoms
418 std::map<atomId_t, Vector> GatheredUpdates; //!< gathers all updates which are applied at the end
419
420 LOG(3, "DEBUG: current step is " << currentStep << ", given time step is " << CurrentTimeStep);
421 const BondVectors::mapped_t bondvectors = bv.getBondVectorsAtStep(CurrentTimeStep);
422
423 for (BondVectors::container_t::const_iterator bondsiter = sorted_bonds.begin();
424 bondsiter != sorted_bonds.end(); ++bondsiter) {
425 const bond::ptr &current_bond = *bondsiter;
426 const size_t index = bv.getIndexForBond(current_bond);
427 const atom* bondatom[MAX_sides] = {
428 current_bond->leftatom,
429 current_bond->rightatom
430 };
431
432 // remove the edge
433#ifndef NDEBUG
434 const bool status =
435#endif
436 BGcreator.removeEdge(bondatom[leftside]->getId(), bondatom[rightside]->getId());
437 ASSERT( status, "ForceAnnealing() - edge to found bond is not present?");
438
439 // gather nodes for either atom
440 BoostGraphHelpers::Nodeset_t bondside_set[MAX_sides];
441 BreadthFirstSearchGatherer::distance_map_t distance_map[MAX_sides];
442 for (size_t side=leftside;side<MAX_sides;++side) {
443 bondside_set[side] = NodeGatherer(bondatom[side]->getId(), max_distance);
444 distance_map[side] = NodeGatherer.getDistances();
445 std::sort(bondside_set[side].begin(), bondside_set[side].end());
446 }
447
448 // re-add edge
449 BGcreator.addEdge(bondatom[leftside]->getId(), bondatom[rightside]->getId());
450
451 // do for both leftatom and rightatom of bond
452 for (size_t side = leftside; side < MAX_sides; ++side) {
453 const double &bondforce = projected_forces[0][side][index];
454 const double &oldbondforce = projected_forces[1][side][index];
455 const double bondforcedifference = (bondforce - oldbondforce);
456 // if difference or bondforce itself is zero, do nothing
457 if ((fabs(bondforce) < MYEPSILON) || (fabs(bondforcedifference) < MYEPSILON))
458 continue;
459 const BondVectors::mapped_t::const_iterator bviter =
460 bondvectors.find(current_bond);
461 ASSERT( bviter != bondvectors.end(),
462 "ForceAnnealing() - cannot find current_bond ?");
463 const Vector &BondVector = bviter->second;
464
465 // calculate gradient and position differences for stepwidth
466 const Vector currentGradient = bondforce * BondVector;
467 LOG(4, "DEBUG: current projected gradient for "
468 << (side == leftside ? "left" : "right") << " side of bond is " << currentGradient);
469 const Vector &oldPosition = bondatom[side]->getPositionAtStep(CurrentTimeStep-2 >= 0 ? CurrentTimeStep - 2 : 0);
470 const Vector &currentPosition = bondatom[side]->getPositionAtStep(CurrentTimeStep-1>=0 ? CurrentTimeStep - 1 : 0);
471 const Vector PositionDifference = currentPosition - oldPosition;
472 LOG(4, "DEBUG: old position is " << oldPosition);
473 LOG(4, "DEBUG: current position is " << currentPosition);
474 LOG(4, "DEBUG: difference in position is " << PositionDifference);
475 LOG(4, "DEBUG: bondvector is " << BondVector);
476 const double projected_PositionDifference = PositionDifference.ScalarProduct(BondVector);
477 LOG(4, "DEBUG: difference in position projected onto bondvector is "
478 << projected_PositionDifference);
479 LOG(4, "DEBUG: abs. difference in forces is " << bondforcedifference);
480
481 // calculate step width
482 Vector PositionUpdate;
483 double stepwidth =
484 fabs(projected_PositionDifference)/bondforcedifference;
485 if (fabs(stepwidth) < 1e-10) {
486 // dont' warn in first step, deltat usage normal
487 if (currentStep != 1)
488 ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead.");
489 PositionUpdate = currentDeltat * BondVector;
490 }
491 LOG(3, "DEBUG: Update would be " << PositionUpdate);
492
493 // add PositionUpdate for all nodes in the bondside_set
494 for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set[side].begin();
495 setiter != bondside_set[side].end(); ++setiter) {
496 const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter
497 = distance_map[side].find(*setiter);
498 ASSERT( diter != distance_map[side].end(),
499 "ForceAnnealing() - could not find distance to an atom.");
500 const double factor = pow(damping_factor, diter->second);
501 LOG(3, "DEBUG: Update for atom #" << *setiter << " will be "
502 << factor << "*" << PositionUpdate);
503 if (GatheredUpdates.count((*setiter))) {
504 GatheredUpdates[(*setiter)] += factor*PositionUpdate;
505 } else {
506 GatheredUpdates.insert(
507 std::make_pair(
508 (*setiter),
509 factor*PositionUpdate) );
510 }
511 }
512 }
513 }
514
515 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();
516 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
517 atom &walker = *(*iter);
518 // extract largest components for showing progress of annealing
519 const Vector currentGradient = walker.getAtomicForceAtStep(CurrentTimeStep-1>=0 ? CurrentTimeStep-1 : 0);
520 for(size_t i=0;i<NDIM;++i)
521 maxComponents[i] = std::max(maxComponents[i], fabs(currentGradient[i]));
522
523 // reset force vector for next step except on final one
524 if (currentStep != maxSteps)
525 walker.setAtomicForce(zeroVec);
526 }
527
528 // apply the gathered updates
529 for (std::map<atomId_t, Vector>::const_iterator iter = GatheredUpdates.begin();
530 iter != GatheredUpdates.end(); ++iter) {
531 const atomId_t &atomid = iter->first;
532 const Vector &update = iter->second;
533 atom* const walker = World::getInstance().getAtom(AtomById(atomid));
534 ASSERT( walker != NULL,
535 "ForceAnnealing() - walker with id "+toString(atomid)+" has suddenly disappeared.");
536 LOG(3, "DEBUG: Applying update " << update << " to atom #" << atomid
537 << ", namely " << *walker);
538 walker->setPosition(
539 walker->getPositionAtStep(CurrentTimeStep-1>=0 ? CurrentTimeStep - 1 : 0)
540 + update);
541 walker->setAtomicVelocity(update);
542// walker->setAtomicForce( RemnantGradient_per_atom[walker->getId()] );
543 }
544 }
545
546 /** Reset function to unset static entities and artificial velocities.
547 *
548 */
549 void reset()
550 {
551 currentDeltat = 0.;
552 currentStep = 0;
553 }
554
555private:
556 //!> contains the current step in relation to maxsteps
557 static size_t currentStep;
558 //!> contains the maximum number of steps, determines initial and final step with currentStep
559 size_t maxSteps;
560 static double currentDeltat;
561 //!> minimum deltat for internal while loop (adaptive step width)
562 static double MinimumDeltat;
563 //!> contains the maximum bond graph distance up to which shifts of a single atom are spread
564 const int max_distance;
565 //!> the shifted is dampened by this factor with the power of the bond graph distance to the shift causing atom
566 const double damping_factor;
567};
568
569template <class T>
570double ForceAnnealing<T>::currentDeltat = 0.;
571template <class T>
572size_t ForceAnnealing<T>::currentStep = 0;
573template <class T>
574double ForceAnnealing<T>::MinimumDeltat = 1e-8;
575
576#endif /* FORCEANNEALING_HPP_ */
Note: See TracBrowser for help on using the repository browser.