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 |
|
---|
8 | /*
|
---|
9 | * molecule_dynamics.cpp
|
---|
10 | *
|
---|
11 | * Created on: Oct 5, 2009
|
---|
12 | * Author: heber
|
---|
13 | */
|
---|
14 |
|
---|
15 | // include config.h
|
---|
16 | #ifdef HAVE_CONFIG_H
|
---|
17 | #include <config.h>
|
---|
18 | #endif
|
---|
19 |
|
---|
20 | #include "CodePatterns/MemDebug.hpp"
|
---|
21 |
|
---|
22 | #include "World.hpp"
|
---|
23 | #include "atom.hpp"
|
---|
24 | #include "config.hpp"
|
---|
25 | #include "Dynamics/MinimiseConstrainedPotential.hpp"
|
---|
26 | //#include "element.hpp"
|
---|
27 | #include "CodePatterns/Info.hpp"
|
---|
28 | //#include "CodePatterns/Verbose.hpp"
|
---|
29 | //#include "CodePatterns/Log.hpp"
|
---|
30 | #include "molecule.hpp"
|
---|
31 | #include "parser.hpp"
|
---|
32 | //#include "LinearAlgebra/Plane.hpp"
|
---|
33 | #include "ThermoStatContainer.hpp"
|
---|
34 | #include "Thermostats/Berendsen.hpp"
|
---|
35 |
|
---|
36 | #include "CodePatterns/enumeration.hpp"
|
---|
37 |
|
---|
38 | /************************************* Functions for class molecule *********************************/
|
---|
39 |
|
---|
40 |
|
---|
41 | /** Performs a linear interpolation between two desired atomic configurations with a given number of steps.
|
---|
42 | * Note, step number is config::MaxOuterStep
|
---|
43 | * \param *out output stream for debugging
|
---|
44 | * \param startstep stating initial configuration in molecule::Trajectories
|
---|
45 | * \param endstep stating final configuration in molecule::Trajectories
|
---|
46 | * \param &prefix path and prefix
|
---|
47 | * \param &config configuration structure
|
---|
48 | * \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()
|
---|
49 | * \return true - success in writing step files, false - error writing files or only one step in molecule::Trajectories
|
---|
50 | */
|
---|
51 | bool molecule::LinearInterpolationBetweenConfiguration(int startstep, int endstep, std::string prefix, config &configuration, bool MapByIdentity)
|
---|
52 | {
|
---|
53 | // TODO: rewrite permutationMaps using enumeration objects
|
---|
54 | molecule *mol = NULL;
|
---|
55 | bool status = true;
|
---|
56 | int MaxSteps = configuration.MaxOuterStep;
|
---|
57 | MoleculeListClass *MoleculePerStep = new MoleculeListClass(World::getPointer());
|
---|
58 | // Get the Permutation Map by MinimiseConstrainedPotential
|
---|
59 | atom **PermutationMap = NULL;
|
---|
60 | atom *Sprinter = NULL;
|
---|
61 | if (!MapByIdentity) {
|
---|
62 | MinimiseConstrainedPotential Minimiser(atoms);
|
---|
63 | Minimiser(PermutationMap, startstep, endstep, configuration.GetIsAngstroem());
|
---|
64 | } else {
|
---|
65 | // TODO: construction of enumeration goes here
|
---|
66 | PermutationMap = new atom *[getAtomCount()];
|
---|
67 | for(internal_iterator iter = atoms.begin(); iter != atoms.end();++iter){
|
---|
68 | PermutationMap[(*iter)->getNr()] = (*iter);
|
---|
69 | }
|
---|
70 | }
|
---|
71 |
|
---|
72 | // check whether we have sufficient space in Trajectories for each atom
|
---|
73 | LOG(1, "STATUS: Extending each trajectory size to " << MaxSteps+1 << ".");
|
---|
74 | for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::ResizeTrajectory),MaxSteps+1));
|
---|
75 | // push endstep to last one
|
---|
76 | for_each(atoms.begin(),atoms.end(),boost::bind(&atom::CopyStepOnStep,_1,MaxSteps,endstep));
|
---|
77 | endstep = MaxSteps;
|
---|
78 |
|
---|
79 | // go through all steps and add the molecular configuration to the list and to the Trajectories of \a this molecule
|
---|
80 | DoLog(1) && (Log() << Verbose(1) << "Filling intermediate " << MaxSteps << " steps with MDSteps of " << MDSteps << "." << endl);
|
---|
81 | for (int step = 0; step <= MaxSteps; step++) {
|
---|
82 | mol = World::getInstance().createMolecule();
|
---|
83 | MoleculePerStep->insert(mol);
|
---|
84 | for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
|
---|
85 | // add to molecule list
|
---|
86 | Sprinter = mol->AddCopyAtom((*iter));
|
---|
87 | // add to Trajectories
|
---|
88 | Vector temp = (*iter)->getPositionAtStep(startstep) + (PermutationMap[(*iter)->getNr()]->getPositionAtStep(endstep) - (*iter)->getPositionAtStep(startstep))*((double)step/(double)MaxSteps);
|
---|
89 | Sprinter->setPosition(temp);
|
---|
90 | (*iter)->setAtomicVelocityAtStep(step, zeroVec);
|
---|
91 | (*iter)->setAtomicForceAtStep(step, zeroVec);
|
---|
92 | //Log() << Verbose(3) << step << ">=" << MDSteps-1 << endl;
|
---|
93 | }
|
---|
94 | }
|
---|
95 | MDSteps = MaxSteps+1; // otherwise new Trajectories' points aren't stored on save&exit
|
---|
96 |
|
---|
97 | // store the list to single step files
|
---|
98 | int *SortIndex = new int[getAtomCount()];
|
---|
99 | for (int i=getAtomCount(); i--; )
|
---|
100 | SortIndex[i] = i;
|
---|
101 |
|
---|
102 | status = MoleculePerStep->OutputConfigForListOfFragments(prefix, SortIndex);
|
---|
103 | delete[](SortIndex);
|
---|
104 |
|
---|
105 | // free and return
|
---|
106 | delete[](PermutationMap);
|
---|
107 | delete(MoleculePerStep);
|
---|
108 | return status;
|
---|
109 | };
|
---|
110 |
|
---|
111 | /** Parses nuclear forces from file and performs Verlet integration.
|
---|
112 | * Note that we assume the parsed forces to be in atomic units (hence, if coordinates are in angstroem, we
|
---|
113 | * have to transform them).
|
---|
114 | * This adds a new MD step to the config file.
|
---|
115 | * \param *file filename
|
---|
116 | * \param config structure with config::Deltat, config::IsAngstroem, config::DoConstrained
|
---|
117 | * \param offset offset in matrix file to the first force component
|
---|
118 | * \return true - file found and parsed, false - file not found or imparsable
|
---|
119 | * \todo This is not yet checked if it is correctly working with DoConstrained set to true.
|
---|
120 | */
|
---|
121 | bool molecule::VerletForceIntegration(char *file, config &configuration, const size_t offset)
|
---|
122 | {
|
---|
123 | Info FunctionInfo(__func__);
|
---|
124 | string token;
|
---|
125 | stringstream item;
|
---|
126 | double IonMass, ConstrainedPotentialEnergy, ActualTemp;
|
---|
127 | Vector Velocity;
|
---|
128 | ForceMatrix Force;
|
---|
129 |
|
---|
130 | const int AtomCount = getAtomCount();
|
---|
131 | // parse file into ForceMatrix
|
---|
132 | std::ifstream input(file);
|
---|
133 | if ((input.good()) && (!Force.ParseMatrix(input, 0,0,0))) {
|
---|
134 | DoeLog(0) && (eLog()<< Verbose(0) << "Could not parse Force Matrix file " << file << "." << endl);
|
---|
135 | performCriticalExit();
|
---|
136 | return false;
|
---|
137 | }
|
---|
138 | input.close();
|
---|
139 | if (Force.RowCounter[0] != AtomCount) {
|
---|
140 | DoeLog(0) && (eLog()<< Verbose(0) << "Mismatch between number of atoms in file " << Force.RowCounter[0] << " and in molecule " << getAtomCount() << "." << endl);
|
---|
141 | performCriticalExit();
|
---|
142 | return false;
|
---|
143 | }
|
---|
144 | // correct Forces
|
---|
145 | Velocity.Zero();
|
---|
146 | for(int i=0;i<AtomCount;i++)
|
---|
147 | for(int d=0;d<NDIM;d++) {
|
---|
148 | Velocity[d] += Force.Matrix[0][i][d+offset];
|
---|
149 | }
|
---|
150 | for(int i=0;i<AtomCount;i++)
|
---|
151 | for(int d=0;d<NDIM;d++) {
|
---|
152 | Force.Matrix[0][i][d+offset] -= Velocity[d]/static_cast<double>(AtomCount);
|
---|
153 | }
|
---|
154 | // solve a constrained potential if we are meant to
|
---|
155 | if (configuration.DoConstrainedMD) {
|
---|
156 | // calculate forces and potential
|
---|
157 | atom **PermutationMap = NULL;
|
---|
158 | MinimiseConstrainedPotential Minimiser(atoms);
|
---|
159 | //double ConstrainedPotentialEnergy =
|
---|
160 | Minimiser(PermutationMap, configuration.DoConstrainedMD, 0, configuration.GetIsAngstroem());
|
---|
161 | Minimiser.EvaluateConstrainedForces(&Force);
|
---|
162 | delete[](PermutationMap);
|
---|
163 | }
|
---|
164 |
|
---|
165 | // and perform Verlet integration for each atom with position, velocity and force vector
|
---|
166 | // check size of vectors
|
---|
167 | BOOST_FOREACH(atom *_atom, atoms) {
|
---|
168 | _atom->VelocityVerletUpdate(_atom->getNr(), MDSteps+1, &configuration, &Force, (const size_t) 0);
|
---|
169 | }
|
---|
170 |
|
---|
171 | // correct velocities (rather momenta) so that center of mass remains motionless
|
---|
172 | Velocity = atoms.totalMomentumAtStep(MDSteps+1);
|
---|
173 | IonMass = atoms.totalMass();
|
---|
174 |
|
---|
175 | // correct velocities (rather momenta) so that center of mass remains motionless
|
---|
176 | Velocity *= 1./IonMass;
|
---|
177 |
|
---|
178 | atoms.addVelocityAtStep(-1*Velocity,MDSteps+1);
|
---|
179 | ActualTemp = atoms.totalTemperatureAtStep(MDSteps+1);
|
---|
180 | Berendsen berendsen = Berendsen();
|
---|
181 | berendsen.addToContainer(World::getInstance().getThermostats());
|
---|
182 | double ekin = berendsen.scaleAtoms(MDSteps,ActualTemp,atoms);
|
---|
183 | DoLog(1) && (Log() << Verbose(1) << "Kinetic energy is " << ekin << "." << endl);
|
---|
184 | MDSteps++;
|
---|
185 |
|
---|
186 | // exit
|
---|
187 | return true;
|
---|
188 | };
|
---|