VPTissue Reference Manual
Sim.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 #include "Sim.h"
21 
22 #include "CoreData.h"
23 #include "SimState.h"
24 #include "TimeSlicer.h"
25 
26 #include "bio/Cell.h"
27 #include "bio/CBMBuilder.h"
28 #include "bio/MBMBuilder.h"
29 #include "bio/Mesh.h"
30 #include "bio/MeshCheck.h"
31 #include "bio/PBMBuilder.h"
32 #include "bio/Wall.h"
33 #include "math/RandomEngine.h"
34 #include "math/RandomEngineType.h"
37 #include "util/clock_man/Utils.h"
38 #include "util/misc/Exception.h"
39 #include "util/misc/log_debug.h"
40 
41 #include <boost/optional.hpp>
42 #include <boost/property_tree/exceptions.hpp>
43 #include <boost/property_tree/xml_parser.hpp>
44 
45 #include <algorithm>
46 #include <functional>
47 #include <iomanip>
48 #include <limits>
49 #include <sstream>
50 #include <string>
51 #include <tuple>
52 
53 using namespace std;
54 using namespace std::chrono;
55 using namespace std::placeholders;
56 using namespace boost::property_tree;
57 using namespace boost::property_tree::xml_parser;
58 using boost::optional;
59 using namespace SimPT_Sim::ClockMan;
60 using namespace SimPT_Sim::Util;
61 using namespace SimPT_Sim;
62 
63 namespace SimPT_Sim {
64 
65 Sim::Sim()
66  : m_is_stationary(false)
67 {
68  m_cd.m_coupled_sim_transfer_data = make_shared<CoreData::TransferMapType>();
69  m_cd.m_parameters = make_shared<ptree>();
70  m_cd.m_random_engine = make_shared<RandomEngine>();
71  m_cd.m_time_data = make_shared<TimeData>();
72 }
73 
74 Sim& Sim::operator=(const Sim& other)
75 {
76  if (this != &other) {
77  //The mutex doesn't have to be copied.
78 
79  m_is_stationary = other.m_is_stationary;
80  m_project_name = other.m_project_name;
81  m_run_date = other.m_run_date;
82  m_timings = other.m_timings;
83 
84  m_cd.m_coupled_sim_transfer_data = make_shared<CoreData::TransferMapType>();
85  m_cd.m_mesh = CBMBuilder().Build(*other.m_cd.m_mesh);
86  m_cd.m_parameters = make_shared<ptree>(*other.m_cd.m_parameters);
87  m_cd.m_time_data = other.m_cd.m_time_data;
88  m_cd.m_random_engine = make_shared<RandomEngine>(*other.m_cd.m_random_engine);
89  }
90  return *this;
91 }
92 
94 {
95 }
96 
97 const ptree& Sim::GetParameters() const
98 {
99  return *m_cd.m_parameters;
100 }
101 
102 string Sim::GetProjectName() const
103 {
104  return m_project_name;
105 }
106 
107 std::string Sim::GetRunDate() const
108 {
109  return m_run_date;
110 }
111 
112 int Sim::GetSimStep() const
113 {
114  return m_cd.m_time_data->m_sim_step;
115 }
116 
117 double Sim::GetSimTime() const
118 {
119  return m_cd.m_time_data->m_sim_time;
120 }
121 
123 {
124  SimState sim_state;
125  sim_state.SetProjectName(m_project_name); // Project name
126  sim_state.SetTimeStep(GetSimStep()); // Sim steps
127  sim_state.SetTime(GetSimTime()); // Sim time
128  sim_state.SetParameters(*m_cd.m_parameters); // Parameters
129  sim_state.SetMeshState(m_cd.m_mesh->GetState()); // Mesh
130 
131  ptree re_state;
132  RandomEngineType::Info re_info = m_cd.m_random_engine->GetInfo();
133  re_state.put("type", re_info.type); // Random Engine
134  re_state.put("seed", re_info.seed); // Random Engine
135  re_state.put("state", re_info.state); // Random Engine
136  sim_state.SetRandomEngineState(re_state); // Random Engine
137 
138  return sim_state;
139 }
140 
141 string Sim::GetStatusMessage() const
142 {
143  stringstream ss;
144  unsigned int i = static_cast<unsigned int>(GetSimTime());
145  ss << "Step: " << GetSimStep()
146  << " ; Time: " << i << " -- " << Utils::ToColonString(seconds(i))
147  << " ; Cells: " << m_cd.m_mesh->GetCells().size();
148  return ss.str();
149 }
150 
151 Sim::Timings Sim::GetTimings() const
152 {
153  return m_timings;
154 }
155 
156 void Sim::Initialize(const ptree& root_pt)
157 {
158  ptree const& sim_pt = root_pt.get_child("vleaf2");
159 
160  // Initialize global info.
161  m_project_name = sim_pt.get<string>("project");
162  m_run_date = TimeStamp().ToString();
163  m_cd.m_time_data = std::make_shared<TimeData>();
164 
165  // Initilize CoreData: time info
166  m_cd.m_time_data->m_sim_step = sim_pt.get<unsigned int>("sim_step", 0U);
167  m_cd.m_time_data->m_sim_time = sim_pt.get<double>("sim_time");
168 
169  // Initilize CoreData: parameters
170  Reinitialize(sim_pt.get_child("parameters"));
171 
172  // Initilize CoreData: build mesh.
173  PBMBuilder build_director;
174  m_cd.m_mesh = build_director.Build(sim_pt.get_child("mesh"));
175 
176  // Initilize CoreData: random engine.
177  RandomEngineInitialize(sim_pt);
178 }
179 
180 void Sim::Initialize(const SimState& sim_state)
181 {
182  // Initialize global info.
183  m_project_name = sim_state.GetProjectName();
184  m_run_date = TimeStamp().ToString();
185 
186  // Initilize CoreData: time info
187  m_cd.m_time_data = make_shared<TimeData>();
188  m_cd.m_time_data->m_sim_step = sim_state.GetTimeStep();
189  m_cd.m_time_data->m_sim_time = sim_state.GetTime();
190 
191  // Initilize CoreData: parameters
192  Reinitialize(sim_state.GetParameters());
193 
194  // Initilize CoreData: build mesh.
195  MBMBuilder build_director;
196  m_cd.m_mesh = build_director.Build(sim_state.GetMeshState());
197 
198  // Initilize CoreData: random engine.
199  RandomEngineInitialize(sim_state);
200 }
201 
203 {
204  const double sim_time = GetSimTime();
205  const unsigned int sim_step = GetSimStep();
206  const unsigned int cell_count = m_cd.m_mesh->GetCells().size();
207  const bool is_stationary = IsStationary();
208 
209  const double max_sim_time
210  = m_cd.m_parameters->get<double>("termination.max_sim_time", numeric_limits<double>::max());
211  const unsigned int max_sim_step
212  = m_cd.m_parameters->get<unsigned int>("termination.max_sim_steps", numeric_limits<unsigned int>::max());
213  const unsigned int max_cell_count
214  = m_cd.m_parameters->get<unsigned int>("termination.max_cell_count", numeric_limits<unsigned int>::max());
215  const bool stationarity_check
216  = m_cd.m_parameters->get<bool>("termination.stationarity_check");
217 
218  return (sim_time >= max_sim_time) || (sim_step >= max_sim_step)
219  || (cell_count >= max_cell_count) || (stationarity_check && is_stationary);
220 }
221 
222 bool Sim::IsStationary() const
223 {
224  return m_is_stationary;
225 }
226 
227 bool Sim::RandomEngineInitialize(const ptree& sim_pt)
228 {
229  // A random engine as defined in RandomEngineType.h has 3 properties:
230  // 'type', 'seed' and 'state'. The 'type' and 'seed' define the starting
231  // condition of the engine. The 'state' defines the state of the engine at
232  // some point in time.
233  //
234  // 'type' and 'seed' are saved in the parameters ptree.
235  // 'type', 'seed' and 'state' are saved in the random_engine ptree
236  //
237  // Initialization logic:
238  // If re_state is empty, initialize a new engine from param's type / seed;
239  // Else
240  // If re_state and parameters.random_engine match on type / seed
241  // initialize from state info in re_state;
242  // Else
243  // initialize a new engine from param's type / seed (i.e: ignore re_state);
244 
245  bool status = false; // Gets to be true is reinitialization succeeds.
246 
247  // Random engine info from parameters.random_engine (type & seed):
248  const ptree& parameters = sim_pt.get_child("parameters");
249  const ptree& re_params_pt = parameters.get_child("random_engine");
250 
251  // Optional random engine state info from random_engine_state:
252  optional<const ptree&> re_state = sim_pt.get_child_optional("random_engine_state");
253 
254  if (!re_state) {
255  status = m_cd.m_random_engine->Reinitialize(re_params_pt);
256  } else {
257  const auto params_type = re_params_pt.get<string>("type");
258  optional<unsigned int> params_seed = re_params_pt.get_optional<unsigned int>("seed");
259  const ptree& re_state_pt = re_state.get();
260  const auto state_type = re_state_pt.get<string>("type");
261  const auto state_seed = re_state_pt.get<unsigned int>("seed");
262 
263  const bool types_match = (params_type == state_type);
264  const bool seeds_match = params_seed ? (params_seed.get() == state_seed) : true;
265 
266  if (types_match && seeds_match) {
267  status = m_cd.m_random_engine->Reinitialize(re_state_pt);
268  } else {
269  status = m_cd.m_random_engine->Reinitialize(re_params_pt);
270  }
271  }
272 
273  return status;
274 }
275 
276 bool Sim::RandomEngineInitialize(const SimState& sim_state)
277 {
278  // Logic for this method: see RandomEngineInitialize(const ptree&)
279 
280  bool status = false; // Gets to be true is reinitialization succeeds.
281 
282  // Random engine info from parameters.random_engine (type & seed):
283  const ptree& parameters = sim_state.GetParameters();
284  const ptree& re_params_pt = parameters.get_child("random_engine");
285 
286  // Optional random engine state info from random_engine_state:
287  const ptree& re_state_pt = sim_state.GetRandomEngineState();
288  optional<string> re_state_type = re_state_pt.get_optional<string>("type");
289  optional<unsigned int> re_state_seed = re_state_pt.get_optional<unsigned int>("seed");
290  optional<string> re_state_state = re_state_pt.get_optional<string>("state");
291 
292  if (!re_state_type || !re_state_seed || !re_state_state) {
293  status = m_cd.m_random_engine->Reinitialize(re_params_pt);
294  } else {
295  const auto params_type = re_params_pt.get<string>("type");
296  optional<unsigned int> params_seed = re_params_pt.get_optional<unsigned int>("seed");
297  const bool types_match = (params_type == re_state_type.get());
298  const bool seeds_match = params_seed ? (params_seed.get() == re_state_seed.get()) : true;
299 
300  if (types_match && seeds_match) {
301  m_cd.m_random_engine->Reinitialize(re_state_pt);
302  } else {
303  status = m_cd.m_random_engine->Reinitialize(re_params_pt);
304  }
305  }
306 
307  return status;
308 }
309 
310 void Sim::Reinitialize(const ptree& p)
311 {
312  lock_guard<mutex> timestep_guard(m_timestep_mutex);
313  *m_cd.m_parameters = p;
314 }
315 
317 {
318  m_timings.Clear();
319 }
320 
321 void Sim::TimeSliceGo(const std::lock_guard<std::mutex>&, double time_slice, SimPhase phase)
322 {
323  // Pre-condition.
324  assert((m_time_evolver != nullptr) && ("TimeEvolver factory produces nullptr."));
325  assert((m_cd.Check()) && "CoreData do no check out!");
326  assert(MeshCheck(*m_cd.m_mesh).CheckAll() && "Mesh inconsistent!");
327 
328  // Effect time step, record timings, advance step counter ...
329  const auto tup = m_time_evolver(time_slice, phase);
330  m_timings.Merge(get<0>(tup));
331  m_is_stationary = get<1>(tup);
332 
333  // Post-condition.
334  assert(MeshCheck(*m_cd.m_mesh).CheckAll() && "Mesh inconsistent!");
335 }
336 
337 void Sim::TimeSliceSetup(const std::lock_guard<std::mutex>&)
338 {
339  // Pre-condition.
340  assert((m_cd.Check()) && "CoreData do no check out!");
341 
342  // Create and initialize time evolver with current parameters.
343  const auto f = ComponentFactoryProxy::Create(m_cd.m_parameters->get<string>("model.group", ""));
344  m_time_evolver = f->CreateTimeEvolver(m_cd);
345 
346  // Post condition.
347  assert((m_time_evolver != nullptr) && ("Time evolver factory produces nullptr."));
348 }
349 
350 void Sim::TimeSliceWrapup(const std::lock_guard<std::mutex>&)
351 {
352  m_time_evolver = TimeEvolverComponent();
353 }
354 
355 unique_ptr<TimeSlicer> Sim::TimeSlicing()
356 {
357  return unique_ptr<TimeSlicer>(new TimeSlicer(m_timestep_mutex, this));
358 }
359 
361 {
362  auto slicer = TimeSlicing();
363  const double time_step = m_cd.m_parameters->get<double>("model.time_step");
364  slicer->Go(time_step);
365  ++m_cd.m_time_data->m_sim_step;
366 }
367 
368 ptree Sim::ToPtree() const
369 {
370  ptree sim_pt;
371  const string time_stamp = TimeStamp().ToString();
372  const string mark = " Generated by SimPT processing at " + time_stamp;
373  sim_pt.add("<xmlcomment>", mark);
374 
375  sim_pt.put("vleaf2.project", GetProjectName());
376  sim_pt.put("vleaf2.run_date", GetRunDate());
377  sim_pt.put("vleaf2.sim_step", GetSimStep());
378  sim_pt.put("vleaf2.sim_time", GetSimTime());
379  sim_pt.put_child("vleaf2.parameters", GetParameters());
380  sim_pt.put_child("vleaf2.mesh", m_cd.m_mesh->ToPtree());
381 
382  RandomEngineType::Info info = m_cd.m_random_engine->GetInfo();
383  sim_pt.put("vleaf2.random_engine_state.type", info.type);
384  sim_pt.put("vleaf2.random_engine_state.seed", info.seed);
385  sim_pt.put("vleaf2.random_engine_state.state", info.state);
386 
387  return sim_pt;
388 }
389 
390 } // namespace
void TimeStep()
Definition: Sim.cpp:360
double GetTime() const
Returns the value of the current time step in seconds.
Definition: SimState.cpp:40
Interface for MBMBBuilder.
STL namespace.
bool IsStationary() const
Definition: Sim.cpp:222
void SetRandomEngineState(boost::property_tree::ptree const &re_state)
Sets the state of the random number engine used for generating random in the simulation.
Definition: SimState.cpp:90
Core data used during model execution.
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
MeshState GetMeshState() const
Get the state of the mesh.
Definition: SimState.cpp:45
Simulator: mesh & parameters, model & algorithms.
Definition: Sim.h:50
static std::shared_ptr< ComponentFactoryProxy > Create(const string &group_name, bool throw_ok=true)
Create a factory proxy.
bool CheckAll() const
Runs all of the of checks to verify consistency of the mesh.
Definition: MeshCheck.cpp:63
std::string GetRunDate() const
Definition: Sim.cpp:107
Interface of RandomEngine.
Interface for TimeKeeper::Utils.
virtual ~Sim()
Destructor is virtual (.
Definition: Sim.cpp:93
std::unique_ptr< TimeSlicer > TimeSlicing()
Return a SimTimeSlicer to proceed through a time step using time slices.
Definition: Sim.cpp:355
The Copy-Based Mesh Builder directs the Mesh building process using another mesh. ...
Definition: CBMBuilder.h:32
double GetSimTime() const
Definition: Sim.cpp:117
Namespace for the core simulator.
friend class TimeSlicer
Make Timeslicer our friend.
Definition: Sim.h:125
Interface for Cell.
void Initialize(const boost::property_tree::ptree &pt)
Initialize with full configuration (global info, parameters, random engine, mesh) i...
Checks mesh concistency.
Definition: MeshCheck.h:29
Interface for MeshCheck.
Interface for PBMBBuilder.
Macro defs for debug and logging.
void SetMeshState(MeshState const &mesh_state)
Sets the current state of the mesh in the simulation.
Definition: SimState.cpp:75
Header for SimState.
Class that directs ptree based mesh building process.
Definition: PBMBuilder.h:33
std::string GetProjectName() const
Definition: Sim.cpp:102
void SetTimeStep(int step)
Sets the index of the current time step.
Definition: SimState.cpp:65
std::shared_ptr< Mesh > Build(const Mesh &mesh)
Build a mesh exactly like the given mesh.
Definition: CBMBuilder.cpp:37
Proxy for dealing with the factories.
Interface of RandomEngineType.
TimeStamp class.
std::string GetStatusMessage() const
Return a status message (time, steps, cellcount).
Definition: Sim.cpp:141
Sim & operator=(const Sim &other)
Assignment operator rebuilds copy of mesh.
Definition: Sim.cpp:74
std::string GetProjectName() const
Returns the name of the associated project.
Definition: SimState.cpp:55
Sim, the actual simulator.
void Reinitialize(const boost::property_tree::ptree &p)
Definition: Sim.cpp:310
boost::property_tree::ptree ToPtree() const
Serialize into ptree.
Definition: Sim.cpp:368
void SetParameters(boost::property_tree::ptree const &parameters)
Sets the parameters currently used simulation model.
Definition: SimState.cpp:80
Contains the state of the whole Simulator at a given simulation step.
Definition: SimState.h:33
boost::property_tree::ptree GetParameters() const
Returns the parameters currently used simulation model.
Definition: SimState.cpp:50
bool IsAtTermination() const
Definition: Sim.cpp:202
const boost::property_tree::ptree & GetParameters() const
Definition: Sim.cpp:97
Provides wall-clock time stamp using the time call.
Definition: TimeStamp.h:37
Header file for Exception class.
int GetSimStep() const
Definition: Sim.cpp:112
std::string ToString() const
Returns string with the time stamp after eliminating newline.
Definition: TimeStamp.h:44
int GetTimeStep() const
Returns the index of the current time step.
Definition: SimState.cpp:35
Timings GetTimings() const
Definition: Sim.cpp:151
void ResetTimings()
Resets the execution timings.
Definition: Sim.cpp:316
void SetTime(double t)
Sets the value of the current time step in seconds.
Definition: SimState.cpp:70
void SetProjectName(std::string project_name)
Sets the name of the associated project.
Definition: SimState.cpp:85
boost::property_tree::ptree GetRandomEngineState() const
Returns the state of the random engine in a ptree.
Definition: SimState.cpp:60
Time slice propagation.
std::function< std::tuple< SimTimingTraits::CumulativeTimings, bool >(double, SimPhase)> TimeEvolverComponent
Time Evolver component interface.
Interface of CBMBuilder.
bool Check() const
Verify all pointers non-null.
Definition: CoreData.h:53
SimState GetState() const
Provide sim state in format suitable for i/o.
Definition: Sim.cpp:122
Namespace for clock and timekeeping related classes.
Definition: ClockCLib.h:27
Interface for Wall.
MBMBDirector directs the Mesh building process using a MeshState object.
Definition: MBMBuilder.h:33
Interface for Mesh.