source: src/Dynamics/ForceAnnealing.hpp@ 83956e

AutomationFragmentation_failures Candidate_v1.6.1 ChemicalSpaceEvaluator Exclude_Hydrogens_annealWithBondGraph ForceAnnealing_with_BondGraph_contraction-expansion StoppableMakroAction
Last change on this file since 83956e was 83956e, checked in by Frederik Heber <frederik.heber@…>, 7 years ago

Rewrote annealWithBondGraph_BarzilaiBorwein() to simply distinguish expansion and contraction in bonds.

  • we shift the neighboring set away in case of expansion and towards in case of contraction.
  • Property mode set to 100644
File size: 29.1 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 _TimeStep time step to update (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 _TimeStep,
100 const size_t _offset,
101 const bool _UseBondgraph)
102 {
103 const int CurrentTimeStep = _TimeStep-1;
104 ASSERT( CurrentTimeStep >= 0,
105 "ForceAnnealing::operator() - a new time step (upon which we work) must already have been copied.");
106
107 // make sum of forces equal zero
108 AtomicForceManipulator<T>::correctForceMatrixForFixedCenterOfMass(
109 _offset,
110 CurrentTimeStep);
111
112 // are we in initial step? Then set static entities
113 Vector maxComponents(zeroVec);
114 if (currentStep == 0) {
115 currentDeltat = AtomicForceManipulator<T>::Deltat;
116 currentStep = 1;
117 LOG(2, "DEBUG: Initial step, setting values, current step is #" << currentStep);
118
119 // always use atomic annealing on first step
120 maxComponents = anneal(_TimeStep);
121 } else {
122 ++currentStep;
123 LOG(2, "DEBUG: current step is #" << currentStep);
124
125 // bond graph annealing is always followed by a normal annealing
126 if (_UseBondgraph)
127 maxComponents = annealWithBondGraph_BarzilaiBorwein(_TimeStep);
128 // cannot store RemnantGradient in Atom's Force as it ruins BB stepwidth calculation
129 else
130 maxComponents = anneal_BarzilaiBorwein(_TimeStep);
131 }
132
133
134 LOG(1, "STATUS: Largest remaining force components at step #"
135 << currentStep << " are " << maxComponents);
136
137 // are we in final step? Remember to reset static entities
138 if (currentStep == maxSteps) {
139 LOG(2, "DEBUG: Final step, resetting values");
140 reset();
141 }
142 }
143
144 /** Helper function to calculate the Barzilai-Borwein stepwidth.
145 *
146 * \param _PositionDifference difference in position between current and last step
147 * \param _GradientDifference difference in gradient between current and last step
148 * \return step width according to Barzilai-Borwein
149 */
150 double getBarzilaiBorweinStepwidth(const Vector &_PositionDifference, const Vector &_GradientDifference)
151 {
152 double stepwidth = 0.;
153 if (_GradientDifference.NormSquared() > MYEPSILON)
154 stepwidth = fabs(_PositionDifference.ScalarProduct(_GradientDifference))/
155 _GradientDifference.NormSquared();
156 if (fabs(stepwidth) < 1e-10) {
157 // dont' warn in first step, deltat usage normal
158 if (currentStep != 1)
159 ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead.");
160 stepwidth = currentDeltat;
161 }
162 return stepwidth;
163 }
164
165 /** Performs Gradient optimization on the atoms.
166 *
167 * We assume that forces have just been calculated.
168 *
169 * \param _TimeStep time step to update (i.e. \f$ t + \Delta t \f$ in the sense of the velocity verlet)
170 * \return to be filled with maximum force component over all atoms
171 */
172 Vector anneal(
173 const int _TimeStep)
174 {
175 const int CurrentTimeStep = _TimeStep-1;
176 ASSERT( CurrentTimeStep >= 0,
177 "ForceAnnealing::anneal() - a new time step (upon which we work) must already have been copied.");
178
179 LOG(1, "STATUS: performing simple anneal with default stepwidth " << currentDeltat << " at step #" << currentStep);
180
181 Vector maxComponents;
182 bool deltat_decreased = false;
183 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();
184 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
185 // atom's force vector gives steepest descent direction
186 const Vector currentPosition = (*iter)->getPositionAtStep(CurrentTimeStep);
187 const Vector currentGradient = (*iter)->getAtomicForceAtStep(CurrentTimeStep);
188 LOG(4, "DEBUG: currentPosition for atom #" << (*iter)->getId() << " is " << currentPosition);
189 LOG(4, "DEBUG: currentGradient for atom #" << (*iter)->getId() << " is " << currentGradient);
190// LOG(4, "DEBUG: Force for atom " << **iter << " is " << currentGradient);
191
192 // we use Barzilai-Borwein update with position reversed to get descent
193 double stepwidth = currentDeltat;
194 Vector PositionUpdate = stepwidth * currentGradient;
195 LOG(3, "DEBUG: Update would be " << stepwidth << "*" << currentGradient << " = " << PositionUpdate);
196
197 // extract largest components for showing progress of annealing
198 for(size_t i=0;i<NDIM;++i)
199 maxComponents[i] = std::max(maxComponents[i], fabs(currentGradient[i]));
200
201 // steps may go back and forth again (updates are of same magnitude but
202 // have different sign: Check whether this is the case and one step with
203 // deltat to interrupt this sequence
204 if (currentStep > 1) {
205 const int OldTimeStep = CurrentTimeStep-1;
206 ASSERT( OldTimeStep >= 0,
207 "ForceAnnealing::anneal() - if currentStep is "+toString(currentStep)
208 +", then there should be at least three time steps.");
209 const Vector &oldPosition = (*iter)->getPositionAtStep(OldTimeStep);
210 const Vector PositionDifference = currentPosition - oldPosition;
211 LOG(4, "DEBUG: oldPosition for atom #" << (*iter)->getId() << " is " << oldPosition);
212 LOG(4, "DEBUG: PositionDifference for atom #" << (*iter)->getId() << " is " << PositionDifference);
213 if ((PositionUpdate.ScalarProduct(PositionDifference) < 0)
214 && (fabs(PositionUpdate.NormSquared()-PositionDifference.NormSquared()) < 1e-3)) {
215 // for convergence we want a null sequence here, too
216 if (!deltat_decreased) {
217 deltat_decreased = true;
218 currentDeltat = .5*currentDeltat;
219 }
220 LOG(2, "DEBUG: Upgrade in other direction: " << PositionUpdate
221 << " > " << PositionDifference
222 << ", using deltat: " << currentDeltat);
223 PositionUpdate = currentDeltat * currentGradient;
224 }
225 }
226
227 // finally set new values
228 (*iter)->setPositionAtStep(_TimeStep, currentPosition + PositionUpdate);
229 }
230
231 return maxComponents;
232 }
233
234 /** Performs Gradient optimization on the atoms using BarzilaiBorwein step width.
235 *
236 * \note this can only be called when there are at least two optimization
237 * time steps present, i.e. this must be preceeded by a simple anneal().
238 *
239 * We assume that forces have just been calculated.
240 *
241 * \param _TimeStep time step to update (i.e. \f$ t + \Delta t \f$ in the sense of the velocity verlet)
242 * \return to be filled with maximum force component over all atoms
243 */
244 Vector anneal_BarzilaiBorwein(
245 const int _TimeStep)
246 {
247 const int OldTimeStep = _TimeStep-2;
248 const int CurrentTimeStep = _TimeStep-1;
249 ASSERT( OldTimeStep >= 0,
250 "ForceAnnealing::anneal_BarzilaiBorwein() - we need two present optimization steps to compute stepwidth.");
251 ASSERT(currentStep > 1,
252 "ForceAnnealing::anneal_BarzilaiBorwein() - we need two present optimization steps to compute stepwidth.");
253
254 LOG(1, "STATUS: performing BarzilaiBorwein anneal at step #" << currentStep);
255
256 Vector maxComponents;
257 bool deltat_decreased = false;
258 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();
259 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
260 // atom's force vector gives steepest descent direction
261 const Vector &oldPosition = (*iter)->getPositionAtStep(OldTimeStep);
262 const Vector &currentPosition = (*iter)->getPositionAtStep(CurrentTimeStep);
263 const Vector &oldGradient = (*iter)->getAtomicForceAtStep(OldTimeStep);
264 const Vector &currentGradient = (*iter)->getAtomicForceAtStep(CurrentTimeStep);
265 LOG(4, "DEBUG: oldPosition for atom #" << (*iter)->getId() << " is " << oldPosition);
266 LOG(4, "DEBUG: currentPosition for atom #" << (*iter)->getId() << " is " << currentPosition);
267 LOG(4, "DEBUG: oldGradient for atom #" << (*iter)->getId() << " is " << oldGradient);
268 LOG(4, "DEBUG: currentGradient for atom #" << (*iter)->getId() << " is " << currentGradient);
269// LOG(4, "DEBUG: Force for atom #" << (*iter)->getId() << " is " << currentGradient);
270
271 // we use Barzilai-Borwein update with position reversed to get descent
272 const Vector PositionDifference = currentPosition - oldPosition;
273 const Vector GradientDifference = (currentGradient - oldGradient);
274 double stepwidth = getBarzilaiBorweinStepwidth(PositionDifference, GradientDifference);
275 Vector PositionUpdate = stepwidth * currentGradient;
276 LOG(3, "DEBUG: Update would be " << stepwidth << "*" << currentGradient << " = " << PositionUpdate);
277
278 // extract largest components for showing progress of annealing
279 for(size_t i=0;i<NDIM;++i)
280 maxComponents[i] = std::max(maxComponents[i], fabs(currentGradient[i]));
281
282// // steps may go back and forth again (updates are of same magnitude but
283// // have different sign: Check whether this is the case and one step with
284// // deltat to interrupt this sequence
285// if (!PositionDifference.IsZero())
286// if ((PositionUpdate.ScalarProduct(PositionDifference) < 0)
287// && (fabs(PositionUpdate.NormSquared()-PositionDifference.NormSquared()) < 1e-3)) {
288// // for convergence we want a null sequence here, too
289// if (!deltat_decreased) {
290// deltat_decreased = true;
291// currentDeltat = .5*currentDeltat;
292// }
293// LOG(2, "DEBUG: Upgrade in other direction: " << PositionUpdate
294// << " > " << PositionDifference
295// << ", using deltat: " << currentDeltat);
296// PositionUpdate = currentDeltat * currentGradient;
297// }
298
299 // finally set new values
300 (*iter)->setPositionAtStep(_TimeStep, currentPosition + PositionUpdate);
301 }
302
303 return maxComponents;
304 }
305
306 /** Performs Gradient optimization on the bonds with BarzilaiBorwein stepwdith.
307 *
308 * \note this can only be called when there are at least two optimization
309 * time steps present, i.e. this must be preceeded by a simple anneal().
310 *
311 * We assume that forces have just been calculated. These forces are projected
312 * onto the bonds and these are annealed subsequently by moving atoms in the
313 * bond neighborhood on either side conjunctively.
314 *
315 *
316 * \param _TimeStep time step to update (i.e. \f$ t + \Delta t \f$ in the sense of the velocity verlet)
317 * \param maxComponents to be filled with maximum force component over all atoms
318 */
319 Vector annealWithBondGraph_BarzilaiBorwein(
320 const int _TimeStep)
321 {
322 const int OldTimeStep = _TimeStep-2;
323 const int CurrentTimeStep = _TimeStep-1;
324 ASSERT(OldTimeStep >= 0,
325 "annealWithBondGraph_BarzilaiBorwein() - we need two present optimization steps to compute stepwidth, and the new one to update on already present.");
326 ASSERT(currentStep > 1,
327 "annealWithBondGraph_BarzilaiBorwein() - we need two present optimization steps to compute stepwidth.");
328
329 LOG(1, "STATUS: performing BarzilaiBorwein anneal on bonds at step #" << currentStep);
330
331 Vector maxComponents;
332
333 // get nodes on either side of selected bond via BFS discovery
334 BoostGraphCreator BGcreator;
335 BGcreator.createFromRange(
336 AtomicForceManipulator<T>::atoms.begin(),
337 AtomicForceManipulator<T>::atoms.end(),
338 AtomicForceManipulator<T>::atoms.size(),
339 BreadthFirstSearchGatherer::AlwaysTruePredicate);
340 BreadthFirstSearchGatherer NodeGatherer(BGcreator);
341
342 /** We assume that a force is local, i.e. a bond is too short yet and hence
343 * the atom needs to be moved. However, all the adjacent (bound) atoms might
344 * already be at the perfect distance. If we just move the atom alone, we ruin
345 * all the other bonds. Hence, it would be sensible to move every atom found
346 * through the bond graph in the direction of the force as well by the same
347 * PositionUpdate. This is almost what we are going to do, see below.
348 *
349 * This is to make the force a little more global in the sense of a multigrid
350 * solver that uses various coarser grids to transport errors more effectively
351 * over finely resolved grids.
352 *
353 */
354
355 /** The idea is that we project the gradients onto the bond vectors and determine
356 * from the sum of projected gradients from either side whether the bond is
357 * to contract or to expand. As the gradient acting as the normal vector of
358 * a plane supported at the position of the atom separates all bonds into two
359 * sets, we check whether all on one side are contracting and all on the other
360 * side are expanding. In this case we may move not only the atom itself but
361 * may propagate its update along a limited-horizon BFS to neighboring atoms.
362 *
363 */
364
365 // initialize helper class for bond vectors using bonds from range of atoms
366 BondVectors bv;
367 bv.setFromAtomRange< T >(
368 AtomicForceManipulator<T>::atoms.begin(),
369 AtomicForceManipulator<T>::atoms.end(),
370 _TimeStep); // use time step to update here as this is the current set of bonds
371
372 std::vector< // which bond side
373 std::vector<double> > // over all bonds
374 projected_forces; // one for leftatoms, one for rightatoms
375 projected_forces.resize(BondVectors::MAX_sides);
376 for (size_t j=0;j<BondVectors::MAX_sides;++j)
377 projected_forces[j].resize(bv.size(), 0.);
378
379 // for each atom we need to project the gradient
380 for(typename AtomSetMixin<T>::const_iterator iter = AtomicForceManipulator<T>::atoms.begin();
381 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
382 const atom &walker = *(*iter);
383 const Vector &walkerGradient = walker.getAtomicForceAtStep(CurrentTimeStep);
384 const double GradientNorm = walkerGradient.Norm();
385 LOG(3, "DEBUG: Gradient of atom #" << walker.getId() << ", namely "
386 << walker << " is " << walkerGradient << " with magnitude of "
387 << GradientNorm);
388
389 if (GradientNorm > MYEPSILON) {
390 bv.getProjectedGradientsForAtomAtStep(
391 walker, walkerGradient, CurrentTimeStep, projected_forces
392 );
393 } else {
394 LOG(2, "DEBUG: Gradient is " << walkerGradient << " less than "
395 << MYEPSILON << " for atom " << walker);
396 // note that projected_forces is initialized to full length and filled
397 // with zeros. Hence, nothing to do here
398 }
399 }
400
401 std::map<atomId_t, Vector> GatheredUpdates; //!< gathers all updates which are applied at the end
402 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();
403 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
404 atom &walker = *(*iter);
405
406 /// calculate step width
407 const Vector &oldPosition = (*iter)->getPositionAtStep(OldTimeStep);
408 const Vector &currentPosition = (*iter)->getPositionAtStep(CurrentTimeStep);
409 const Vector &oldGradient = (*iter)->getAtomicForceAtStep(OldTimeStep);
410 const Vector &currentGradient = (*iter)->getAtomicForceAtStep(CurrentTimeStep);
411 LOG(4, "DEBUG: oldPosition for atom #" << (*iter)->getId() << " is " << oldPosition);
412 LOG(4, "DEBUG: currentPosition for atom #" << (*iter)->getId() << " is " << currentPosition);
413 LOG(4, "DEBUG: oldGradient for atom #" << (*iter)->getId() << " is " << oldGradient);
414 LOG(4, "DEBUG: currentGradient for atom #" << (*iter)->getId() << " is " << currentGradient);
415// LOG(4, "DEBUG: Force for atom #" << (*iter)->getId() << " is " << currentGradient);
416
417 // we use Barzilai-Borwein update with position reversed to get descent
418 const Vector PositionDifference = currentPosition - oldPosition;
419 const Vector GradientDifference = (currentGradient - oldGradient);
420 double stepwidth = 0.;
421 if (GradientDifference.Norm() > MYEPSILON)
422 stepwidth = fabs(PositionDifference.ScalarProduct(GradientDifference))/
423 GradientDifference.NormSquared();
424 if (fabs(stepwidth) < 1e-10) {
425 // dont' warn in first step, deltat usage normal
426 if (currentStep != 1)
427 ELOG(1, "INFO: Barzilai-Borwein stepwidth is zero, using deltat " << currentDeltat << " instead.");
428 stepwidth = currentDeltat;
429 }
430 Vector PositionUpdate = stepwidth * currentGradient;
431 LOG(3, "DEBUG: Update would be " << stepwidth << "*" << currentGradient << " = " << PositionUpdate);
432
433 /** go through all bonds and check projected_forces and side of plane
434 * the idea is that if all bonds on one side are contracting ones or expanding,
435 * respectively, then we may shift not only the atom with respect to its
436 * gradient but also its neighbors (towards contraction or towards
437 * expansion depending on direction of gradient).
438 * if they are mixed on both sides of the plane, then we simply shift
439 * only the atom itself.
440 * if they are not mixed on either side, then we also only shift the
441 * atom, namely away from expanding and towards contracting bonds.
442 */
443
444 // sign encodes side of plane and also encodes contracting(-) or expanding(+)
445 typedef std::vector<int> sides_t;
446 typedef std::vector<int> types_t;
447 sides_t sides;
448 types_t types;
449 const BondList& ListOfBonds = walker.getListOfBonds();
450 for(BondList::const_iterator bonditer = ListOfBonds.begin();
451 bonditer != ListOfBonds.end(); ++bonditer) {
452 const bond::ptr &current_bond = *bonditer;
453
454 // BondVector goes from bond::rightatom to bond::leftatom
455 const size_t index = bv.getIndexForBond(current_bond);
456 std::vector<double> &forcelist = (&walker == current_bond->leftatom) ?
457 projected_forces[BondVectors::leftside] : projected_forces[BondVectors::rightside];
458 const double &temp = forcelist[index];
459 sides.push_back( -1.*temp/fabs(temp) ); // BondVectors has exactly opposite sign for sides decision
460 const double sum =
461 projected_forces[BondVectors::leftside][index]+projected_forces[BondVectors::rightside][index];
462 types.push_back( sum/fabs(sum) );
463 LOG(4, "DEBUG: Bond " << *current_bond << " is on side " << sides.back()
464 << " and has type " << types.back());
465 }
466// /// check whether both conditions are compatible:
467// // i.e. either we have ++/-- for all entries in sides and types
468// // or we have +-/-+ for all entries
469// // hence, multiplying and taking the sum and its absolute value
470// // should be equal to the maximum number of entries
471// sides_t results;
472// std::transform(
473// sides.begin(), sides.end(),
474// types.begin(),
475// std::back_inserter(results),
476// std::multiplies<int>);
477// int result = abs(std::accumulate(results.begin(), results.end(), 0, std::plus<int>));
478
479 std::vector<size_t> first_per_side(2, (size_t)-1); //!< mark down one representative from either side
480 std::vector< std::vector<int> > types_per_side(2); //!< gather all types on each side
481 types_t::const_iterator typesiter = types.begin();
482 for (sides_t::const_iterator sidesiter = sides.begin();
483 sidesiter != sides.end(); ++sidesiter, ++typesiter) {
484 const size_t index = (*sidesiter+1)/2;
485 types_per_side[index].push_back(*typesiter);
486 if (first_per_side[index] == (size_t)-1)
487 first_per_side[index] = std::distance(const_cast<const sides_t &>(sides).begin(), sidesiter);
488 }
489 LOG(4, "DEBUG: First on side minus is " << first_per_side[0] << ", and first on side plus is "
490 << first_per_side[1]);
491 //!> enumerate types per side with a little witching with the numbers to allow easy setting from types
492 enum whichtypes_t {
493 contracting=0,
494 unset=1,
495 expanding=2,
496 mixed
497 };
498 std::vector<int> typeside(2, unset);
499 for(size_t i=0;i<2;++i) {
500 for (std::vector<int>::const_iterator tpsiter = types_per_side[i].begin();
501 tpsiter != types_per_side[i].end(); ++tpsiter) {
502 if (typeside[i] == unset) {
503 typeside[i] = *tpsiter+1; //contracting(0) or expanding(2)
504 } else {
505 if (typeside[i] != (*tpsiter+1)) // no longer he same type
506 typeside[i] = mixed;
507 }
508 }
509 }
510 LOG(4, "DEBUG: Minus side is " << typeside[0] << " and plus side is " << typeside[1]);
511
512 typedef std::vector< std::pair<atomId_t, atomId_t> > RemovedEdges_t;
513 if ((typeside[0] != mixed) || (typeside[1] != mixed)) {
514 const size_t sideno = ((typeside[0] != mixed) && (typeside[0] != unset)) ? 0 : 1;
515 LOG(4, "DEBUG: Chosen side is " << sideno << " with type " << typeside[sideno]);
516 ASSERT( (typeside[sideno] == contracting) || (typeside[sideno] == expanding),
517 "annealWithBondGraph_BB() - chosen side is either expanding nor contracting.");
518 // one side is not mixed, all bonds on one side are of same type
519 // hence, find out which bonds to exclude
520 const BondList& ListOfBonds = walker.getListOfBonds();
521
522 // away from gradient (minus) and contracting
523 // or towards gradient (plus) and expanding
524 // gather all on same side and remove
525 const double sign =
526 (sides[first_per_side[sideno]] == types[first_per_side[sideno]])
527 ? sides[first_per_side[sideno]] : -1.*sides[first_per_side[sideno]];
528 LOG(4, "DEBUG: Removing edges from side with sign " << sign);
529 BondList::const_iterator bonditer = ListOfBonds.begin();
530 RemovedEdges_t RemovedEdges;
531 for (sides_t::const_iterator sidesiter = sides.begin();
532 sidesiter != sides.end(); ++sidesiter, ++bonditer) {
533 if (*sidesiter == sign) {
534 // remove the edge
535 const bond::ptr &current_bond = *bonditer;
536 LOG(5, "DEBUG: Removing edge " << *current_bond);
537 RemovedEdges.push_back( std::make_pair(
538 current_bond->leftatom->getId(),
539 current_bond->rightatom->getId())
540 );
541#ifndef NDEBUG
542 const bool status =
543#endif
544 BGcreator.removeEdge(RemovedEdges.back());
545 ASSERT( status, "ForceAnnealing() - edge to found bond is not present?");
546 }
547 }
548 // perform limited-horizon BFS
549 BoostGraphHelpers::Nodeset_t bondside_set;
550 BreadthFirstSearchGatherer::distance_map_t distance_map;
551 bondside_set = NodeGatherer(walker.getId(), max_distance);
552 distance_map = NodeGatherer.getDistances();
553 std::sort(bondside_set.begin(), bondside_set.end());
554
555 // re-add edge
556 for (RemovedEdges_t::const_iterator edgeiter = RemovedEdges.begin();
557 edgeiter != RemovedEdges.end(); ++edgeiter)
558 BGcreator.addEdge(edgeiter->first, edgeiter->second);
559
560 // update position with dampening factor on the discovered bonds
561 for (BoostGraphHelpers::Nodeset_t::const_iterator setiter = bondside_set.begin();
562 setiter != bondside_set.end(); ++setiter) {
563 const BreadthFirstSearchGatherer::distance_map_t::const_iterator diter
564 = distance_map.find(*setiter);
565 ASSERT( diter != distance_map.end(),
566 "ForceAnnealing() - could not find distance to an atom.");
567 const double factor = pow(damping_factor, diter->second+1);
568 LOG(3, "DEBUG: Update for atom #" << *setiter << " will be "
569 << factor << "*" << PositionUpdate);
570 if (GatheredUpdates.count((*setiter))) {
571 GatheredUpdates[(*setiter)] += factor*PositionUpdate;
572 } else {
573 GatheredUpdates.insert(
574 std::make_pair(
575 (*setiter),
576 factor*PositionUpdate) );
577 }
578 }
579 } else {
580 // simple atomic annealing, i.e. damping factor of 1
581 LOG(3, "DEBUG: Update for atom #" << walker.getId() << " will be " << PositionUpdate);
582 GatheredUpdates.insert(
583 std::make_pair(
584 walker.getId(),
585 PositionUpdate) );
586 }
587 }
588
589 for(typename AtomSetMixin<T>::iterator iter = AtomicForceManipulator<T>::atoms.begin();
590 iter != AtomicForceManipulator<T>::atoms.end(); ++iter) {
591 atom &walker = *(*iter);
592 // extract largest components for showing progress of annealing
593 const Vector currentGradient = walker.getAtomicForceAtStep(CurrentTimeStep);
594 for(size_t i=0;i<NDIM;++i)
595 maxComponents[i] = std::max(maxComponents[i], fabs(currentGradient[i]));
596 }
597
598// // remove center of weight translation from gathered updates
599// Vector CommonTranslation;
600// for (std::map<atomId_t, Vector>::const_iterator iter = GatheredUpdates.begin();
601// iter != GatheredUpdates.end(); ++iter) {
602// const Vector &update = iter->second;
603// CommonTranslation += update;
604// }
605// CommonTranslation *= 1./(double)GatheredUpdates.size();
606// LOG(3, "DEBUG: Subtracting common translation " << CommonTranslation
607// << " from all updates.");
608
609 // apply the gathered updates and set remnant gradients for atomic annealing
610 for (std::map<atomId_t, Vector>::const_iterator iter = GatheredUpdates.begin();
611 iter != GatheredUpdates.end(); ++iter) {
612 const atomId_t &atomid = iter->first;
613 const Vector &update = iter->second;
614 atom* const walker = World::getInstance().getAtom(AtomById(atomid));
615 ASSERT( walker != NULL,
616 "ForceAnnealing() - walker with id "+toString(atomid)+" has suddenly disappeared.");
617 LOG(3, "DEBUG: Applying update " << update << " to atom #" << atomid
618 << ", namely " << *walker);
619 walker->setPositionAtStep(_TimeStep,
620 walker->getPositionAtStep(CurrentTimeStep) + update); // - CommonTranslation);
621 }
622
623 return maxComponents;
624 }
625
626 /** Reset function to unset static entities and artificial velocities.
627 *
628 */
629 void reset()
630 {
631 currentDeltat = 0.;
632 currentStep = 0;
633 }
634
635private:
636 //!> contains the current step in relation to maxsteps
637 static size_t currentStep;
638 //!> contains the maximum number of steps, determines initial and final step with currentStep
639 size_t maxSteps;
640 static double currentDeltat;
641 //!> minimum deltat for internal while loop (adaptive step width)
642 static double MinimumDeltat;
643 //!> contains the maximum bond graph distance up to which shifts of a single atom are spread
644 const int max_distance;
645 //!> the shifted is dampened by this factor with the power of the bond graph distance to the shift causing atom
646 const double damping_factor;
647};
648
649template <class T>
650double ForceAnnealing<T>::currentDeltat = 0.;
651template <class T>
652size_t ForceAnnealing<T>::currentStep = 0;
653template <class T>
654double ForceAnnealing<T>::MinimumDeltat = 1e-8;
655
656#endif /* FORCEANNEALING_HPP_ */
Note: See TracBrowser for help on using the repository browser.