FFSM++ 1.1.0
French Forest Sector Model ++
Loading...
Searching...
No Matches
ThreadManager.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2015 by Laboratoire d'Economie Forestière *
3 * http://ffsm-project.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version, given the compliance with the *
9 * exceptions listed in the file COPYING that is distribued together *
10 * with this file. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22#include <iostream>
23
24#include <QtCore>
25//#include <QMutex>
26#include <QMutexLocker>
27
28#include "ThreadManager.h"
29#include "BaseClass.h"
30#include "MainProgram.h"
31#include "MainWindow.h"
32
33using namespace std;
34
36 running=false;
37 stopped=false;
38 layerQueryPos = -1;
39
40 // initializing pointers...
41 MD = NULL;
42 GIS = NULL;
43 INIT = NULL;
44 SCD = NULL;
45 DO = NULL;
46 CORE = NULL;
47 SCORE = NULL;
48 TEST = NULL;
49 CBAL = NULL;
50 //randev = NULL;
51 gen = NULL;
52
53 GUI = false;
54
55 scenarioName="";
58
59}
60
61void
62ThreadManager::setMessage(const QString &message){
63 messageStr = message;
64}
65
67 running=true;
68 stopped=false;
69
70 srand(1);
71 GUI=true;
72
73 emit upgradeLogArea("**INFO: Start running the model...");
74
75 MainProgram* myProgram;
76 try{
79
80
81 QFileInfo file(inputFileName);
82 QDir baseDir = file.absoluteDir();
83 baseDirectory = baseDir.absolutePath()+"/";
84 myProgram = new MainProgram(this);
85
86 //myProgram->setBaseDirectory(baseDirectory);
87
88 vector<string> scenarios = MD->getScenarios();
89 QVector<QString> qscenarios;
90 for(uint i=0;i<scenarios.size();i++){
91 qscenarios.push_back(scenarios.at(i).c_str());
92 }
93 running = false;
94 emit sendScenarioOptionsToGUI(qscenarios);
95 refreshGUI();
96
97 myProgram->run();
98
99 // Here the model has come to an end...
100 running=false;
101 stopped=true;
102 delete myProgram;
103 refreshGUI();
104
105 }catch (...) {
106 // Here the model has come to an end...
107 running=false;
108 stopped=true;
109 delete myProgram;
110 emit upgradeLogArea("**INFO: Model has stopped or rised an error (read previous line).");
111 }
112 emit upgradeLogArea("**INFO: Model has ended.");
113
114}
115
116void
117ThreadManager::retrieveScenarioNameFromGUI(const QString &scenarioName_h){
118 scenarioName = scenarioName_h;
119 msgOut(MSG_INFO, "Selected scenario: "+scenarioName.toStdString());
120 cout << "Selected scenario: "+scenarioName.toStdString() << endl;
121 resume();
122}
123
124void
125ThreadManager::runFromConsole(QString inputFileName_h, QString scenarioName_h){
126 try{
127 GUI = false;
128 scenarioName = scenarioName_h;
129 inputFileName = inputFileName_h;
130 QFileInfo file(inputFileName);
131 QDir baseDir = file.absoluteDir();
132 baseDirectory = baseDir.absolutePath()+"/";
133 cout <<"Using base directory: "<< baseDirectory.toStdString() << endl;
134
135
136 MainProgram* myProgram = new MainProgram(this);
137
138 if( scenarioName_h == ""){ // if the scenario option has not been choosed, go for the first one!
139 vector<string> scenarios = MD->getScenarios();
140 scenarioName = scenarios.at(0).c_str();
141 }
142
143 //myProgram->setBaseDirectory(baseDirectory);
144 myProgram->run();
145 }catch (...) {
146 exit(EXIT_FAILURE);
147 }
148}
149
150void
151ThreadManager::setInputFileName(QString inputFileName_h){
152 inputFileName= inputFileName_h;
153 QFileInfo file(inputFileName);
154 QDir baseDir = file.absoluteDir();
155 baseDirectory = baseDir.absolutePath()+"/";
156}
157
158/**
159Delete the pointers (e.g. GIS) eventually remained from a previous run.
160<br>This function is called at the START of a new simulation, and it will check if model pointers (e.g. GIS) exist , and if so it will delete them.
161<br>This is useful when we keep the MainWindow open but we run the model for a second time.
162<br>Why we don't delete them at the end of a simulation, instead of deleting them on a new run? That's because we want let the user to interface with the model even when this is ended, w.g. for query the map.
163*/
164void
166 if (DO) {delete DO; DO=0;}
167 if (INIT) {delete INIT; INIT=0;}
168 if (SCD) {delete SCD; SCD=0;}
169 if (GIS) {delete GIS; GIS=0;}
170 if (MD) {delete MD; MD=0;}
171 if (CORE){delete CORE; CORE=0;}
172 if (SCORE){delete SCORE; SCORE=0;}
173 if (CBAL) {delete CBAL; CBAL=0;}
174 //if (OPT) {delete OPT; OPT=0;} // not needed, it's a "smart point"
175 if(TEST){delete TEST; TEST=0;}
176 //if(randev){delete randev; randev=0;}
177 if(gen){delete gen; gen=0;}
178}
179
180void
182 stopped = true;
183 emit upgradeLogArea("STOP cliccked stopping");
184}
185
186void
188 if(!stopped){
189 if(running){
190 running= false;
191 emit upgradeLogArea("PAUSE cliccked PAUSING");
192 }
193 else {
194 running=true;
195 emit upgradeLogArea("PAUSE cliccked RESUMING");
196 emit setGUIUnsavedStatus(true);
197 }
198 }
199 return;
200}
201
202void
204 if(!stopped){
205 if(running){
206 running= false;
207 }
208 else {
209 return;
210 }
211 }
212 return;
213}
214
215void
217 if(!stopped){
218 if(running){
219 return;
220 }
221 else {
222 running=true;
223 emit setGUIUnsavedStatus(true);
224 }
225 }
226 return;
227}
228
229void
231 checkQuery(0,0,false);
232 while (!running){
233 if(stopped){
234 break;
235 }
236 }
237 if (stopped){
238 emit upgradeLogArea("Model has been stopped.");
239 running= false;
240 throw(2);
241 }
242}
243
244void
245ThreadManager::msgOut(const int msgCode_h, const string message_h){
246 QString message = message_h.c_str();
247 emit upgradeLogArea(message);
248 if (msgCode_h == 2){
249 emit upgradeMainSBLabelToGui(message);
250 }
251}
252
253void
254ThreadManager::setOutputDirName(string outputDirname_h){
255 emit setOutputDirNameToGui(outputDirname_h);
256}
257
258void
259ThreadManager::addLayer(string layerName_h, string layerLabel_h){
260 QString layerName = layerName_h.c_str();
261 QString layerLabel = layerLabel_h.c_str();
262 emit addLayerToGui(layerName, layerLabel);
263}
264
265void
266ThreadManager::updatePixel(string layerName_h, int x_h, int y_h, QColor color_h){
267 emit updatePixelToGui(layerName_h.c_str(), x_h, y_h, color_h);
268}
269
270void
271ThreadManager::updateImage(string layerName_h, const QImage &image_h){
272 emit updateImageToGui(layerName_h.c_str(), image_h);
273}
274
275void
276ThreadManager::upgradeMainSBLabel(const string message_h){
277 emit upgradeMainSBLabelToGui(message_h.c_str());
278}
279
280void
282 QString temp;
283 temp= i2s(year).c_str();
284 emit upgradeYearSBLabelToGui(temp);
285}
286
287/**
288checkQuery() is a function that can be called my the GUI trough a signal or from the running thread under refreshGUI(), and it is protected with a mutex.
289<br>It's role is to control the status of pxQueryID and layerQueryPos member variables.
290<br>If the call come from the GUI, it is a new request and we set them to the new values, otherwise we gonna see if they are just beed changed and if so (layerQueryPos>=0) we call computeQuery().
291*/
292void
293ThreadManager::checkQuery(int px_ID, int currentLayerIndex, bool newRequest){
294 QMutexLocker locker(&mutex);
295 if(newRequest){
296 pxQueryID = px_ID;
297 layerQueryPos = currentLayerIndex;
298 if(stopped){computeQuery(pxQueryID, layerQueryPos);layerQueryPos = -1;} // model is stopped, no way the model thread will do the query work
299 else{emit publishQueryResults("<i>..wait.. processing query..</i>");} // model is running.. it will be the model thread to execute the query
300 return;
301 } else {
302 if(layerQueryPos<0){
303 return;
304 } else {
306 layerQueryPos = -1;
307 return;
308 }
309 }
310}
311
312void
313ThreadManager::computeQuery(int px_ID, int currentLayerIndex){
314
315 // IMPORTANT: this function is called at refreshGUI() times, so if there are output messages, call them with the option to NOT refresh the gui, otherwise we go to an infinite loop...
316
317 vector<Layers*> layers;
318 try {
319 layers = GIS->getLayerPointers();
320 }catch (...) {
321 emit activateTab(2); // tell the gui to activate the 3rd page, those with the pixel info
322 emit publishQueryResults("GIS pointer is dead.. maybe simulation has ended???");
323 return;
324 }
325 QString result= "";
326 int realID = GIS->sub2realID(px_ID);
327 if (realID<0) {
328 emit publishQueryResults("Query result: Spatial data is not yet ready in the model. Please click again later.");
329 return; // on early stage we may have errors, and here we prevent this error to have further consequences.
330 }
331 Pixel* px;
332 try {
333 px = GIS->getPixel(realID);
334 }catch (...) {
335 emit activateTab(2); // tell the gui to activate the 3rd page, those with the pixel info
336 emit publishQueryResults("Query result: Spatial data is not yet ready in the model. Please click again later.");
337 return;
338 }
339 result += "Pixel: ";
340 result += i2s(realID).c_str();
341 result += " (";
342 result += i2s(px->getX()).c_str();
343 result += ",";
344 result += i2s(px->getY()).c_str();
345 result += ")";
346 result +="<p><table>";
347 uint countVisibleLayers = 0;
348 for (uint i=0;i<layers.size();i++){
349 if(!layers[i]->getDisplay()){
350 continue;
351 }
352 QString boldStart="";
353 QString boldEnd = "";
354 if (countVisibleLayers == currentLayerIndex){
355 boldStart = "<b>";
356 boldEnd = "</b>";
357 }
358 result += "<tr>";
359 string layerName = layers[i]->getName();
360 double value = px->getDoubleValue(layerName);
361 string category = layers[i]->getCategory(value);
362 //QColor color = layers[i]->getColor(value);
363 result += "<td>";
364 result += boldStart;
365 result += layerName.c_str();
366 result += boldEnd;
367 result += "</td><td>";
368 result += boldStart;
369 result += category.c_str();
370 result += boldEnd;
371 result += "</td>";
372 result += "</tr>";
373 if(layers[i]->getDisplay()){ // if not really needed, but ok if we decide to change and get displayed also hidden layers
374 countVisibleLayers++;
375 }
376 }
377 result += "</table>";
378 emit activateTab(2); // tell the gui to activate the 3rd page, those with the pixel info
379 emit publishQueryResults(result);
380}
381
382
This file is the header of BaseClass and it is included by ALL compiled code.
@ MSG_INFO
Print an INFO message.
Definition BaseClass.h:59
string i2s(const int &int_h) const
integer to string conversion
vector< Layers * > getLayerPointers()
Return a vector of pointers of existing layers.
Definition Gis.cpp:881
Pixel * getPixel(int x_h, int y_h)
Definition Gis.h:134
int sub2realID(int id_h)
Transform the ID of a pixel in subregion coordinates to the real (and model used) coordinates.
Definition Gis.cpp:982
Main program scheleton. It control the flow of the program.
Definition MainProgram.h:47
void run()
Run the program.
vector< string > getScenarios()
Pixel-level class.
Definition Pixel.h:47
double getDoubleValue(const string &layerName_h, const bool &returnZeroForNoValue=false) const
Return the value for a specific layer.
Definition Pixel.cpp:158
int getX() const
Definition Pixel.h:68
int getY() const
Definition Pixel.h:69
QString scenarioName
QString baseDirectory
void activateTab(int pos_h)
void sendScenarioOptionsToGUI(const QVector< QString > &scenarios_h)
Init * INIT
the Init object (pre-simulation scheduler)
QString inputFileName
void upgradeMainSBLabelToGui(const QString &logMessage)
volatile int pxQueryID
void resetGUIForNewSimulation()
void upgradeMainSBLabel(const string message_h)
void updateImage(string layerName_h, const QImage &image_h)
void updatePixel(string layerName_h, int x_h, int y_h, QColor color)
void runFromConsole(QString inputFileName_h, QString scenarioName_h)
Re-draw the map making it to fit (with the right proportions) to the widget.
Carbon * CBAL
Module for the Carbon Balance.
Scheduler * SCD
the scheduler object (simulation-loops scheduler)
ModelCoreSpatial * SCORE
Core of the model (spatial version)
void publishQueryResults(const QString &results)
Sandbox * TEST
Various debugging code for development.
void addLayerToGui(QString layerName, QString layerLabel)
void upgradeYearSBLabelToGui(const QString &logMessage)
volatile bool running
void msgOut(const int msgCode_h, const string message_h)
Gis * GIS
GIS information and methods.
volatile int layerQueryPos
volatile bool stopped
ModelData * MD
the model data object
void updateImageToGui(QString layerName_h, QImage image_h)
std::mt19937 * gen
used in the sampling from normal distribution
void setGUIUnsavedStatus(bool status_h)
void addLayer(string layerName_h, string layerLabel_h)
void deleteDeadOldPointers()
Useful for several model running without leaving the GUI.
Output * DO
data output
ModelCore * CORE
Core of the model.
void upgradeYearSBLabel(int year)
void setInputFileName(QString inputFileName_h)
void setMessage(const QString &message)
void checkQuery(int px_ID, int currentLayerIndex, bool newRequest=true)
Switch and control the access to pxQueryID and layerQueryPos members.
void setOutputDirNameToGui(string outputDirname_h)
void upgradeLogArea(const QString &logMessage)
void retrieveScenarioNameFromGUI(const QString &scenarioName_h)
void updatePixelToGui(QString layerName_h, int x_h, int y_h, QColor color)
void computeQuery(int px_ID, int currentLayerIndex)
Compute the pixel query and return it to the GUI (with a signal)
void setOutputDirName(string outputDirname_h)