Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion include/realizations/catchment/Bmi_Module_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class Bmi_C_Pet_IT;
class Bmi_Cpp_Multi_Array_Test;

namespace realization {
static bool is_ngen_realization_time_input(const std::string& var_name) {
return var_name == "ngen_realization_start_time" ||
var_name == "ngen_realization_end_time" ||
var_name == "ngen_realization_dt";
}

/**
* Abstraction of a formulation with a single backing model object that implements the BMI.
Expand Down Expand Up @@ -308,7 +313,6 @@ namespace realization {
}

protected:

/**
* @brief Get correct BMI variable name, which may be the output or something mapped to this output.
*
Expand Down Expand Up @@ -393,6 +397,11 @@ namespace realization {
*/
void set_initial_bmi_parameters(geojson::PropertyMap properties);

/**
* If supported by the BMI module, pass realization timing metadata through legal BMI SetValue calls.
*/
void set_realization_time_inputs();

/**
* Test whether backing model has fixed time step size.
*
Expand Down
3 changes: 3 additions & 0 deletions include/realizations/catchment/Bmi_Multi_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,9 @@ namespace realization {
std::shared_ptr<std::map<std::string, std::string>> var_aliases;
var_aliases = std::make_shared<std::map<std::string, std::string>>(std::map<std::string, std::string>());
for (const std::string &var_name : mod->get_bmi_input_variables()) {
if (is_ngen_realization_time_input(var_name)) {
continue;
}
std::string framework_alias = mod->get_config_mapped_variable_name(var_name);
(*var_aliases)[framework_alias] = var_name;
// If framework_name is not yet in collection from which we have available data sources ...
Expand Down
69 changes: 69 additions & 0 deletions src/realizations/catchment/Bmi_Module_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
#include "state_save_restore/State_Save_Utils.hpp"
#include <state_save_restore/State_Save_Restore.hpp>

#include <ctime>
#include <iomanip>
#include <sstream>
#include <boost/algorithm/string.hpp>

std::stringstream bmiform_ss;

namespace realization {
Expand Down Expand Up @@ -426,6 +431,56 @@ namespace realization {
return bmi_model_start_time_forcing_offset_s;
}

void Bmi_Module_Formulation::set_realization_time_inputs() {
auto model = get_bmi_model();
if (model == nullptr) {
return;
}

std::vector<std::string> input_vars = model->GetInputVarNames();

const bool has_start =
std::find(input_vars.begin(), input_vars.end(), "ngen_realization_start_time") != input_vars.end();
const bool has_end =
std::find(input_vars.begin(), input_vars.end(), "ngen_realization_end_time") != input_vars.end();
const bool has_dt =
std::find(input_vars.begin(), input_vars.end(), "ngen_realization_dt") != input_vars.end();

if (!has_start && !has_end && !has_dt) {
return;
}

const double start_time_value = static_cast<double>(forcing->get_data_start_time());
const double end_time_value = static_cast<double>(forcing->get_data_stop_time());
const double dt_value = static_cast<double>(forcing->record_duration());

if (dt_value <= 0.0) {
throw std::runtime_error(
"Invalid realization record duration while setting BMI realization time inputs for catchment '" +
this->get_id() + "'."
);
}

if (has_start) {
model->SetValue("ngen_realization_start_time", (void *)&start_time_value);
}

if (has_end) {
model->SetValue("ngen_realization_end_time", (void *)&end_time_value);
}

if (has_dt) {
model->SetValue("ngen_realization_dt", (void *)&dt_value);
}

std::stringstream ss;
ss << "Applied realization time inputs via BMI SetValue for catchment '" << this->get_id()
<< "': start_utime=" << static_cast<long>(start_time_value)
<< ", end_utime=" << static_cast<long>(end_time_value)
<< ", dt_seconds=" << static_cast<long>(dt_value);
LOG(ss.str(), LogLevel::INFO);
}

void Bmi_Module_Formulation::inner_create_formulation(geojson::PropertyMap properties, bool needs_param_validation) {
if (needs_param_validation) {
validate_parameters(properties);
Expand All @@ -435,6 +490,11 @@ namespace realization {
set_bmi_main_output_var(properties.at(BMI_REALIZATION_CFG_PARAM_REQ__MAIN_OUT_VAR).as_string());
set_model_type_name(properties.at(BMI_REALIZATION_CFG_PARAM_REQ__MODEL_TYPE).as_string());

const std::string model_type_name =
boost::algorithm::to_lower_copy(
properties.at(BMI_REALIZATION_CFG_PARAM_REQ__MODEL_TYPE).as_string()
);

// Then optional ...

auto uses_forcings_it = properties.find(BMI_REALIZATION_CFG_PARAM_OPT__USES_FORCINGS);
Expand Down Expand Up @@ -473,6 +533,9 @@ namespace realization {
//and set them before it is run
set_initial_bmi_parameters(properties);

// Pass realization timing to BMI modules that explicitly advertise these inputs.
set_realization_time_inputs();

// Make sure that this is able to interpret model time and convert to real time, since BMI model time is
// usually starting at 0 and just counting up
determine_model_time_offset();
Expand Down Expand Up @@ -885,6 +948,9 @@ namespace realization {
time_t model_epoch_time = convert_model_time(model_init_time) + get_bmi_model_start_time_forcing_offset_s();

for (std::string & var_name : in_var_names) {
if (is_ngen_realization_time_input(var_name)) {
continue;
}
data_access::GenericDataProvider *provider;
std::string var_map_alias = get_config_mapped_variable_name(var_name);
if (input_forcing_providers.find(var_map_alias) != input_forcing_providers.end()) {
Expand Down Expand Up @@ -972,6 +1038,9 @@ namespace realization {
inputs << "Input variables were as follows:";

for (std::string & var_name : in_var_names) {
if (is_ngen_realization_time_input(var_name)) {
continue;
}
data_access::GenericDataProvider *provider;
std::string var_map_alias = get_config_mapped_variable_name(var_name);
if (input_forcing_providers.find(var_map_alias) != input_forcing_providers.end()) {
Expand Down
Loading