<commit_before>/*
  Copyright (C) 2014-2017 <NAME> <<EMAIL>>
  <NAME> <<EMAIL>>

  This file is part of Acclimate.

  Acclimate is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of
  the License, or (at your option) any later version.

  Acclimate is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Acclimate.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ModelRun.h"

#include <cfenv>
#include <chrono>
#include <csignal>
#include <ostream>
#include <string>
#include <utility>

#include "checkpointing.h"
#include "input/ModelInitializer.h"
#include "model/EconomicAgent.h"
#include "model/Government.h"
#include "model/Model.h"
#include "model/PurchasingManager.h"
#include "model/Region.h"
#include "model/Storage.h"
#include "output/ArrayOutput.h"
#include "output/ConsoleOutput.h"
#include "output/DamageOutput.h"
#include "output/GnuplotOutput.h"
#include "output/HistogramOutput.h"
#include "output/JSONNetworkOutput.h"
#include "output/JSONOutput.h"
#include "output/NetCDFOutput.h"
#include "output/ProgressOutput.h"
#include "scenario/DirectPopulation.h"
#include "scenario/EventSeriesScenario.h"
#include "scenario/Flooding.h"
#include "scenario/HeatLaborProductivity.h"
#include "scenario/Hurricanes.h"
#include "scenario/Scenario.h"
#include "scenario/Taxes.h"

namespace acclimate {

static void handle_fpe_error(int /* signal */) {
    if constexpr (options::FLOATING_POINT_EXCEPTIONS) {
        unsigned int exceptions = fetestexcept(FE_ALL_EXCEPT);  // NOLINT(hicpp-signed-bitwise)
        feclearexcept(FE_ALL_EXCEPT);                           // NOLINT(hicpp-signed-bitwise)
        if (exceptions == 0) {
            return;
        }
        if ((exceptions & FE_OVERFLOW) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FPE_OVERFLOW");
        }
        if ((exceptions & FE_INVALID) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FPE_INVALID");
        }
        if ((exceptions & FE_DIVBYZERO) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FPE_DIVBYZERO");
        }
        if ((exceptions & FE_INEXACT) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FE_INEXACT");
        }
        if ((exceptions & FE_UNDERFLOW) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FE_UNDERFLOW");
        }
        if constexpr (options::FATAL_FLOATING_POINT_EXCEPTIONS) {
            error_("Floating point exception");
        }
    }
}

ModelRun::ModelRun(const settings::SettingsNode& settings) {
    step(IterationStep::INITIALIZATION);

    if constexpr (options::BANKERS_ROUNDING) {
        fesetround(FE_TONEAREST);
    }

    if constexpr (options::FLOATING_POINT_EXCEPTIONS) {
        signal(SIGFPE, handle_fpe_error);
        feenableexcept(FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);  // NOLINT(hicpp-signed-bitwise)
    }

    if constexpr (options::CHECKPOINTING) {
        checkpoint::initialize();
    }

    auto model = new Model(this);
    {
        ModelInitializer model_initializer(model, settings);
        model_initializer.initialize();
        if constexpr (options::DEBUGGING) {
            model_initializer.print_network_characteristics();
        }
        model_m.reset(model);
    }

    for (const auto& scenario_node : settings["scenarios"].as_sequence()) {
        Scenario* scenario = nullptr;
        const std::string& type = scenario_node["type"].template as<std::string>();
        // TODO use switch
        if (type == "events") {
            scenario = new Scenario(settings, scenario_node, model);
        } else if (type == "taxes") {
            scenario = new Taxes(settings, scenario_node, model);
        } else if (type == "flooding") {
            scenario = new Flooding(settings, scenario_node, model);
        } else if (type == "hurricanes") {
            scenario = new Hurricanes(settings, scenario_node, model);
        } else if (type == "direct_population") {
            scenario = new DirectPopulation(settings, scenario_node, model);
        } else if (type == "heat_labor_productivity") {
            scenario = new HeatLaborProductivity(settings, scenario_node, model);
        } else if (type == "event_series") {
            scenario = new EventSeriesScenario(settings, scenario_node, model);
        } else {
            error_("Unknown scenario type '" << type << "'");
        }
        scenarios_m.emplace_back(scenario);
    }

    for (const auto& node : settings["outputs"].as_sequence()) {
        Output* output = nullptr;
        const std::string& type = node["format"].template as<std::string>();
        // TODO use switch
        if (type == "console") {
            output = new ConsoleOutput(settings, model, node);
        } else if (type == "json") {
            output = new JSONOutput(settings, model, node);
        } else if (type == "json_network") {
            output = new JSONNetworkOutput(settings, model, node);
        } else if (type == "netcdf") {
            output = new NetCDFOutput(settings, model, node);
        } else if (type == "histogram") {
            output = new HistogramOutput(settings, model, node);
        } else if (type == "gnuplot") {
            output = new GnuplotOutput(settings, model, node);
        } else if (type == "damage") {
            output = new DamageOutput(settings, model, node);
        } else if (type == "array") {
            output = new ArrayOutput(settings, model, node);
        } else if (type == "progress") {
            output = new ProgressOutput(settings, model, node);
        } else {
            error_("Unknown output format '" << type << "'");
        }
        output->initialize();
        outputs_m.emplace_back(output);
    }
}<commit_msg>Use switch for scenario and output type<commit_after>/*
  Copyright (C) 2014-2017 <NAME> <<EMAIL>>
  <NAME> <<EMAIL>>

  This file is part of Acclimate.

  Acclimate is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of
  the License, or (at your option) any later version.

  Acclimate is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Acclimate.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ModelRun.h"

#include <cfenv>
#include <chrono>
#include <csignal>
#include <ostream>
#include <string>
#include <utility>

#include "checkpointing.h"
#include "input/ModelInitializer.h"
#include "model/EconomicAgent.h"
#include "model/Government.h"
#include "model/Model.h"
#include "model/PurchasingManager.h"
#include "model/Region.h"
#include "model/Storage.h"
#include "output/ArrayOutput.h"
#include "output/ConsoleOutput.h"
#include "output/DamageOutput.h"
#include "output/GnuplotOutput.h"
#include "output/HistogramOutput.h"
#include "output/JSONNetworkOutput.h"
#include "output/JSONOutput.h"
#include "output/NetCDFOutput.h"
#include "output/ProgressOutput.h"
#include "scenario/DirectPopulation.h"
#include "scenario/EventSeriesScenario.h"
#include "scenario/Flooding.h"
#include "scenario/HeatLaborProductivity.h"
#include "scenario/Hurricanes.h"
#include "scenario/Scenario.h"
#include "scenario/Taxes.h"

namespace acclimate {

static void handle_fpe_error(int /* signal */) {
    if constexpr (options::FLOATING_POINT_EXCEPTIONS) {
        unsigned int exceptions = fetestexcept(FE_ALL_EXCEPT);  // NOLINT(hicpp-signed-bitwise)
        feclearexcept(FE_ALL_EXCEPT);                           // NOLINT(hicpp-signed-bitwise)
        if (exceptions == 0) {
            return;
        }
        if ((exceptions & FE_OVERFLOW) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FPE_OVERFLOW");
        }
        if ((exceptions & FE_INVALID) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FPE_INVALID");
        }
        if ((exceptions & FE_DIVBYZERO) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FPE_DIVBYZERO");
        }
        if ((exceptions & FE_INEXACT) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FE_INEXACT");
        }
        if ((exceptions & FE_UNDERFLOW) != 0) {  // NOLINT(hicpp-signed-bitwise)
            warning_("FE_UNDERFLOW");
        }
        if constexpr (options::FATAL_FLOATING_POINT_EXCEPTIONS) {
            error_("Floating point exception");
        }
    }
}

ModelRun::ModelRun(const settings::SettingsNode& settings) {
    step(IterationStep::INITIALIZATION);

    if constexpr (options::BANKERS_ROUNDING) {
        fesetround(FE_TONEAREST);
    }

    if constexpr (options::FLOATING_POINT_EXCEPTIONS) {
        signal(SIGFPE, handle_fpe_error);
        feenableexcept(FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);  // NOLINT(hicpp-signed-bitwise)
    }

    if constexpr (options::CHECKPOINTING) {
        checkpoint::initialize();
    }

    auto model = new Model(this);
    {
        ModelInitializer model_initializer(model, settings);
        model_initializer.initialize();
        if constexpr (options::DEBUGGING) {
            model_initializer.print_network_characteristics();
        }
        model_m.reset(model);
    }

    for (const auto& scenario_node : settings["scenarios"].as_sequence()) {
        Scenario* scenario = nullptr;
        const auto& type = scenario_node["type"].template as<hstring>();
        switch (type) {
            case hstring::hash("events"):
                scenario = new Scenario(settings, scenario_node, model);
                break;
            case hstring::hash("taxes"):
                scenario = new Taxes(settings, scenario_node, model);
                break;
            case hstring::hash("flooding"):
                scenario = new Flooding(settings, scenario_node, model);
                break;
            case hstring::hash("hurricanes"):
                scenario = new Hurricanes(settings, scenario_node, model);
                break;
            case hstring::hash("direct_population"):
                scenario = new DirectPopulation(settings, scenario_node, model);
                break;
            case hstring::hash("heat_labor_productivity"):
                scenario = new HeatLaborProductivity(settings, scenario_node, model);
                break;
            case hstring::hash("event_series"):
                scenario = new EventSeriesScenario(settings, scenario_node, model);
                break;
            default:
                error_("Unknown scenario type '" << type << "'");
        }
        scenarios_m.emplace_back(scenario);
    }

    for (const auto& node : settings["outputs"].as_sequence()) {
        Output* output = nullptr;
        const auto& type = node["format"].template as<hstring>();
        switch (type) {
            case hstring::hash("console"):
                output = new ConsoleOutput(settings, model, node);
                break;
            case hstring::hash("json"):
                output = new JSONOutput(settings, model, node);
                break;
            case hstring::hash("json_network"):
                output = new JSONNetworkOutput(settings, model, node);
                break;
            case hstring::hash("netcdf"):
                output = new NetCDFOutput(settings, model, node);
                break;
            case hstring::hash("histogram"):
                output = new HistogramOutput(settings, model, node);
                break;
            case hstring::hash("gnuplot"):
                output = new GnuplotOutput(settings, model, node);
                break;
            case hstring::hash("damage"):
                output = new DamageOutput(settings, model, node);
                break;
            case hstring::hash("array"):
                output = new ArrayOutput(settings, model, node);
                break;
            case hstring::hash("progress"):
                output = new ProgressOutput(settings, model, node);
                break;
            default:
                error_("Unknown output format '" << type << "'");
        }
        output->initialize();
        outputs_m.emplace_back(output);
    }
}
{'fraction_non_alphanumeric': 0.11855345911949686, 'fraction_numerical': 0.0023584905660377358, 'mean_word_length': 2.610843031507238, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5853696', 'n_tokens_mistral': 3815, 'n_tokens_neox': 3701, 'n_words': 894}