-
Wuttke, Joachim authoredWuttke, Joachim authored
FitSessionController.cpp 6.07 KiB
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/View/Fit/FitSessionController.cpp
//! @brief Implements class FitSessionController
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "GUI/View/Fit/FitSessionController.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Data/IntensityDataItem.h"
#include "GUI/Model/Job/FitParameterContainerItem.h"
#include "GUI/Model/Job/FitParameterItem.h"
#include "GUI/Model/Job/FitSuiteItem.h"
#include "GUI/Model/Job/JobItem.h"
#include "GUI/Support/Util/Error.h"
#include "GUI/Support/Util/Path.h"
#include "GUI/View/Fit/FitLog.h"
#include "GUI/View/Fit/FitObjectiveBuilder.h"
#include "GUI/View/Fit/FitWorkerLauncher.h"
#include "GUI/View/Fit/GUIFitObserver.h"
namespace {
const bool use_fit_objective = true;
}
FitSessionController::FitSessionController(QObject* parent)
: QObject(parent)
, m_jobItem(nullptr)
, m_runFitManager(new FitWorkerLauncher(this))
, m_observer(new GUIFitObserver)
, m_fitlog(new FitLog(this))
, m_block_progress_update(false)
{
connect(m_observer.get(), &GUIFitObserver::updateReady, this,
&FitSessionController::onObserverUpdate);
connect(m_runFitManager, &FitWorkerLauncher::fittingStarted, this,
&FitSessionController::onFittingStarted);
connect(m_runFitManager, &FitWorkerLauncher::fittingFinished, this,
&FitSessionController::onFittingFinished);
connect(m_runFitManager, &FitWorkerLauncher::fittingError, this,
&FitSessionController::onFittingError);
}
FitSessionController::~FitSessionController() = default;
void FitSessionController::setJobItem(JobItem* jobItem)
{
if (m_jobItem && m_jobItem != jobItem)
throw Error("FitSuiteManager::setJobItem() -> JobItem was already set.");
m_jobItem = jobItem;
ASSERT(m_jobItem);
// no need to unsubscribe from jobItem on jobItem destroy. FitSessionManager deletes
// controller right after the jobItem.
// Propagates update interval from FitSuiteItem to fit observer.
connect(m_jobItem->fitSuiteItem(), &FitSuiteItem::updateIntervalChanged, m_observer.get(),
&GUIFitObserver::setInterval, Qt::UniqueConnection);
}
void FitSessionController::onStartFittingRequest()
{
if (!m_jobItem)
return;
try {
m_objectiveBuilder = std::make_unique<FitObjectiveBuilder>(m_jobItem);
m_observer->setInterval(m_jobItem->fitSuiteItem()->updateInterval());
m_objectiveBuilder->attachObserver(m_observer);
m_observer->finishedPlotting();
m_runFitManager->runFitting(m_objectiveBuilder);
} catch (std::exception& e) {
m_jobItem->setStatus(JobStatus::Failed);
m_fitlog->append(e.what(), FitLogLevel::Error);
emit fittingError(QString::fromStdString(e.what()));
}
}
FitLog* FitSessionController::fitLog()
{
return m_fitlog.get();
}
void FitSessionController::onStopFittingRequest()
{
m_runFitManager->interruptFitting();
}
void FitSessionController::onObserverUpdate()
{
auto progressInfo = m_observer->progressInfo();
m_jobItem->simulatedDataItem()->setRawDataVector(progressInfo.simValues());
updateIterationCount(progressInfo);
if (!use_fit_objective)
updateFitParameterValues(progressInfo);
updateLog(progressInfo);
if (!progressInfo.logInfo().empty())
m_fitlog->append(progressInfo.logInfo(), FitLogLevel::Default);
m_observer->finishedPlotting();
}
void FitSessionController::onFittingStarted()
{
m_fitlog->clearLog();
m_jobItem->setStatus(JobStatus::Fitting);
m_jobItem->setProgress(0);
m_jobItem->setBeginTime(m_runFitManager->fitStart());
m_jobItem->setEndTime(QDateTime());
emit fittingStarted();
}
void FitSessionController::onFittingFinished()
{
if (m_jobItem->status() != JobStatus::Failed)
m_jobItem->setStatus(JobStatus::Completed);
m_jobItem->setEndTime(m_runFitManager->fitEnd());
m_jobItem->setProgress(100);
if (m_jobItem->isCompleted())
m_fitlog->append("Done", FitLogLevel::Success);
emit fittingFinished();
}
void FitSessionController::onFittingError(const QString& text)
{
QString message;
message.append("Current settings cause fitting failure.\n\n");
message.append(text);
m_fitlog->append(message.toStdString(), FitLogLevel::Error);
m_jobItem->setEndTime(m_runFitManager->fitEnd());
emit fittingError(message);
}
void FitSessionController::updateIterationCount(const FitProgressInfo& info)
{
FitSuiteItem* fitSuiteItem = m_jobItem->fitSuiteItem();
// FIXME FitFlowWidget updates chi2 and n_iteration on P_ITERATION_COUNT change
// The order of two lines below is important
fitSuiteItem->setChi2(info.chi2());
fitSuiteItem->setIterationCount(info.iterationCount());
}
void FitSessionController::updateFitParameterValues(const FitProgressInfo& info)
{
FitParameterContainerItem* fitParContainer = m_jobItem->fitParameterContainerItem();
fitParContainer->setValuesInParameterContainer(info.parValues(),
m_jobItem->parameterContainerItem());
}
void FitSessionController::updateLog(const FitProgressInfo& info)
{
QString message = QString("NCalls:%1 chi2:%2 \n").arg(info.iterationCount()).arg(info.chi2());
FitParameterContainerItem* fitParContainer = m_jobItem->fitParameterContainerItem();
int index(0);
for (FitParameterItem* item : fitParContainer->fitParameterItems()) {
if (item->linkItems().empty())
continue;
QString parinfo =
QString(" %1 %2\n").arg(item->displayName()).arg(info.parValues()[index++]);
message.append(parinfo);
}
m_fitlog->append(message.toStdString(), FitLogLevel::Default);
}