source: src/molecule_dynamics.cpp@ fc5c3a

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since fc5c3a was e4afb4, checked in by Frederik Heber <heber@…>, 14 years ago

Huge refactoring: Introduction of Traits to Actions.

This change is really big but the introduction of the Trait concept (at least
in its current light form) is so fundamental that lots of pieces had to be
changed in order to get everything working.

The main point why it was necessary to add these traits in the first place was
to comfortably allow for adding extension of Actions information-wise, i.e.
with stuff that is only important for the QtUI, such as icons, or tooltips, ...
This extra information should not be stored with Action itself, as it has
nothing to do with the workings of the Action. And neither should it get
stored with some blown-out-of-proportions MapOfActions class ...

The gist of the change is as follows:

  • OptionTrait contains the token, description, shortform and type of an option, such as ("position", "position in space, none, typeid(Vector)).
  • ActionTrait is the derived form for actions where additionally MenuPosition and MenuName are stored (and probably more to come for the GUI), also we have a set of OptionTrait instances, one for each option of the Action.
  • Action then contains this ActionTrait, specialized for each Action.
  • the preprocessor macros have been enhanced to gather all this information from the .def files.
  • MapOfActions is gone. Completely. Most of its use was to store this extra information and the ValueStorage part now is just in class ValueStorage.
  • ValueStorage is no more an interface to MapOfActions but as the name says a (type-safe) ValueStorage.

Listing the (remaining) changes in alphabetical order of the class:

  • Action
    • member value ::name dropped, ::getName() uses ActionTraits::getName()
    • new define NODEFAULT which is used in paramdefaults in .def files
    • all derived actions classes such as Process, Calculations, MakroAction,... have been adapated to use the ActionTrait concept as well.
  • ActionHistory
    • extraced RedoAction and UndoAction, shifted implementation into their own object files and they use .def files as well (i.e. streamlined with method used for other actions)
  • MenuDescription
    • contain information on Menus such as name, ...
    • new unit test checks for consistency
  • molecule
    • const member functions: Copy(), Output() and OutputBonds()
  • OptionRegistry
    • new registry class for options only
    • we want the same type throughout the code for each token, e.g. "position"
    • the registry containts checks for consistency
  • OptionTrait
    • default values are specified in paramdefaults, none are given by NODEFAULT
    • introduced default for translate-atoms, point-correlation, pair-correlation
  • Registry pattern
    • new unit test, but only sceleton code so far
  • ...Query, also ...Pipe
    • atoms, molecule and elements are now all const
    • also ValueStorage's signatures all have const therein
  • ValueStorage
    • set/queryCurrentValue from MapOfActions
    • at times VectorValue has been in .def files where Vector was in the signature. This is cleared. Such stuff is only present for e.g. BoxVector being queried as a Vector. But this is a feature and intended.
  • World
    • most of the (un)selection functions now work on const atoms and molecules
    • in one case we need a const_cast to remove this, but this is intentional, as the vector of selected atoms stores non-const pointers and this is ok.

There is only one test which had to be changed slightly because a specific
option token as "position" must now have the same type everywhere, e.g. always
Vector.

  • TESTFIX: Simple_configuration/2: --position -> --domain-position (and associated to BoxVector)
  • Property mode set to 100644
File size: 31.6 KB
RevLine 
[bcf653]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
[cee0b57]8/*
9 * molecule_dynamics.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
[bf3817]15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
[112b09]20#include "Helpers/MemDebug.hpp"
21
[cbc5fb]22#include "World.hpp"
[f66195]23#include "atom.hpp"
[cee0b57]24#include "config.hpp"
[f66195]25#include "element.hpp"
[952f38]26#include "Helpers/Info.hpp"
27#include "Helpers/Verbose.hpp"
28#include "Helpers/Log.hpp"
[cee0b57]29#include "molecule.hpp"
[f66195]30#include "parser.hpp"
[57f243]31#include "LinearAlgebra/Plane.hpp"
[a3fded]32#include "ThermoStatContainer.hpp"
[14c57a]33#include "Thermostats/Berendsen.hpp"
[cee0b57]34
[aafd77]35#include <gsl/gsl_matrix.h>
36#include <gsl/gsl_vector.h>
37#include <gsl/gsl_linalg.h>
38
[cee0b57]39/************************************* Functions for class molecule *********************************/
40
[ccd9f5]41/** Penalizes long trajectories.
42 * \param *Walker atom to check against others
43 * \param *mol molecule with other atoms
44 * \param &Params constraint potential parameters
45 * \return penalty times each distance
46 */
47double SumDistanceOfTrajectories(atom *Walker, molecule *mol, struct EvaluatePotential &Params)
48{
49 gsl_matrix *A = gsl_matrix_alloc(NDIM,NDIM);
50 gsl_vector *x = gsl_vector_alloc(NDIM);
51 atom *Sprinter = NULL;
52 Vector trajectory1, trajectory2, normal, TestVector;
53 double Norm1, Norm2, tmp, result = 0.;
54
[9879f6]55 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
56 if ((*iter) == Walker) // hence, we only go up to the Walker, not beyond (similar to i=0; i<j; i++)
[ccd9f5]57 break;
58 // determine normalized trajectories direction vector (n1, n2)
59 Sprinter = Params.PermutationMap[Walker->nr]; // find first target point
[273382]60 trajectory1 = Sprinter->Trajectory.R.at(Params.endstep) - Walker->Trajectory.R.at(Params.startstep);
[ccd9f5]61 trajectory1.Normalize();
62 Norm1 = trajectory1.Norm();
[9879f6]63 Sprinter = Params.PermutationMap[(*iter)->nr]; // find second target point
[a7b761b]64 trajectory2 = Sprinter->Trajectory.R.at(Params.endstep) - (*iter)->Trajectory.R.at(Params.startstep);
[ccd9f5]65 trajectory2.Normalize();
66 Norm2 = trajectory1.Norm();
67 // check whether either is zero()
68 if ((Norm1 < MYEPSILON) && (Norm2 < MYEPSILON)) {
[a7b761b]69 tmp = Walker->Trajectory.R.at(Params.startstep).distance((*iter)->Trajectory.R.at(Params.startstep));
[ccd9f5]70 } else if (Norm1 < MYEPSILON) {
71 Sprinter = Params.PermutationMap[Walker->nr]; // find first target point
[a7b761b]72 trajectory1 = Sprinter->Trajectory.R.at(Params.endstep) - (*iter)->Trajectory.R.at(Params.startstep);
[273382]73 trajectory2 *= trajectory1.ScalarProduct(trajectory2); // trajectory2 is scaled to unity, hence we don't need to divide by anything
74 trajectory1 -= trajectory2; // project the part in norm direction away
[ccd9f5]75 tmp = trajectory1.Norm(); // remaining norm is distance
76 } else if (Norm2 < MYEPSILON) {
[9879f6]77 Sprinter = Params.PermutationMap[(*iter)->nr]; // find second target point
[273382]78 trajectory2 = Sprinter->Trajectory.R.at(Params.endstep) - Walker->Trajectory.R.at(Params.startstep); // copy second offset
79 trajectory1 *= trajectory2.ScalarProduct(trajectory1); // trajectory1 is scaled to unity, hence we don't need to divide by anything
80 trajectory2 -= trajectory1; // project the part in norm direction away
[ccd9f5]81 tmp = trajectory2.Norm(); // remaining norm is distance
[273382]82 } else if ((fabs(trajectory1.ScalarProduct(trajectory2)/Norm1/Norm2) - 1.) < MYEPSILON) { // check whether they're linear dependent
[e138de]83 // Log() << Verbose(3) << "Both trajectories of " << *Walker << " and " << *Runner << " are linear dependent: ";
84 // Log() << Verbose(0) << trajectory1;
85 // Log() << Verbose(0) << " and ";
86 // Log() << Verbose(0) << trajectory2;
[a7b761b]87 tmp = Walker->Trajectory.R.at(Params.startstep).distance((*iter)->Trajectory.R.at(Params.startstep));
[e138de]88 // Log() << Verbose(0) << " with distance " << tmp << "." << endl;
[ccd9f5]89 } else { // determine distance by finding minimum distance
[9879f6]90 // Log() << Verbose(3) << "Both trajectories of " << *Walker << " and " << *(*iter) << " are linear independent ";
[e138de]91 // Log() << Verbose(0) << endl;
92 // Log() << Verbose(0) << "First Trajectory: ";
93 // Log() << Verbose(0) << trajectory1 << endl;
94 // Log() << Verbose(0) << "Second Trajectory: ";
95 // Log() << Verbose(0) << trajectory2 << endl;
[ccd9f5]96 // determine normal vector for both
[0a4f7f]97 normal = Plane(trajectory1, trajectory2,0).getNormal();
[ccd9f5]98 // print all vectors for debugging
[e138de]99 // Log() << Verbose(0) << "Normal vector in between: ";
100 // Log() << Verbose(0) << normal << endl;
[ccd9f5]101 // setup matrix
102 for (int i=NDIM;i--;) {
[0a4f7f]103 gsl_matrix_set(A, 0, i, trajectory1[i]);
104 gsl_matrix_set(A, 1, i, trajectory2[i]);
105 gsl_matrix_set(A, 2, i, normal[i]);
[a7b761b]106 gsl_vector_set(x,i, (Walker->Trajectory.R.at(Params.startstep)[i] - (*iter)->Trajectory.R.at(Params.startstep)[i]));
[ccd9f5]107 }
108 // solve the linear system by Householder transformations
109 gsl_linalg_HH_svx(A, x);
110 // distance from last component
111 tmp = gsl_vector_get(x,2);
[e138de]112 // Log() << Verbose(0) << " with distance " << tmp << "." << endl;
[ccd9f5]113 // test whether we really have the intersection (by checking on c_1 and c_2)
[273382]114 trajectory1.Scale(gsl_vector_get(x,0));
[ccd9f5]115 trajectory2.Scale(gsl_vector_get(x,1));
116 normal.Scale(gsl_vector_get(x,2));
[a7b761b]117 TestVector = (*iter)->Trajectory.R.at(Params.startstep) + trajectory2 + normal
[273382]118 - (Walker->Trajectory.R.at(Params.startstep) + trajectory1);
[ccd9f5]119 if (TestVector.Norm() < MYEPSILON) {
[e138de]120 // Log() << Verbose(2) << "Test: ok.\tDistance of " << tmp << " is correct." << endl;
[ccd9f5]121 } else {
[e138de]122 // Log() << Verbose(2) << "Test: failed.\tIntersection is off by ";
123 // Log() << Verbose(0) << TestVector;
124 // Log() << Verbose(0) << "." << endl;
[ccd9f5]125 }
126 }
127 // add up
128 tmp *= Params.IsAngstroem ? 1. : 1./AtomicLengthToAngstroem;
129 if (fabs(tmp) > MYEPSILON) {
130 result += Params.PenaltyConstants[1] * 1./tmp;
[e138de]131 //Log() << Verbose(4) << "Adding " << 1./tmp*constants[1] << "." << endl;
[ccd9f5]132 }
133 }
134 return result;
135};
136
137/** Penalizes atoms heading to same target.
138 * \param *Walker atom to check against others
139 * \param *mol molecule with other atoms
140 * \param &Params constrained potential parameters
141 * \return \a penalty times the number of equal targets
142 */
143double PenalizeEqualTargets(atom *Walker, molecule *mol, struct EvaluatePotential &Params)
144{
145 double result = 0.;
[9879f6]146 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
147 if ((Params.PermutationMap[Walker->nr] == Params.PermutationMap[(*iter)->nr]) && (Walker->nr < (*iter)->nr)) {
[ccd9f5]148 // atom *Sprinter = PermutationMap[Walker->nr];
[9879f6]149 // Log() << Verbose(0) << *Walker << " and " << *(*iter) << " are heading to the same target at ";
[e138de]150 // Log() << Verbose(0) << Sprinter->Trajectory.R.at(endstep);
151 // Log() << Verbose(0) << ", penalting." << endl;
[ccd9f5]152 result += Params.PenaltyConstants[2];
[e138de]153 //Log() << Verbose(4) << "Adding " << constants[2] << "." << endl;
[ccd9f5]154 }
155 }
156 return result;
157};
[cee0b57]158
159/** Evaluates the potential energy used for constrained molecular dynamics.
160 * \f$V_i^{con} = c^{bond} \cdot | r_{P(i)} - R_i | + sum_{i \neq j} C^{min} \cdot \frac{1}{C_{ij}} + C^{inj} \Bigl (1 - \theta \bigl (\prod_{i \neq j} (P(i) - P(j)) \bigr ) \Bigr )\f$
161 * where the first term points to the target in minimum distance, the second is a penalty for trajectories lying too close to each other (\f$C_{ij}\f$ is minimum distance between
162 * trajectories i and j) and the third term is a penalty for two atoms trying to each the same target point.
163 * Note that for the second term we have to solve the following linear system:
164 * \f$-c_1 \cdot n_1 + c_2 \cdot n_2 + C \cdot n_3 = - p_2 + p_1\f$, where \f$c_1\f$, \f$c_2\f$ and \f$C\f$ are constants,
165 * offset vector \f$p_1\f$ in direction \f$n_1\f$, offset vector \f$p_2\f$ in direction \f$n_2\f$,
166 * \f$n_3\f$ is the normal vector to both directions. \f$C\f$ would be the minimum distance between the two lines.
167 * \sa molecule::MinimiseConstrainedPotential(), molecule::VerletForceIntegration()
168 * \param *out output stream for debugging
[ccd9f5]169 * \param &Params constrained potential parameters
[cee0b57]170 * \return potential energy
171 * \note This routine is scaling quadratically which is not optimal.
172 * \todo There's a bit double counting going on for the first time, bu nothing to worry really about.
173 */
[e138de]174double molecule::ConstrainedPotential(struct EvaluatePotential &Params)
[cee0b57]175{
[e3cbf9]176 double tmp = 0.;
177 double result = 0.;
[cee0b57]178 // go through every atom
[ccd9f5]179 atom *Runner = NULL;
[9879f6]180 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
[cee0b57]181 // first term: distance to target
[9879f6]182 Runner = Params.PermutationMap[(*iter)->nr]; // find target point
[a7b761b]183 tmp = ((*iter)->Trajectory.R.at(Params.startstep).distance(Runner->Trajectory.R.at(Params.endstep)));
[ccd9f5]184 tmp *= Params.IsAngstroem ? 1. : 1./AtomicLengthToAngstroem;
185 result += Params.PenaltyConstants[0] * tmp;
[e138de]186 //Log() << Verbose(4) << "Adding " << tmp*constants[0] << "." << endl;
[cee0b57]187
188 // second term: sum of distances to other trajectories
[9879f6]189 result += SumDistanceOfTrajectories((*iter), this, Params);
[cee0b57]190
191 // third term: penalty for equal targets
[9879f6]192 result += PenalizeEqualTargets((*iter), this, Params);
[cee0b57]193 }
194
195 return result;
196};
197
[ccd9f5]198/** print the current permutation map.
199 * \param *out output stream for debugging
200 * \param &Params constrained potential parameters
201 * \param AtomCount number of atoms
202 */
[e138de]203void PrintPermutationMap(int AtomCount, struct EvaluatePotential &Params)
[cee0b57]204{
205 stringstream zeile1, zeile2;
[920c70]206 int *DoubleList = new int[AtomCount];
207 for(int i=0;i<AtomCount;i++)
208 DoubleList[i] = 0;
[cee0b57]209 int doubles = 0;
210 zeile1 << "PermutationMap: ";
211 zeile2 << " ";
[ccd9f5]212 for (int i=0;i<AtomCount;i++) {
213 Params.DoubleList[Params.PermutationMap[i]->nr]++;
[cee0b57]214 zeile1 << i << " ";
[ccd9f5]215 zeile2 << Params.PermutationMap[i]->nr << " ";
[cee0b57]216 }
[ccd9f5]217 for (int i=0;i<AtomCount;i++)
218 if (Params.DoubleList[i] > 1)
[cee0b57]219 doubles++;
[ccd9f5]220 if (doubles >0)
[a67d19]221 DoLog(2) && (Log() << Verbose(2) << "Found " << doubles << " Doubles." << endl);
[920c70]222 delete[](DoubleList);
[e138de]223// Log() << Verbose(2) << zeile1.str() << endl << zeile2.str() << endl;
[cee0b57]224};
225
[ccd9f5]226/** \f$O(N^2)\f$ operation of calculation distance between each atom pair and putting into DistanceList.
227 * \param *mol molecule to scan distances in
228 * \param &Params constrained potential parameters
229 */
230void FillDistanceList(molecule *mol, struct EvaluatePotential &Params)
231{
[ea7176]232 for (int i=mol->getAtomCount(); i--;) {
[ccd9f5]233 Params.DistanceList[i] = new DistanceMap; // is the distance sorted target list per atom
234 Params.DistanceList[i]->clear();
235 }
236
[9879f6]237 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
238 for (molecule::const_iterator runner = mol->begin(); runner != mol->end(); ++runner) {
[a7b761b]239 Params.DistanceList[(*iter)->nr]->insert( DistancePair((*iter)->Trajectory.R.at(Params.startstep).distance((*runner)->Trajectory.R.at(Params.endstep)), (*runner)) );
[ccd9f5]240 }
241 }
242};
243
244/** initialize lists.
245 * \param *out output stream for debugging
246 * \param *mol molecule to scan distances in
247 * \param &Params constrained potential parameters
248 */
[e138de]249void CreateInitialLists(molecule *mol, struct EvaluatePotential &Params)
[ccd9f5]250{
[9879f6]251 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
252 Params.StepList[(*iter)->nr] = Params.DistanceList[(*iter)->nr]->begin(); // stores the step to the next iterator that could be a possible next target
253 Params.PermutationMap[(*iter)->nr] = Params.DistanceList[(*iter)->nr]->begin()->second; // always pick target with the smallest distance
254 Params.DoubleList[Params.DistanceList[(*iter)->nr]->begin()->second->nr]++; // increase this target's source count (>1? not injective)
255 Params.DistanceIterators[(*iter)->nr] = Params.DistanceList[(*iter)->nr]->begin(); // and remember which one we picked
[a7b761b]256 DoLog(2) && (Log() << Verbose(2) << **iter << " starts with distance " << Params.DistanceList[(*iter)->nr]->begin()->first << "." << endl);
[ccd9f5]257 }
258};
259
260/** Try the next nearest neighbour in order to make the permutation map injective.
261 * \param *out output stream for debugging
262 * \param *mol molecule
263 * \param *Walker atom to change its target
264 * \param &OldPotential old value of constraint potential to see if we do better with new target
265 * \param &Params constrained potential parameters
266 */
[e138de]267double TryNextNearestNeighbourForInjectivePermutation(molecule *mol, atom *Walker, double &OldPotential, struct EvaluatePotential &Params)
[ccd9f5]268{
269 double Potential = 0;
270 DistanceMap::iterator NewBase = Params.DistanceIterators[Walker->nr]; // store old base
271 do {
272 NewBase++; // take next further distance in distance to targets list that's a target of no one
273 } while ((Params.DoubleList[NewBase->second->nr] != 0) && (NewBase != Params.DistanceList[Walker->nr]->end()));
274 if (NewBase != Params.DistanceList[Walker->nr]->end()) {
275 Params.PermutationMap[Walker->nr] = NewBase->second;
[e138de]276 Potential = fabs(mol->ConstrainedPotential(Params));
[ccd9f5]277 if (Potential > OldPotential) { // undo
278 Params.PermutationMap[Walker->nr] = Params.DistanceIterators[Walker->nr]->second;
279 } else { // do
280 Params.DoubleList[Params.DistanceIterators[Walker->nr]->second->nr]--; // decrease the old entry in the doubles list
281 Params.DoubleList[NewBase->second->nr]++; // increase the old entry in the doubles list
282 Params.DistanceIterators[Walker->nr] = NewBase;
283 OldPotential = Potential;
[a67d19]284 DoLog(3) && (Log() << Verbose(3) << "Found a new permutation, new potential is " << OldPotential << "." << endl);
[ccd9f5]285 }
286 }
287 return Potential;
288};
289
290/** Permutes \a **&PermutationMap until the penalty is below constants[2].
291 * \param *out output stream for debugging
292 * \param *mol molecule to scan distances in
293 * \param &Params constrained potential parameters
294 */
[e138de]295void MakeInjectivePermutation(molecule *mol, struct EvaluatePotential &Params)
[ccd9f5]296{
[9879f6]297 molecule::const_iterator iter = mol->begin();
[ccd9f5]298 DistanceMap::iterator NewBase;
[e138de]299 double Potential = fabs(mol->ConstrainedPotential(Params));
[ccd9f5]300
[9879f6]301 if (mol->empty()) {
302 eLog() << Verbose(1) << "Molecule is empty." << endl;
303 return;
304 }
[ccd9f5]305 while ((Potential) > Params.PenaltyConstants[2]) {
[ea7176]306 PrintPermutationMap(mol->getAtomCount(), Params);
[9879f6]307 iter++;
308 if (iter == mol->end()) // round-robin at the end
309 iter = mol->begin();
310 if (Params.DoubleList[Params.DistanceIterators[(*iter)->nr]->second->nr] <= 1) // no need to make those injective that aren't
[ccd9f5]311 continue;
312 // now, try finding a new one
[9879f6]313 Potential = TryNextNearestNeighbourForInjectivePermutation(mol, (*iter), Potential, Params);
[ccd9f5]314 }
[ea7176]315 for (int i=mol->getAtomCount(); i--;) // now each single entry in the DoubleList should be <=1
[ccd9f5]316 if (Params.DoubleList[i] > 1) {
[58ed4a]317 DoeLog(0) && (eLog()<< Verbose(0) << "Failed to create an injective PermutationMap!" << endl);
[e359a8]318 performCriticalExit();
[ccd9f5]319 }
[a67d19]320 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
[ccd9f5]321};
322
[cee0b57]323/** Minimises the extra potential for constrained molecular dynamics and gives forces and the constrained potential energy.
324 * We do the following:
325 * -# Generate a distance list from all source to all target points
326 * -# Sort this per source point
327 * -# Take for each source point the target point with minimum distance, use this as initial permutation
328 * -# check whether molecule::ConstrainedPotential() is greater than injective penalty
329 * -# If so, we go through each source point, stepping down in the sorted target point distance list and re-checking potential.
330 * -# Next, we only apply transformations that keep the injectivity of the permutations list.
331 * -# Hence, for one source point we step down the ladder and seek the corresponding owner of this new target
332 * point and try to change it for one with lesser distance, or for the next one with greater distance, but only
333 * if this decreases the conditional potential.
334 * -# finished.
335 * -# Then, we calculate the forces by taking the spatial derivative, where we scale the potential to such a degree,
336 * that the total force is always pointing in direction of the constraint force (ensuring that we move in the
337 * right direction).
338 * -# Finally, we calculate the potential energy and return.
339 * \param *out output stream for debugging
340 * \param **PermutationMap on return: mapping between the atom label of the initial and the final configuration
341 * \param startstep current MD step giving initial position between which and \a endstep we perform the constrained MD (as further steps are always concatenated)
342 * \param endstep step giving final position in constrained MD
343 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false)
344 * \sa molecule::VerletForceIntegration()
345 * \return potential energy (and allocated **PermutationMap (array of molecule::AtomCount ^2)
346 * \todo The constrained potential's constants are set to fixed values right now, but they should scale based on checks of the system in order
347 * to ensure they're properties (e.g. constants[2] always greater than the energy of the system).
348 * \bug this all is not O(N log N) but O(N^2)
349 */
[e138de]350double molecule::MinimiseConstrainedPotential(atom **&PermutationMap, int startstep, int endstep, bool IsAngstroem)
[cee0b57]351{
352 double Potential, OldPotential, OlderPotential;
[ccd9f5]353 struct EvaluatePotential Params;
[1024cb]354 Params.PermutationMap = new atom *[getAtomCount()];
355 Params.DistanceList = new DistanceMap *[getAtomCount()];
356 Params.DistanceIterators = new DistanceMap::iterator[getAtomCount()];
357 Params.DoubleList = new int[getAtomCount()];
358 Params.StepList = new DistanceMap::iterator[getAtomCount()];
[cee0b57]359 int round;
[9879f6]360 atom *Sprinter = NULL;
[cee0b57]361 DistanceMap::iterator Rider, Strider;
362
[920c70]363 // set to zero
[1024cb]364 for (int i=0;i<getAtomCount();i++) {
[920c70]365 Params.PermutationMap[i] = NULL;
366 Params.DoubleList[i] = 0;
367 }
368
[cee0b57]369 /// Minimise the potential
370 // set Lagrange multiplier constants
[ccd9f5]371 Params.PenaltyConstants[0] = 10.;
372 Params.PenaltyConstants[1] = 1.;
373 Params.PenaltyConstants[2] = 1e+7; // just a huge penalty
[cee0b57]374 // generate the distance list
[a67d19]375 DoLog(1) && (Log() << Verbose(1) << "Allocating, initializting and filling the distance list ... " << endl);
[ccd9f5]376 FillDistanceList(this, Params);
377
[cee0b57]378 // create the initial PermutationMap (source -> target)
[e138de]379 CreateInitialLists(this, Params);
[ccd9f5]380
[cee0b57]381 // make the PermutationMap injective by checking whether we have a non-zero constants[2] term in it
[a67d19]382 DoLog(1) && (Log() << Verbose(1) << "Making the PermutationMap injective ... " << endl);
[e138de]383 MakeInjectivePermutation(this, Params);
[920c70]384 delete[](Params.DoubleList);
[ccd9f5]385
[cee0b57]386 // argument minimise the constrained potential in this injective PermutationMap
[a67d19]387 DoLog(1) && (Log() << Verbose(1) << "Argument minimising the PermutationMap." << endl);
[cee0b57]388 OldPotential = 1e+10;
389 round = 0;
390 do {
[a67d19]391 DoLog(2) && (Log() << Verbose(2) << "Starting round " << ++round << ", at current potential " << OldPotential << " ... " << endl);
[cee0b57]392 OlderPotential = OldPotential;
[9879f6]393 molecule::const_iterator iter;
[cee0b57]394 do {
[9879f6]395 iter = begin();
396 for (; iter != end(); ++iter) {
[ea7176]397 PrintPermutationMap(getAtomCount(), Params);
[9879f6]398 Sprinter = Params.DistanceIterators[(*iter)->nr]->second; // store initial partner
399 Strider = Params.DistanceIterators[(*iter)->nr]; //remember old iterator
400 Params.DistanceIterators[(*iter)->nr] = Params.StepList[(*iter)->nr];
401 if (Params.DistanceIterators[(*iter)->nr] == Params.DistanceList[(*iter)->nr]->end()) {// stop, before we run through the list and still on
402 Params.DistanceIterators[(*iter)->nr] == Params.DistanceList[(*iter)->nr]->begin();
[cee0b57]403 break;
404 }
[9879f6]405 //Log() << Verbose(2) << "Current Walker: " << *(*iter) << " with old/next candidate " << *Sprinter << "/" << *DistanceIterators[(*iter)->nr]->second << "." << endl;
[cee0b57]406 // find source of the new target
[9879f6]407 molecule::const_iterator runner = begin();
408 for (; runner != end(); ++runner) { // find the source whose toes we might be stepping on (Walker's new target should be in use by another already)
409 if (Params.PermutationMap[(*runner)->nr] == Params.DistanceIterators[(*iter)->nr]->second) {
410 //Log() << Verbose(2) << "Found the corresponding owner " << *(*runner) << " to " << *PermutationMap[(*runner)->nr] << "." << endl;
[cee0b57]411 break;
412 }
413 }
[9879f6]414 if (runner != end()) { // we found the other source
[cee0b57]415 // then look in its distance list for Sprinter
[9879f6]416 Rider = Params.DistanceList[(*runner)->nr]->begin();
417 for (; Rider != Params.DistanceList[(*runner)->nr]->end(); Rider++)
[cee0b57]418 if (Rider->second == Sprinter)
419 break;
[9879f6]420 if (Rider != Params.DistanceList[(*runner)->nr]->end()) { // if we have found one
421 //Log() << Verbose(2) << "Current Other: " << *(*runner) << " with old/next candidate " << *PermutationMap[(*runner)->nr] << "/" << *Rider->second << "." << endl;
[cee0b57]422 // exchange both
[9879f6]423 Params.PermutationMap[(*iter)->nr] = Params.DistanceIterators[(*iter)->nr]->second; // put next farther distance into PermutationMap
424 Params.PermutationMap[(*runner)->nr] = Sprinter; // and hand the old target to its respective owner
[ea7176]425 PrintPermutationMap(getAtomCount(), Params);
[cee0b57]426 // calculate the new potential
[e138de]427 //Log() << Verbose(2) << "Checking new potential ..." << endl;
428 Potential = ConstrainedPotential(Params);
[cee0b57]429 if (Potential > OldPotential) { // we made everything worse! Undo ...
[e138de]430 //Log() << Verbose(3) << "Nay, made the potential worse: " << Potential << " vs. " << OldPotential << "!" << endl;
[9879f6]431 //Log() << Verbose(3) << "Setting " << *(*runner) << "'s source to " << *Params.DistanceIterators[(*runner)->nr]->second << "." << endl;
[cee0b57]432 // Undo for Runner (note, we haven't moved the iteration yet, we may use this)
[9879f6]433 Params.PermutationMap[(*runner)->nr] = Params.DistanceIterators[(*runner)->nr]->second;
[cee0b57]434 // Undo for Walker
[9879f6]435 Params.DistanceIterators[(*iter)->nr] = Strider; // take next farther distance target
436 //Log() << Verbose(3) << "Setting " << *(*iter) << "'s source to " << *Params.DistanceIterators[(*iter)->nr]->second << "." << endl;
437 Params.PermutationMap[(*iter)->nr] = Params.DistanceIterators[(*iter)->nr]->second;
[cee0b57]438 } else {
[9879f6]439 Params.DistanceIterators[(*runner)->nr] = Rider; // if successful also move the pointer in the iterator list
[a67d19]440 DoLog(3) && (Log() << Verbose(3) << "Found a better permutation, new potential is " << Potential << " vs." << OldPotential << "." << endl);
[cee0b57]441 OldPotential = Potential;
442 }
[ccd9f5]443 if (Potential > Params.PenaltyConstants[2]) {
[58ed4a]444 DoeLog(1) && (eLog()<< Verbose(1) << "The two-step permutation procedure did not maintain injectivity!" << endl);
[cee0b57]445 exit(255);
446 }
[e138de]447 //Log() << Verbose(0) << endl;
[cee0b57]448 } else {
[a7b761b]449 DoeLog(1) && (eLog()<< Verbose(1) << **runner << " was not the owner of " << *Sprinter << "!" << endl);
[cee0b57]450 exit(255);
451 }
452 } else {
[9879f6]453 Params.PermutationMap[(*iter)->nr] = Params.DistanceIterators[(*iter)->nr]->second; // new target has no source!
[cee0b57]454 }
[9879f6]455 Params.StepList[(*iter)->nr]++; // take next farther distance target
[cee0b57]456 }
[9879f6]457 } while (++iter != end());
[cee0b57]458 } while ((OlderPotential - OldPotential) > 1e-3);
[a67d19]459 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
[cee0b57]460
461
462 /// free memory and return with evaluated potential
[ea7176]463 for (int i=getAtomCount(); i--;)
[ccd9f5]464 Params.DistanceList[i]->clear();
[920c70]465 delete[](Params.DistanceList);
466 delete[](Params.DistanceIterators);
[e138de]467 return ConstrainedPotential(Params);
[cee0b57]468};
469
[ccd9f5]470
[cee0b57]471/** Evaluates the (distance-related part) of the constrained potential for the constrained forces.
472 * \param *out output stream for debugging
473 * \param startstep current MD step giving initial position between which and \a endstep we perform the constrained MD (as further steps are always concatenated)
474 * \param endstep step giving final position in constrained MD
475 * \param **PermutationMap mapping between the atom label of the initial and the final configuration
476 * \param *Force ForceMatrix containing force vectors from the external energy functional minimisation.
477 * \todo the constant for the constrained potential distance part is hard-coded independently of the hard-coded value in MinimiseConstrainedPotential()
478 */
[e138de]479void molecule::EvaluateConstrainedForces(int startstep, int endstep, atom **PermutationMap, ForceMatrix *Force)
[cee0b57]480{
481 /// evaluate forces (only the distance to target dependent part) with the final PermutationMap
[a67d19]482 DoLog(1) && (Log() << Verbose(1) << "Calculating forces and adding onto ForceMatrix ... " << endl);
[2be37b]483 for_each(atoms.begin(),
484 atoms.end(),
485 boost::bind(&atom::EvaluateConstrainedForce,_1,startstep,endstep,PermutationMap,Force));
486 //ActOnAllAtoms( &atom::EvaluateConstrainedForce, startstep, endstep, PermutationMap, Force );
[a67d19]487 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
[cee0b57]488};
489
490/** Performs a linear interpolation between two desired atomic configurations with a given number of steps.
491 * Note, step number is config::MaxOuterStep
492 * \param *out output stream for debugging
493 * \param startstep stating initial configuration in molecule::Trajectories
494 * \param endstep stating final configuration in molecule::Trajectories
[35b698]495 * \param &prefix path and prefix
[cee0b57]496 * \param &config configuration structure
497 * \param MapByIdentity if true we just use the identity to map atoms in start config to end config, if not we find mapping by \sa MinimiseConstrainedPotential()
498 * \return true - success in writing step files, false - error writing files or only one step in molecule::Trajectories
499 */
[e4afb4]500bool molecule::LinearInterpolationBetweenConfiguration(int startstep, int endstep, std::string prefix, config &configuration, bool MapByIdentity)
[cee0b57]501{
[32ea56]502 // TODO: rewrite permutationMaps using enumeration objects
[cee0b57]503 molecule *mol = NULL;
504 bool status = true;
505 int MaxSteps = configuration.MaxOuterStep;
[23b547]506 MoleculeListClass *MoleculePerStep = new MoleculeListClass(World::getPointer());
[cee0b57]507 // Get the Permutation Map by MinimiseConstrainedPotential
508 atom **PermutationMap = NULL;
[9879f6]509 atom *Sprinter = NULL;
[cee0b57]510 if (!MapByIdentity)
[e138de]511 MinimiseConstrainedPotential(PermutationMap, startstep, endstep, configuration.GetIsAngstroem());
[cee0b57]512 else {
[32ea56]513 // TODO: construction of enumeration goes here
[1024cb]514 PermutationMap = new atom *[getAtomCount()];
[32ea56]515 for(internal_iterator iter = atoms.begin(); iter != atoms.end();++iter){
516 PermutationMap[(*iter)->nr] = (*iter);
517 }
[cee0b57]518 }
519
520 // check whether we have sufficient space in Trajectories for each atom
[c743f8]521 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::ResizeTrajectory),MaxSteps));
[cee0b57]522 // push endstep to last one
[c743f8]523 for_each(atoms.begin(),atoms.end(),boost::bind(&atom::CopyStepOnStep,_1,MaxSteps,endstep));
[cee0b57]524 endstep = MaxSteps;
525
526 // go through all steps and add the molecular configuration to the list and to the Trajectories of \a this molecule
[a67d19]527 DoLog(1) && (Log() << Verbose(1) << "Filling intermediate " << MaxSteps << " steps with MDSteps of " << MDSteps << "." << endl);
[cee0b57]528 for (int step = 0; step <= MaxSteps; step++) {
[23b547]529 mol = World::getInstance().createMolecule();
[cee0b57]530 MoleculePerStep->insert(mol);
[9879f6]531 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
[cee0b57]532 // add to molecule list
[9879f6]533 Sprinter = mol->AddCopyAtom((*iter));
[cee0b57]534 for (int n=NDIM;n--;) {
[d74077]535 Sprinter->set(n, (*iter)->Trajectory.R.at(startstep)[n] + (PermutationMap[(*iter)->nr]->Trajectory.R.at(endstep)[n] - (*iter)->Trajectory.R.at(startstep)[n])*((double)step/(double)MaxSteps));
[cee0b57]536 // add to Trajectories
[e138de]537 //Log() << Verbose(3) << step << ">=" << MDSteps-1 << endl;
[cee0b57]538 if (step < MaxSteps) {
[a7b761b]539 (*iter)->Trajectory.R.at(step)[n] = (*iter)->Trajectory.R.at(startstep)[n] + (PermutationMap[(*iter)->nr]->Trajectory.R.at(endstep)[n] - (*iter)->Trajectory.R.at(startstep)[n])*((double)step/(double)MaxSteps);
540 (*iter)->Trajectory.U.at(step)[n] = 0.;
541 (*iter)->Trajectory.F.at(step)[n] = 0.;
[cee0b57]542 }
543 }
544 }
545 }
546 MDSteps = MaxSteps+1; // otherwise new Trajectories' points aren't stored on save&exit
547
548 // store the list to single step files
[1024cb]549 int *SortIndex = new int[getAtomCount()];
[ea7176]550 for (int i=getAtomCount(); i--; )
[cee0b57]551 SortIndex[i] = i;
[35b698]552
553 status = MoleculePerStep->OutputConfigForListOfFragments(prefix, SortIndex);
[920c70]554 delete[](SortIndex);
[cee0b57]555
556 // free and return
[920c70]557 delete[](PermutationMap);
[cee0b57]558 delete(MoleculePerStep);
559 return status;
560};
561
562/** Parses nuclear forces from file and performs Verlet integration.
563 * Note that we assume the parsed forces to be in atomic units (hence, if coordinates are in angstroem, we
564 * have to transform them).
565 * This adds a new MD step to the config file.
566 * \param *file filename
567 * \param config structure with config::Deltat, config::IsAngstroem, config::DoConstrained
[ef7d30]568 * \param offset offset in matrix file to the first force component
[cee0b57]569 * \return true - file found and parsed, false - file not found or imparsable
570 * \todo This is not yet checked if it is correctly working with DoConstrained set to true.
571 */
[ef7d30]572bool molecule::VerletForceIntegration(char *file, config &configuration, const size_t offset)
[cee0b57]573{
[c7a473]574 Info FunctionInfo(__func__);
[cee0b57]575 ifstream input(file);
576 string token;
577 stringstream item;
[4a7776a]578 double IonMass, ConstrainedPotentialEnergy, ActualTemp;
579 Vector Velocity;
[cee0b57]580 ForceMatrix Force;
581
[ef7d30]582 const int AtomCount = getAtomCount();
[cee0b57]583 // check file
584 if (input == NULL) {
585 return false;
586 } else {
587 // parse file into ForceMatrix
588 if (!Force.ParseMatrix(file, 0,0,0)) {
[58ed4a]589 DoeLog(0) && (eLog()<< Verbose(0) << "Could not parse Force Matrix file " << file << "." << endl);
[e359a8]590 performCriticalExit();
[cee0b57]591 return false;
592 }
[ef7d30]593 if (Force.RowCounter[0] != AtomCount) {
[a7b761b]594 DoeLog(0) && (eLog()<< Verbose(0) << "Mismatch between number of atoms in file " << Force.RowCounter[0] << " and in molecule " << getAtomCount() << "." << endl);
[e359a8]595 performCriticalExit();
[cee0b57]596 return false;
597 }
598 // correct Forces
[4a7776a]599 Velocity.Zero();
[ef7d30]600 for(int i=0;i<AtomCount;i++)
[cee0b57]601 for(int d=0;d<NDIM;d++) {
[ef7d30]602 Velocity[d] += Force.Matrix[0][i][d+offset];
[cee0b57]603 }
[ef7d30]604 for(int i=0;i<AtomCount;i++)
[cee0b57]605 for(int d=0;d<NDIM;d++) {
[ef7d30]606 Force.Matrix[0][i][d+offset] -= Velocity[d]/static_cast<double>(AtomCount);
[cee0b57]607 }
608 // solve a constrained potential if we are meant to
609 if (configuration.DoConstrainedMD) {
610 // calculate forces and potential
611 atom **PermutationMap = NULL;
[e138de]612 ConstrainedPotentialEnergy = MinimiseConstrainedPotential(PermutationMap,configuration.DoConstrainedMD, 0, configuration.GetIsAngstroem());
613 EvaluateConstrainedForces(configuration.DoConstrainedMD, 0, PermutationMap, &Force);
[920c70]614 delete[](PermutationMap);
[cee0b57]615 }
616
617 // and perform Verlet integration for each atom with position, velocity and force vector
[4a7776a]618 // check size of vectors
[c7a473]619 //ActOnAllAtoms( &atom::ResizeTrajectory, MDSteps+10 );
[2be37b]620 for_each(atoms.begin(),
621 atoms.end(),
622 boost::bind(&atom::VelocityVerletUpdate,_1,MDSteps+1, &configuration, &Force, (const size_t) 0));
[cee0b57]623 }
624 // correct velocities (rather momenta) so that center of mass remains motionless
[259b2b]625 Velocity = atoms.totalMomentumAtStep(MDSteps+1);
626 IonMass = atoms.totalMass();
[4a7776a]627
[cee0b57]628 // correct velocities (rather momenta) so that center of mass remains motionless
[5cd333c]629 Velocity *= 1./IonMass;
[259b2b]630
631 atoms.addVelocityAtStep(-1*Velocity,MDSteps+1);
632 ActualTemp = atoms.totalTemperatureAtStep(MDSteps+1);
[14c57a]633 Berendsen berendsen = Berendsen();
634 berendsen.addToContainer(configuration.Thermostats);
635 double ekin = berendsen.scaleAtoms(MDSteps,ActualTemp,atoms);
636 DoLog(1) && (Log() << Verbose(1) << "Kinetic energy is " << ekin << "." << endl);
[cee0b57]637 MDSteps++;
638
639 // exit
640 return true;
641};
Note: See TracBrowser for help on using the repository browser.