@@ -61,13 +61,29 @@ namespace realization {
6161 }
6262 }
6363
64+ int update_method;
6465 while (next_time_step_index <= t_index) {
6566 double model_initial_time = get_bmi_model ()->GetCurrentTime ();
6667 set_model_inputs_prior_to_update (model_initial_time, t_delta);
67- if (t_delta_model_units == get_bmi_model ()->GetTimeStep ())
68- get_bmi_model ()->Update ();
69- else
70- get_bmi_model ()->UpdateUntil (model_initial_time + t_delta_model_units);
68+ try {
69+ if (t_delta_model_units == get_bmi_model ()->GetTimeStep ()) {
70+ update_method = 0 ;
71+ get_bmi_model ()->Update ();
72+ }
73+ else {
74+ update_method = 1 ;
75+ get_bmi_model ()->UpdateUntil (model_initial_time + t_delta_model_units);
76+ }
77+ } catch (const std::exception &e) {
78+ std::stringstream error_message;
79+ error_message << " Model " << (update_method == 0 ? " Update" : " UpdateUntil" )
80+ << " failed on catchment " << this ->get_catchment_id ()
81+ << " . t_index=" << t_index
82+ << " , next_step_index=" << next_time_step_index << " \n " ;
83+ append_model_inputs_to_stream (model_initial_time, t_delta, error_message);
84+ Logger::Log (LogLevel::FATAL , error_message.str ());
85+ throw ;
86+ }
7187 // TODO: again, consider whether we should store any historic response, ts_delta, or other var values
7288 next_time_step_index++;
7389 }
@@ -717,6 +733,136 @@ namespace realization {
717733 }
718734 }
719735
736+
737+ void Bmi_Module_Formulation::append_model_inputs_to_stream (const double &model_init_time, time_step_t t_delta, std::stringstream &inputs) {
738+ std::vector<std::string> in_var_names = get_bmi_model ()->GetInputVarNames ();
739+ time_t model_epoch_time = convert_model_time (model_init_time) + get_bmi_model_start_time_forcing_offset_s ();
740+ inputs << " Input variables were as follows:" ;
741+
742+ for (std::string & var_name : in_var_names) {
743+ data_access::GenericDataProvider *provider;
744+ std::string var_map_alias = get_config_mapped_variable_name (var_name);
745+ if (input_forcing_providers.find (var_map_alias) != input_forcing_providers.end ()) {
746+ provider = input_forcing_providers[var_map_alias].get ();
747+ }
748+ else if (var_map_alias != var_name && input_forcing_providers.find (var_name) != input_forcing_providers.end ()) {
749+ provider = input_forcing_providers[var_name].get ();
750+ }
751+ else {
752+ provider = forcing.get ();
753+ }
754+
755+ // TODO: probably need to actually allow this by default and warn, but have config option to activate
756+ // this type of behavior
757+ // TODO: account for arrays later
758+ int nbytes = get_bmi_model ()->GetVarNbytes (var_name);
759+ int varItemSize = get_bmi_model ()->GetVarItemsize (var_name);
760+ int numItems = nbytes / varItemSize;
761+
762+ std::shared_ptr<void > value_ptr;
763+ // Finally, use the value obtained to set the model input
764+ std::string type = get_bmi_model ()->get_analogous_cxx_type (get_bmi_model ()->GetVarType (var_name),
765+ varItemSize);
766+
767+ inputs << " \n " << var_map_alias << " = " ;
768+ if (numItems != 1 ) {
769+ // more than a single value needed for var_name
770+ auto values = provider->get_values (CatchmentAggrDataSelector (this ->get_catchment_id (),var_map_alias, model_epoch_time, t_delta,
771+ get_bmi_model ()->GetVarUnits (var_name)));
772+ value_ptr = get_values_as_type ( type, values.begin (), values.end () );
773+ // array like input: precipitation_mm_per_h = [0.2, 0.8, 1.8]
774+ this ->append_inputs (type, value_ptr, numItems, inputs);
775+
776+ } else {
777+ // scalar value
778+ double value = provider->get_value (CatchmentAggrDataSelector (this ->get_catchment_id (),var_map_alias, model_epoch_time, t_delta,
779+ get_bmi_model ()->GetVarUnits (var_name)));
780+ this ->append_input (type, value, inputs);
781+ }
782+ }
783+ }
784+
785+ template <typename T>
786+ void Bmi_Module_Formulation::append_inputs (std::shared_ptr<void > values, int num_items, std::stringstream &inputs) {
787+ T *array = (T*)values.get ();
788+ inputs << " [" ;
789+ for (int i = 0 ; i < num_items; ++i) {
790+ if (i != 0 )
791+ inputs << " , " ;
792+ inputs << array[i];
793+ }
794+ inputs << " ]" ;
795+ }
796+
797+ void Bmi_Module_Formulation::append_inputs (std::string type, std::shared_ptr<void > values, int num_items, std::stringstream &inputs) {
798+
799+ if (type == " double" || type == " double precision" )
800+ this ->append_inputs <double >(values, num_items, inputs);
801+
802+ else if (type == " float" || type == " real" )
803+ this ->append_inputs <float >(values, num_items, inputs);
804+
805+ else if (type == " short" || type == " short int" || type == " signed short" || type == " signed short int" )
806+ this ->append_inputs <short >(values, num_items, inputs);
807+
808+ else if (type == " unsigned short" || type == " unsigned short int" )
809+ this ->append_inputs <unsigned short >(values, num_items, inputs);
810+
811+ else if (type == " int" || type == " signed" || type == " signed int" || type == " integer" )
812+ this ->append_inputs <int >(values, num_items, inputs);
813+
814+ else if (type == " unsigned" || type == " unsigned int" )
815+ this ->append_inputs <unsigned int >(values, num_items, inputs);
816+
817+ else if (type == " long" || type == " long int" || type == " signed long" || type == " signed long int" )
818+ this ->append_inputs <long >(values, num_items, inputs);
819+
820+ else if (type == " unsigned long" || type == " unsigned long int" )
821+ this ->append_inputs <unsigned long >(values, num_items, inputs);
822+
823+ else if (type == " long long" || type == " long long int" || type == " signed long long" || type == " signed long long int" )
824+ this ->append_inputs <long long >(values, num_items, inputs);
825+
826+ else if (type == " unsigned long long" || type == " unsigned long long int" )
827+ this ->append_inputs <unsigned long long >(values, num_items, inputs);
828+
829+ }
830+
831+ template <typename T>
832+ void Bmi_Module_Formulation::append_input (std::string type, T value, std::stringstream &inputs) {
833+
834+ if (type == " double" || type == " double precision" )
835+ inputs << static_cast <double >(value);
836+
837+ else if (type == " float" || type == " real" )
838+ inputs << static_cast <float >(value);
839+
840+ else if (type == " short" || type == " short int" || type == " signed short" || type == " signed short int" )
841+ inputs << static_cast <short >(value);
842+
843+ else if (type == " unsigned short" || type == " unsigned short int" )
844+ inputs << static_cast <unsigned short >(value);
845+
846+ else if (type == " int" || type == " signed" || type == " signed int" || type == " integer" )
847+ inputs << static_cast <int >(value);
848+
849+ else if (type == " unsigned" || type == " unsigned int" )
850+ inputs << static_cast <unsigned int >(value);
851+
852+ else if (type == " long" || type == " long int" || type == " signed long" || type == " signed long int" )
853+ inputs << static_cast <long >(value);
854+
855+ else if (type == " unsigned long" || type == " unsigned long int" )
856+ inputs << static_cast <unsigned long >(value);
857+
858+ else if (type == " long long" || type == " long long int" || type == " signed long long" || type == " signed long long int" )
859+ inputs << static_cast <long long >(value);
860+
861+ else if (type == " unsigned long long" || type == " unsigned long long int" )
862+ inputs << static_cast <unsigned long long >(value);
863+
864+ }
865+
720866 const boost::span<char > Bmi_Module_Formulation::get_serialization_state () const {
721867 auto bmi = this ->bmi_model ;
722868 // create a new serialized state, getting the amount of data that was saved
0 commit comments