//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Option/SimulationOptions.cpp
//! @brief     Implements class SimulationOptions.
//!
//! @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 "Sample/Option/SimulationOptions.h"
#include "Base/Util/Assert.h"
#include <cstdlib>
#include <iostream>
#include <string>
#include <thread>

SimulationOptions::SimulationOptions()
    : m_mc_integration(false)
    , m_include_specular(false)
    , m_use_avg_materials(true)
    , m_mc_points(1)
{
    if (const char* env_p = std::getenv("BA_NTHREADS")) {
        m_n_threads = std::stoi(env_p);
        if (m_n_threads > 0)
            return;
    }
    m_n_threads = hardwareConcurrency();
}

void SimulationOptions::setMonteCarloIntegration(bool flag, size_t mc_points)
{
    m_mc_integration = flag;
    m_mc_points = mc_points;
}

void SimulationOptions::setNumberOfThreads(int nthreads)
{
    ASSERT(nthreads >= 0);
    if (nthreads == 0)
        m_n_threads = hardwareConcurrency();
    else
        m_n_threads = nthreads;
    ASSERT(m_n_threads > 0);
}

void SimulationOptions::setNumberOfBatches(int nbatches)
{
    ASSERT(nbatches > 0);
    m_n_batches = nbatches;
}

void SimulationOptions::setMesoReciprocalSum(bool use_rec_sum, double rad_factor)
{
    m_meso_options.use_reciprocal_sum = use_rec_sum;
    m_meso_options.radius_factor = rad_factor;
}

void SimulationOptions::setOffspecIntegratorOptions(const std::string& type,
                                                    const std::map<std::string, double>& pars)
{
    m_offspec_integrator_options.type = type;
    m_offspec_integrator_options.pars = pars;
}

bool SimulationOptions::isIntegrate() const
{
    return m_mc_integration && m_mc_points > 1;
}

unsigned SimulationOptions::numberOfThreads() const
{
    ASSERT(m_n_threads > 0);
    return m_n_threads;
}

unsigned SimulationOptions::numberOfBatches() const
{
    ASSERT(m_n_batches > 0);
    return m_n_batches;
}

unsigned SimulationOptions::currentBatch() const
{
    unsigned result = m_current_batch;
    ASSERT(result < m_n_batches);
    return result;
}

unsigned SimulationOptions::hardwareConcurrency() const
{
    return std::thread::hardware_concurrency();
}
