VPTissue Reference Manual
SimSessionCoupled.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  */
21 
22 #include "session/SimSession.h"
23 #include "session/SimWorker.h"
24 #include "viewer/RootViewerNode.h"
26 #include "sim/CoreData.h"
27 #include "sim/CoupledSim.h"
28 #include "sim/Sim.h"
29 #include "util/misc/Exception.h"
30 #include "viewer/ViewerNode.h"
31 #include "workspace/IFile.h"
32 #include "workspace/IProject.h"
33 #include "workspace/IWorkspace.h"
34 
35 #include <QTimer>
36 #include <QThread>
37 
38 using namespace std;
39 using namespace SimPT_Sim;
41 
42 namespace SimShell {namespace Viewer {
43  template <>
44  struct viewer_is_widget<SimPT_Shell::LogWindowViewer>
45  {
46  static const bool value = true;
47  };
48 }}
49 
50 
51 namespace SimPT_Shell {
52 namespace Session {
53 
54 SimSessionCoupled::SimSessionCoupled(
55  const std::shared_ptr<MergedPreferences>& prefs,
56  const ptree& project_info,
57  const std::shared_ptr<SimShell::Ws::IWorkspace>& workspaceModel
58  )
59  :
60  m_preferences(prefs),
61  m_sim(make_shared<CoupledSim>()),
62  m_steps_limit(0),
63  m_running(false),
64  m_sim_thread(new QThread(this)),
65  m_parameter_buffer({ false, ptree() })
66 {
67  auto projects = ReadSubprojectList(project_info);
68  if (projects.empty()) {
69  throw Exception("Failed to open coupled project: subproject list is empty");
70  }
71 
72  for (const auto& project : projects) {
73  m_projects[project.first] =
74  OpenSubproject(project.first, project.second, workspaceModel);
75  }
76 
77  vector<shared_ptr<Sim>> sims;
78  for (const auto& project : m_projects) {
79  sims.push_back(static_pointer_cast<ISimSession>(project.second->GetSession())->GetSim());
80  }
81  m_sim->Initialize(project_info, sims);
82 }
83 
85 {
86  // Close sub projects
87  for (auto project : m_projects) {
88  if (project.second->IsOpened()) {
89  project.second->Close();
90  }
91  }
92 }
93 
94 std::shared_ptr<SimSessionCoupled::RootViewerType>
96 {
97  SimShell::Viewer::IViewerNode::ChildrenMap m;
98  m["Log Dock Window"] = make_shared<SimShell::Viewer::ViewerNode<LogWindowViewer, SimPT_Sim::CoupledSim>>(
99  m_preferences->GetChild("viewers.logwindow"), parent);
100  for (auto project : m_projects) {
101  auto project_root_viewer = project.second->GetSession()->CreateRootViewer(parent);
102  m[project.first] = make_shared<SimShell::Viewer::SubjectViewerNodeWrapper<CoupledSim>>(project_root_viewer);
103  }
104  return make_shared<SimShell::Viewer::SubjectNode<CoupledSim>>(m_preferences->GetChild("viewers"), m_sim, move(m));
105 }
106 
107 SimSessionCoupled::ExportersType
109 {
110  // TODO Think about nesting the exporters of the subprojects into this list
111  return {};
112 }
113 
115 {
116  return m_sim->GetParameters();
117 }
118 
120 {
121  // TODO Multiple lines: suitable for Qt status bar?
122  stringstream ss;
123  ss << "Coupled simulation:";
124 
125  for (auto project : m_projects) {
126  ss << std::endl;
127  ss << '\t' << project.first
128  << " : " << static_pointer_cast<ISimSession>(
129  project.second->GetSession())->GetStatusMessage();
130  }
131  return ss.str();
132 }
133 
134 SimSessionCoupled::Timings SimSessionCoupled::GetTimings() const
135 {
136  auto timings = m_sim->GetTimings();
137  timings.Merge(m_timings);
138  return timings.GetRecords<Duration>();
139 }
140 
142 {
143  lock_guard<mutex> parameters_guard(m_viewers_mutex);
144 
145  for (auto project : m_projects) {
146  project.second->GetSession()->ForceExport();
147  }
148 }
149 
150 std::shared_ptr<SimShell::Ws::IProject> SimSessionCoupled::OpenSubproject(
151  const string& project_name,
152  const string& file_name,
153  const shared_ptr<SimShell::Ws::IWorkspace>& workspaceModel)
154 {
155  shared_ptr<SimShell::Ws::IProject> p;
156  try {
157  auto project_it = workspaceModel->Find(project_name); // may throw
158  if (project_it == workspaceModel->end() ) {
159  throw Exception("Failed to open subproject " + project_name+": Not Found");
160  }
161  if (!file_name.empty()) {
162  project_it->second->Open(file_name);
163  } else {
164  project_it->second->Open();
165  }
166  p = project_it->second.Project();
167  } catch (std::runtime_error& e) {
168  throw Exception("Failed to open subproject " + project_name + ": " + e.what());
169  }
170 
171  if (!p || !p->IsOpened()) {
172  throw Exception("Failed to open subproject " + project_name);
173  }
174 
175  return p;
176 }
177 
178 void SimSessionCoupled::SetParameters(const ptree& pt)
179 {
180  lock_guard<mutex> parameters_guard(m_parameters_mutex);
181  m_parameter_buffer.pt = pt;
182  m_parameter_buffer.updated = true;
183 }
184 
186 {
187  assert(steps >= -1 && "Steps should be positive or -1");
188  m_steps_limit = steps;
189 
190  // Create worker instance
191  auto sim_worker = new SimWorker(m_sim);
192  sim_worker->moveToThread(m_sim_thread);
193 
194  // The signals & slots magic
195  connect(m_sim_thread, SIGNAL(started()), sim_worker, SLOT(Work()));
196  connect(this, SIGNAL(ExecuteWorkUnit()), sim_worker, SLOT(Work()));
197  connect(sim_worker, SIGNAL(Worked(QString)), this, SLOT(ExecuteViewUnit(QString)));
198  connect(m_sim_thread, SIGNAL(finished()), sim_worker, SLOT(deleteLater()));
199 
200  // Get the ball rolling
201  m_running = true;
202  if (m_parameter_buffer.updated) {
203  m_sim->Reinitialize(m_parameter_buffer.pt);
204  // Notify viewers (preferences can't be changed during notification).
205  {
206  lock_guard<mutex> viewers_guard(m_viewers_mutex);
207  m_sim->Notify(SimPT_Sim::Event::CoupledSimEvent(m_sim, m_sim->GetSimStep(),
208  SimPT_Sim::Event::CoupledSimEvent::Type::Forced));
209  }
210  m_parameter_buffer.updated = false;
211  }
212  m_sim_thread->start();
213  emit InfoMessage(GetStatusMessage(), InfoMessageReason::Started);
214 }
215 
217 {
218 
219  m_running = false;
220  m_sim_thread->quit();
221  m_sim_thread->wait();
222  m_steps_limit = -1;
223  emit InfoMessage(GetStatusMessage(), InfoMessageReason::Stopped);
224 }
225 
226 std::vector<std::pair<std::string, std::string>>
227 SimSessionCoupled::ReadSubprojectList(const ptree& pt)
228 {
229  vector<pair<string, string>> projects;
230  const auto& projects_pt = pt.get_child("vleaf2.coupled_project.subproject_array");
231  for (auto pair : projects_pt) {
232  const auto& project_pt = pair.second;
233  projects.push_back(make_pair(
234  project_pt.get<std::string>("name"),
235  project_pt.get<std::string>("file", "")
236  ));
237  }
238  return projects;
239 }
240 
241 void SimSessionCoupled::ExecuteViewUnit(QString worker_message)
242 {
243  if (worker_message != "") {
244  throw Exception(worker_message.toStdString());
245  }
246  {
247  lock_guard<mutex> viewers_guard(m_viewers_mutex);
248  // TODO Refactor to protected function in interface for projects?
249  // TODO Strides, forced export (on parameter change) for coupled simulation?
250  Stopclock viewersChrono("viewers", true);
251  for (auto project : m_projects) {
252  auto sim = static_pointer_cast<ISimSession>(project.second->GetSession())->GetSim();
253  SimPT_Sim::Event::SimEvent e(sim, sim->GetSimStep(),
254  SimPT_Sim::Event::SimEvent::Type::Stepped);
255  sim->Notify(e);
256  }
257  SimPT_Sim::Event::CoupledSimEvent e(m_sim, m_sim->GetSimStep(),
258  SimPT_Sim::Event::CoupledSimEvent::Type::Stepped);
259  m_sim->Notify(e);
260  m_timings.Record(viewersChrono.GetName(), viewersChrono.Get());
261  }
262  emit InfoMessage(GetStatusMessage(), InfoMessageReason::Stepped);
263  --m_steps_limit;
264 
265  if (m_running) {
266  if ((m_steps_limit == 0) || m_sim->IsAtTermination()) {
267  StopSimulation();
268  } else {
269  { // Check if parameters were changed.
270  lock_guard<mutex> parameters_guard(m_parameters_mutex);
271  if (m_parameter_buffer.updated) {
272  m_sim->Reinitialize(m_parameter_buffer.pt);
273  // Notify viewers (preferences can't be changed during notification).
274  {
275  lock_guard<mutex> viewers_guard(m_viewers_mutex);
276  m_sim->Notify(SimPT_Sim::Event::CoupledSimEvent(
277  m_sim, m_sim->GetSimStep(),
278  SimPT_Sim::Event::CoupledSimEvent::Type::Forced));
279  }
280  m_parameter_buffer.updated = false;
281  }
282  }
283  emit ExecuteWorkUnit();
284  }
285  }
286 }
287 
289 {
290  StartSimulation(1);
291 }
292 
293 } // namespace
294 } // namespace
295 
Interface for SimSessionCoupled.
virtual void SetParameters(const ptree &)
Interface for IFile.
STL namespace.
void InfoMessage(const std::string &message, const InfoMessageReason &reason)
Emitted when an event with an accompanying info message has been done/occurred (Multithreading cannot...
Core data used during model execution.
An event transmitted by a simulator.
Definition: SimEvent.h:35
ptree pt
Ptree containing parameters.
Namespace for SimPT shell package.
Definition: Client.cpp:50
Interface for handling an opened/running simulation.
Definition: ISimSession.h:31
virtual ~SimSessionCoupled()
Destructor virtual, just in case.
Extremely simple Exception root class.
Definition: Exception.h:28
virtual std::shared_ptr< RootViewerType > CreateRootViewer(SimShell::Gui::Controller::AppController *parent=nullptr)
Namespace for the core simulator.
Interface for IProject.
Utility for running simulation in a separate thread.
Definition: SimWorker.h:35
Interface for ViewerNode.
Header for LogWindowViewer.
Interface for RootViewerNode.
An event transmitted by a Coupled Simulator.
Sim, the actual simulator.
Interface for IWorkspace.
Interfaces for simulator session.
std::string GetStatusMessage() const
Return the status message.
virtual Timings GetTimings() const
Get timing information from simulation and viewers.
virtual void StartSimulation(int steps=-1)
Header for SimWorker.
Header file for Exception class.
virtual const ptree & GetParameters() const
Coupled Simulator: multiple simulators and couplers.
Definition: CoupledSim.h:42
SimPT_Sim::ClockMan::Stopwatch< std::chrono::system_clock > Stopclock
Stopwatch to measure time durations.
Definition: ClockTraits.h:43
Namespace for generic graphical shell for simulators.
Definition: SimSession.h:32
typename std::chrono::system_clock::duration Duration
Type for time duration units.
Definition: ClockTraits.h:46
Interface for CoupledSim.