FFSM++  1.1.0
French Forest Sector Model ++
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 
33 using 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="";
56  inputFileName="";
57  baseDirectory="";
58 
59 }
60 
61 void
62 ThreadManager::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{
77  deleteDeadOldPointers();
78  emit resetGUIForNewSimulation();
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 
116 void
117 ThreadManager::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 
124 void
125 ThreadManager::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 
150 void
151 ThreadManager::setInputFileName(QString inputFileName_h){
152  inputFileName= inputFileName_h;
153  QFileInfo file(inputFileName);
154  QDir baseDir = file.absoluteDir();
155  baseDirectory = baseDir.absolutePath()+"/";
156 }
157 
158 /**
159 Delete 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 */
164 void
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 
180 void
182  stopped = true;
183  emit upgradeLogArea("STOP cliccked stopping");
184 }
185 
186 void
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 
202 void
204  if(!stopped){
205  if(running){
206  running= false;
207  }
208  else {
209  return;
210  }
211  }
212  return;
213 }
214 
215 void
217  if(!stopped){
218  if(running){
219  return;
220  }
221  else {
222  running=true;
223  emit setGUIUnsavedStatus(true);
224  }
225  }
226  return;
227 }
228 
229 void
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 
244 void
245 ThreadManager::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 
253 void
254 ThreadManager::setOutputDirName(string outputDirname_h){
255  emit setOutputDirNameToGui(outputDirname_h);
256 }
257 
258 void
259 ThreadManager::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 
265 void
266 ThreadManager::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 
270 void
271 ThreadManager::updateImage(string layerName_h, const QImage &image_h){
272  emit updateImageToGui(layerName_h.c_str(), image_h);
273 }
274 
275 void
276 ThreadManager::upgradeMainSBLabel(const string message_h){
277  emit upgradeMainSBLabelToGui(message_h.c_str());
278 }
279 
280 void
282  QString temp;
283  temp= i2s(year).c_str();
284  emit upgradeYearSBLabelToGui(temp);
285 }
286 
287 /**
288 checkQuery() 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 */
292 void
293 ThreadManager::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 {
305  computeQuery(pxQueryID, layerQueryPos);
306  layerQueryPos = -1;
307  return;
308  }
309  }
310 }
311 
312 void
313 ThreadManager::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 
int getX() const
Definition: Pixel.h:68
STL namespace.
Main program scheleton. It control the flow of the program.
Definition: MainProgram.h:47
void upgradeYearSBLabel(int year)
void upgradeMainSBLabel(const string message_h)
void setOutputDirName(string outputDirname_h)
void deleteDeadOldPointers()
Useful for several model running without leaving the GUI.
double getDoubleValue(const string &layerName_h, const bool &returnZeroForNoValue=false) const
Return the value for a specific layer.
Definition: Pixel.cpp:158
Pixel-level class.
Definition: Pixel.h:47
void computeQuery(int px_ID, int currentLayerIndex)
Compute the pixel query and return it to the GUI (with a signal)
void setInputFileName(QString inputFileName_h)
void checkQuery(int px_ID, int currentLayerIndex, bool newRequest=true)
Switch and control the access to pxQueryID and layerQueryPos members.
void retrieveScenarioNameFromGUI(const QString &scenarioName_h)
void addLayer(string layerName_h, string layerLabel_h)
void runFromConsole(QString inputFileName_h, QString scenarioName_h)
Re-draw the map making it to fit (with the right proportions) to the widget.
void run()
Run the program.
Definition: MainProgram.cpp:58
Print an INFO message.
Definition: BaseClass.h:59
void setMessage(const QString &message)
void updateImage(string layerName_h, const QImage &image_h)
This file is the header of BaseClass and it is included by ALL compiled code.
void msgOut(const int msgCode_h, const string message_h)
int getY() const
Definition: Pixel.h:69
void updatePixel(string layerName_h, int x_h, int y_h, QColor color)