From 1404841db23049f2f0269c8346580b0e6407e82f Mon Sep 17 00:00:00 2001 From: program-- Date: Tue, 25 Jul 2023 15:00:26 -0700 Subject: [PATCH] #554: initial external model_params parsing --- .../catchment/Formulation_Manager.hpp | 77 +++++++++++++++++-- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/include/realizations/catchment/Formulation_Manager.hpp b/include/realizations/catchment/Formulation_Manager.hpp index 31f957c5a3..172174d1c0 100644 --- a/include/realizations/catchment/Formulation_Manager.hpp +++ b/include/realizations/catchment/Formulation_Manager.hpp @@ -12,6 +12,7 @@ #include #include #include +#include "JSONProperty.hpp" #include "features/Features.hpp" #include #include "Formulation_Constructors.hpp" @@ -158,20 +159,29 @@ namespace realization { if (possible_catchment_configs) { for (std::pair catchment_config : *possible_catchment_configs) { - if( fabric->find(catchment_config.first) == -1 ) + int catchment_index = fabric->find(catchment_config.first); + if( catchment_index == -1 ) { - #ifndef NGEN_QUIET - std::cerr<<"WARNING Formulation_Manager::read: Cannot create formulation for catchment " - <get_feature(catchment_index); auto formulations = catchment_config.second.get_child_optional("formulations"); if( !formulations ) { throw std::runtime_error("ERROR: No formulations defined for "+catchment_config.first+"."); } + // Parse catchment-specific model_params + auto model_params = formulations->get_child_optional("params.model_params"); + if (model_params) { + parse_external_model_params(*model_params, catchment_feature); + } + for (const auto &formulation: *formulations) { this->add_formulation( this->construct_formulation_from_tree( @@ -489,6 +499,59 @@ namespace realization { throw std::runtime_error("Forcing data could not be found for '" + identifier + "'"); } + /** + * @brief Parse a `model_params` property tree and replace external parameters + * with values from a catchment's properties + * + * @param model_params Property tree with root key "model_params" + * @param catchment_feature Associated catchment feature + */ + void parse_external_model_params(boost::property_tree::ptree& model_params, const geojson::Feature catchment_feature) { + for (auto& param : model_params) { + auto param_source = param.second.get_child_optional("source"); + if (!param_source) { + continue; + } + + auto param_source_name = param_source->get_value(); + if (param_source_name != "hydrofabric") { + // temporary until the logic for alternative sources is designed + throw std::logic_error("ERROR: 'model_params' source `" + param_source_name + "` not currently supported. Only `hydrofabric` is supported."); + } + + auto param_name = param.second.get_child_optional("from") + ? param.second.get_child("from").get_value() + : param.first; + + model_params.erase(param.first); + + if (catchment_feature->has_property(param_name)) { + auto catchment_attribute = catchment_feature->get_property(param_name); + switch (catchment_attribute.get_type()) { + case geojson::PropertyType::Natural: + model_params.put(param_name, catchment_attribute.as_natural_number()); + break; + case geojson::PropertyType::Boolean: + model_params.put(param_name, catchment_attribute.as_boolean()); + break; + case geojson::PropertyType::Real: + model_params.put(param_name, catchment_attribute.as_real_number()); + break; + case geojson::PropertyType::String: + model_params.put(param_name, catchment_attribute.as_string()); + break; + + case geojson::PropertyType::List: + case geojson::PropertyType::Object: + default: + std::cerr << "WARNING: property type " << static_cast(catchment_attribute.get_type()) << " not allowed as model parameter. " + << "Must be one of: Natural (int), Real (double), Boolean, or String" << std::endl; + break; + } + } + } + } + boost::property_tree::ptree tree; boost::property_tree::ptree global_formulation_tree;