Line data Source code
1 : // Copyright (C) 2016 Technische Universitaet Muenchen
2 : // This file is part of the Mamico project. For conditions of distribution
3 : // and use, please see the copyright notice in Mamico's main folder, or at
4 : // www5.in.tum.de/mamico
5 : #ifndef _INSTANCE_HANDLING_H_
6 : #define _INSTANCE_HANDLING_H_
7 :
8 : #include "coupling/interface/MDSimulationFactory.h"
9 : #include "coupling/services/MultiMDCellService.h"
10 : #include "tarch/utils/MultiMDService.h"
11 :
12 : namespace coupling {
13 : template <class LinkedCell, unsigned int dim> class InstanceHandling;
14 : }
15 : class InstanceHandlingTest;
16 :
17 : /** holds one vector of MDSimulation and one vector for MDSolverInterface.
18 : *Initialization, execution of MD time steps and shutdown are abstracted into
19 : *this class. In order to launch a new MF simulatio, a slot has to be chosen
20 : *first (either manualy or using coupling::MultiMDMediator). Then
21 : *MultiMDCellService initializes a new CouplingCellService via
22 : *MultiMDMediator. In the activated slot, a new MD simulation is launched. The
23 : *new MD instance has to be equilibrated first and then it can be coupled to the
24 : *simulation. In order to remove a MD simulation, the MD simulation and its
25 : *corresponding MDSolverInterface are shut down. Then, the respective instance
26 : *of the CouplingCellService is removed. Finally, the selected slot will be
27 : *set to inactive. This slot is now available again for the launch of a new MD
28 : *instance in the future.
29 : * @brief Simulation slots are managed (i.e., added/removed) via this
30 : *class. Works and interacts with the class coupling::MultiMDMediator closely.
31 : * @tparam LinkedCell type of the cell
32 : * @tparam dim Number of dimensions; it can be 1, 2 or 3
33 : * @sa see also coupling::MultiMDMediator
34 : * @author Niklas Wittmer
35 : */
36 : template <class LinkedCell, unsigned int dim> class coupling::InstanceHandling {
37 :
38 : public:
39 : /** Constructor:
40 : * @param mdConfig
41 : * @param mamicoConfig
42 : * @param multiMDService
43 : */
44 4 : InstanceHandling(simplemd::configurations::MolecularDynamicsConfiguration& mdConfig, coupling::configurations::MaMiCoConfiguration<dim>& mamicoConfig,
45 : tarch::utils::MultiMDService<dim>& multiMDService)
46 4 : : _mdSimulations(), _mdSolverInterface(), _mdConfig(mdConfig), _mamicoConfig(mamicoConfig), _multiMDService(multiMDService) {
47 12 : for (unsigned int i = 0; i < multiMDService.getLocalNumberOfMDSimulations(); i++) {
48 8 : _mdSimulations.push_back(coupling::interface::SimulationAndInterfaceFactory::getInstance().getMDSimulation(_mdConfig, _mamicoConfig
49 : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
50 : ,
51 16 : _multiMDService.getLocalCommunicator()
52 : #endif
53 : ));
54 :
55 8 : if (_mdSimulations[i] == nullptr) {
56 0 : std::cout << "ERROR InstanceHandling : _mdSimulations [" << i << "] == NULL!" << std::endl;
57 0 : std::exit(EXIT_FAILURE);
58 : }
59 :
60 8 : _mdSimulations[i]->init(_multiMDService, _multiMDService.getGlobalNumberOfLocalMDSimulation(i));
61 : }
62 4 : }
63 :
64 : /** Destructor:
65 : */
66 4 : ~InstanceHandling() { shutdown(); }
67 :
68 : /** switches off the coupling between the new MD simulations and Macroscopic
69 : *solver and lets the MD simulations run t time steps starting from the time
70 : *step T to equilibrate. It should be called before switchOnCoupling()
71 : * @param T
72 : * @param t
73 : */
74 4 : void equilibrate(const unsigned int& t, const unsigned int& T) {
75 12 : for (auto& md : _mdSimulations) {
76 8 : md->switchOffCoupling();
77 8 : md->simulateTimesteps(t, T);
78 : }
79 4 : }
80 :
81 : /** returns the vector of MD simulations
82 : * @return _mdSimulations
83 : */
84 : auto& getSimpleMD() const { return _mdSimulations; }
85 :
86 : /** Allocates Coupling interfaces
87 : * This method has to be called after switchOnCoupling()
88 : */
89 4 : void setMDSolverInterface() {
90 :
91 12 : for (unsigned int i = 0; i < _mdSimulations.size(); ++i) {
92 16 : _mdSolverInterface.push_back(
93 8 : coupling::interface::SimulationAndInterfaceFactory::getInstance().getMDSolverInterface(_mdConfig, _mamicoConfig, _mdSimulations[i]));
94 8 : if (_mdSolverInterface[i] == NULL) {
95 0 : std::cout << "ERROR InstanceHandling: mdSolverInterface[" << i << "] == NULL!" << std::endl;
96 0 : exit(EXIT_FAILURE);
97 : }
98 : }
99 4 : }
100 :
101 : /** Returns the MD solver onterface
102 : * @return _mdSolverInterface
103 : */
104 : auto& getMDSolverInterface() const { return _mdSolverInterface; }
105 :
106 : /** switches on the coupling between ALL new MD simulations and Macroscopic
107 : *solver after the new MD instances are equilibrated. It should be called
108 : *right after equilibrate() and before setMDSolverInterface()
109 : */
110 4 : void switchOnCoupling() {
111 12 : for (auto& simpleMD : _mdSimulations) {
112 8 : simpleMD->switchOnCoupling();
113 : }
114 4 : }
115 :
116 : /** switches on the coupling between a specific new MD simulation with the
117 : *index number i and Macroscopic solver. It should be called right after
118 : *equilibrate() and before setMDSolverInterface()
119 : * @param i
120 : */
121 : void switchOnCoupling(const unsigned int& i) { _mdSimulations[i]->switchOnCoupling(); }
122 :
123 : /** switches off the coupling between All new MD simulations and Macroscopic
124 : * solver.
125 : */
126 4 : void switchOffCoupling() {
127 12 : for (auto& simpleMD : _mdSimulations) {
128 8 : simpleMD->switchOffCoupling();
129 : }
130 4 : }
131 :
132 : /** switches off the coupling between a new MD simulation with the index i and
133 : * Macroscopic solver.
134 : * @param i index number of the MD simulation
135 : */
136 : void switchOffCoupling(const unsigned int& i) { _mdSimulations[i]->switchOffCoupling(); }
137 :
138 : /** Simulates t timesteps starting from current timestep T on all instances.
139 : * @param T
140 : * @param t
141 : */
142 4 : void simulateTimesteps(const unsigned int& t, unsigned int& T) {
143 12 : for (auto& simpleMD : _mdSimulations) {
144 8 : simpleMD->simulateTimesteps(t, T);
145 : }
146 4 : }
147 :
148 : /** Saves the simulation result of the first MD instance as check point in the
149 : * file filestem
150 : * @param filestem
151 : * @param T
152 : */
153 4 : void writeCheckpoint(const std::string& filestem, const unsigned int& T) const {
154 4 : if (_mdSimulations.size() > 0 && _mdSimulations[0] != nullptr) {
155 4 : _mdSimulations[0]->writeCheckpoint(filestem, T);
156 : }
157 4 : }
158 :
159 : /** Simulates t timesteps starting from current timestep T on all instances
160 : * and additionally uses MamicoInterfaceProvider for interfacing MD to FD.
161 : * @param t
162 : * @param T
163 : * @param multiMDCellService
164 : */
165 : void simulateTimesteps(const unsigned int& t, unsigned int& T, coupling::services::MultiMDCellService<LinkedCell, dim>& multiMDCellService) {
166 : for (unsigned int i = 0; i < _mdSimulations.size(); ++i) {
167 : coupling::interface::MamicoInterfaceProvider<LinkedCell, dim>::getInstance().setCouplingCellService(&multiMDCellService.getCouplingCellService(i));
168 : coupling::interface::MamicoInterfaceProvider<LinkedCell, dim>::getInstance().setMDSolverInterface(_mdSolverInterface[i]);
169 :
170 : if (_mdSimulations[i] != nullptr) {
171 : _mdSimulations[i]->simulateTimesteps(t, T);
172 : }
173 : }
174 : }
175 :
176 : /** Simulates t timesteps starting from current timestep T on all instances
177 : * but only performs simulation on one particular instance
178 : * @param t
179 : * @param T
180 : * @param i
181 : */
182 8 : void simulateTimesteps(const unsigned int& t, unsigned int& T, const unsigned int& i) { _mdSimulations[i]->simulateTimesteps(t, T); }
183 :
184 : /** add a nullptr to the MD simulation vector and the vector of the MD solver
185 : * interface.
186 : */
187 8 : void addSimulationBlock() {
188 8 : _mdSimulations.push_back(nullptr);
189 8 : _mdSolverInterface.push_back(nullptr);
190 8 : }
191 :
192 : /** rempve the last element of the MD simulation vector and the last element
193 : * of the vector of the MD solver interface.
194 : */
195 8 : void rmSimulationBlock() {
196 8 : _mdSimulations.pop_back();
197 8 : _mdSolverInterface.pop_back();
198 : }
199 :
200 : /** adds one MS instance with the identifier localIndex to the slot "slot" and
201 : * return the corresponding MD solver interface. It initializes first an
202 : * instance of the slot "slot". Then set the _mdSimulations[localIndex] to this new
203 : * instance.
204 : * @param slot
205 : * @param localIndex
206 : * @return _mdSolverInterface[localIndex]
207 : */
208 4 : coupling::interface::MDSolverInterface<LinkedCell, dim>* addMDSimulation(unsigned int slot, unsigned int localIndex) {
209 4 : auto* mdSim = coupling::interface::SimulationAndInterfaceFactory::getInstance().getMDSimulation(_mdConfig, _mamicoConfig
210 : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
211 : ,
212 4 : _multiMDService.getLocalCommunicator()
213 : #endif
214 : );
215 4 : if (mdSim == NULL) {
216 0 : std::cout << "ERROR! coupling::InstanceHandling::addMDSimulation(): "
217 : "mdSim == NULL!"
218 0 : << std::endl;
219 0 : std::exit(EXIT_FAILURE);
220 : }
221 : // NB: ls1 coupling will break if getMDSolverInterface does not happen immediately after init()
222 : // since the solver interface relies on the global simulation instance set by ls1 in init()
223 :
224 4 : mdSim->init(_multiMDService, slot);
225 :
226 4 : _mdSimulations[localIndex] = mdSim;
227 :
228 4 : _mdSolverInterface[localIndex] =
229 4 : coupling::interface::SimulationAndInterfaceFactory::getInstance().getMDSolverInterface(_mdConfig, _mamicoConfig, _mdSimulations[localIndex]);
230 :
231 4 : return _mdSolverInterface[localIndex];
232 : }
233 :
234 : /** removes one MS instance with the identifier index and delete the
235 : * corresponding MD solver interface.
236 : * @param index
237 : */
238 4 : void rmMDSimulation(const unsigned int& index) {
239 4 : if (_mdSimulations[index] != nullptr) {
240 4 : _mdSimulations[index]->shutdown();
241 4 : delete _mdSimulations[index];
242 4 : _mdSimulations[index] = nullptr;
243 : } else {
244 0 : std::cout << "WARNING coupling::InstanceHandling::rmMDSimulation() : "
245 : "_mdSimulations at index "
246 0 : << index << " == null!" << std::endl;
247 : }
248 : //_mdSimulations.erase(_mdSimulations.begin()+index);
249 :
250 4 : if (_mdSolverInterface[index] != nullptr) {
251 4 : delete _mdSolverInterface[index];
252 4 : _mdSolverInterface[index] = nullptr;
253 : } else {
254 0 : std::cout << "WARNING coupling::InstanceHandling::rmMDSimulation() : "
255 : "_mdSolverInterface at index "
256 0 : << index << " == null!" << std::endl;
257 : }
258 : //_mdSolverInterface.erase(_mdSolverInterface.begin()+index);
259 4 : }
260 :
261 : /** sets single cell services in each MD simulation after initialising
262 : * coupling cell service for multi-MD case
263 : * @param multiMDCellService
264 : */
265 : void setCouplingCellServices(coupling::services::MultiMDCellService<LinkedCell, dim>& multiMDCellService) {
266 : for (unsigned int i = 0; i < _mdSimulations.size(); ++i) {
267 : _mdSimulations[i]->setCouplingCellService(&(multiMDCellService.getCouplingCellService(i)));
268 : }
269 : }
270 :
271 : private:
272 4 : void shutdown() {
273 12 : for (unsigned int i = 0; i < _mdSimulations.size(); ++i) {
274 8 : coupling::interface::MamicoInterfaceProvider<LinkedCell, dim>::getInstance().setMDSolverInterface(_mdSolverInterface[i]);
275 8 : if (_mdSimulations[i] != nullptr) {
276 8 : _mdSimulations[i]->shutdown();
277 8 : delete _mdSimulations[i];
278 8 : _mdSimulations[i] = nullptr;
279 : }
280 8 : _mdSolverInterface[i] = coupling::interface::MamicoInterfaceProvider<LinkedCell, dim>::getInstance().getMDSolverInterface();
281 : }
282 4 : _mdSimulations.clear();
283 12 : for (auto& solverInterface : _mdSolverInterface) {
284 8 : if (solverInterface != nullptr) {
285 8 : delete solverInterface;
286 8 : solverInterface = nullptr;
287 : }
288 : }
289 4 : _mdSolverInterface.clear();
290 4 : }
291 :
292 : std::vector<coupling::interface::MDSimulation*> _mdSimulations;
293 : std::vector<coupling::interface::MDSolverInterface<LinkedCell, dim>*> _mdSolverInterface;
294 :
295 : simplemd::configurations::MolecularDynamicsConfiguration& _mdConfig;
296 : coupling::configurations::MaMiCoConfiguration<dim>& _mamicoConfig;
297 :
298 : const tarch::utils::MultiMDService<dim>& _multiMDService;
299 : friend InstanceHandlingTest;
300 : };
301 :
302 : #endif //_INSTANCE_HANDLING_H_
|