Skip to content

Commit

Permalink
reafctor: Move Formulation::get_output_line_for_timestep implementati…
Browse files Browse the repository at this point in the history
…on from duplicates per-language to Bmi_Module_Formulation
  • Loading branch information
PhilMiller committed Mar 20, 2024
1 parent c0b6216 commit 30f42d9
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 237 deletions.
48 changes: 0 additions & 48 deletions include/realizations/catchment/Bmi_C_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,6 @@ namespace realization {
*/
std::string get_output_header_line(std::string delimiter) override;

/**
* Get a delimited string with all the output variable values for the given time step.
*
* This method is useful for preparing calculated data in a representation useful for output files, such as
* CSV files.
*
* The resulting string contains only the calculated output values for the time step, and not the time step
* index itself.
*
* An empty string is returned if the time step value is not in the range of valid time steps for which there
* are calculated values for all variables.
*
* The default delimiter is a comma.
*
* Implementations will throw `invalid_argument` exceptions if data for the provided time step parameter is not
* accessible. Note that, for this type, only the last processed time step is accessible, because formulations
* do not save results from previous time steps. This also has the consequence of there being no valid set of
* arguments before a least one call to @ref get_response has been made.
*
* @param timestep The time step for which data is desired.
* @return A delimited string with all the output variable values for the given time step.
*/
std::string get_output_line_for_timestep(int timestep, std::string delimiter) override;

/**
* Get the model response for a time step.
*
Expand Down Expand Up @@ -188,30 +164,6 @@ namespace realization {
friend class ::Bmi_Formulation_Test;
friend class ::Bmi_C_Formulation_Test;
friend class ::Bmi_C_Pet_IT;

private:

/**
* Index value (0-based) of the time step that will be processed by the next update of the model.
*
* A formulation time step for BMI types can be thought of as the execution of a call to any of the functions of
* the underlying BMI model that advance the model (either `update` or `update_until`). This member stores the
* ordinal index of the next time step to be executed. Except in the initial formulation state, this will be
* one greater than the index of the last executed time step.
*
* E.g., on initialization, before any calls to @ref get_response, this value will be ``0``. After a call to
* @ref get_response (assuming ``0`` as the passed ``t_index`` argument), time step ``0`` will be processed, and
* this member would be incremented by 1, thus making it ``1``.
*
* The member serves as an implicit marker of how many time steps have been processed so far. Knowing this is
* required to maintain valid behavior in certain things, such as @ref get_response (we may want to process
* multiple time steps forward to a particular index other than the next, but it would not be valid to receive
* a ``t_index`` earlier than the last processed time step) and @ref get_output_line_for_timestep (because
* formulations do not save results from previous time steps, only the results from the last processed time step
* can be used to generate output).
*/
int next_time_step_index = 0;

};

}
Expand Down
7 changes: 0 additions & 7 deletions include/realizations/catchment/Bmi_Cpp_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ namespace realization {

std::string get_output_header_line(std::string delimiter) override;

std::string get_output_line_for_timestep(int timestep, std::string delimiter) 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;
Expand Down Expand Up @@ -55,11 +53,6 @@ namespace realization {
// Unit test access
friend class ::Bmi_Formulation_Test;
friend class ::Bmi_Cpp_Formulation_Test;

private:

int next_time_step_index = 0;

};

}
Expand Down
46 changes: 0 additions & 46 deletions include/realizations/catchment/Bmi_Fortran_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,6 @@ namespace realization {

std::string get_formulation_type() override;

/**
* Get a delimited string with all the output variable values for the given time step.
*
* This method is useful for preparing calculated data in a representation useful for output files, such as
* CSV files.
*
* The resulting string contains only the calculated output values for the time step, and not the time step
* index itself.
*
* An empty string is returned if the time step value is not in the range of valid time steps for which there
* are calculated values for all variables.
*
* The default delimiter is a comma.
*
* Implementations will throw `invalid_argument` exceptions if data for the provided time step parameter is not
* accessible. Note that, for this type, only the last processed time step is accessible, because formulations
* do not save results from previous time steps. This also has the consequence of there being no valid set of
* arguments before a least one call to @ref get_response has been made.
*
* @param timestep The time step for which data is desired.
* @return A delimited string with all the output variable values for the given time step.
*/
std::string get_output_line_for_timestep(int timestep, std::string delimiter) override;

/**
* Get the model response for a time step.
*
Expand Down Expand Up @@ -112,28 +88,6 @@ namespace realization {
friend class ::Bmi_Multi_Formulation_Test;
friend class ::Bmi_Formulation_Test;
friend class ::Bmi_Fortran_Formulation_Test;

private:
/**
* Index value (0-based) of the time step that will be processed by the next update of the model.
*
* A formulation time step for BMI types can be thought of as the execution of a call to any of the functions of
* the underlying BMI model that advance the model (either `update` or `update_until`). This member stores the
* ordinal index of the next time step to be executed. Except in the initial formulation state, this will be
* one greater than the index of the last executed time step.
*
* E.g., on initialization, before any calls to @ref get_response, this value will be ``0``. After a call to
* @ref get_response (assuming ``0`` as the passed ``t_index`` argument), time step ``0`` will be processed, and
* this member would be incremented by 1, thus making it ``1``.
*
* The member serves as an implicit marker of how many time steps have been processed so far. Knowing this is
* required to maintain valid behavior in certain things, such as @ref get_response (we may want to process
* multiple time steps forward to a particular index other than the next, but it would not be valid to receive
* a ``t_index`` earlier than the last processed time step) and @ref get_output_line_for_timestep (because
* formulations do not save results from previous time steps, only the results from the last processed time step
* can be used to generate output).
*/
int next_time_step_index = 0;
};

}
Expand Down
57 changes: 57 additions & 0 deletions include/realizations/catchment/Bmi_Module_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,42 @@ namespace realization {
return available_forcings;
}

/**
* Get a delimited string with all the output variable values for the given time step.
*
* This method is useful for preparing calculated data in a representation useful for output files, such as
* CSV files.
*
* The resulting string contains only the calculated output values for the time step, and not the time step
* index itself.
*
* An empty string is returned if the time step value is not in the range of valid time steps for which there
* are calculated values for all variables.
*
* The default delimiter is a comma.
*
* Implementations will throw `invalid_argument` exceptions if data for the provided time step parameter is not
* accessible. Note that, for this type, only the last processed time step is accessible, because formulations
* do not save results from previous time steps. This also has the consequence of there being no valid set of
* arguments before a least one call to @ref get_response has been made.
*
* @param timestep The time step for which data is desired.
* @return A delimited string with all the output variable values for the given time step.
*/
std::string get_output_line_for_timestep(int timestep, std::string delimiter) override {
// TODO: something must be added to store values if more than the current time step is wanted
// TODO: if such a thing is added, it should probably be configurable to turn it off
if (timestep != (next_time_step_index - 1)) {
throw std::invalid_argument("Only current time step valid when getting output for BMI C++ formulation");
}
std::string output_str;

for (const std::string& name : get_output_variable_names()) {
output_str += (output_str.empty() ? "" : ",") + std::to_string(get_var_value_as_double(name));
}
return output_str;
}

/**
* Get the inclusive beginning of the period of time over which this instance can provide data for this forcing.
*
Expand Down Expand Up @@ -934,6 +970,27 @@ namespace realization {
friend class ::Bmi_Cpp_Formulation_Test;
friend class ::Bmi_Cpp_Multi_Array_Test;

/**
* Index value (0-based) of the time step that will be processed by the next update of the model.
*
* A formulation time step for BMI types can be thought of as the execution of a call to any of the functions of
* the underlying BMI model that advance the model (either `update` or `update_until`). This member stores the
* ordinal index of the next time step to be executed. Except in the initial formulation state, this will be
* one greater than the index of the last executed time step.
*
* E.g., on initialization, before any calls to @ref get_response, this value will be ``0``. After a call to
* @ref get_response (assuming ``0`` as the passed ``t_index`` argument), time step ``0`` will be processed, and
* this member would be incremented by 1, thus making it ``1``.
*
* The member serves as an implicit marker of how many time steps have been processed so far. Knowing this is
* required to maintain valid behavior in certain things, such as @ref get_response (we may want to process
* multiple time steps forward to a particular index other than the next, but it would not be valid to receive
* a ``t_index`` earlier than the last processed time step) and @ref get_output_line_for_timestep (because
* formulations do not save results from previous time steps, only the results from the last processed time step
* can be used to generate output).
*/
int next_time_step_index = 0;

private:
/**
* Whether model ``Update`` calls are allowed and handled in some way by the backing model for time steps after
Expand Down
48 changes: 0 additions & 48 deletions include/realizations/catchment/Bmi_Py_Formulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,6 @@ namespace realization {

std::string get_formulation_type() override;

/**
* Get a delimited string with all the output variable values for the given time step.
*
* This method is useful for preparing calculated data in a representation useful for output files, such as
* CSV files.
*
* The resulting string contains only the calculated output values for the time step, and not the time step
* index itself.
*
* An empty string is returned if the time step value is not in the range of valid time steps for which there
* are calculated values for all variables.
*
* The default delimiter is a comma.
*
* Implementations will throw `invalid_argument` exceptions if data for the provided time step parameter is not
* accessible. Note that, for this type, only the last processed time step is accessible, because formulations
* do not save results from previous time steps. This also has the consequence of there being no valid set of
* arguments before a least one call to @ref get_response has been made.
*
* @param timestep The time step for which data is desired.
* @return A delimited string with all the output variable values for the given time step.
*/
std::string get_output_line_for_timestep(int timestep, std::string delimiter) override;

/**
* Get the model response for a time step.
*
Expand Down Expand Up @@ -121,30 +97,6 @@ namespace realization {
friend class ::Bmi_Formulation_Test;
friend class ::Bmi_Py_Formulation_Test;
friend class ::Bmi_Multi_Formulation_Test;

private:

/**
* Index value (0-based) of the time step that will be processed by the next update of the model.
*
* A formulation time step for BMI types can be thought of as the execution of a call to any of the functions of
* the underlying BMI model that advance the model (either `update` or `update_until`). This member stores the
* ordinal index of the next time step to be executed. Except in the initial formulation state, this will be
* one greater than the index of the last executed time step.
*
* E.g., on initialization, before any calls to @ref get_response, this value will be ``0``. After a call to
* @ref get_response (assuming ``0`` as the passed ``t_index`` argument), time step ``0`` will be processed, and
* this member would be incremented by 1, thus making it ``1``.
*
* The member serves as an implicit marker of how many time steps have been processed so far. Knowing this is
* required to maintain valid behavior in certain things, such as @ref get_response (we may want to process
* multiple time steps forward to a particular index other than the next, but it would not be valid to receive
* a ``t_index`` earlier than the last processed time step) and @ref get_output_line_for_timestep (because
* formulations do not save results from previous time steps, only the results from the last processed time step
* can be used to generate output).
*/
int next_time_step_index = 0;

};

}
Expand Down
25 changes: 0 additions & 25 deletions src/realizations/catchment/Bmi_C_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,6 @@ std::string Bmi_C_Formulation::get_output_header_line(std::string delimiter) {
return boost::algorithm::join(get_output_header_fields(), delimiter);
}

std::string Bmi_C_Formulation::get_output_line_for_timestep(int timestep, std::string delimiter) {
// TODO: something must be added to store values if more than the current time step is wanted
// TODO: if such a thing is added, it should probably be configurable to turn it off
if (timestep != (next_time_step_index - 1)) {
throw std::invalid_argument("Only current time step valid when getting output for BMI C formulation");
}

// TODO: see Github issue 355: this design (and formulation output handling in general) needs to be reworked
// Clear anything currently in there
output_text_stream->str(std::string());

const std::vector<std::string> &output_var_names = get_output_variable_names();
// This probably should never happen, but just to be safe ...
if (output_var_names.empty()) { return ""; }

// Do the first separately, without the leading comma
*output_text_stream << get_var_value_as_double(output_var_names[0]);

// Do the rest with a leading comma
for (int i = 1; i < output_var_names.size(); ++i) {
*output_text_stream << "," << get_var_value_as_double(output_var_names[i]);
}
return output_text_stream->str();
}

/**
* Get the model response for a time step.
*
Expand Down
14 changes: 0 additions & 14 deletions src/realizations/catchment/Bmi_Cpp_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,6 @@ std::string Bmi_Cpp_Formulation::get_output_header_line(std::string delimiter) {
return boost::algorithm::join(get_output_header_fields(), delimiter);
}

std::string Bmi_Cpp_Formulation::get_output_line_for_timestep(int timestep, std::string delimiter) {
// TODO: something must be added to store values if more than the current time step is wanted
// TODO: if such a thing is added, it should probably be configurable to turn it off
if (timestep != (next_time_step_index - 1)) {
throw std::invalid_argument("Only current time step valid when getting output for BMI C++ formulation");
}
std::string output_str;

for (const std::string& name : get_output_variable_names()) {
output_str += (output_str.empty() ? "" : ",") + std::to_string(get_var_value_as_double(name));
}
return output_str;
}

/**
* Get the model response for a time step.
*
Expand Down
24 changes: 0 additions & 24 deletions src/realizations/catchment/Bmi_Fortran_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,30 +92,6 @@ double Bmi_Fortran_Formulation::get_var_value_as_double(const int &index, const
" as double: no logic for converting variable type " + type);
}

std::string Bmi_Fortran_Formulation::get_output_line_for_timestep(int timestep, std::string delimiter) {
// TODO: something must be added to store values if more than the current time step is wanted
// TODO: if such a thing is added, it should probably be configurable to turn it off

// TODO: for now, just get current value, and ignore the timestep param

// TODO: see Github issue 355: this design (and formulation output handling in general) needs to be reworked
// Clear anything currently in there
output_text_stream->str(std::string());

const std::vector<std::string> &output_var_names = get_output_variable_names();
// This probably should never happen, but just to be safe ...
if (output_var_names.empty()) { return ""; }

// Do the first separately, without the leading comma
*output_text_stream << get_var_value_as_double(output_var_names[0]);

// Do the rest with a leading comma
for (int i = 1; i < output_var_names.size(); ++i) {
*output_text_stream << "," << get_var_value_as_double(output_var_names[i]);
}
return output_text_stream->str();
}

/**
* Get the model response for a time step.
*
Expand Down
25 changes: 0 additions & 25 deletions src/realizations/catchment/Bmi_Py_Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,31 +47,6 @@ std::string Bmi_Py_Formulation::get_formulation_type() {
return "bmi_py";
}

std::string Bmi_Py_Formulation::get_output_line_for_timestep(int timestep, std::string delimiter) {
// TODO: something must be added to store values if more than the current time step is wanted
// TODO: if such a thing is added, it should probably be configurable to turn it off
if (timestep != (next_time_step_index - 1)) {
throw std::invalid_argument("Only current time step valid when getting output for BMI Python formulation");
}

// TODO: see Github issue 355: this design (and formulation output handling in general) needs to be reworked
// Clear anything currently in there
output_text_stream->str(std::string());

const std::vector<std::string> &output_var_names = get_output_variable_names();
// This probably should never happen, but just to be safe ...
if (output_var_names.empty()) { return ""; }

// Do the first separately, without the leading comma
*output_text_stream << get_var_value_as_double(output_var_names[0]);

// Do the rest with a leading comma
for (int i = 1; i < output_var_names.size(); ++i) {
*output_text_stream << "," << get_var_value_as_double(output_var_names[i]);
}
return output_text_stream->str();
}

double Bmi_Py_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 Python formulation.");
Expand Down

0 comments on commit 30f42d9

Please sign in to comment.