/*
* Build data structures
*/
+ topologyHolder_ =
+ std::make_unique<TopologyHolder>(*top_global, cr, inputrec, fr, mdAtoms, constr, vsite);
+
std::unique_ptr<FreeEnergyPerturbationElement> freeEnergyPerturbationElement = nullptr;
FreeEnergyPerturbationElement* freeEnergyPerturbationElementPtr = nullptr;
if (inputrec->efep != efepNO)
auto statePropagatorData = std::make_unique<StatePropagatorData>(
top_global->natoms, fplog, cr, state_global, inputrec->nstxout, inputrec->nstvout,
inputrec->nstfout, inputrec->nstxout_compressed, fr->nbv->useGpu(),
- freeEnergyPerturbationElementPtr, inputrec, mdAtoms->mdatoms());
+ freeEnergyPerturbationElementPtr, topologyHolder_.get(), fr->bMolPBC,
+ mdrunOptions.writeConfout, opt2fn("-c", nfile, fnm), inputrec, mdAtoms->mdatoms());
auto statePropagatorDataPtr = compat::make_not_null(statePropagatorData.get());
auto energyElement = std::make_unique<EnergyElement>(
startingBehavior);
auto energyElementPtr = compat::make_not_null(energyElement.get());
- topologyHolder_ =
- std::make_unique<TopologyHolder>(*top_global, cr, inputrec, fr, mdAtoms, constr, vsite);
-
/*
* Build stop handler
*/
*/
trajectoryElementBuilder.registerWriterClient(statePropagatorDataPtr);
trajectoryElementBuilder.registerSignallerClient(statePropagatorDataPtr);
+ lastStepSignallerBuilder.registerSignallerClient(statePropagatorDataPtr);
trajectoryElementBuilder.registerWriterClient(energyElementPtr);
trajectoryElementBuilder.registerSignallerClient(energyElementPtr);
#include "statepropagatordata.h"
+#include "gromacs/domdec/collect.h"
#include "gromacs/domdec/domdec.h"
+#include "gromacs/fileio/confio.h"
#include "gromacs/math/vec.h"
#include "gromacs/mdlib/gmx_omp_nthreads.h"
#include "gromacs/mdlib/mdoutf.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/mdatom.h"
#include "gromacs/mdtypes/state.h"
+#include "gromacs/pbcutil/pbc.h"
#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/topology.h"
#include "freeenergyperturbationelement.h"
int nstxout_compressed,
bool useGPU,
FreeEnergyPerturbationElement* freeEnergyPerturbationElement,
- const t_inputrec* inputrec,
- const t_mdatoms* mdatoms) :
+ const TopologyHolder* topologyHolder,
+ bool canMoleculesBeDistributedOverPBC,
+ bool writeFinalConfiguration,
+ std::string finalConfigurationFilename,
+ const t_inputrec* inputrec,
+ const t_mdatoms* mdatoms) :
totalNumAtoms_(numAtoms),
nstxout_(nstxout),
nstvout_(nstvout),
writeOutStep_(-1),
vvResetVelocities_(false),
freeEnergyPerturbationElement_(freeEnergyPerturbationElement),
+ isRegularSimulationEnd_(false),
+ lastStep_(-1),
+ canMoleculesBeDistributedOverPBC_(canMoleculesBeDistributedOverPBC),
+ systemHasPeriodicMolecules_(inputrec->bPeriodicMols),
+ pbcType_(inputrec->ePBC),
+ topologyHolder_(topologyHolder),
+ lastPlannedStep_(inputrec->nsteps + inputrec->init_step),
+ writeFinalConfiguration_(writeFinalConfiguration),
+ finalConfigurationFilename_(std::move(finalConfigurationFilename)),
fplog_(fplog),
cr_(cr),
globalState_(globalState)
// copy x -> previousX
(*registerRunFunction)(std::make_unique<SimulatorRunFunction>([this]() { copyPosition(); }));
// if it's a write out step, keep a copy for writeout
- if (step == writeOutStep_)
+ if (step == writeOutStep_ || (step == lastStep_ && writeFinalConfiguration_))
{
(*registerRunFunction)(std::make_unique<SimulatorRunFunction>([this]() { saveState(); }));
}
void StatePropagatorData::write(gmx_mdoutf_t outf, Step currentStep, Time currentTime)
{
+ wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
unsigned int mdof_flags = 0;
if (do_per_step(currentStep, nstxout_))
{
if (mdof_flags == 0)
{
+ wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
return;
}
GMX_ASSERT(localStateBackup_, "Trajectory writing called, but no state saved.");
totalNumAtoms_, currentStep, currentTime,
localStateBackup_.get(), globalState_, observablesHistory, f_);
- localStateBackup_.reset();
+ if (currentStep != lastStep_ || !isRegularSimulationEnd_)
+ {
+ localStateBackup_.reset();
+ }
+ wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
}
void StatePropagatorData::elementSetup()
localState->flags |= (1U << estX) | (1U << estV) | (1U << estBOX);
}
+void StatePropagatorData::trajectoryWriterTeardown(gmx_mdoutf* gmx_unused outf)
+{
+ // Note that part of this code is duplicated in do_md_trajectory_writing.
+ // This duplication is needed while both legacy and modular code paths are in use.
+ // TODO: Remove duplication asap, make sure to keep in sync in the meantime.
+ if (!writeFinalConfiguration_ || !isRegularSimulationEnd_)
+ {
+ return;
+ }
+
+ GMX_ASSERT(localStateBackup_, "Final trajectory writing called, but no state saved.");
+
+ wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
+ if (DOMAINDECOMP(cr_))
+ {
+ auto globalXRef = MASTER(cr_) ? globalState_->x : gmx::ArrayRef<gmx::RVec>();
+ dd_collect_vec(cr_->dd, localStateBackup_.get(), localStateBackup_->x, globalXRef);
+ auto globalVRef = MASTER(cr_) ? globalState_->v : gmx::ArrayRef<gmx::RVec>();
+ dd_collect_vec(cr_->dd, localStateBackup_.get(), localStateBackup_->v, globalVRef);
+ }
+ else
+ {
+ // We have the whole state locally: copy the local state pointer
+ globalState_ = localStateBackup_.get();
+ }
+
+ if (MASTER(cr_))
+ {
+ fprintf(stderr, "\nWriting final coordinates.\n");
+ if (canMoleculesBeDistributedOverPBC_ && !systemHasPeriodicMolecules_)
+ {
+ // Make molecules whole only for confout writing
+ do_pbc_mtop(pbcType_, localStateBackup_->box, &topologyHolder_->globalTopology(),
+ globalState_->x.rvec_array());
+ }
+ write_sto_conf_mtop(finalConfigurationFilename_.c_str(), *topologyHolder_->globalTopology().name,
+ &topologyHolder_->globalTopology(), globalState_->x.rvec_array(),
+ globalState_->v.rvec_array(), pbcType_, localStateBackup_->box);
+ }
+ wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
+}
+
+SignallerCallbackPtr StatePropagatorData::registerLastStepCallback()
+{
+ return std::make_unique<SignallerCallback>([this](Step step, Time) {
+ lastStep_ = step;
+ isRegularSimulationEnd_ = (step == lastPlannedStep_);
+ });
+}
+
} // namespace gmx
#include "gromacs/math/vectypes.h"
#include "modularsimulatorinterfaces.h"
+#include "topologyholder.h"
struct gmx_mdoutf;
struct t_commrec;
public ISimulatorElement,
public ITrajectoryWriterClient,
public ITrajectorySignallerClient,
- public ICheckpointHelperClient
+ public ICheckpointHelperClient,
+ public ILastStepSignallerClient
{
public:
//! Constructor
int nstxout_compressed,
bool useGPU,
FreeEnergyPerturbationElement* freeEnergyPerturbationElement,
+ const TopologyHolder* topologyHolder,
+ bool canMoleculesBeDistributedOverPBC,
+ bool writeFinalConfiguration,
+ std::string finalConfigurationFilename,
const t_inputrec* inputrec,
const t_mdatoms* mdatoms);
//! ICheckpointHelperClient implementation
void writeCheckpoint(t_state* localState, t_state* globalState) override;
+ //! ILastStepSignallerClient implementation (used for final output only)
+ SignallerCallbackPtr registerLastStepCallback() override;
+
//! Callback writing the state to file
void write(gmx_mdoutf* outf, Step step, Time time);
//! Pointer to the free energy perturbation element (for trajectory writing only)
FreeEnergyPerturbationElement* freeEnergyPerturbationElement_;
+ //! Whether planned total number of steps was reached (used for final output only)
+ bool isRegularSimulationEnd_;
+ //! The signalled last step (used for final output only)
+ Step lastStep_;
+
+ //! Whether system can have molecules distributed over PBC boundaries (used for final output only)
+ const bool canMoleculesBeDistributedOverPBC_;
+ //! Whether system has molecules self-interacting through PBC (used for final output only)
+ const bool systemHasPeriodicMolecules_;
+ //! The PBC type (used for final output only)
+ const int pbcType_;
+ //! Pointer to the topology (used for final output only)
+ const TopologyHolder* topologyHolder_;
+ //! The (planned) last step - determines whether final configuration is written (used for final output only)
+ const Step lastPlannedStep_;
+ //! Whether final configuration was chosen in mdrun options (used for final output only)
+ const bool writeFinalConfiguration_;
+ //! The filename of the final configuration file (used for final output only)
+ const std::string finalConfigurationFilename_;
+
// Access to ISimulator data
//! Handles logging.
FILE* fplog_;
//! No trajectory writer setup needed
void trajectoryWriterSetup(gmx_mdoutf gmx_unused* outf) override {}
- //! No trajectory writer teardown needed
- void trajectoryWriterTeardown(gmx_mdoutf gmx_unused* outf) override {}
+ //! Trajectory writer teardown - write final coordinates
+ void trajectoryWriterTeardown(gmx_mdoutf* outf) override;
};
} // namespace gmx