2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019,2020, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
36 * \brief Defines the modular simulator
38 * \author Pascal Merz <pascal.merz@me.com>
39 * \ingroup module_modularsimulator
44 #include "modularsimulator.h"
46 #include "gromacs/commandline/filenm.h"
47 #include "gromacs/domdec/domdec.h"
48 #include "gromacs/ewald/pme.h"
49 #include "gromacs/ewald/pme_load_balancing.h"
50 #include "gromacs/ewald/pme_pp.h"
51 #include "gromacs/gmxlib/network.h"
52 #include "gromacs/gmxlib/nrnb.h"
53 #include "gromacs/listed_forces/listed_forces.h"
54 #include "gromacs/mdlib/checkpointhandler.h"
55 #include "gromacs/mdlib/constr.h"
56 #include "gromacs/mdlib/coupling.h"
57 #include "gromacs/mdlib/energyoutput.h"
58 #include "gromacs/mdlib/mdatoms.h"
59 #include "gromacs/mdlib/resethandler.h"
60 #include "gromacs/mdlib/update.h"
61 #include "gromacs/mdrun/replicaexchange.h"
62 #include "gromacs/mdrun/shellfc.h"
63 #include "gromacs/mdrunutility/handlerestart.h"
64 #include "gromacs/mdrunutility/printtime.h"
65 #include "gromacs/mdtypes/commrec.h"
66 #include "gromacs/mdtypes/fcdata.h"
67 #include "gromacs/mdtypes/forcerec.h"
68 #include "gromacs/mdtypes/inputrec.h"
69 #include "gromacs/mdtypes/mdatom.h"
70 #include "gromacs/mdtypes/mdrunoptions.h"
71 #include "gromacs/mdtypes/observableshistory.h"
72 #include "gromacs/nbnxm/nbnxm.h"
73 #include "gromacs/topology/mtop_util.h"
74 #include "gromacs/topology/topology.h"
75 #include "gromacs/utility/fatalerror.h"
77 #include "compositesimulatorelement.h"
78 #include "computeglobalselement.h"
79 #include "constraintelement.h"
80 #include "energydata.h"
81 #include "forceelement.h"
82 #include "freeenergyperturbationdata.h"
83 #include "parrinellorahmanbarostat.h"
84 #include "propagator.h"
85 #include "signallers.h"
86 #include "simulatoralgorithm.h"
87 #include "statepropagatordata.h"
88 #include "trajectoryelement.h"
89 #include "vrescalethermostat.h"
93 void ModularSimulator::run()
95 GMX_LOG(legacySimulatorData_->mdlog.info)
97 .appendText("Using the modular simulator.");
99 ModularSimulatorAlgorithmBuilder algorithmBuilder(compat::make_not_null(legacySimulatorData_.get()));
100 auto algorithm = algorithmBuilder.build();
102 while (const auto* task = algorithm.getNextTask())
109 std::unique_ptr<ISimulatorElement> ModularSimulatorAlgorithmBuilder::buildForces(
110 SignallerBuilder<NeighborSearchSignaller>* neighborSearchSignallerBuilder,
111 SignallerBuilder<EnergySignaller>* energySignallerBuilder,
112 StatePropagatorData* statePropagatorDataPtr,
113 EnergyData* energyDataPtr,
114 FreeEnergyPerturbationData* freeEnergyPerturbationDataPtr,
115 TopologyHolder::Builder* topologyHolderBuilder)
117 const bool isVerbose = legacySimulatorData_->mdrunOptions.verbose;
118 const bool isDynamicBox = inputrecDynamicBox(legacySimulatorData_->inputrec);
120 auto forceElement = std::make_unique<ForceElement>(
121 statePropagatorDataPtr, energyDataPtr, freeEnergyPerturbationDataPtr, isVerbose, isDynamicBox,
122 legacySimulatorData_->fplog, legacySimulatorData_->cr, legacySimulatorData_->inputrec,
123 legacySimulatorData_->mdAtoms, legacySimulatorData_->nrnb, legacySimulatorData_->fr,
124 legacySimulatorData_->wcycle, legacySimulatorData_->runScheduleWork,
125 legacySimulatorData_->vsite, legacySimulatorData_->imdSession,
126 legacySimulatorData_->pull_work, legacySimulatorData_->constr,
127 legacySimulatorData_->top_global, legacySimulatorData_->enforcedRotation);
128 topologyHolderBuilder->registerClient(forceElement.get());
129 neighborSearchSignallerBuilder->registerSignallerClient(compat::make_not_null(forceElement.get()));
130 energySignallerBuilder->registerSignallerClient(compat::make_not_null(forceElement.get()));
132 // std::move *should* not be needed with c++-14, but clang-3.6 still requires it
133 return std::move(forceElement);
136 std::unique_ptr<ISimulatorElement> ModularSimulatorAlgorithmBuilder::buildIntegrator(
137 SignallerBuilder<NeighborSearchSignaller>* neighborSearchSignallerBuilder,
138 SignallerBuilder<LastStepSignaller>* lastStepSignallerBuilder,
139 SignallerBuilder<EnergySignaller>* energySignallerBuilder,
140 SignallerBuilder<LoggingSignaller>* loggingSignallerBuilder,
141 SignallerBuilder<TrajectorySignaller>* trajectorySignallerBuilder,
142 TrajectoryElementBuilder* trajectoryElementBuilder,
143 std::vector<ICheckpointHelperClient*>* checkpointClients,
144 compat::not_null<StatePropagatorData*> statePropagatorDataPtr,
145 compat::not_null<EnergyData*> energyDataPtr,
146 FreeEnergyPerturbationData* freeEnergyPerturbationDataPtr,
147 bool hasReadEkinState,
148 TopologyHolder::Builder* topologyHolderBuilder,
149 GlobalCommunicationHelper* globalCommunicationHelper)
151 auto forceElement = buildForces(neighborSearchSignallerBuilder, energySignallerBuilder,
152 statePropagatorDataPtr, energyDataPtr,
153 freeEnergyPerturbationDataPtr, topologyHolderBuilder);
155 // list of elements owned by the simulator composite object
156 std::vector<std::unique_ptr<ISimulatorElement>> elementsOwnershipList;
157 // call list of the simulator composite object
158 std::vector<compat::not_null<ISimulatorElement*>> elementCallList;
160 std::function<void()> needToCheckNumberOfBondedInteractions;
161 if (legacySimulatorData_->inputrec->eI == eiMD)
163 auto computeGlobalsElement =
164 std::make_unique<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>(
165 statePropagatorDataPtr, energyDataPtr, freeEnergyPerturbationDataPtr,
166 globalCommunicationHelper->simulationSignals(),
167 globalCommunicationHelper->nstglobalcomm(), legacySimulatorData_->fplog,
168 legacySimulatorData_->mdlog, legacySimulatorData_->cr,
169 legacySimulatorData_->inputrec, legacySimulatorData_->mdAtoms,
170 legacySimulatorData_->nrnb, legacySimulatorData_->wcycle,
171 legacySimulatorData_->fr, legacySimulatorData_->top_global,
172 legacySimulatorData_->constr, hasReadEkinState);
173 topologyHolderBuilder->registerClient(computeGlobalsElement.get());
174 energySignallerBuilder->registerSignallerClient(compat::make_not_null(computeGlobalsElement.get()));
175 trajectorySignallerBuilder->registerSignallerClient(
176 compat::make_not_null(computeGlobalsElement.get()));
178 globalCommunicationHelper->setCheckBondedInteractionsCallback(
179 computeGlobalsElement->getCheckNumberOfBondedInteractionsCallback());
181 auto propagator = std::make_unique<Propagator<IntegrationStep::LeapFrog>>(
182 legacySimulatorData_->inputrec->delta_t, statePropagatorDataPtr,
183 legacySimulatorData_->mdAtoms, legacySimulatorData_->wcycle);
185 addToCallListAndMove(std::move(forceElement), elementCallList, elementsOwnershipList);
186 auto stateElement = compat::make_not_null(statePropagatorDataPtr->element());
187 trajectoryElementBuilder->registerWriterClient(stateElement);
188 trajectorySignallerBuilder->registerSignallerClient(stateElement);
189 lastStepSignallerBuilder->registerSignallerClient(stateElement);
190 checkpointClients->emplace_back(stateElement);
191 // we have a full microstate at time t here!
192 addToCallList(stateElement, elementCallList);
193 if (legacySimulatorData_->inputrec->etc == etcVRESCALE)
195 // TODO: With increased complexity of the propagator, this will need further development,
196 // e.g. using propagators templated for velocity propagation policies and a builder
197 propagator->setNumVelocityScalingVariables(legacySimulatorData_->inputrec->opts.ngtc);
198 auto thermostat = std::make_unique<VRescaleThermostat>(
199 legacySimulatorData_->inputrec->nsttcouple, -1, false,
200 legacySimulatorData_->inputrec->ld_seed, legacySimulatorData_->inputrec->opts.ngtc,
201 legacySimulatorData_->inputrec->delta_t * legacySimulatorData_->inputrec->nsttcouple,
202 legacySimulatorData_->inputrec->opts.ref_t,
203 legacySimulatorData_->inputrec->opts.tau_t, legacySimulatorData_->inputrec->opts.nrdf,
204 energyDataPtr, propagator->viewOnVelocityScaling(),
205 propagator->velocityScalingCallback(), legacySimulatorData_->state_global,
206 legacySimulatorData_->cr, legacySimulatorData_->inputrec->bContinuation);
207 checkpointClients->emplace_back(thermostat.get());
208 energyDataPtr->setVRescaleThermostat(thermostat.get());
209 addToCallListAndMove(std::move(thermostat), elementCallList, elementsOwnershipList);
212 std::unique_ptr<ParrinelloRahmanBarostat> prBarostat = nullptr;
213 if (legacySimulatorData_->inputrec->epc == epcPARRINELLORAHMAN)
215 // Building the PR barostat here since it needs access to the propagator
216 // and we want to be able to move the propagator object
217 prBarostat = std::make_unique<ParrinelloRahmanBarostat>(
218 legacySimulatorData_->inputrec->nstpcouple, -1,
219 legacySimulatorData_->inputrec->delta_t * legacySimulatorData_->inputrec->nstpcouple,
220 legacySimulatorData_->inputrec->init_step, propagator->viewOnPRScalingMatrix(),
221 propagator->prScalingCallback(), statePropagatorDataPtr, energyDataPtr,
222 legacySimulatorData_->fplog, legacySimulatorData_->inputrec,
223 legacySimulatorData_->mdAtoms, legacySimulatorData_->state_global,
224 legacySimulatorData_->cr, legacySimulatorData_->inputrec->bContinuation);
225 energyDataPtr->setParrinelloRahamnBarostat(prBarostat.get());
226 checkpointClients->emplace_back(prBarostat.get());
228 addToCallListAndMove(std::move(propagator), elementCallList, elementsOwnershipList);
229 if (legacySimulatorData_->constr)
231 auto constraintElement = std::make_unique<ConstraintsElement<ConstraintVariable::Positions>>(
232 legacySimulatorData_->constr, statePropagatorDataPtr, energyDataPtr,
233 freeEnergyPerturbationDataPtr, MASTER(legacySimulatorData_->cr),
234 legacySimulatorData_->fplog, legacySimulatorData_->inputrec,
235 legacySimulatorData_->mdAtoms->mdatoms());
236 auto constraintElementPtr = compat::make_not_null(constraintElement.get());
237 energySignallerBuilder->registerSignallerClient(constraintElementPtr);
238 trajectorySignallerBuilder->registerSignallerClient(constraintElementPtr);
239 loggingSignallerBuilder->registerSignallerClient(constraintElementPtr);
241 addToCallListAndMove(std::move(constraintElement), elementCallList, elementsOwnershipList);
244 addToCallListAndMove(std::move(computeGlobalsElement), elementCallList, elementsOwnershipList);
245 auto energyElement = compat::make_not_null(energyDataPtr->element());
246 trajectoryElementBuilder->registerWriterClient(energyElement);
247 trajectorySignallerBuilder->registerSignallerClient(energyElement);
248 energySignallerBuilder->registerSignallerClient(energyElement);
249 checkpointClients->emplace_back(energyElement);
250 // we have the energies at time t here!
251 addToCallList(energyElement, elementCallList);
254 addToCallListAndMove(std::move(prBarostat), elementCallList, elementsOwnershipList);
257 else if (legacySimulatorData_->inputrec->eI == eiVV)
259 auto computeGlobalsElement =
260 std::make_unique<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>(
261 statePropagatorDataPtr, energyDataPtr, freeEnergyPerturbationDataPtr,
262 globalCommunicationHelper->simulationSignals(),
263 globalCommunicationHelper->nstglobalcomm(), legacySimulatorData_->fplog,
264 legacySimulatorData_->mdlog, legacySimulatorData_->cr,
265 legacySimulatorData_->inputrec, legacySimulatorData_->mdAtoms,
266 legacySimulatorData_->nrnb, legacySimulatorData_->wcycle,
267 legacySimulatorData_->fr, legacySimulatorData_->top_global,
268 legacySimulatorData_->constr, hasReadEkinState);
269 topologyHolderBuilder->registerClient(computeGlobalsElement.get());
270 energySignallerBuilder->registerSignallerClient(compat::make_not_null(computeGlobalsElement.get()));
271 trajectorySignallerBuilder->registerSignallerClient(
272 compat::make_not_null(computeGlobalsElement.get()));
274 globalCommunicationHelper->setCheckBondedInteractionsCallback(
275 computeGlobalsElement->getCheckNumberOfBondedInteractionsCallback());
277 auto propagatorVelocities = std::make_unique<Propagator<IntegrationStep::VelocitiesOnly>>(
278 legacySimulatorData_->inputrec->delta_t * 0.5, statePropagatorDataPtr,
279 legacySimulatorData_->mdAtoms, legacySimulatorData_->wcycle);
280 auto propagatorVelocitiesAndPositions =
281 std::make_unique<Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>>(
282 legacySimulatorData_->inputrec->delta_t, statePropagatorDataPtr,
283 legacySimulatorData_->mdAtoms, legacySimulatorData_->wcycle);
285 addToCallListAndMove(std::move(forceElement), elementCallList, elementsOwnershipList);
287 std::unique_ptr<ParrinelloRahmanBarostat> prBarostat = nullptr;
288 if (legacySimulatorData_->inputrec->epc == epcPARRINELLORAHMAN)
290 // Building the PR barostat here since it needs access to the propagator
291 // and we want to be able to move the propagator object
292 prBarostat = std::make_unique<ParrinelloRahmanBarostat>(
293 legacySimulatorData_->inputrec->nstpcouple, -1,
294 legacySimulatorData_->inputrec->delta_t * legacySimulatorData_->inputrec->nstpcouple,
295 legacySimulatorData_->inputrec->init_step,
296 propagatorVelocities->viewOnPRScalingMatrix(),
297 propagatorVelocities->prScalingCallback(), statePropagatorDataPtr,
298 energyDataPtr, legacySimulatorData_->fplog, legacySimulatorData_->inputrec,
299 legacySimulatorData_->mdAtoms, legacySimulatorData_->state_global,
300 legacySimulatorData_->cr, legacySimulatorData_->inputrec->bContinuation);
301 energyDataPtr->setParrinelloRahamnBarostat(prBarostat.get());
302 checkpointClients->emplace_back(prBarostat.get());
304 addToCallListAndMove(std::move(propagatorVelocities), elementCallList, elementsOwnershipList);
305 if (legacySimulatorData_->constr)
307 auto constraintElement = std::make_unique<ConstraintsElement<ConstraintVariable::Velocities>>(
308 legacySimulatorData_->constr, statePropagatorDataPtr, energyDataPtr,
309 freeEnergyPerturbationDataPtr, MASTER(legacySimulatorData_->cr),
310 legacySimulatorData_->fplog, legacySimulatorData_->inputrec,
311 legacySimulatorData_->mdAtoms->mdatoms());
312 energySignallerBuilder->registerSignallerClient(compat::make_not_null(constraintElement.get()));
313 trajectorySignallerBuilder->registerSignallerClient(
314 compat::make_not_null(constraintElement.get()));
315 loggingSignallerBuilder->registerSignallerClient(
316 compat::make_not_null(constraintElement.get()));
318 addToCallListAndMove(std::move(constraintElement), elementCallList, elementsOwnershipList);
320 addToCallList(compat::make_not_null(computeGlobalsElement.get()), elementCallList);
321 auto stateElement = compat::make_not_null(statePropagatorDataPtr->element());
322 trajectoryElementBuilder->registerWriterClient(stateElement);
323 trajectorySignallerBuilder->registerSignallerClient(stateElement);
324 lastStepSignallerBuilder->registerSignallerClient(stateElement);
325 checkpointClients->emplace_back(stateElement);
326 // we have a full microstate at time t here!
327 addToCallList(stateElement, elementCallList);
328 if (legacySimulatorData_->inputrec->etc == etcVRESCALE)
330 // TODO: With increased complexity of the propagator, this will need further development,
331 // e.g. using propagators templated for velocity propagation policies and a builder
332 propagatorVelocitiesAndPositions->setNumVelocityScalingVariables(
333 legacySimulatorData_->inputrec->opts.ngtc);
334 auto thermostat = std::make_unique<VRescaleThermostat>(
335 legacySimulatorData_->inputrec->nsttcouple, 0, true,
336 legacySimulatorData_->inputrec->ld_seed, legacySimulatorData_->inputrec->opts.ngtc,
337 legacySimulatorData_->inputrec->delta_t * legacySimulatorData_->inputrec->nsttcouple,
338 legacySimulatorData_->inputrec->opts.ref_t,
339 legacySimulatorData_->inputrec->opts.tau_t, legacySimulatorData_->inputrec->opts.nrdf,
340 energyDataPtr, propagatorVelocitiesAndPositions->viewOnVelocityScaling(),
341 propagatorVelocitiesAndPositions->velocityScalingCallback(),
342 legacySimulatorData_->state_global, legacySimulatorData_->cr,
343 legacySimulatorData_->inputrec->bContinuation);
344 checkpointClients->emplace_back(thermostat.get());
345 energyDataPtr->setVRescaleThermostat(thermostat.get());
346 addToCallListAndMove(std::move(thermostat), elementCallList, elementsOwnershipList);
348 addToCallListAndMove(std::move(propagatorVelocitiesAndPositions), elementCallList,
349 elementsOwnershipList);
350 if (legacySimulatorData_->constr)
352 auto constraintElement = std::make_unique<ConstraintsElement<ConstraintVariable::Positions>>(
353 legacySimulatorData_->constr, statePropagatorDataPtr, energyDataPtr,
354 freeEnergyPerturbationDataPtr, MASTER(legacySimulatorData_->cr),
355 legacySimulatorData_->fplog, legacySimulatorData_->inputrec,
356 legacySimulatorData_->mdAtoms->mdatoms());
357 energySignallerBuilder->registerSignallerClient(compat::make_not_null(constraintElement.get()));
358 trajectorySignallerBuilder->registerSignallerClient(
359 compat::make_not_null(constraintElement.get()));
360 loggingSignallerBuilder->registerSignallerClient(
361 compat::make_not_null(constraintElement.get()));
363 addToCallListAndMove(std::move(constraintElement), elementCallList, elementsOwnershipList);
365 addToCallListAndMove(std::move(computeGlobalsElement), elementCallList, elementsOwnershipList);
366 auto energyElement = compat::make_not_null(energyDataPtr->element());
367 trajectoryElementBuilder->registerWriterClient(energyElement);
368 trajectorySignallerBuilder->registerSignallerClient(energyElement);
369 energySignallerBuilder->registerSignallerClient(energyElement);
370 checkpointClients->emplace_back(energyElement);
371 // we have the energies at time t here!
372 addToCallList(energyElement, elementCallList);
375 addToCallListAndMove(std::move(prBarostat), elementCallList, elementsOwnershipList);
380 gmx_fatal(FARGS, "Integrator not implemented for the modular simulator.");
383 auto integrator = std::make_unique<CompositeSimulatorElement>(std::move(elementCallList),
384 std::move(elementsOwnershipList));
385 // std::move *should* not be needed with c++-14, but clang-3.6 still requires it
386 return std::move(integrator);
389 bool ModularSimulator::isInputCompatible(bool exitOnFailure,
390 const t_inputrec* inputrec,
392 const gmx_mtop_t& globalTopology,
393 const gmx_multisim_t* ms,
394 const ReplicaExchangeParameters& replExParams,
396 bool doEssentialDynamics,
399 auto conditionalAssert = [exitOnFailure](bool condition, const char* message) {
402 GMX_RELEASE_ASSERT(condition, message);
407 bool isInputCompatible = true;
409 // GMX_USE_MODULAR_SIMULATOR allows to use modular simulator also for non-standard uses,
410 // such as the leap-frog integrator
411 const auto modularSimulatorExplicitlyTurnedOn = (getenv("GMX_USE_MODULAR_SIMULATOR") != nullptr);
412 // GMX_USE_MODULAR_SIMULATOR allows to use disable modular simulator for all uses,
413 // including the velocity-verlet integrator used by default
414 const auto modularSimulatorExplicitlyTurnedOff = (getenv("GMX_DISABLE_MODULAR_SIMULATOR") != nullptr);
417 !(modularSimulatorExplicitlyTurnedOn && modularSimulatorExplicitlyTurnedOff),
418 "Cannot have both GMX_USE_MODULAR_SIMULATOR=ON and GMX_DISABLE_MODULAR_SIMULATOR=ON. "
419 "Unset one of the two environment variables to explicitly chose which simulator to "
421 "or unset both to recover default behavior.");
424 !(modularSimulatorExplicitlyTurnedOff && inputrec->eI == eiVV
425 && inputrec->epc == epcPARRINELLORAHMAN),
426 "Cannot use a Parrinello-Rahman barostat with md-vv and "
427 "GMX_DISABLE_MODULAR_SIMULATOR=ON, "
428 "as the Parrinello-Rahman barostat is not implemented in the legacy simulator. Unset "
429 "GMX_DISABLE_MODULAR_SIMULATOR or use a different pressure control algorithm.");
433 && conditionalAssert(
434 inputrec->eI == eiMD || inputrec->eI == eiVV,
435 "Only integrators md and md-vv are supported by the modular simulator.");
436 isInputCompatible = isInputCompatible
437 && conditionalAssert(inputrec->eI != eiMD || modularSimulatorExplicitlyTurnedOn,
438 "Set GMX_USE_MODULAR_SIMULATOR=ON to use the modular "
439 "simulator with integrator md.");
442 && conditionalAssert(!doRerun, "Rerun is not supported by the modular simulator.");
445 && conditionalAssert(
446 inputrec->etc == etcNO || inputrec->etc == etcVRESCALE,
447 "Only v-rescale thermostat is supported by the modular simulator.");
450 && conditionalAssert(
451 inputrec->epc == epcNO || inputrec->epc == epcPARRINELLORAHMAN,
452 "Only Parrinello-Rahman barostat is supported by the modular simulator.");
455 && conditionalAssert(
456 !(inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec)
457 || inputrecNvtTrotter(inputrec)),
458 "Legacy Trotter decomposition is not supported by the modular simulator.");
459 isInputCompatible = isInputCompatible
460 && conditionalAssert(inputrec->efep == efepNO || inputrec->efep == efepYES
461 || inputrec->efep == efepSLOWGROWTH,
462 "Expanded ensemble free energy calculation is not "
463 "supported by the modular simulator.");
464 isInputCompatible = isInputCompatible
465 && conditionalAssert(!inputrec->bPull,
466 "Pulling is not supported by the modular simulator.");
469 && conditionalAssert(inputrec->opts.ngacc == 1 && inputrec->opts.acc[0][XX] == 0.0
470 && inputrec->opts.acc[0][YY] == 0.0
471 && inputrec->opts.acc[0][ZZ] == 0.0 && inputrec->cos_accel == 0.0,
472 "Acceleration is not supported by the modular simulator.");
475 && conditionalAssert(inputrec->opts.ngfrz == 1 && inputrec->opts.nFreeze[0][XX] == 0
476 && inputrec->opts.nFreeze[0][YY] == 0
477 && inputrec->opts.nFreeze[0][ZZ] == 0,
478 "Freeze groups are not supported by the modular simulator.");
481 && conditionalAssert(
482 inputrec->deform[XX][XX] == 0.0 && inputrec->deform[XX][YY] == 0.0
483 && inputrec->deform[XX][ZZ] == 0.0 && inputrec->deform[YY][XX] == 0.0
484 && inputrec->deform[YY][YY] == 0.0 && inputrec->deform[YY][ZZ] == 0.0
485 && inputrec->deform[ZZ][XX] == 0.0 && inputrec->deform[ZZ][YY] == 0.0
486 && inputrec->deform[ZZ][ZZ] == 0.0,
487 "Deformation is not supported by the modular simulator.");
490 && conditionalAssert(gmx_mtop_interaction_count(globalTopology, IF_VSITE) == 0,
491 "Virtual sites are not supported by the modular simulator.");
492 isInputCompatible = isInputCompatible
493 && conditionalAssert(!inputrec->bDoAwh,
494 "AWH is not supported by the modular simulator.");
497 && conditionalAssert(gmx_mtop_ftype_count(globalTopology, F_DISRES) == 0,
498 "Distance restraints are not supported by the modular simulator.");
501 && conditionalAssert(
502 gmx_mtop_ftype_count(globalTopology, F_ORIRES) == 0,
503 "Orientation restraints are not supported by the modular simulator.");
506 && conditionalAssert(ms == nullptr,
507 "Multi-sim are not supported by the modular simulator.");
510 && conditionalAssert(replExParams.exchangeInterval == 0,
511 "Replica exchange is not supported by the modular simulator.");
513 int numEnsembleRestraintSystems;
516 numEnsembleRestraintSystems = fcd->disres->nsystems;
520 auto distantRestraintEnsembleEnvVar = getenv("GMX_DISRE_ENSEMBLE_SIZE");
521 numEnsembleRestraintSystems =
522 (ms != nullptr && distantRestraintEnsembleEnvVar != nullptr)
523 ? static_cast<int>(strtol(distantRestraintEnsembleEnvVar, nullptr, 10))
528 && conditionalAssert(numEnsembleRestraintSystems <= 1,
529 "Ensemble restraints are not supported by the modular simulator.");
532 && conditionalAssert(!doSimulatedAnnealing(inputrec),
533 "Simulated annealing is not supported by the modular simulator.");
536 && conditionalAssert(!inputrec->bSimTemp,
537 "Simulated tempering is not supported by the modular simulator.");
538 isInputCompatible = isInputCompatible
539 && conditionalAssert(!inputrec->bExpanded,
540 "Expanded ensemble simulations are not supported by "
541 "the modular simulator.");
544 && conditionalAssert(!doEssentialDynamics,
545 "Essential dynamics is not supported by the modular simulator.");
546 isInputCompatible = isInputCompatible
547 && conditionalAssert(inputrec->eSwapCoords == eswapNO,
548 "Ion / water position swapping is not supported by "
549 "the modular simulator.");
552 && conditionalAssert(!inputrec->bIMD,
553 "Interactive MD is not supported by the modular simulator.");
556 && conditionalAssert(!doMembed,
557 "Membrane embedding is not supported by the modular simulator.");
558 // TODO: Change this to the boolean passed when we merge the user interface change for the GPU update.
561 && conditionalAssert(
562 getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") == nullptr,
563 "Integration on the GPU is not supported by the modular simulator.");
564 // Modular simulator is centered around NS updates
565 // TODO: think how to handle nstlist == 0
566 isInputCompatible = isInputCompatible
567 && conditionalAssert(inputrec->nstlist != 0,
568 "Simulations without neighbor list update are not "
569 "supported by the modular simulator.");
570 isInputCompatible = isInputCompatible
571 && conditionalAssert(!GMX_FAHCORE,
572 "GMX_FAHCORE not supported by the modular simulator.");
574 return isInputCompatible;
577 ModularSimulator::ModularSimulator(std::unique_ptr<LegacySimulatorData> legacySimulatorData) :
578 legacySimulatorData_(std::move(legacySimulatorData))
580 checkInputForDisabledFunctionality();
583 void ModularSimulator::checkInputForDisabledFunctionality()
585 isInputCompatible(true, legacySimulatorData_->inputrec,
586 legacySimulatorData_->mdrunOptions.rerun, *legacySimulatorData_->top_global,
587 legacySimulatorData_->ms, legacySimulatorData_->replExParams,
588 &legacySimulatorData_->fr->listedForces->fcdata(),
589 opt2bSet("-ei", legacySimulatorData_->nfile, legacySimulatorData_->fnm),
590 legacySimulatorData_->membed != nullptr);
591 if (legacySimulatorData_->observablesHistory->edsamHistory)
594 "The checkpoint is from a run with essential dynamics sampling, "
595 "but the current run did not specify the -ei option. "
596 "Either specify the -ei option to mdrun, or do not use this checkpoint file.");