OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
Integrator.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
48#include "integrators/Integrator.hpp"
49
50#include <memory>
51#include <utility>
52
53#include "brains/Snapshot.hpp"
54#include "flucq/FluctuatingChargeDamped.hpp"
55#include "flucq/FluctuatingChargeLangevin.hpp"
56#include "flucq/FluctuatingChargeNVE.hpp"
57#include "flucq/FluctuatingChargeNVT.hpp"
58#include "integrators/DLM.hpp"
59#include "rnemd/MethodFactory.hpp"
60#include "rnemd/RNEMD.hpp"
61#include "rnemd/SPFForceManager.hpp"
62#include "utils/CI_String.hpp"
63#include "utils/CaseConversion.hpp"
64#include "utils/simError.h"
65
66namespace OpenMD {
67
68 Integrator::Integrator(SimInfo* info) :
69 info_(info), forceMan_(NULL), rotAlgo_(NULL), flucQ_(NULL), rattle_(NULL),
70 velocitizer_(nullptr), needPotential(false), needVirial(false),
71 needReset(false), needVelocityScaling(false), useRNEMD(false),
72 dumpWriter(NULL), statWriter(NULL), thermo(info_),
73 snap(info_->getSnapshotManager()->getCurrentSnapshot()) {
74 simParams = info->getSimParams();
75
76 if (simParams->haveDt()) {
77 dt = simParams->getDt();
78 dt2 = 0.5 * dt;
79 } else {
80 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
81 "Integrator Error: dt is not set\n");
82 painCave.isFatal = 1;
83 simError();
84 }
85
86 if (simParams->haveRunTime()) {
87 runTime = simParams->getRunTime();
88 } else {
89 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
90 "Integrator Error: runTime is not set\n");
91 painCave.isFatal = 1;
92 simError();
93 }
94
95 // set the status, sample, and thermal kick times
96 if (simParams->haveSampleTime()) {
97 sampleTime = simParams->getSampleTime();
98 statusTime = sampleTime;
99 } else {
100 sampleTime = simParams->getRunTime();
101 statusTime = sampleTime;
102 }
103
104 if (simParams->haveStatusTime()) {
105 statusTime = simParams->getStatusTime();
106 }
107
108 if (simParams->haveThermalTime()) {
109 thermalTime = simParams->getThermalTime();
110 } else {
111 thermalTime = simParams->getRunTime();
112 }
113
114 if (!simParams->getUseInitalTime()) { snap->setTime(0.0); }
115
116 if (simParams->haveResetTime()) {
117 needReset = true;
118 resetTime = simParams->getResetTime();
119 }
120
121 // check for the temperature set flag (velocity scaling)
122 needVelocityScaling = false;
123 if (simParams->haveTempSet()) {
124 needVelocityScaling = simParams->getTempSet();
125 }
126
127 if (needVelocityScaling) {
128 if (simParams->haveTargetTemp()) {
129 targetScalingTemp = simParams->getTargetTemp();
130 } else {
131 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
132 "Integrator Error: Target Temperature must be set to turn on "
133 "tempSet\n");
134 painCave.isFatal = 1;
135 simError();
136 }
137 }
138
139 // Create a default a velocitizer: If the subclass wants to use
140 // a different velocitizer, use setVelocitizer
141 velocitizer_ = std::make_unique<Velocitizer>(info);
142
143 if (simParams->getRNEMDParameters()->haveUseRNEMD()) {
144 useRNEMD = simParams->getRNEMDParameters()->getUseRNEMD();
145
146 if (useRNEMD) {
147 // ForceManager will only be changed if SPF-RNEMD is enabled
148 if (Utils::traits_cast<Utils::ci_char_traits>(
149 simParams->getRNEMDParameters()->getMethod()) == "SPF") {
150 forceMan_ = new RNEMD::SPFForceManager(info);
151 }
152
153 RNEMD::MethodFactory rnemdMethod {
154 simParams->getRNEMDParameters()->getMethod()};
155 rnemd_ = rnemdMethod.create(info, forceMan_);
156
157 if (simParams->getRNEMDParameters()->haveExchangeTime()) {
158 RNEMD_exchangeTime =
159 simParams->getRNEMDParameters()->getExchangeTime();
160
161 // check to make sure exchange time is a multiple of dt;
162 RealType newET = ceil(RNEMD_exchangeTime / dt) * dt;
163 if (std::fabs(newET - RNEMD_exchangeTime) > 1e-6) {
164 RNEMD_exchangeTime = newET;
165 }
166 }
167 }
168 }
169
170 if (forceMan_ == NULL) forceMan_ = new ForceManager(info);
171
172 rotAlgo_ = new DLM();
173 rattle_ = new Rattle(info);
174
175 if (simParams->getFluctuatingChargeParameters()->havePropagator()) {
176 std::string prop = toUpperCopy(
177 simParams->getFluctuatingChargeParameters()->getPropagator());
178 if (prop.compare("NVT") == 0) {
179 flucQ_ = new FluctuatingChargeNVT(info);
180 } else if (prop.compare("NVE") == 0) {
181 flucQ_ = new FluctuatingChargeNVE(info);
182 } else if (prop.compare("LANGEVIN") == 0) {
183 flucQ_ = new FluctuatingChargeLangevin(info);
184 } else if (prop.compare("DAMPED") == 0) {
185 flucQ_ = new FluctuatingChargeDamped(info);
186 } else {
187 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
188 "Integrator Error: Unknown Fluctuating Charge propagator (%s) "
189 "requested\n",
190 simParams->getFluctuatingChargeParameters()
191 ->getPropagator()
192 .c_str());
193 painCave.isFatal = 1;
194 }
195 }
196
197 flucQ_->setForceManager(forceMan_);
198 }
199
201 delete forceMan_;
202 delete flucQ_;
203 delete rotAlgo_;
204 delete rattle_;
205 delete dumpWriter;
206 delete stats;
207 delete statWriter;
208 }
209
210 void Integrator::updateSizes() {
211 doUpdateSizes();
212 flucQ_->updateSizes();
213 }
214
215 void Integrator::setVelocitizer(std::unique_ptr<Velocitizer> velocitizer) {
216 velocitizer_ = std::move(velocitizer);
217 }
218
219 void Integrator::setFluctuatingChargePropagator(
220 FluctuatingChargePropagator* prop) {
221 if (prop != flucQ_ && flucQ_ != NULL) { delete flucQ_; }
222 flucQ_ = prop;
223 if (forceMan_ != NULL) { flucQ_->setForceManager(forceMan_); }
224 }
225
226 void Integrator::setRotationAlgorithm(RotationAlgorithm* algo) {
227 if (algo != rotAlgo_ && rotAlgo_ != NULL) { delete rotAlgo_; }
228
229 rotAlgo_ = algo;
230 }
231
232 void Integrator::setRNEMD(std::unique_ptr<RNEMD::RNEMD> rnemd) {
233 rnemd_ = std::move(rnemd);
234 }
235
236 void Integrator::integrate() {
237 initialize();
238
239 while (snap->getTime() <= runTime) {
240 preStep();
241 step();
242 postStep();
243 }
244
245 finalize();
246 }
247
248 void Integrator::saveConservedQuantity() {
249 snap->setConservedQuantity(calcConservedQuantity());
250 }
251
252 void Integrator::initialize() {
253 forceMan_->initialize();
254
255 // remove center of mass drift velocity (in case we passed in a
256 // configuration that was drifting)
257 if (simParams->getConserveLinearMomentum()) velocitizer_->removeComDrift();
258
259 // find the initial fluctuating charges.
260 flucQ_->initialize();
261 // initialize the forces before the first step
262 calcForce();
263 // execute the constraint algorithm to make sure that the system is
264 // constrained at the very beginning
265 if (info_->getNGlobalConstraints() > 0) {
266 rattle_->constraintA();
267 calcForce();
268 rattle_->constraintB();
269 // copy the current snapshot to previous snapshot
270 info_->getSnapshotManager()->advance();
271 }
272
273 if (needVelocityScaling) { velocitizer_->randomize(targetScalingTemp); }
274
275 dumpWriter = createDumpWriter();
276 statWriter = createStatWriter();
277 dumpWriter->writeDumpAndEor();
278
279 progressBar = std::make_unique<ProgressBar>();
280
281 // save statistics, before writeStat, we must save statistics
282 saveConservedQuantity();
283 stats->collectStats();
284
285 if (useRNEMD) rnemd_->getStarted();
286
287 statWriter->writeStat();
288
289 currSample = sampleTime + snap->getTime();
290 currStatus = statusTime + snap->getTime();
291 currThermal = thermalTime + snap->getTime();
292 if (needReset) { currReset = resetTime + snap->getTime(); }
293 if (useRNEMD) { currRNEMD = RNEMD_exchangeTime + snap->getTime(); }
294 needPotential = false;
295 needVirial = false;
296 }
297
298 void Integrator::preStep() {
299 RealType difference = snap->getTime() + dt - currStatus;
300
301 if (difference > 0 || std::fabs(difference) <= dtEps) {
302 needPotential = true;
303 needVirial = true;
304 }
305 }
306
307 void Integrator::calcForce() {
308 forceMan_->calcForces();
309 flucQ_->applyConstraints();
310 }
311
312 void Integrator::postStep() {
313 RealType difference;
314
315 if (needVelocityScaling) {
316 difference = snap->getTime() - currThermal;
317
318 if (difference > 0 || std::fabs(difference) <= dtEps) {
319 velocitizer_->randomize(targetScalingTemp);
320 currThermal += thermalTime;
321 }
322 }
323
324 if (useRNEMD) {
325 difference = snap->getTime() - currRNEMD;
326
327 if (difference > 0 || std::fabs(difference) <= dtEps) {
328 rnemd_->doRNEMD();
329 currRNEMD += RNEMD_exchangeTime;
330 }
331
332 rnemd_->collectData();
333 rnemd_->writeOutputFile();
334 }
335
336 saveConservedQuantity();
337
338 difference = snap->getTime() - currSample;
339
340 if (difference > 0 || std::fabs(difference) <= dtEps) {
341 dumpWriter->writeDumpAndEor();
342 currSample += sampleTime;
343 }
344
345 difference = snap->getTime() - currStatus;
346
347 if (difference > 0 || std::fabs(difference) <= dtEps) {
348 stats->collectStats();
349
350 statWriter->writeStat();
351
352 progressBar->setStatus(snap->getTime(), runTime);
353 progressBar->update();
354
355 needPotential = false;
356 needVirial = false;
357 currStatus += statusTime;
358 }
359
360 difference = snap->getTime() - currReset;
361
362 if (needReset && (difference > 0 || std::fabs(difference) <= dtEps)) {
363 resetIntegrator();
364 currReset += resetTime;
365 }
366 // save snapshot
367 info_->getSnapshotManager()->advance();
368
369 // increase time
370 snap->increaseTime(dt);
371 }
372
373 void Integrator::finalize() {
374 dumpWriter->writeEor();
375 if (useRNEMD) { rnemd_->writeOutputFile(); }
376 progressBar->setStatus(runTime, runTime);
377 progressBar->update();
378
379 statWriter->writeStatReport();
380 }
381
382 DumpWriter* Integrator::createDumpWriter() { return new DumpWriter(info_); }
383
384 StatWriter* Integrator::createStatWriter() {
385 stats = new Stats(info_);
386 statWriter = new StatWriter(info_->getStatFileName(), stats);
387 statWriter->setReportFileName(info_->getReportFileName());
388
389 return statWriter;
390 }
391} // namespace OpenMD
virtual ~Integrator()
Default Destructor.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.