domDecHelper_->setup();
}
- for (auto& element : elementsOwnershipList_)
+ for (auto& element : elementSetupTeardownList_)
{
element->elementSetup();
}
void ModularSimulatorAlgorithm::teardown()
{
- for (auto& element : elementsOwnershipList_)
+ for (auto& element : elementSetupTeardownList_)
{
element->elementTeardown();
}
{
freeEnergyPerturbationData_ = std::make_unique<FreeEnergyPerturbationData>(
legacySimulatorData->fplog, *legacySimulatorData->inputrec, legacySimulatorData->mdAtoms);
+ registerExistingElement(freeEnergyPerturbationData_->element());
}
statePropagatorData_ = std::make_unique<StatePropagatorData>(
legacySimulatorData->inputrec,
legacySimulatorData->mdAtoms->mdatoms(),
legacySimulatorData->top_global);
+ registerExistingElement(statePropagatorData_->element());
// Multi sim is turned off
const bool simulationsShareState = false;
legacySimulatorData->observablesHistory,
legacySimulatorData->startingBehavior,
simulationsShareState);
+ registerExistingElement(energyData_->element());
}
ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
{
if (algorithmHasBeenBuilt_)
{
- throw SimulationAlgorithmSetupError(
- "Tried to build ModularSimulationAlgorithm more than once.");
+ GMX_THROW(SimulationAlgorithmSetupError(
+ "Tried to build ModularSimulationAlgorithm more than once."));
}
algorithmHasBeenBuilt_ = true;
simulationsShareState);
registerWithInfrastructureAndSignallers(trajectoryElement.get());
- // Build free energy element
- std::unique_ptr<FreeEnergyPerturbationData::Element> freeEnergyPerturbationElement = nullptr;
- if (algorithm.freeEnergyPerturbationData_)
- {
- freeEnergyPerturbationElement = std::make_unique<FreeEnergyPerturbationData::Element>(
- algorithm.freeEnergyPerturbationData_.get(),
- legacySimulatorData_->inputrec->fepvals->delta_lambda);
- registerWithInfrastructureAndSignallers(freeEnergyPerturbationElement.get());
- }
-
- // Build domdec helper (free energy element is a client, so keep this after it is built)
+ // Build domdec helper
if (DOMAINDECOMP(legacySimulatorData_->cr))
{
algorithm.domDecHelper_ =
inputrec->nstlist, inputrec->init_step, inputrec->init_t));
}
+ // Move setup / teardown list
+ algorithm.elementSetupTeardownList_ = std::move(setupAndTeardownList_);
+
// Create element list
// Checkpoint helper needs to be in the call list (as first element!) to react to last step
algorithm.elementCallList_.emplace_back(algorithm.checkpointHelper_.get());
// Next, update the free energy lambda vector if needed
- if (freeEnergyPerturbationElement)
+ if (algorithm.freeEnergyPerturbationData_)
{
- algorithm.elementsOwnershipList_.emplace_back(std::move(freeEnergyPerturbationElement));
- algorithm.elementCallList_.emplace_back(algorithm.elementsOwnershipList_.back().get());
+ algorithm.elementCallList_.emplace_back(algorithm.freeEnergyPerturbationData_->element());
}
// Then, move the built algorithm
algorithm.elementsOwnershipList_.insert(algorithm.elementsOwnershipList_.end(),
// (relevant data was stored by elements through energy signaller)
algorithm.elementsOwnershipList_.emplace_back(std::move(trajectoryElement));
algorithm.elementCallList_.emplace_back(algorithm.elementsOwnershipList_.back().get());
+ algorithm.elementSetupTeardownList_.emplace_back(algorithm.elementsOwnershipList_.back().get());
algorithm.setup();
return algorithm;
}
-ISimulatorElement* ModularSimulatorAlgorithmBuilder::addElementToSimulatorAlgorithm(
- std::unique_ptr<ISimulatorElement> element)
-{
- elements_.emplace_back(std::move(element));
- return elements_.back().get();
-}
-
bool ModularSimulatorAlgorithmBuilder::elementExists(const ISimulatorElement* element) const
{
// Check whether element exists in element list
return true;
}
// Check whether element exists in other places controlled by *this
- return (statePropagatorData_->element() == element || energyData_->element() == element
+ return ((statePropagatorData_ && statePropagatorData_->element() == element)
+ || (energyData_ && energyData_->element() == element)
|| (freeEnergyPerturbationData_ && freeEnergyPerturbationData_->element() == element));
}
-void ModularSimulatorAlgorithmBuilder::addElementToSetupTeardownList(ISimulatorElement* element)
-{
- // Add element if it's not already in the list
- if (std::find(setupAndTeardownList_.begin(), setupAndTeardownList_.end(), element)
- == setupAndTeardownList_.end())
- {
- setupAndTeardownList_.emplace_back(element);
- }
-}
-
std::optional<SignallerCallback> ModularSimulatorAlgorithm::SignalHelper::registerLastStepCallback()
{
return [this](Step step, Time gmx_unused time) { this->lastStep_ = step; };
{
}
-ISimulatorElement* ModularSimulatorAlgorithmBuilderHelper::storeElement(std::unique_ptr<ISimulatorElement> element)
-{
- return builder_->addElementToSimulatorAlgorithm(std::move(element));
-}
-
bool ModularSimulatorAlgorithmBuilderHelper::elementIsStored(const ISimulatorElement* element) const
{
return builder_->elementExists(element);
std::vector<std::unique_ptr<ISignaller>> signallerList_;
//! List of schedulerElements (ownership)
std::vector<std::unique_ptr<ISimulatorElement>> elementsOwnershipList_;
- //! List of schedulerElements (calling sequence)
+ //! List of schedulerElements (run calling sequence)
std::vector<ISimulatorElement*> elementCallList_;
+ //! List of schedulerElements (setup / teardown calling sequence)
+ std::vector<ISimulatorElement*> elementSetupTeardownList_;
// Infrastructure elements
//! The domain decomposition element
//! Constructor
ModularSimulatorAlgorithmBuilderHelper(ModularSimulatorAlgorithmBuilder* builder);
//! Store an element to the ModularSimulatorAlgorithmBuilder
- ISimulatorElement* storeElement(std::unique_ptr<ISimulatorElement> element);
+ template<typename Element>
+ Element* storeElement(std::unique_ptr<Element> element);
//! Check if an element is stored in the ModularSimulatorAlgorithmBuilder
bool elementIsStored(const ISimulatorElement* element) const;
/*! \brief Set arbitrary data in the ModularSimulatorAlgorithmBuilder
*
* This function returns a non-owning pointer to the new location of that
* element, allowing further usage (e.g. adding the element to the call list).
- * Note that simply addin an element using this function will not call it
+ * This will also add the element to the setup / teardown list, and register
+ * it with all applicable signallers and infrastructure objects.
+ * Note that simply adding an element using this function will not call it
* during the simulation - it needs to be added to the call list separately.
- * Note that generally, users will want to add elements to the call list, but
- * it might not be practical to do this in the same order.
+ * Also note that generally, users will want to add elements to the call list,
+ * but it might not be practical to do this in the same order.
*
+ * \tparam Element Type of the Element
* \param element A unique pointer to the element
* \return A non-owning (raw) pointer to the element for further usage
*/
- ISimulatorElement* addElementToSimulatorAlgorithm(std::unique_ptr<ISimulatorElement> element);
+ template<typename Element>
+ Element* addElementToSimulatorAlgorithm(std::unique_ptr<Element> element);
+
+ /*! \brief Register existing element to infrastructure
+ *
+ * This function adds existing elements to the setup / teardown list, and
+ * registers them with all applicable signallers and infrastructure objects.
+ * This is only permissible for elements owned directly by the builder or
+ * indirectly through data objects. Before registering the element, the function
+ * checks that the element is owned by the builder or a known object.
+ *
+ * \tparam Element Type of the Element
+ * \param element A non-owning (raw) pointer to the element
+ */
+ template<typename Element>
+ void registerExistingElement(Element* element);
/*! \brief Check if element is owned by *this
*
*/
[[nodiscard]] bool elementExists(const ISimulatorElement* element) const;
- /*! \brief Add element to setupAndTeardownList_ if it's not already there
- *
- * \param element Element pointer to be added
- */
- void addElementToSetupTeardownList(ISimulatorElement* element);
-
//! Vector to store elements, allowing the SimulatorAlgorithm to control their lifetime
std::vector<std::unique_ptr<ISimulatorElement>> elements_;
/*! \brief List defining in which order elements are called every step
{
if (algorithmHasBeenBuilt_)
{
- throw SimulationAlgorithmSetupError(
- "Tried to add an element after ModularSimulationAlgorithm was built.");
+ GMX_THROW(SimulationAlgorithmSetupError(
+ "Tried to add an element after ModularSimulationAlgorithm was built."));
}
// Get element from factory method
// Ensuring this makes sure we can control the life time
if (!elementExists(element))
{
- throw ElementNotFoundError("Tried to append non-existing element to call list.");
+ GMX_THROW(ElementNotFoundError("Tried to append non-existing element to call list."));
}
// Add to call list
callList_.emplace_back(element);
- // Add to setup / teardown list if element hasn't been added yet
- addElementToSetupTeardownList(element);
- // Register element to all applicable signallers
- registerWithInfrastructureAndSignallers(element);
}
//! Returns a pointer casted to type Base if the Element is derived from Base
domDecHelperBuilder_.registerClient(castOrNull<IDomDecHelperClient, Element>(element));
}
+template<typename Element>
+Element* ModularSimulatorAlgorithmBuilder::addElementToSimulatorAlgorithm(std::unique_ptr<Element> element)
+{
+ // Store element
+ elements_.emplace_back(std::move(element));
+ // Get non-owning pointer for further use
+ Element* elementPtr = static_cast<Element*>(elements_.back().get());
+ // Register element to infrastructure
+ registerExistingElement(elementPtr);
+
+ return elementPtr;
+}
+
+template<typename Element>
+void ModularSimulatorAlgorithmBuilder::registerExistingElement(Element* element)
+{
+ // Make sure the element pointer is owned by *this
+ // Ensuring this makes sure we can control the life time
+ if (!elementExists(element))
+ {
+ GMX_THROW(
+ ElementNotFoundError("Tried to register non-existing element to infrastructure."));
+ }
+
+ // Add to setup / teardown list
+ setupAndTeardownList_.emplace_back(element);
+ // Register element to all applicable signallers
+ registerWithInfrastructureAndSignallers(element);
+}
+
+template<typename Element>
+Element* ModularSimulatorAlgorithmBuilderHelper::storeElement(std::unique_ptr<Element> element)
+{
+ return builder_->addElementToSimulatorAlgorithm(std::move(element));
+}
+
template<typename ValueType>
void ModularSimulatorAlgorithmBuilderHelper::storeBuilderData(const std::string& key, const ValueType& value)
{