Skip to content
Snippets Groups Projects
Commit a588d140 authored by Wuttke, Joachim's avatar Wuttke, Joachim
Browse files

ProgressHandler is now a member of Simulation.

parent 31275546
No related branches found
No related tags found
No related merge requests found
Showing
with 99 additions and 213 deletions
......@@ -18,42 +18,40 @@
#include <iostream>
#include <mutex>
#include <stdexcept> // need overlooked by g++ 5.4
#include <stdexcept>
//! @class ISingleton
//! Base class for singletons.
//! @ingroup tools_internal
//! @brief Singleton pattern.
template <class T>
class ISingleton
{
public:
static T& instance()
{
static T& instance() {
static std::mutex single_mutex;
std::unique_lock<std::mutex> single_lock( single_mutex );
if( !m_instance) {
if( m_destroyed )
throw std::runtime_error("Bug in ISingleton: object was destructed!");
// In BornAgain, an ISingleton is deleted when and only when the application
// terminates. Therefore there is no point in re-creating a deleted ISingleton.
// To be 110% sure, we explicitly forbid re-creation.
throw std::runtime_error("Invalid attempt to re-create a deleted ISingleton");
static T theInstance;
m_instance = &theInstance;
}
return *m_instance;
}
return *m_instance; }
protected:
ISingleton(){}
virtual ~ISingleton()
{
virtual ~ISingleton() {
m_instance = nullptr;
m_destroyed = true;
}
m_destroyed = true; }
private:
ISingleton(const ISingleton&) = delete;
ISingleton& operator=(const ISingleton&) = delete;
static T* m_instance;
static bool m_destroyed;
static bool m_destroyed; //!< to detect re-creation
};
// for templated classes, initializations go into the .h file:
......
......@@ -26,7 +26,6 @@
#include "RoughMultiLayerComputation.h"
#include "ScalarSpecularInfoMap.h"
#include "ProgressHandler.h"
#include "ProgressHandlerDWBA.h"
#include "SimulationElement.h"
#include "SpecularMagnetic.h"
#include "SpecularMatrix.h"
......@@ -37,10 +36,11 @@
MainComputation::MainComputation(
const MultiLayer* p_multi_layer,
const SimulationOptions& options,
ProgressHandler* progress,
ProgressHandler& progress,
const std::vector<SimulationElement>::iterator& begin_it,
const std::vector<SimulationElement>::iterator& end_it)
: m_sim_options(options)
, m_progress(&progress)
, mp_roughness_computation(nullptr)
{
mp_multi_layer = p_multi_layer->clone();
......@@ -49,10 +49,6 @@ MainComputation::MainComputation(
m_begin_it = begin_it;
m_end_it = end_it;
// initialising call backs
if (progress)
m_progress.setCallback( [&] (int n) {return progress->update(n);} );
for (size_t i=0; i<mp_multi_layer->getNumberOfLayers(); ++i) {
m_layer_computation.push_back({});
for (size_t j=0; j<mp_multi_layer->getLayer(i)->getNumberOfLayouts(); ++j)
......@@ -115,6 +111,7 @@ void MainComputation::runProtected()
mp_roughness_computation->eval(layer_elements.begin(), layer_elements.end());
addElementsWithWeight(layer_elements.begin(), layer_elements.end(), m_begin_it, 1.0);
}
m_progress->incrementDone(1);
}
void MainComputation::collectRTCoefficientsScalar()
......
......@@ -19,7 +19,6 @@
#include "ComputationOutcome.h"
#include "Complex.h"
#include "INoncopyable.h"
#include "ProgressHandlerDWBA.h"
#include "SimulationOptions.h"
#include <vector>
......@@ -29,7 +28,11 @@ class RoughMultiLayerComputation;
class ProgressHandler;
class SimulationElement;
//! Performs a DWBA calculation with given sample and simulation parameters
//! Performs a single-threaded DWBA computation with given sample and simulation parameters,
//! for a given span of detector bins.
//!
//! Controlled by the multi-threading machinery in Simulation::runSingleSimulation().
//!
//! @ingroup algorithms_internal
class BA_CORE_API_ MainComputation : public INoncopyable
......@@ -38,7 +41,7 @@ public:
MainComputation(
const MultiLayer* p_multi_layer,
const SimulationOptions& options,
ProgressHandler* progress,
ProgressHandler& progress,
const std::vector<SimulationElement>::iterator& begin_it,
const std::vector<SimulationElement>::iterator& end_it);
~MainComputation();
......@@ -55,16 +58,15 @@ private:
void collectRTCoefficientsScalar();
void collectRTCoefficientsMatrix();
//! Iterators that defines the sequence of elements that this simulation will work on
std::vector<SimulationElement>::iterator m_begin_it, m_end_it;
MultiLayer* mp_multi_layer;
SimulationOptions m_sim_options;
ProgressHandler* m_progress;
//! these iterators define the span of detector bins this simulation will work on
std::vector<SimulationElement>::iterator m_begin_it, m_end_it;
ProgressHandlerDWBA m_progress;
std::vector<std::vector<DecoratedLayerComputation*>> m_layer_computation;
MultiLayer* mp_multi_layer;
RoughMultiLayerComputation* mp_roughness_computation;
std::vector<std::vector<DecoratedLayerComputation*>> m_layer_computation;
ComputationOutcome m_outcome;
};
......
......@@ -18,33 +18,31 @@
#include "LayerInterface.h"
#include "MultiLayer.h"
#include <mutex>
#include <stdexcept>
ProgressHandler::ProgressHandler()
: m_callback(nullptr)
, m_completed_nticks(0)
, m_expected_nticks(0)
, m_percentage_done(0)
{}
void ProgressHandler::subscribe(ProgressHandler::Callback_t inform)
{
if (m_inform)
throw std::runtime_error("Invalid call of ProgressHandler::subscribe: "
"currently, no more than one subscriber is allowed");
m_inform = inform;
}
//! Collects number of ticks processed by different Computation's.
//! Calculates general progress and inform GUI if progress has changed.
//! Return flag is obtained from GUI and transferred to Computation to ask
//! them to stop calculations.
bool ProgressHandler::update(size_t ticks_done)
//! Increments number of completed computation steps (ticks).
//! Performs callback (method m_inform) to inform the subscriber about
//! the state of the computation and to obtain as return value a flag
//! that indicates whether to continue the computation. Returns the
//! value of that flag to request the owner to terminate.
bool ProgressHandler::incrementDone(size_t ticks_done)
{
static std::mutex single_mutex;
std::unique_lock<std::mutex> single_lock( single_mutex );
// this flag is to inform Simulation that GUI wants it to be terminated
bool continue_calculations(true);
m_completed_nticks += ticks_done;
if (m_completed_nticks > m_expected_nticks)
m_expected_nticks = m_completed_nticks+1;
m_percentage_done = int(100.*m_completed_nticks/m_expected_nticks);
//std::cout << "ProgressHandler::update done" << ticks_done << " of " << m_expected_nticks
// << " => progress:" << progress << std::endl;
if(m_callback)
continue_calculations = m_callback(m_percentage_done); // report to gui
return continue_calculations;
if(!m_inform)
return true;
return m_inform(percentage_done()); // report to subscriber, and get continuation flag
}
......@@ -22,29 +22,35 @@
class MultiLayer;
//! Provides the functionality to calculate the progress of running simulation and report it to GUI.
//!
//! Thread safe to be used from Computation.
//! Maintains information about progress of a computation.
//! Owner is the computation, which periodically calls the thread-safe function incrementDone(..).
//! An application (GUI or script) may subscribe(..) to be informed about progress.
//! It is then periodically called back by inform(..).
//! The return value of inform(..) can be used to request termination of the computation.
//!
//! @ingroup algorithms_internal
class BA_CORE_API_ ProgressHandler : public INoncopyable
class BA_CORE_API_ ProgressHandler
{
public:
typedef std::function<bool(size_t)> Callback_t;
ProgressHandler();
void setCallback(ProgressHandler::Callback_t callback) { m_callback = callback; }
ProgressHandler() : m_inform(nullptr), m_expected_nticks(0), m_completed_nticks(0) {}
ProgressHandler(const ProgressHandler& other)
: m_inform(nullptr) // not clear whether we want to copy subscriptions
, m_expected_nticks(other.m_expected_nticks)
, m_completed_nticks(other.m_completed_nticks) {}
void subscribe(ProgressHandler::Callback_t callback);
void reset() { m_completed_nticks = 0; }
void setExpectedNTicks(size_t n) { m_expected_nticks = n; }
bool incrementDone(size_t ticks_done);
bool update(size_t ticks_done);
int percentage_done() const { return 100.*m_completed_nticks/m_expected_nticks; }
private:
ProgressHandler::Callback_t m_callback;
size_t m_completed_nticks;
ProgressHandler::Callback_t m_inform;
size_t m_expected_nticks;
int m_percentage_done;
size_t m_completed_nticks;
};
#endif // PROGRESSHANDLER_H
// ************************************************************************** //
//
// BornAgain: simulate and fit scattering at grazing incidence
//
//! @file Core/Computation/ProgressHandlerDWBA.cpp
//! @brief Implements class ProgressHandlerDWBA.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2015
//! @authors Scientific Computing Group at MLZ Garching
//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
//
// ************************************************************************** //
#include "ProgressHandlerDWBA.h"
ProgressHandlerDWBA::ProgressHandlerDWBA()
: m_nitems(0)
, m_nitems_total(0)
, m_report_every_nth(100)
{}
//! Method increments number of items processed.
//! Every n'th processed item the Simulation is informed via thread safe callback.
//! Return flag false is used to inform DWBSimulation to interrupt calculations.
bool ProgressHandlerDWBA::update()
{
bool continue_calculations(true);
if(!m_callback)
return continue_calculations;
m_nitems_total++;
m_nitems++;
if(m_nitems >= m_report_every_nth) {
continue_calculations = m_callback(m_nitems); // report to the Simulation
m_nitems=0;
}
return continue_calculations;
}
//! finalize report to the simulation
bool ProgressHandlerDWBA::finished()
{
if(m_callback) {
m_callback(m_nitems); // report to the Simulation
m_nitems = 0;
}
return true;
}
// ************************************************************************** //
//
// BornAgain: simulate and fit scattering at grazing incidence
//
//! @file Core/Computation/ProgressHandlerDWBA.h
//! @brief Defines class ProgressHandlerDWBA.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2015
//! @authors Scientific Computing Group at MLZ Garching
//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
//
// ************************************************************************** //
#ifndef PROGRESSHANDLERDWBA_H
#define PROGRESSHANDLERDWBA_H
#include "ProgressHandler.h"
//! Holds number of items processed by Computation,
//! and informs Simulation every time n items have been processed.
//! @ingroup algorithms_internal
class ProgressHandlerDWBA
{
public:
ProgressHandlerDWBA();
void setCallback(ProgressHandler::Callback_t callback) { m_callback = callback; }
ProgressHandler::Callback_t getCallback() const { return m_callback; }
bool update();
bool finished();
private:
ProgressHandler::Callback_t m_callback;
long m_nitems;
long m_nitems_total;
long m_report_every_nth;
};
#endif // PROGRESSHANDLERDWBA_H
......@@ -19,21 +19,12 @@
#include "Transform3D.h"
#include <gsl/gsl_linalg.h>
Lattice::Lattice()
: mp_selection_rule(0)
, m_cache_ok(false)
, m_is_zero(true)
{
initialize();
}
Lattice::Lattice(const kvector_t a1, const kvector_t a2, const kvector_t a3)
: mp_selection_rule(0)
, m_a1(a1)
, m_a2(a2)
, m_a3(a3)
, m_cache_ok(false)
, m_is_zero(false)
{
initialize();
}
......@@ -44,7 +35,6 @@ Lattice::Lattice(const Lattice& lattice)
, m_a2(lattice.m_a2)
, m_a3(lattice.m_a3)
, m_cache_ok(false)
, m_is_zero(false)
{
initialize();
if( lattice.mp_selection_rule ) setSelectionRule(*lattice.mp_selection_rule);
......
......@@ -28,7 +28,7 @@ class Transform3D;
class BA_CORE_API_ Lattice
{
public:
Lattice();
Lattice() =delete;
Lattice(const kvector_t a1, const kvector_t a2, const kvector_t a3);
Lattice(const Lattice& lattice);
~Lattice();
......@@ -87,7 +87,7 @@ private:
kvector_t m_a1, m_a2, m_a3; //!< Basis vectors in real space
mutable kvector_t m_b1, m_b2, m_b3; //!< Cache of basis vectors in reciprocal space
//! Boolean indicating if the reciprocal vectors are already initialized in the cache
mutable bool m_cache_ok, m_is_zero;
mutable bool m_cache_ok;
};
#endif // LATTICE_H
......@@ -157,6 +157,6 @@ double IInterferenceFunctionStrategy::evaluate_for_fixed_angles_pol(
SimulationElement* pars = static_cast<SimulationElement*>(params);
SimulationElement sim_element(*pars, par0, par1);
calculateFormFactorLists(sim_element);
calculateFormFactorListPol(sim_element);
return pars->getIntegrationFactor(par0, par1) * evaluateForMatrixList(sim_element, m_ff_pol);
}
......@@ -27,7 +27,6 @@
#include <thread>
Simulation::Simulation()
: m_progress(nullptr)
{}
Simulation::~Simulation() {} // forward class declaration prevents move to .h
......@@ -61,15 +60,18 @@ void Simulation::prepareSimulation()
//! Run simulation with possible averaging over parameter distributions
void Simulation::runSimulation()
{
updateSample();
if (!mP_sample)
throw Exceptions::NullPointerException("Simulation::runSimulation() -> Error! No sample.");
prepareSimulation();
size_t param_combinations = m_distribution_handler.getTotalNumberOfSamples();
if (m_progress) {
int prefac = ( mP_sample->totalNofLayouts()>0 ? 1 : 0 )
+ ( mP_sample->hasRoughness() ? 1 : 0 );
m_progress->setExpectedNTicks(prefac*param_combinations*getNumberOfSimulationElements());
}
m_progress.reset();
int prefac = ( mP_sample->totalNofLayouts()>0 ? 1 : 0 )
+ ( mP_sample->hasRoughness() ? 1 : 0 );
m_progress.setExpectedNTicks(prefac*param_combinations*getNumberOfSimulationElements());
// no averaging needed:
if (param_combinations == 1) {
......
......@@ -81,15 +81,14 @@ public:
const DistributionHandler& getDistributionHandler() const;
//! sets progress handler (used by GUI)
void setProgressHandler(ProgressHandler* progress) { m_progress = progress; }
//unused friend class OMPISimulation;
void setOptions(const SimulationOptions& options) { m_options = options; }
const SimulationOptions& getOptions() const { return m_options; }
SimulationOptions& getOptions() { return m_options; }
ProgressHandler& progressHandler() { return m_progress; }
protected:
Simulation(const Simulation& other);
......@@ -123,7 +122,7 @@ protected:
std::shared_ptr<IMultiLayerBuilder> mp_sample_builder;
SimulationOptions m_options;
DistributionHandler m_distribution_handler;
ProgressHandler* m_progress;
ProgressHandler m_progress;
std::vector<SimulationElement> m_sim_elements;
private:
......
......@@ -32,13 +32,6 @@ JobWorker::JobWorker(QString identifier, GISASSimulation *simulation)
}
int JobWorker::getProgress() const
{
// sometimes simulation underestimate the number of iterations required
// and progress can be greater than 100
return m_percentage_done < 100 ? m_percentage_done : 100;
}
void JobWorker::start()
{
qDebug() << "JobRunner::start() " << m_simulation;
......@@ -47,11 +40,9 @@ void JobWorker::start()
emit started();
if(m_simulation) {
std::unique_ptr<ProgressHandler> progressHandler(new ProgressHandler());
ProgressHandler::Callback_t callback = [this] (int percentage_done) {
return simulationProgressCallback(percentage_done); };
progressHandler->setCallback(callback);
m_simulation->setProgressHandler(progressHandler.get());
m_simulation->progressHandler().subscribe(
[this] (int percentage_done) {
return calledbackByProgressHandler(percentage_done); } );
m_job_status = Constants::STATUS_RUNNING;
......@@ -84,8 +75,9 @@ void JobWorker::start()
emit finished();
}
//! function which is called by the simulation to report its progress
bool JobWorker::simulationProgressCallback(int percentage_done)
//! Informs us about progress of the simulation. Returns true if we want to continue the simulation.
//! To be registered as callback function via ProgressHandler::subscribe().
bool JobWorker::calledbackByProgressHandler(int percentage_done)
{
if (percentage_done > m_percentage_done) {
m_percentage_done = percentage_done;
......
......@@ -34,9 +34,9 @@ public:
QString getIdentifier() const { return m_identifier; }
void setIdentifier(QString identifier) { m_identifier = identifier; }
int getProgress() const;
int getProgress() const { return m_percentage_done; }
bool simulationProgressCallback(int);
bool calledbackByProgressHandler(int);
bool isTerminated() { return m_terminate_request_flag; }
......
......@@ -21,8 +21,8 @@ class CoreStandardTest : public IStandardTest
{
public:
CoreStandardTest() : IStandardTest("CoreStandardTest") {}
IFunctionalTest* getTest() const { return new CoreTest(
getName(), getTestDescription(), getSimulation(), getTestThreshold() ); }
std::unique_ptr<IFunctionalTest> getTest() const { return std::unique_ptr<IFunctionalTest>
(new CoreTest(getName(), getTestDescription(), getSimulation(), getTestThreshold())); }
};
//! Runs CoreTest on a standard simulation indicated by argv[1].
......
......@@ -22,8 +22,8 @@ class GUIStandardTest : public IStandardTest
{
public:
GUIStandardTest() : IStandardTest("GUIStandardTest") {}
IFunctionalTest* getTest() const { return new GUITest(
getName(), getTestDescription(), getSimulation(), getTestThreshold()); }
std::unique_ptr<IFunctionalTest> getTest() const { return std::unique_ptr<IFunctionalTest>
(new GUITest(getName(), getTestDescription(), getSimulation(), getTestThreshold())); }
};
//! Runs GUITest on a standard simulation indicated by argv[1].
......
......@@ -21,8 +21,9 @@ class PyExportStandardTest : public IStandardTest
{
public:
PyExportStandardTest() : IStandardTest("PyExport") {}
IFunctionalTest* getTest() const { return new PyExportTest(
getName(), getTestDescription(), getSimulation(), getTestThreshold()); }
std::unique_ptr<IFunctionalTest> getTest() const { return std::unique_ptr<IFunctionalTest>
(new PyExportTest(
getName(), getTestDescription(), getSimulation(), getTestThreshold())); }
};
//! Runs PyExportTest on a standard simulation indicated by argv[1].
......
......@@ -19,9 +19,8 @@
#include "INamed.h"
#include <map>
//! Base class for all functional tests.
//! @class IFunctionalTest
//! @ingroup standard_samples
//! @brief Base class for all functional tests.
class IFunctionalTest : public INamed
{
......
......@@ -21,9 +21,8 @@
#include <map>
#include <string>
//! @class IReferencedTest
//! Base class for tests that compare results with reference data.
//! @ingroup standard_samples
//! @brief Base class for tests that compare results with reference data.
class IReferencedTest : public IFunctionalTest
{
......@@ -33,7 +32,7 @@ public:
: IFunctionalTest(name, description), m_threshold(threshold) {}
virtual ~IReferencedTest() {}
bool runTest() = 0;
bool runTest() =0;
protected:
double m_threshold;
......
......@@ -47,8 +47,7 @@ bool IStandardTest::execute(int argc, char** argv) {
bool IStandardTest::execute_onetest()
{
setName( m_info->m_test_name );
IFunctionalTest* test( getTest() );
return test->runTest();
return getTest()->runTest();
}
//! Runs all available subtests, and returns true if all succeed
......@@ -73,13 +72,10 @@ bool IStandardTest::execute_subtests()
for (size_t i = 0; i < n_subtests; ++i) {
setName( m_info->m_test_name + "_" + subtest_names[i] );
m_subtest_item = subtest_registry->getItem(subtest_names[i]);
IFunctionalTest* subtest( getTest() );
std::cout << "IStandardTest::execute() -> " << getName()
<< " " << i+1 << "/" << n_subtests << " (" << subtest_names[i] << ")\n";
if(!subtest->runTest()) {
if(!getTest()->runTest())
++number_of_failed_tests;
delete subtest;
}
}
delete subtest_registry;
......@@ -99,13 +95,12 @@ double IStandardTest::getTestThreshold() const { return m_info->m_threshold; }
GISASSimulation* IStandardTest::getSimulation() const
{
SimulationFactory sim_registry;
GISASSimulation* result = sim_registry.createItem(m_info->m_simulation_name);
SampleBuilderFactory sample_factory;
std::shared_ptr<IMultiLayerBuilder> sample_builder(
sample_factory.createItem(m_info->m_sample_builder_name) );
SampleBuilderFactory().createItem(m_info->m_sample_builder_name) );
if(m_subtest_item)
sample_builder->set_subtest(m_subtest_item);
GISASSimulation* result = SimulationFactory().createItem(m_info->m_simulation_name);
result->setSampleBuilder(sample_builder);
return result;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment