BornAgain  1.19.0
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/coregui/Models/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 
23 #include <QThread>
24 
25 namespace {
26 }
27 
28 JobQueueData::JobQueueData(JobModel* jobModel) : m_jobModel(jobModel) {}
29 
31 {
32  return m_simulations.size();
33 }
34 
35 //! Submits job and run it in a thread.
36 
38 {
39  QString identifier = jobItem->getIdentifier();
40  if (getThread(identifier))
41  return;
42 
43  if (getSimulation(identifier))
44  throw GUIHelpers::Error(
45  "JobQueueData::runJob() -> Error. ISimulation is already existing.");
46 
47  try {
49  jobItem->multiLayerItem(), 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("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("Running");
111  jobItem->setBeginTime(GUIHelpers::currentDateTime());
112  jobItem->setEndTime(QString());
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 //! emmits appropriate signal.
153 
155 {
156  int global_progress(0);
157  int nRunningJobs(0);
158  QModelIndex parentIndex;
159  for (int i_row = 0; i_row < m_jobModel->rowCount(parentIndex); ++i_row) {
160  QModelIndex itemIndex = m_jobModel->index(i_row, 0, parentIndex);
161  JobItem* jobItem = m_jobModel->getJobItemForIndex(itemIndex);
162  if (jobItem->isRunning()) {
163  global_progress += jobItem->getProgress();
164  nRunningJobs++;
165  }
166  }
167 
168  if (nRunningJobs)
169  global_progress /= nRunningJobs;
170  else
171  global_progress = -1;
172 
173  emit globalProgress(global_progress);
174 }
175 
176 //! Cancels all running jobs.
177 
179 {
180  for (const auto& key : m_threads.keys())
181  cancelJob(key);
182 }
183 
184 //! Removes QThread from the map of known threads, assigns it for deletion.
185 
186 void JobQueueData::assignForDeletion(QThread* thread)
187 {
188  for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
189  if (it.value() == thread) {
190  thread->deleteLater();
191  m_threads.erase(it);
192  return;
193  }
194  }
195 
196  throw GUIHelpers::Error("JobQueueData::assignForDeletion() -> Error! Can't find thread.");
197 }
198 
199 //! Removes JobRunner from the map of known runners, assigns it for deletion.
200 
202 {
203  ASSERT(worker);
204  worker->disconnect();
205  for (auto it = m_workers.begin(); it != m_workers.end(); ++it) {
206  if (it.value() == worker) {
207  m_workers.erase(it);
208  delete worker;
209  return;
210  }
211  }
212 
213  throw GUIHelpers::Error("JobQueueData::assignForDeletion() -> Error! Can't find the runner.");
214 }
215 
216 void JobQueueData::clearSimulation(const QString& identifier)
217 {
218  auto simulation = getSimulation(identifier);
219  m_simulations.remove(identifier);
220  delete simulation;
221 }
222 
223 //! Set all data of finished job
224 
226 {
228  jobItem->setDuration(worker->simulationDuration());
229 
230  // propagating status of runner
231  if (worker->status() == "Failed") {
232  jobItem->setComments(worker->failureMessage());
233  } else {
234  // propagating simulation results
235  auto simulation = getSimulation(worker->identifier());
236  jobItem->setResults(simulation);
237  }
238  jobItem->setStatus(worker->status());
239 
240  // fixing job progress (if job was successfull, but due to wrong estimation, progress not 100%)
241  if (jobItem->isCompleted())
242  jobItem->setProgress(100);
243 }
244 
245 //! Returns the thread for given identifier.
246 
247 QThread* JobQueueData::getThread(const QString& identifier)
248 {
249  auto it = m_threads.find(identifier);
250  return it != m_threads.end() ? it.value() : nullptr;
251 }
252 
253 //! Returns job runner for given identifier.
254 
255 JobWorker* JobQueueData::getWorker(const QString& identifier)
256 {
257  auto it = m_workers.find(identifier);
258  return it != m_workers.end() ? it.value() : nullptr;
259 }
260 
261 //! Returns the simulation (if exists) for given identifier.
262 
263 ISimulation* JobQueueData::getSimulation(const QString& identifier)
264 {
265  auto it = m_simulations.find(identifier);
266  return it != m_simulations.end() ? it.value() : nullptr;
267 }
#define ASSERT(condition)
Definition: Assert.h:31
Defines class DomainSimulationBuilder.
Defines class GISASSimulation.
Defines class GUIHelpers functions.
Defines InstrumentItems classes.
Defines class JobItem.
Defines class JobModel.
Defines class JobQueueData.
Defines class JobWorker.
Abstract base class of OffSpecularSimulation, GISASSimulation and SpecularSimulation.
Definition: ISimulation.h:38
void setComments(const QString &comments)
Definition: JobItem.cpp:194
void setResults(const ISimulation *simulation)
Definition: JobItem.cpp:229
InstrumentItem * instrumentItem()
Definition: JobItem.cpp:224
void setProgress(int progress)
Definition: JobItem.cpp:204
int getProgress() const
Definition: JobItem.cpp:199
bool isCompleted() const
Definition: JobItem.cpp:150
QString getIdentifier() const
Definition: JobItem.cpp:103
SimulationOptionsItem * simulationOptionsItem()
Definition: JobItem.cpp:290
MultiLayerItem * multiLayerItem()
Definition: JobItem.cpp:219
void setDuration(int duration)
Definition: JobItem.cpp:181
bool isRunning() const
Definition: JobItem.cpp:145
void setStatus(const QString &status)
Definition: JobItem.cpp:128
void setEndTime(const QString &end_time)
Definition: JobItem.cpp:175
const JobItem * getJobItemForIndex(const QModelIndex &index) const
Definition: JobModel.cpp:46
JobItem * getJobItemForIdentifier(const QString &identifier)
Definition: JobModel.cpp:60
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 emmits 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:24
void progressUpdate()
QString failureMessage() const
Definition: JobWorker.cpp:86
QString identifier() const
Definition: JobWorker.cpp:30
QString status() const
Definition: JobWorker.cpp:81
void start()
Definition: JobWorker.cpp:40
int simulationDuration() const
Definition: JobWorker.cpp:91
void finished()
void terminate()
Sets request for JobRunner to terminate underlying domain simulation.
Definition: JobWorker.cpp:98
void started()
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
virtual int rowCount(const QModelIndex &parent) const
std::unique_ptr< ISimulation > createSimulation(const MultiLayerItem *sampleItem, const InstrumentItem *instrumentItem, const SimulationOptionsItem *optionsItem=nullptr)
Creates domain simulation from sample and instrument items.
QString currentDateTime()
Definition: GUIHelpers.cpp:210