BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
JobQueueData.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/Model/Model/JobQueueData.cpp
6 //! @brief Implements class JobQueueData
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Device/Histo/SimulationResult.h"
17 #include "GUI/Model/Job/JobItem.h"
21 #include "GUI/Util/Error.h"
22 #include "GUI/Util/Path.h"
23 #include "Sim/Simulation/ISimulation.h"
24 #include <QThread>
25 
27  : m_jobModel(jobModel)
28 {
29 }
30 
32 {
33  return !m_simulations.empty();
34 }
35 
36 //! Submits job and run it in a thread.
37 
39 {
40  QString identifier = jobItem->getIdentifier();
41  if (getThread(identifier))
42  return;
43 
44  if (getSimulation(identifier))
45  throw Error("JobQueueData::runJob() -> Error. ISimulation is already existing.");
46 
47  try {
49  jobItem->sampleItem(), jobItem->instrumentItem(), jobItem->simulationOptionsItem());
50  m_simulations[identifier] = simulation.release();
51  } catch (const std::exception& ex) {
52  QString message("JobQueueData::runJob() -> Error. "
53  "Attempt to create sample/instrument object from user description "
54  "has failed with following error message.\n\n");
55  message += QString::fromStdString(std::string(ex.what()));
56  jobItem->setComments(message);
57  jobItem->setProgress(100);
58  jobItem->setStatus(JobStatus::Failed);
59  emit focusRequest(jobItem);
60  return;
61  }
62 
63  auto* worker = new JobWorker(identifier, m_simulations[identifier]);
64  m_workers[identifier] = worker;
65 
66  auto* thread = new QThread;
67  worker->moveToThread(thread);
68  m_threads[identifier] = thread;
69 
70  // thread will start the worker
71  connect(thread, &QThread::started, worker, &JobWorker::start);
72 
73  // finished thread will be removed from the list
74  connect(thread, &QThread::finished, this, &JobQueueData::onFinishedThread);
75 
76  // connecting the worker to started/progress slots
77  connect(worker, &JobWorker::started, this, &JobQueueData::onStartedJob);
79 
80  // finished job will do all cleanup
81  connect(worker, &JobWorker::finished, this, &JobQueueData::onFinishedJob);
82 
83  thread->start();
84 }
85 
86 //! Cancels running job.
87 
88 void JobQueueData::cancelJob(const QString& identifier)
89 {
90  if (getThread(identifier))
91  getWorker(identifier)->terminate();
92 }
93 
94 //! Remove job from list completely.
95 
96 void JobQueueData::removeJob(const QString& identifier)
97 {
98  cancelJob(identifier);
99  clearSimulation(identifier);
100 }
101 
102 //! Sets JobItem properties when the job is going to start.
103 
105 {
106  auto* worker = qobject_cast<JobWorker*>(sender());
107 
108  auto* jobItem = m_jobModel->getJobItemForIdentifier(worker->identifier());
109  jobItem->setProgress(0);
110  jobItem->setStatus(JobStatus::Running);
111  jobItem->setBeginTime(worker->simulationStart());
112  jobItem->setEndTime(QDateTime());
113 }
114 
115 //! Performs necessary actions when job is finished.
116 
118 {
119  auto* worker = qobject_cast<JobWorker*>(sender());
120 
121  auto* jobItem = m_jobModel->getJobItemForIdentifier(worker->identifier());
122  processFinishedJob(worker, jobItem);
123 
124  // I tell to the thread to exit here (instead of connecting JobRunner::finished
125  // to the QThread::quit because of strange behaviour)
126  getThread(worker->identifier())->quit();
127 
128  emit focusRequest(jobItem);
129 
130  clearSimulation(worker->identifier());
131  assignForDeletion(worker);
132 
133  if (!hasUnfinishedJobs())
134  emit globalProgress(100);
135 }
136 
138 {
139  auto* thread = qobject_cast<QThread*>(sender());
140  assignForDeletion(thread);
141 }
142 
144 {
145  auto* worker = qobject_cast<JobWorker*>(sender());
146  auto* jobItem = m_jobModel->getJobItemForIdentifier(worker->identifier());
147  jobItem->setProgress(worker->progress());
149 }
150 
151 //! Estimates global progress from the progress of multiple running jobs and
152 //! emits appropriate signal.
153 
155 {
156  int global_progress(0);
157  int nRunningJobs(0);
158  for (auto* jobItem : m_jobModel->jobItems())
159  if (jobItem->isRunning()) {
160  global_progress += jobItem->getProgress();
161  nRunningJobs++;
162  }
163 
164  if (nRunningJobs)
165  global_progress /= nRunningJobs;
166  else
167  global_progress = -1;
168 
169  emit globalProgress(global_progress);
170 }
171 
172 //! Cancels all running jobs.
173 
175 {
176  for (const auto& key : m_threads.keys())
177  cancelJob(key);
178 }
179 
180 //! Removes QThread from the map of known threads, assigns it for deletion.
181 
182 void JobQueueData::assignForDeletion(QThread* thread)
183 {
184  for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
185  if (it.value() == thread) {
186  thread->deleteLater();
187  m_threads.erase(it);
188  return;
189  }
190  }
191 
192  throw Error("JobQueueData::assignForDeletion() -> Error! Can't find thread.");
193 }
194 
195 //! Removes JobRunner from the map of known runners, assigns it for deletion.
196 
198 {
199  ASSERT(worker);
200  worker->disconnect();
201  for (auto it = m_workers.begin(); it != m_workers.end(); ++it) {
202  if (it.value() == worker) {
203  m_workers.erase(it);
204  delete worker;
205  return;
206  }
207  }
208 
209  throw Error("JobQueueData::assignForDeletion() -> Error! Can't find the runner.");
210 }
211 
212 void JobQueueData::clearSimulation(const QString& identifier)
213 {
214  auto* simulation = getSimulation(identifier);
215  m_simulations.remove(identifier);
216  delete simulation;
217 }
218 
219 //! Set all data of finished job
220 
222 {
223  jobItem->setEndTime(worker->simulationEnd());
224 
225  // propagating status of runner
226  if (worker->status() == JobStatus::Failed)
227  jobItem->setComments(worker->failureMessage());
228  else {
229  ASSERT(worker->result());
230  jobItem->setResults(*worker->result());
231  }
232  jobItem->setStatus(worker->status());
233 
234  // fixing job progress (if job was successfull, but due to wrong estimation, progress not 100%)
235  if (jobItem->isCompleted())
236  jobItem->setProgress(100);
237 }
238 
239 //! Returns the thread for given identifier.
240 
241 QThread* JobQueueData::getThread(const QString& identifier)
242 {
243  auto it = m_threads.find(identifier);
244  return it != m_threads.end() ? it.value() : nullptr;
245 }
246 
247 //! Returns job runner for given identifier.
248 
249 JobWorker* JobQueueData::getWorker(const QString& identifier)
250 {
251  auto it = m_workers.find(identifier);
252  return it != m_workers.end() ? it.value() : nullptr;
253 }
254 
255 //! Returns the simulation (if exists) for given identifier.
256 
257 ISimulation* JobQueueData::getSimulation(const QString& identifier)
258 {
259  auto it = m_simulations.find(identifier);
260  return it != m_simulations.end() ? it.value() : nullptr;
261 }
Defines error class.
Defines class JobItem.
Defines class JobModel.
Defines class JobQueueData.
@ Running
the job is busy calculating
@ Failed
the job aborted because it hit an error
Defines class JobWorker.
Defines class Helpers functions.
Defines namespace GUI::Transform::ToCore.
void setComments(const QString &comments)
Definition: JobItem.cpp:195
void setEndTime(const QDateTime &end_time)
Definition: JobItem.cpp:175
const SimulationOptionsItem & simulationOptionsItem() const
Definition: JobItem.cpp:415
void setStatus(JobStatus status)
Definition: JobItem.cpp:111
void setResults(const SimulationResult &result)
Definition: JobItem.cpp:251
MultiLayerItem * sampleItem()
Definition: JobItem.cpp:222
void setProgress(int progress)
Definition: JobItem.cpp:206
bool isCompleted() const
Definition: JobItem.cpp:134
InstrumentItem * instrumentItem() const
Definition: JobItem.cpp:233
QString getIdentifier() const
Definition: JobItem.cpp:73
QVector< JobItem * > jobItems() const
Definition: JobModel.cpp:77
JobItem * getJobItemForIdentifier(const QString &identifier)
Definition: JobModel.cpp:42
JobWorker * getWorker(const QString &identifier)
Returns job runner for given identifier.
bool hasUnfinishedJobs()
void onStartedJob()
Sets JobItem properties when the job is going to start.
void focusRequest(JobItem *jobItem)
void updateGlobalProgress()
Estimates global progress from the progress of multiple running jobs and emits appropriate signal.
void globalProgress(int)
QThread * getThread(const QString &identifier)
Returns the thread for given identifier.
JobQueueData(JobModel *jobModel)
ISimulation * getSimulation(const QString &identifier)
Returns the simulation (if exists) for given identifier.
void removeJob(const QString &identifier)
Remove job from list completely.
void processFinishedJob(JobWorker *worker, JobItem *jobItem)
Set all data of finished job.
void cancelJob(const QString &identifier)
Cancels running job.
QMap< QString, ISimulation * > m_simulations
job identifier to jobWorker
Definition: JobQueueData.h:65
void clearSimulation(const QString &identifier)
void onFinishedJob()
Performs necessary actions when job is finished.
void onProgressUpdate()
void onFinishedThread()
void assignForDeletion(QThread *thread)
Removes QThread from the map of known threads, assigns it for deletion.
JobModel * m_jobModel
job identifier to simulation
Definition: JobQueueData.h:67
QMap< QString, JobWorker * > m_workers
job identifier to the thread
Definition: JobQueueData.h:64
QMap< QString, QThread * > m_threads
Definition: JobQueueData.h:63
void runJob(JobItem *jobItem)
Submits job and run it in a thread.
void onCancelAllJobs()
Cancels all running jobs.
The JobWorker class provides running the domain simulation in a thread.
Definition: JobWorker.h:28
void progressUpdate()
QString failureMessage() const
Definition: JobWorker.cpp:87
void start()
Definition: JobWorker.cpp:43
const SimulationResult * result() const
Definition: JobWorker.cpp:102
void finished()
const QDateTime & simulationEnd() const
Definition: JobWorker.cpp:97
void terminate()
Sets request for JobRunner to terminate underlying domain simulation.
Definition: JobWorker.cpp:109
void started()
JobStatus status() const
Definition: JobWorker.cpp:82
std::unique_ptr< ISimulation > itemsToSimulation(const MultiLayerItem *sampleItem, const InstrumentItem *instrumentItem, const SimulationOptionsItem &optionsItem)
Creates domain simulation from sample and instrument items.