Simpatico  v1.10
TwoStepIntegrator.cpp
1 /*
2 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
3 *
4 * Copyright 2010 - 2017, The Regents of the University of Minnesota
5 * Distributed under the terms of the GNU General Public License.
6 */
7 
8 #include "TwoStepIntegrator.h"
9 #include <ddMd/simulation/Simulation.h>
10 #include <ddMd/storage/AtomStorage.h>
11 #include <ddMd/communicate/Exchanger.h>
12 #ifdef DDMD_MODIFIERS
13 #include <ddMd/modifiers/ModifierManager.h>
14 #endif
15 #include <ddMd/analyzers/AnalyzerManager.h>
16 #include <ddMd/potentials/pair/PairPotential.h>
17 #include <simp/ensembles/BoundaryEnsemble.h>
18 #include <util/misc/Log.h>
19 #include <util/global.h>
20 
21 // Uncomment to enable paranoid validity checks.
22 //#define DDMD_INTEGRATOR_DEBUG
23 
24 namespace DdMd
25 {
26 
27  using namespace Util;
28  using namespace Simp;
29 
30  /*
31  * Constructor.
32  */
34  : Integrator(simulation)
35  {}
36 
37  /*
38  * Destructor.
39  */
41  {}
42 
43  /*
44  * Run integrator for nStep steps.
45  */
46  void TwoStepIntegrator::run(int nStep)
47  {
48  // Precondition
49  if (atomStorage().isCartesian()) {
50  UTIL_THROW("Error: Atom coordinates are Cartesian");
51  }
52 
53  // References to managers
54  #ifdef DDMD_MODIFIERS
55  ModifierManager& modifierManager = simulation().modifierManager();
56  #endif
57  AnalyzerManager& analyzerManager = simulation().analyzerManager();
58 
59  // Unset all stored computations.
61 
62  // Recompute nAtomTotal.
64  atomStorage().computeNAtomTotal(domain().communicator());
65 
66  // Setup required before main loop (atoms, ghosts, groups, forces, etc)
67  // Atomic coordinates are Cartesian on exit from Integrator::setup().
68  // Atomic forces should be set on exit from Integrator::setup().
69  setup();
70  #ifdef DDMD_MODIFIERS
71  modifierManager.setup();
72  #endif
73  analyzerManager.setup();
74 
75  // Main MD loop
76  timer().start();
77  exchanger().timer().start();
78  int beginStep = iStep_;
79  int endStep = iStep_ + nStep;
80  bool needExchange;
81  for ( ; iStep_ < endStep; ++iStep_) {
82 
83  // Atomic coordinates must be Cartesian on entry to loop body.
84  if (!atomStorage().isCartesian()) {
85  UTIL_THROW("Error: Atomic coordinates are not Cartesian");
86  }
87 
88  // Sample analyzers, if scheduled.
89  analyzerManager.sample(iStep_);
90 
91  // Write restart file, if scheduled.
92  if (saveInterval() > 0) {
93  if (iStep_ % saveInterval() == 0) {
94  if (iStep_ > beginStep) {
96  }
97  }
98  }
99  timer().stamp(ANALYZER);
100 
101  #ifdef DDMD_MODIFIERS
102  modifierManager.preIntegrate1(iStep_);
103  timer().stamp(MODIFIER);
104  #endif
105 
106  // First step of integration: Update positions, half velocity
107  integrateStep1();
108  timer().stamp(INTEGRATE1);
109 
110  // Unset precomputed values of all energies, stresses, etc.
112 
113  #ifdef DDMD_INTEGRATOR_DEBUG
114  // Sanity check
115  simulation().isValid();
116  timer().stamp(DEBUG);
117  #endif
118 
119  #ifdef DDMD_MODIFIERS
120  modifierManager.postIntegrate1(iStep_);
121  timer().stamp(MODIFIER);
122  #endif
123 
124  // Check if exchange and reneighboring is necessary
125  // Note: Integrate::isExchangeNeeded uses timer.
126  needExchange = isExchangeNeeded(pairPotential().skin());
127 
128  if (!atomStorage().isCartesian()) {
129  UTIL_THROW("Error: atomic coordinates are not Cartesian");
130  }
131 
132  // Exchange atoms if necessary
133  if (needExchange) {
134 
135  #ifdef DDMD_MODIFIERS
136  modifierManager.preTransform(iStep_);
137  timer().stamp(MODIFIER);
138  #endif
139 
140  // Transform to scaled [0,1] coordinates
143  timer().stamp(Integrator::TRANSFORM_F);
144 
145  #ifdef DDMD_MODIFIERS
146  modifierManager.preExchange(iStep_);
147  timer().stamp(MODIFIER);
148  #endif
149 
150  // Exchange atom ownership, reidentify ghosts
151  exchanger().exchange();
152  timer().stamp(Integrator::EXCHANGE);
153 
154  #ifdef DDMD_MODIFIERS
155  modifierManager.postExchange(iStep_);
156  timer().stamp(MODIFIER);
157  #endif
158 
159  // Build cell list
161  timer().stamp(Integrator::CELLLIST);
162 
163  // Transform from scaled [0,1] to Cartesian coordinates.
165  timer().stamp(Integrator::TRANSFORM_R);
166 
167  // Build pair list
170  timer().stamp(Integrator::PAIRLIST);
171 
172  #ifdef DDMD_MODIFIERS
173  modifierManager.postNeighbor(iStep_);
174  timer().stamp(MODIFIER);
175  #endif
176 
177  } else { // Update step (no exchange)
178 
179  #ifdef DDMD_MODIFIERS
180  modifierManager.preUpdate(iStep_);
181  timer().stamp(MODIFIER);
182  #endif
183 
184  // Update all ghost atom positions
185  exchanger().update();
186  timer().stamp(UPDATE);
187 
188  #ifdef DDMD_MODIFIERS
189  modifierManager.postUpdate(iStep_);
190  timer().stamp(MODIFIER);
191  #endif
192 
193  }
195 
196  #ifdef DDMD_INTEGRATOR_DEBUG
197  // Sanity check
198  simulation().isValid();
199  timer().stamp(DEBUG);
200  #endif
201 
202  if (!atomStorage().isCartesian()) {
203  UTIL_THROW("Error: Atomic coordinates are not Cartesian");
204  }
205 
206  #ifdef DDMD_MODIFIERS
207  modifierManager.preForce(iStep_);
208  timer().stamp(MODIFIER);
209  #endif
210 
211  // Calculate forces:
212  // Calculate new forces for all local atoms. If constant pressure
213  // ensemble (not rigid), also calculate the virial stress. Both
214  // methods use the timer() internall, and both send the modifyForce
215  // signal.
216  if (simulation().boundaryEnsemble().isRigid()) {
217  computeForces();
218  } else {
220  }
221 
222  #ifdef DDMD_MODIFIERS
223  modifierManager.postForce(iStep_);
224  timer().stamp(MODIFIER);
225  #endif
226 
227  // 2nd step of velocity-Verlet integration. This finishes the velocity
228  // update, and normally calls simulation().velocitySignal().notify()
229  integrateStep2();
230  timer().stamp(INTEGRATE2);
231 
232  #ifdef DDMD_INTEGRATOR_DEBUG
233  // Sanity check
234  simulation().isValid();
235  timer().stamp(DEBUG);
236  #endif
237 
238  #ifdef DDMD_MODIFIERS
239  modifierManager.endOfStep(iStep_);
240  timer().stamp(MODIFIER);
241  #endif
242 
243  }
244  exchanger().timer().stop();
245  timer().stop();
246 
247  // Final analyzers and restart file, if scheduled.
248  analyzerManager.sample(iStep_);
249  if (saveInterval() > 0) {
250  if (iStep_ % saveInterval() == 0) {
252  }
253  }
254 
255  // Transform to scaled coordinates, in preparation for the next run.
257 
258  if (domain().isMaster()) {
259  Log::file() << std::endl;
260  }
261 
262  }
263 
264 }
Signal & modifySignal()
Signal to force unsetting of quantities that depend on x, v, or f.
void makeSnapshot()
Record current positions of all local atoms and lock storage.
PairPotential & pairPotential()
Get the PairPotential.
int iStep_
Current step number.
Definition: Integrator.h:207
ModifierManager & modifierManager()
Return the ModifierManager by reference.
void computeForces()
Compute forces for all local atoms, with timing.
Definition: Integrator.cpp:146
void update()
Update ghost atom coordinates.
Definition: Exchanger.cpp:821
void transformGenToCart(const Boundary &boundary)
Transform positions from generalized to Cartesian coordinates.
void postNeighbor(long iStep)
Call on exchange steps after re-building the neighbor list.
void preTransform(long iStep)
Call on exchange steps before transforming to scaled coordinates.
void postUpdate(long iStep)
Call on update steps after updating ghost positions.
TwoStepIntegrator(Simulation &simulation)
Constructor.
BoundaryEnsemble & boundaryEnsemble()
Get the BoundaryEnsemble.
Manager for a list of Analyzer objects.
void setup()
Call setup method of each Analyzer.
Boundary & boundary()
Get the Boundary.
void buildPairList()
Build the Verlet Pair list.
AnalyzerManager & analyzerManager()
Return the AnalyzerManager by reference.
void stop()
Stop total time accumulation.
Definition: DdTimer.cpp:44
void endOfStep(long iStep)
Call after 2nd integration step, at end of the time step.
bool isExchangeNeeded(double skin)
Determine whether an atom exchange and reneighboring is needed.
Definition: Integrator.cpp:244
File containing preprocessor macros for error handling.
Parallel domain decomposition (DD) MD simulation.
Classes used by all simpatico molecular simulations.
Main object for a domain-decomposition MD simulation.
void buildCellList()
Build a cell list.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
void computeForcesAndVirial()
Compute forces for all local atoms and virial, with timing.
Definition: Integrator.cpp:195
void stamp(int id)
Mark end of interval id.
Definition: DdTimer.cpp:37
virtual void integrateStep1()=0
Execute first step of two-step integrator.
void preIntegrate1(long iStep)
Call just before the first step of velocity-Verlet algorithm.
void sample(long iStep)
Call sample method of each Analyzer, if scheduled.
An Integrator numerically integrates the equations of motion.
Definition: Integrator.h:29
void notify(const T &t)
Notify all observers.
Definition: Signal.cpp:22
Utility classes for scientific computation.
Definition: accumulators.mod:1
virtual void integrateStep2()=0
Execute secodn step of two-step integrator.
void postExchange(long iStep)
Call on exchange steps after atom exchange, before reneighboring.
int saveInterval() const
Get interval for writing a restart file.
Definition: Integrator.h:265
Domain & domain()
Get the Domain.
void preUpdate(long iStep)
Call on update steps before updating ghost positions.
Exchanger & exchanger()
Get the Exchanger.
void clearSnapshot()
Clear previous snapshot.
AtomStorage & atomStorage()
Get the AtomStorage.
void computeNAtomTotal(MPI::Intracomm &communicator)
Compute the total number of local atoms on all processors.
Simulation & simulation()
Get the parent simulation.
static std::ostream & file()
Get log ostream by reference.
Definition: Log.cpp:57
void run(int nStep)
Run a simulation.
Manager for a set of Modifier objects.
DdTimer & timer()
Return internal timer by reference.
Definition: Exchanger.h:234
void preForce(long iStep)
Call after updating but before calculating forces.
virtual void setup()=0
Setup integrator just before integration.
void postIntegrate1(long iStep)
Call just after the first step of velocity-Verlet algorithm.
void exchange()
Exchange local atoms and ghosts.
Definition: Exchanger.cpp:106
bool isValid()
Return true if this Simulation is valid, or throw an Exception.
Signal & exchangeSignal()
Signal to indicate exchange of atoms and groups.
void save(const std::string &filename)
Save state to a restart file.
void setup()
Setup before entering the main loop.
void preExchange(long iStep)
Call on exchange steps after transforming, before exchanging.
void start()
Clear statistics, mark a start time.
Definition: DdTimer.cpp:31
void postForce(long iStep)
Call after calculating forces.
void transformCartToGen(const Boundary &boundary)
Transform positions from Cartesian to generalized coordinates.
void unsetNAtomTotal()
Unset value of NAtomTotal (mark as unknown).
const std::string & saveFileName() const
Get restart file base name.
Definition: Integrator.h:259