2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2018,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.
37 * \brief Implementation details for MD signalling support.
46 #include "gromacs/mdlib/simulationsignal.h"
47 #include "gromacs/mdrun/runner.h"
48 #include "gromacs/utility/gmxassert.h"
50 #include "gmxapi/exceptions.h"
51 #include "gmxapi/session.h"
52 #include "gmxapi/md/mdsignals.h"
54 #include "mdsignals.h"
55 #include "sessionresources.h"
61 Signal::Signal(Signal
&&) noexcept
= default;
62 Signal
& Signal::operator=(Signal
&&) noexcept
= default;
64 Signal::Signal(std::unique_ptr
<SignalImpl
> impl
) : impl_
{ std::move(impl
) } {}
66 Signal::~Signal() = default;
68 void Signal::operator()()
74 void SignalManager::addSignaller(const std::string
& name
)
76 called_
[name
].store(false);
80 * Implement the SignalImpl interface to provide a logical AND for managed MD signals.
82 * The class is a signal issuer and a signal receiver, but
83 * \todo signals received by this operation and received by Mdrunner do not yet have a common interface.
85 * Tracks whether each registered input has issued a signal to this operation. When the
86 * final registered input issues `call()`, the LogicalAND issues `call()` on the output
89 * State is managed by the parent SignalManager. Client code should get a short-lived handle
90 * to a Signal wrapping this implementation object by calling SignalManager::getSignal()
91 * with the unique workflow operation name for the block of client code and a gmxapi::md::signals::STOP
94 * Currently explicitly supports the MD stop signal only.
96 * Version gmxapi 0.0.6: Also, all registered restraints
97 * are automatically in the set of ANDed inputs.
101 class SignalManager::LogicalAND
: public Signal::SignalImpl
105 * \brief Create short-lived signal issuer implementation.
110 * Caller is responsible for ensuring that the object pointed to by
111 * manager remains valid for the life time of a LogicalAND instance.
113 LogicalAND(SignalManager
* manager
, std::string name
) : name_(std::move(name
)), manager_(manager
)
118 ~LogicalAND() override
= default;
122 * \brief Sets the stop condition when the last issuer issues.
124 * Once all participating signal issuers have called for a stop signal,
125 * the stop condition state is updated to stopAtNextNSStep.
129 auto& callCounter
= manager_
->called_
.at(name_
);
130 callCounter
.store(true);
131 using pairType
= typename
decltype(manager_
->called_
)::value_type
;
132 if (std::all_of(manager_
->called_
.cbegin(), manager_
->called_
.cend(),
133 [](const pairType
& p
) { return p
.second
.load(); }))
135 *manager_
->state_
= gmx::StopSignal::stopAtNextNSStep
;
140 //! Named signal issuer for the current operation.
141 const std::string name_
;
143 //! The manager that generated this function object.
144 SignalManager
* manager_
;
147 Signal
SignalManager::getSignal(const std::string
& name
, md::signals signal
)
149 if (called_
.find(name
) == called_
.end())
151 std::string message
= name
+ " is not registered for this signal.";
152 throw gmxapi::ProtocolError(std::move(message
));
155 if (signal
!= md::signals::STOP
)
157 throw gmxapi::NotImplementedError("This signaller only handles stop signals.");
160 auto signalImpl
= std::make_unique
<LogicalAND
>(this, name
);
161 auto functor
= Signal(std::move(signalImpl
));
165 Signal
getMdrunnerSignal(SessionResources
* resources
, md::signals signal
)
167 // while there is only one choice...
168 if (signal
!= md::signals::STOP
)
170 throw gmxapi::NotImplementedError("This signaller only handles stop signals.");
173 if (resources
== nullptr)
175 throw gmxapi::UsageError(
176 "Caller must provide a valid SessionResources to getMdrunnerSignal.");
179 auto signaller
= resources
->getMdrunnerSignal(signal
);
184 } // end namespace gmxapi