Allow more granularity for public interfaces in build tree.
[gromacs.git] / api / gmxapi / cpp / mdsignals.cpp
blob6cf8f6158a9ee6f29def2e89707dc5319618c70b
1 /*
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.
36 /*! \file
37 * \brief Implementation details for MD signalling support.
39 * \ingroup gmxapi_md
42 #include <algorithm>
43 #include <atomic>
44 #include <memory>
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"
57 namespace gmxapi
60 //! \cond
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()()
70 impl_->call();
72 //! \endcond
74 void SignalManager::addSignaller(const std::string& name)
76 called_[name].store(false);
79 /*!
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
87 * signal path.
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
92 * signal argument.
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.
99 * \ingroup gmxapi_md
101 class SignalManager::LogicalAND : public Signal::SignalImpl
103 public:
105 * \brief Create short-lived signal issuer implementation.
107 * \param manager
108 * \param name
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)
117 //! \cond
118 ~LogicalAND() override = default;
119 //! \endcond
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.
127 void call() override
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;
139 private:
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));
162 return functor;
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);
181 return signaller;
184 } // end namespace gmxapi