Skip to content
Snippets Groups Projects
MinimizerSettingsWidget.cpp 11.74 KiB
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Fit/MinimizerSettingsWidget.cpp
//! @brief     Implements class MinimizerSettingsWidget
//!
//! @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/MinimizerSettingsWidget.h"
#include "GUI/Model/Job/FitSuiteItem.h"
#include "GUI/Model/Job/JobItem.h"
#include "GUI/Model/Job/MinimizerItem.h"
#include "GUI/View/Common/DoubleSpinBox.h"
#include "GUI/View/Common/SafeSpinBox.h"
#include "GUI/View/Tool/LayoutUtils.h"
#include "GUI/View/Tool/WidgetUtils.h"
#include <QComboBox>
#include <QFormLayout>
#include <QPushButton>
#include <QVBoxLayout>

MinimizerSettingsWidget::MinimizerSettingsWidget(QWidget* parent)
    : QWidget(parent)
    , m_currentItem(nullptr)
{
    setWindowTitle(QLatin1String("Minimizer Settings"));
    setAttribute(Qt::WA_StyledBackground, true);
    setProperty("stylable", true); // for stylesheet addressing

    m_mainLayout = new QFormLayout(this);
    m_mainLayout->setContentsMargins(8, 8, 8, 8);
    m_mainLayout->setSpacing(5);
}

void MinimizerSettingsWidget::setJobItem(JobItem* jobItem)
{
    ASSERT(jobItem);
    setMinItem(jobItem->fitSuiteItem()->minimizerContainerItem());
}

void MinimizerSettingsWidget::setMinItem(MinimizerContainerItem* minimizerItem)
{
    ASSERT(minimizerItem);

    GUI::Util::Layout::clearLayout(m_mainLayout);
    m_updaters.clear();
    m_currentItem = minimizerItem;

    if (!m_currentItem)
        return;

    m_mainLayout->addRow("Minimizer:", GUI::Util::createComboBox(
        [=] { return m_currentItem->minimizerCombo(); },
        [=](const QString& t) {
            m_currentItem->setCurrentMinimizer(t);
            createMimimizerEdits();
        }, &m_updaters));

    auto* w = new QWidget(this);
    m_minimizerLayout = new QFormLayout(w);
    m_minimizerLayout->setContentsMargins(10, 8, 0, 8);
    m_mainLayout->addRow(w);

    m_mainLayout->addRow("Objective metric:", GUI::Util::createComboBox(
                             [=] { return m_currentItem->objectiveMetricCombo(); },
                             [=](const QString& t) { m_currentItem->setCurrentObjectiveMetric(t); },
                             &m_updaters, "Objective metric to use for estimating distance between simulated and experimental data"));
    m_mainLayout->addRow("Norm function:", GUI::Util::createComboBox(
                             [=] { return m_currentItem->normFunctionCombo(); },
                             [=](const QString& t) { m_currentItem->setCurrentNormFunction(t); },
                             &m_updaters, "Normalization to use for estimating distance between simulated and experimental data"));

    createMimimizerEdits();
    updateUIValues();
}
void MinimizerSettingsWidget::createMimimizerEdits()
{
    GUI::Util::Layout::clearLayout(m_minimizerLayout);

    // Minuit2
    if(m_currentItem->currentMinimizerM_TYPE() == MinuitMinimizerItem::M_TYPE)
        createMinuitEdits();
    else
    // GSL MultiMin
    if(m_currentItem->currentMinimizerM_TYPE() == GSLMultiMinimizerItem::M_TYPE)
        createGSLMultiMinEdits();
    else
    // TMVA Genetic
    if(m_currentItem->currentMinimizerM_TYPE() == GeneticMinimizerItem::M_TYPE)
        createTMVAGeneticEdits();
    else
    // GSL Simulated Annealing
    if(m_currentItem->currentMinimizerM_TYPE() == SimAnMinimizerItem::M_TYPE)
        createGSLSimulatedAnnealingEdits();
    else
    // GSL Levenberg-Marquardt
    if(m_currentItem->currentMinimizerM_TYPE() == GSLLMAMinimizerItem::M_TYPE)
        createGSLLevMarEdits();
    else
        ASSERT(0);
}

void MinimizerSettingsWidget::createMinuitEdits()
{
    MinuitMinimizerItem* minItem = m_currentItem->minimizerItemMinuit();

    m_minimizerLayout->addRow("Algorithm:", GUI::Util::createComboBox(
                             [=] { return minItem->algorithmCombo(); },
                             [=](const QString& t) { minItem->setCurrentAlgorithm(t); },
                             &m_updaters));

    m_minimizerLayout->addRow("Strategy:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->strategy(); },
                             [=](int v) { minItem->setStrategy(v); },
                             &m_updaters, "Minimization strategy (0-low, 1-medium, 2-high quality)",
                             RealLimits::limited(0, 2)));

    m_minimizerLayout->addRow("ErrorDef factor:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->errorDefinition(); },
                             [=](double v) { minItem->setErrorDefinition(v); },
                             &m_updaters, "Error definition factor for parameter error calculation",
                             RealLimits::positive()));

    m_minimizerLayout->addRow("Tolerance:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->tolerance(); },
                             [=](double v) { minItem->setTolerance(v); },
                             &m_updaters, "Tolerance on the function value at the minimum",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Precision:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->precision(); },
                             [=](double v) { minItem->setPrecision(v); },
                             &m_updaters, "Relative floating point arithmetic precision",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Max func calls:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->maxFuncCalls(); },
                             [=](int v) { minItem->setMaxFuncCalls(v); },
                             &m_updaters, "Maximum number of function calls",
                             RealLimits::nonnegative()));
}

void MinimizerSettingsWidget::createGSLMultiMinEdits()
{
    GSLMultiMinimizerItem* minItem = m_currentItem->minimizerItemGSLMulti();

    m_minimizerLayout->addRow("Algorithm:", GUI::Util::createComboBox(
                             [=] { return minItem->algorithmCombo(); },
                             [=](const QString& t) { minItem->setCurrentAlgorithm(t); },
                             &m_updaters));

    m_minimizerLayout->addRow("Max iterations:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->maxIterations(); },
                             [=](int v) { minItem->setMaxIterations(v); },
                             &m_updaters, "Maximum number of iterations",
                             RealLimits::nonnegative()));
}

void MinimizerSettingsWidget::createTMVAGeneticEdits()
{
    GeneticMinimizerItem* minItem = m_currentItem->minimizerItemGenetic();

    m_minimizerLayout->addRow("Tolerance:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->tolerance(); },
                             [=](double v) { minItem->setTolerance(v); },
                             &m_updaters, "Tolerance on the function value at the minimum",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Max iterations:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->maxIterations(); },
                             [=](int v) { minItem->setMaxIterations(v); },
                             &m_updaters, "Maximum number of iterations",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Population:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->populationSize(); },
                             [=](int v) { minItem->setPopulationSize(v); },
                             &m_updaters, "Population size",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Random seed:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->randomSeed(); },
                             [=](int v) { minItem->setRandomSeed(v); },
    &m_updaters));
}

void MinimizerSettingsWidget::createGSLSimulatedAnnealingEdits()
{
    SimAnMinimizerItem* minItem = m_currentItem->minimizerItemSimAn();

    m_minimizerLayout->addRow("Max iterations:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->maxIterations(); },
                             [=](int v) { minItem->setMaxIterations(v); },
                             &m_updaters, "Number of points to try for each step",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Iterations at T:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->iterationsAtEachTemp(); },
                             [=](int v) { minItem->setIterationsAtEachTemp(v); },
                             &m_updaters, "Number of iterations at each temperature",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Step size:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->stepSize(); },
                             [=](double v) { minItem->setStepSize(v); },
                             &m_updaters, "Max step size used in random walk",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("k:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->boltzmanK(); },
                             [=](double v) { minItem->setBoltzmanK(v); },
                             &m_updaters, "Boltzmann k",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("T init:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->boltzmanInitT(); },
                             [=](double v) { minItem->setBoltzmanInitT(v); },
                             &m_updaters, "Boltzmann initial temperature",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("mu:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->boltzmanMu(); },
                             [=](double v) { minItem->setBoltzmanMu(v); },
                             &m_updaters, "Boltzmann mu",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("T min:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->boltzmanMinT(); },
                             [=](double v) { minItem->setBoltzmanMinT(v); },
                             &m_updaters, "Boltzmann minimal temperature",
    RealLimits::nonnegative()));
}

void MinimizerSettingsWidget::createGSLLevMarEdits()
{
    GSLLMAMinimizerItem* minItem = m_currentItem->minimizerItemGSLLMA();

    m_minimizerLayout->addRow("Tolerance:", GUI::Util::createDoubleSpinbox(
                             [=] { return minItem->tolerance(); },
                             [=](double v) { minItem->setTolerance(v); },
                             &m_updaters, "Tolerance on the function value at the minimum",
                             RealLimits::nonnegative()));

    m_minimizerLayout->addRow("Max iterations:", GUI::Util::createIntSpinbox(
                             [=] { return minItem->maxIterations(); },
                             [=](int v) { minItem->setMaxIterations(v); },
                             &m_updaters, "Maximum number of iterations",
                             RealLimits::nonnegative()));
}

void MinimizerSettingsWidget::updateUIValues()
{
    for (const auto& updater : m_updaters)
        updater();
}