cglo_flags_iteration,
step,
&observablesReducer);
+ // Clean up after pre-step use of compute_globals()
+ observablesReducer.markAsReadyToReduce();
+
if (cglo_flags_iteration & CGLO_STOPCM)
{
/* At initialization, do not pass x with acceleration-correction mode
cglo_flags & ~CGLO_PRESSURE,
step,
&observablesReducer);
+ // Clean up after pre-step use of compute_globals()
+ observablesReducer.markAsReadyToReduce();
}
/* Calculate the initial half step temperature, and save the ekinh_old */
/* increase the MD step number */
step++;
step_rel++;
+ observablesReducer.markAsReadyToReduce();
#if GMX_FAHCORE
if (MASTER(cr))
cglo_flags,
step,
&observablesReducer);
+ // Clean up after pre-step use of compute_globals()
+ observablesReducer.markAsReadyToReduce();
}
if (MASTER(cr))
/* increase the MD step number */
step++;
step_rel++;
+ observablesReducer.markAsReadyToReduce();
}
/* End of main MD loop */
* We do not unshift, so molecules are always whole in congrad.c
*/
energyEvaluator.run(s_min, mu_tot, vir, pres, -1, TRUE, step);
+ observablesReducer.markAsReadyToReduce();
if (MASTER(cr))
{
neval++;
/* Calculate energy for the trial step */
energyEvaluator.run(s_c, mu_tot, vir, pres, -1, FALSE, step);
+ observablesReducer.markAsReadyToReduce();
/* Calc derivative along line */
const rvec* pc = s_c->s.cg_p.rvec_array();
neval++;
/* Calculate energy for the trial step */
energyEvaluator.run(s_b, mu_tot, vir, pres, -1, FALSE, step);
+ observablesReducer.markAsReadyToReduce();
/* p does not change within a step, but since the domain decomposition
* might change, we have to use cg_p of s_b here.
* If we have reached machine precision, converged is already set to true.
*/
converged = converged || (s_min->fmax < inputrec->em_tol);
-
+ observablesReducer.markAsReadyToReduce();
} /* End of the loop */
if (converged)
* If we have reached machine precision, converged is already set to true.
*/
converged = converged || (ems.fmax < inputrec->em_tol);
-
+ observablesReducer.markAsReadyToReduce();
} /* End of the loop */
if (converged)
}
count++;
+ observablesReducer.markAsReadyToReduce();
} /* End of the loop */
/* Print some data... */
cglo_flags,
step,
&observablesReducer);
+ // Clean up after pre-step use of compute_globals()
+ observablesReducer.markAsReadyToReduce();
}
if (MASTER(cr))
cglo_flags,
step,
&observablesReducer);
+ // Clean up after pre-step use of compute_globals()
+ observablesReducer.markAsReadyToReduce();
}
/* Note: this is OK, but there are some numerical precision issues with using the convergence of
step++;
step_rel++;
}
+ observablesReducer.markAsReadyToReduce();
}
/* End of main MD loop */
impl_->reduceSoon_ = false;
}
-void ObservablesReducer::stepComplete()
+void ObservablesReducer::markAsReadyToReduce()
{
impl_->status_ = ObservablesReducerStatus::ReadyToReduce;
}
observablesReducer =>> observablesReducer [label="zeroes reduction buffer"];
observablesReducer =>> compute_globals [label="returns"];
+runner =>> observablesReducer [label="notifies at end of step"];
+
+
\endmsc
*
* Three callbacks are produced and called per participating module:
* problematic output after reduction.
*/
void reductionComplete(Step step);
- /*! \brief Notify the ObservablesReducer that this MD step is complete
+ /*! \brief Notify the ObservablesReducer that it should make
+ * ready to receive new values to reduce
*
* Any runner using the ObservablesReducer must call this method
* whenever a step completes, so that subscribed modules can use
* reduction it can notify them of that status. This permits them
* to check their own requirements, e.g. that
* ReductionRequirement::Soon will operate this step or next
- * step. */
- void stepComplete();
+ * step.
+ *
+ * For the same reason, it is also necessary to call this method
+ * at a suitable point after uses of an ObservablesReducer before
+ * the regular steps of a runner. */
+ void markAsReadyToReduce();
//! The builder needs to be able to make the Impl object
friend class ObservablesReducerBuilder;
};
ObservablesReducer observablesReducer(std::move(observablesReducerOriginal));
EXPECT_TRUE(observablesReducer.communicationBuffer().empty())
<< "no buffer available when no subscribers requested reduction";
+ observablesReducer.markAsReadyToReduce();
}
TEST(ObservablesReducerTest, CanBuildAndUseWithNoSubscribers)
EXPECT_TRUE(observablesReducer.communicationBuffer().empty())
<< "no buffer available after reductionComplete()";
- observablesReducer.stepComplete();
+ observablesReducer.markAsReadyToReduce();
}
TEST(ObservablesReducerTest, CanBuildAndUseWithOneSubscriber)
// Note that there's nothing else to check here, because the
// empty buffer means that no reduction should take place.
- observablesReducer.stepComplete();
+ observablesReducer.markAsReadyToReduce();
}
{
SCOPED_TRACE("Test that ReductionRequirement::Soon does trigger behavior");
<< "reduction step is passed through correctly";
EXPECT_THAT(bufferView, testing::AllOf(testing::SizeIs(requiredBufferSize), testing::Each(0.0)))
<< "buffer is zeroed after reduction";
- observablesReducer.stepComplete();
+ observablesReducer.markAsReadyToReduce();
}
}
rankData.observablesReducer.value().reductionComplete(step);
EXPECT_TRUE(rankData.observablesReducer.value().communicationBuffer().empty())
<< "no buffer available after reductionComplete()";
- rankData.observablesReducer.value().stepComplete();
+ rankData.observablesReducer.value().markAsReadyToReduce();
}
}
rankData.observablesReducer.value().reductionComplete(step);
EXPECT_TRUE(rankData.observablesReducer.value().communicationBuffer().empty())
<< "no buffer available after reductionComplete()";
- rankData.observablesReducer.value().stepComplete();
+ rankData.observablesReducer.value().markAsReadyToReduce();
}
}
}
rankData.observablesReducer.value().reductionComplete(step);
EXPECT_TRUE(rankData.observablesReducer.value().communicationBuffer().empty())
<< "no buffer available after reductionComplete()";
- rankData.observablesReducer.value().stepComplete();
+ rankData.observablesReducer.value().markAsReadyToReduce();
}
}
rankData.observablesReducer.value().reductionComplete(step);
EXPECT_TRUE(rankData.observablesReducer.value().communicationBuffer().empty())
<< "no buffer available after reductionComplete()";
- rankData.observablesReducer.value().stepComplete();
+ rankData.observablesReducer.value().markAsReadyToReduce();
}
}
// to call compute_globals twice.
compute(-1, CGLO_GSTAT | CGLO_STOPCM, nullSignaller_.get(), false, true);
+ // Clean up after pre-step use of compute()
+ observablesReducer_->markAsReadyToReduce();
auto v = statePropagatorData_->velocitiesView();
// At initialization, do not pass x with acceleration-correction mode
{
copy_mat(energyData_->ekindata()->tcstat[i].ekinh, energyData_->ekindata()->tcstat[i].ekinh_old);
}
+
+ // Clean up after pre-step use of compute()
+ observablesReducer_->markAsReadyToReduce();
}
template<ComputeGlobalsAlgorithm algorithm>
return std::nullopt;
}
+namespace
+{
+
+/*! \brief Schedule a function for actions that must happen at the end of each step
+ *
+ * After reduction, an ObservablesReducer is marked as unavailable for
+ * further reduction this step. This needs to be reset in order to be
+ * used on the next step.
+ *
+ * \param[in] observablesReducer The ObservablesReducer to mark as ready for use
+ */
+SchedulingFunction registerPostStepSchedulingFunction(ObservablesReducer* observablesReducer)
+{
+ SchedulingFunction postStepSchedulingFunction =
+ [observablesReducer](
+ Step /*step*/, Time /*time*/, const RegisterRunFunction& registerRunFunction) {
+ SimulatorRunFunction completeObservablesReducerStep = [&observablesReducer]() {
+ observablesReducer->markAsReadyToReduce();
+ };
+ registerRunFunction(completeObservablesReducerStep);
+ };
+ return postStepSchedulingFunction;
+}
+
+} // namespace
+
//! Explicit template instantiation
//! \{
template class ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>;
GlobalCommunicationHelper* globalCommunicationHelper,
ObservablesReducer* observablesReducer)
{
- auto* element = builderHelper->storeElement(
+ ComputeGlobalsElement* element = builderHelper->storeElement(
std::make_unique<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>(
statePropagatorData,
energyData,
legacySimulatorData->top_global,
legacySimulatorData->constr,
observablesReducer));
+ builderHelper->registerPostStepScheduling(
+ registerPostStepSchedulingFunction(element->observablesReducer_));
return element;
}
if (cachedValue)
{
- return std::any_cast<ISimulatorElement*>(cachedValue.value());
+ return std::any_cast<ComputeGlobalsElement*>(cachedValue.value());
}
else
{
- ISimulatorElement* vvComputeGlobalsElement = builderHelper->storeElement(
+ ComputeGlobalsElement* vvComputeGlobalsElement = builderHelper->storeElement(
std::make_unique<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>(
statePropagatorData,
energyData,
simulator->constr,
observablesReducer));
builderHelper->storeBuilderData(key, vvComputeGlobalsElement);
+ builderHelper->registerPostStepScheduling(
+ registerPostStepSchedulingFunction(vvComputeGlobalsElement->observablesReducer_));
return vvComputeGlobalsElement;
}
}