Skip to content

Commit

Permalink
Refactor: consolidate duplicate implementations into Bmi_Module_Formu…
Browse files Browse the repository at this point in the history
…lation::get_response
  • Loading branch information
PhilMiller authored and donaldwj committed May 10, 2024
1 parent f18b679 commit f943886
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 367 deletions.
36 changes: 0 additions & 36 deletions include/realizations/catchment/Bmi_C_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,6 @@ namespace realization {

std::string get_formulation_type() override;

/**
* Get the model response for a time step.
*
* Get the model response for the provided time step, executing the backing model formulation one or more times
* as needed.
*
* Function assumes the backing model has been fully initialized an that any additional input values have been
* applied.
*
* The function throws an error if the index of a previously processed time step is supplied, except if it is
* the last processed time step. In that case, the appropriate value is returned as described below, but
* without executing any model update.
*
* Assuming updating to the implied time is valid for the model, the function executes one or more model updates
* to process future time steps for the necessary indexes. Multiple time steps updates occur when the given
* future time step index is not the next time step index to be processed. Regardless, all processed time steps
* have the size supplied in `t_delta`.
*
* However, it is possible to provide `t_index` and `t_delta` values that would result in the aggregate updates
* taking the model's time beyond its `end_time` value. In such cases, if the formulation config indicates this
* model is not allow to exceed its set `end_time`, the function does not update the model and throws an error.
*
* The function will return the value of the primary output variable (see `get_bmi_main_output_var()`) for the
* given time step after the model has been updated to that point. The type returned will always be a `double`,
* with other numeric types being cast if necessary.
*
* The BMI spec requires for variable values to be passed to/from models via as arrays. This function
* essentially treats the variable array reference as if it were just a raw pointer and returns the `0`-th
* array value.
*
* @param t_index The index of the time step for which to run model calculations.
* @param d_delta_s The duration, in seconds, of the time step for which to run model calculations.
* @return The total discharge of the model for the given time step.
*/
double get_response(time_step_t t_index, time_step_t t_delta) override;

bool is_bmi_input_variable(const std::string &var_name) override;

bool is_bmi_output_variable(const std::string &var_name) override;
Expand Down
2 changes: 0 additions & 2 deletions include/realizations/catchment/Bmi_Cpp_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ namespace realization {

std::string get_formulation_type() override;

double get_response(time_step_t t_index, time_step_t t_delta) override;

bool is_bmi_input_variable(const std::string &var_name) override;

bool is_bmi_output_variable(const std::string &var_name) override;
Expand Down
34 changes: 0 additions & 34 deletions include/realizations/catchment/Bmi_Fortran_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,6 @@ namespace realization {

std::string get_formulation_type() override;

/**
* Get the model response for a time step.
*
* Get the model response for the provided time step, executing the backing model formulation one or more times as
* needed.
*
* Function assumes the backing model has been fully initialized an that any additional input values have been applied.
*
* The function throws an error if the index of a previously processed time step is supplied, except if it is the last
* processed time step. In that case, the appropriate value is returned as described below, but without executing any
* model update.
*
* Assuming updating to the implied time is valid for the model, the function executes one or more model updates to
* process future time steps for the necessary indexes. Multiple time steps updates occur when the given future time
* step index is not the next time step index to be processed. Regardless, all processed time steps have the size
* supplied in `t_delta`.
*
* However, it is possible to provide `t_index` and `t_delta` values that would result in the aggregate updates taking
* the model's time beyond its `end_time` value. In such cases, if the formulation config indicates this model is
* not allow to exceed its set `end_time`, the function does not update the model and throws an error.
*
* The function will return the value of the primary output variable (see `get_bmi_main_output_var()`) for the given
* time step after the model has been updated to that point. The type returned will always be a `double`, with other
* numeric types being cast if necessary.
*
* The BMI spec requires for variable values to be passed to/from models via as arrays. This function essentially
* treats the variable array reference as if it were just a raw pointer and returns the `0`-th array value.
*
* @param t_index The index of the time step for which to run model calculations.
* @param d_delta_s The duration, in seconds, of the time step for which to run model calculations.
* @return The total discharge of the model for the given time step.
*/
double get_response(::time_step_t index, ::time_step_t t_delta) override;

protected:

/**
Expand Down
36 changes: 36 additions & 0 deletions include/realizations/catchment/Bmi_Module_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,42 @@ namespace realization {
*/
std::string get_output_line_for_timestep(int timestep, std::string delimiter) override;

/**
* Get the model response for a time step.
*
* Get the model response for the provided time step, executing the backing model formulation one or more times
* as needed.
*
* Function assumes the backing model has been fully initialized an that any additional input values have been
* applied.
*
* The function throws an error if the index of a previously processed time step is supplied, except if it is
* the last processed time step. In that case, the appropriate value is returned as described below, but
* without executing any model update.
*
* Assuming updating to the implied time is valid for the model, the function executes one or more model updates
* to process future time steps for the necessary indexes. Multiple time steps updates occur when the given
* future time step index is not the next time step index to be processed. Regardless, all processed time steps
* have the size supplied in `t_delta`.
*
* However, it is possible to provide `t_index` and `t_delta` values that would result in the aggregate updates
* taking the model's time beyond its `end_time` value. In such cases, if the formulation config indicates this
* model is not allow to exceed its set `end_time`, the function does not update the model and throws an error.
*
* The function will return the value of the primary output variable (see `get_bmi_main_output_var()`) for the
* given time step after the model has been updated to that point. The type returned will always be a `double`,
* with other numeric types being cast if necessary.
*
* The BMI spec requires for variable values to be passed to/from models via as arrays. This function
* essentially treats the variable array reference as if it were just a raw pointer and returns the `0`-th
* array value.
*
* @param t_index The index of the time step for which to run model calculations.
* @param d_delta_s The duration, in seconds, of the time step for which to run model calculations.
* @return The total discharge of the model for the given time step.
*/
double get_response(time_step_t t_index, time_step_t t_delta) override;

/**
* Get the inclusive beginning of the period of time over which this instance can provide data for this forcing.
*
Expand Down
36 changes: 0 additions & 36 deletions include/realizations/catchment/Bmi_Py_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,42 +31,6 @@ namespace realization {

std::string get_formulation_type() override;

/**
* Get the model response for a time step.
*
* Get the model response for the provided time step, executing the backing model formulation one or more times
* as needed.
*
* Function assumes the backing model has been fully initialized an that any additional input values have been
* applied.
*
* The function throws an error if the index of a previously processed time step is supplied, except if it is
* the last processed time step. In that case, the appropriate value is returned as described below, but
* without executing any model update.
*
* Assuming updating to the implied time is valid for the model, the function executes one or more model updates
* to process future time steps for the necessary indexes. Multiple time steps updates occur when the given
* future time step index is not the next time step index to be processed. Regardless, all processed time steps
* have the size supplied in `t_delta`.
*
* However, it is possible to provide `t_index` and `t_delta` values that would result in the aggregate updates
* taking the model's time beyond its `end_time` value. In such cases, if the formulation config indicates this
* model is not allow to exceed its set `end_time`, the function does not update the model and throws an error.
*
* The function will return the value of the primary output variable (see `get_bmi_main_output_var()`) for the
* given time step after the model has been updated to that point. The type returned will always be a `double`,
* with other numeric types being cast if necessary.
*
* The BMI spec requires for variable values to be passed to/from models via as arrays. This function
* essentially treats the variable array reference as if it were just a raw pointer and returns the `0`-th
* array value.
*
* @param t_index The index of the time step for which to run model calculations.
* @param d_delta_s The duration, in seconds, of the time step for which to run model calculations.
* @return The total discharge of the model for the given time step.
*/
double get_response(time_step_t t_index, time_step_t t_delta) override;

bool is_bmi_input_variable(const std::string &var_name) override;

bool is_bmi_output_variable(const std::string &var_name) override;
Expand Down
73 changes: 0 additions & 73 deletions src/realizations/catchment/Bmi_C_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,79 +35,6 @@ std::shared_ptr<Bmi_Adapter> Bmi_C_Formulation::construct_model(const geojson::P
output);
}

/**
* Get the model response for a time step.
*
* Get the model response for the provided time step, executing the backing model formulation one or more times as
* needed.
*
* Function assumes the backing model has been fully initialized an that any additional input values have been applied.
*
* The function throws an error if the index of a previously processed time step is supplied, except if it is the last
* processed time step. In that case, the appropriate value is returned as described below, but without executing any
* model update.
*
* Assuming updating to the implied time is valid for the model, the function executes one or more model updates to
* process future time steps for the necessary indexes. Multiple time steps updates occur when the given future time
* step index is not the next time step index to be processed. Regardless, all processed time steps have the size
* supplied in `t_delta`.
*
* However, it is possible to provide `t_index` and `t_delta` values that would result in the aggregate updates taking
* the model's time beyond its `end_time` value. In such cases, if the formulation config indicates this model is
* not allow to exceed its set `end_time`, the function does not update the model and throws an error.
*
* The function will return the value of the primary output variable (see `get_bmi_main_output_var()`) for the given
* time step after the model has been updated to that point. The type returned will always be a `double`, with other
* numeric types being cast if necessary.
*
* The BMI spec requires for variable values to be passed to/from models via as arrays. This function essentially
* treats the variable array reference as if it were just a raw pointer and returns the `0`-th array value.
*
* @param t_index The index of the time step for which to run model calculations.
* @param d_delta_s The duration, in seconds, of the time step for which to run model calculations.
* @return The total discharge of the model for the given time step.
*/
double Bmi_C_Formulation::get_response(time_step_t t_index, time_step_t t_delta) {
if (get_bmi_model() == nullptr) {
throw std::runtime_error("Trying to process response of improperly created BMI C formulation.");
}
if (t_index < 0) {
throw std::invalid_argument("Getting response of negative time step in BMI C formulation is not allowed.");
}
// Use (next_time_step_index - 1) so that second call with current time step index still works
if (t_index < (next_time_step_index - 1)) {
// TODO: consider whether we should (optionally) store and return historic values
throw std::invalid_argument("Getting response of previous time step in BMI C formulation is not allowed.");
}

// The time step delta size, expressed in the units internally used by the model
double t_delta_model_units;
if (next_time_step_index <= t_index) {
t_delta_model_units = get_bmi_model()->convert_seconds_to_model_time((double)t_delta);
double model_time = get_bmi_model()->GetCurrentTime();
// Also, before running, make sure this doesn't cause a problem with model end_time
if (!get_allow_model_exceed_end_time()) {
int total_time_steps_to_process = abs((int)t_index - next_time_step_index) + 1;
if (get_bmi_model()->GetEndTime() < (model_time + (t_delta_model_units * total_time_steps_to_process))) {
throw std::invalid_argument("Cannot process BMI C formulation to get response of future time step "
"that exceeds model end time.");
}
}
}

while (next_time_step_index <= t_index) {
double model_initial_time = get_bmi_model()->GetCurrentTime();
set_model_inputs_prior_to_update(model_initial_time, t_delta);
if (t_delta_model_units == get_bmi_model()->GetTimeStep())
get_bmi_model()->Update();
else
get_bmi_model()->UpdateUntil(model_initial_time + t_delta_model_units);
// TODO: again, consider whether we should store any historic response, ts_delta, or other var values
next_time_step_index++;
}
return get_var_value_as_double( get_bmi_main_output_var());
}

double Bmi_C_Formulation::get_var_value_as_double(const std::string& var_name) {
return get_var_value_as_double(0, var_name);
}
Expand Down
73 changes: 0 additions & 73 deletions src/realizations/catchment/Bmi_Cpp_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,79 +45,6 @@ std::shared_ptr<Bmi_Adapter> Bmi_Cpp_Formulation::construct_model(const geojson:
output);
}

/**
* Get the model response for a time step.
*
* Get the model response for the provided time step, executing the backing model formulation one or more times as
* needed.
*
* Function assumes the backing model has been fully initialized and that any additional input values have been applied.
*
* The function throws an error if the index of a previously processed time step is supplied, except if it is the last
* processed time step. In that case, the appropriate value is returned as described below, but without executing any
* model update.
*
* Assuming updating to the implied time is valid for the model, the function executes one or more model updates to
* process future time steps for the necessary indexes. Multiple time steps updates occur when the given future time
* step index is not the next time step index to be processed. Regardless, all processed time steps have the size
* supplied in `t_delta`.
*
* However, it is possible to provide `t_index` and `t_delta` values that would result in the aggregate updates taking
* the model's time beyond its `end_time` value. In such cases, if the formulation config indicates this model is
* not allow to exceed its set `end_time`, the function does not update the model and throws an error.
*
* The function will return the value of the primary output variable (see `get_bmi_main_output_var()`) for the given
* time step after the model has been updated to that point. The type returned will always be a `double`, with other
* numeric types being cast if necessary.
*
* The BMI spec requires for variable values to be passed to/from models via as arrays. This function essentially
* treats the variable array reference as if it were just a raw pointer and returns the `0`-th array value.
*
* @param t_index The index of the time step for which to run model calculations.
* @param d_delta_s The duration, in seconds, of the time step for which to run model calculations.
* @return The total discharge of the model for the given time step.
*/
double Bmi_Cpp_Formulation::get_response(time_step_t t_index, time_step_t t_delta) {
if (get_bmi_model() == nullptr) {
throw std::runtime_error("Trying to process response of improperly created BMI C++ formulation.");
}
if (t_index < 0) {
throw std::invalid_argument("Getting response of negative time step in BMI C++ formulation is not allowed.");
}
// Use (next_time_step_index - 1) so that second call with current time step index still works
if (t_index < (next_time_step_index - 1)) {
// TODO: consider whether we should (optionally) store and return historic values
throw std::invalid_argument("Getting response of previous time step in BMI C++ formulation is not allowed.");
}

// The time step delta size, expressed in the units internally used by the model
double t_delta_model_units;
if (next_time_step_index <= t_index) {
t_delta_model_units = get_bmi_model()->convert_seconds_to_model_time((double)t_delta);
double model_time = get_bmi_model()->GetCurrentTime();
// Also, before running, make sure this doesn't cause a problem with model end_time
if (!get_allow_model_exceed_end_time()) {
int total_time_steps_to_process = abs((int)t_index - next_time_step_index) + 1;
if (get_bmi_model()->GetEndTime() < (model_time + (t_delta_model_units * total_time_steps_to_process))) {
throw std::invalid_argument("Cannot process BMI C++ formulation to get response of future time step "
"that exceeds model end time.");
}
}
}

while (next_time_step_index <= t_index) {
double model_initial_time = get_bmi_model()->GetCurrentTime();
set_model_inputs_prior_to_update(model_initial_time, t_delta);
if (t_delta_model_units == get_bmi_model()->GetTimeStep())
get_bmi_model()->Update();
else
get_bmi_model()->UpdateUntil(model_initial_time + t_delta_model_units);
// TODO: again, consider whether we should store any historic response, ts_delta, or other var values
next_time_step_index++;
}
return get_var_value_as_double( get_bmi_main_output_var());
}

double Bmi_Cpp_Formulation::get_var_value_as_double(const std::string& var_name) {
return get_var_value_as_double(0, var_name);
}
Expand Down
Loading

0 comments on commit f943886

Please sign in to comment.