diff --git a/include/realizations/coastal/SchismFormulation.hpp b/include/realizations/coastal/SchismFormulation.hpp index 9ed96e4735..22d63d6571 100644 --- a/include/realizations/coastal/SchismFormulation.hpp +++ b/include/realizations/coastal/SchismFormulation.hpp @@ -49,14 +49,18 @@ class SchismFormulation final : public CoastalFormulation std::unique_ptr bmi_; enum ForcingSelector { METEO, OFFSHORE, INFLOW }; - static std::map expected_input_variables_; + struct InputMapping { ForcingSelector selector; std::string name; }; + static std::map expected_input_variables_; std::map input_variable_units_; std::map input_variable_type_; std::map input_variable_count_; static std::vector exported_output_variable_names_; + std::map output_variable_units_; + std::map output_variable_type_; + std::map output_variable_count_; - std::chrono::time_point current_time_; + std::chrono::time_point current_time_; std::chrono::seconds time_step_length_; // TODO: Some of these maybe should be members of diff --git a/src/realizations/coastal/SchismFormulation.cpp b/src/realizations/coastal/SchismFormulation.cpp index 2e745032b8..590aae08b1 100644 --- a/src/realizations/coastal/SchismFormulation.cpp +++ b/src/realizations/coastal/SchismFormulation.cpp @@ -7,26 +7,26 @@ const static auto s_schism_registration_function = "register_bmi"; -std::map SchismFormulation::expected_input_variables_ = +std::map SchismFormulation::expected_input_variables_ = { /* Meteorological Forcings */ // RAINRATE - precipitation - {"RAINRATE", SchismFormulation::METEO}, + {"RAINRATE", { SchismFormulation::METEO, "RAINRATE"}}, // SFCPRS - surface atmospheric pressure - {"SFCPRS", SchismFormulation::METEO}, + {"SFCPRS", { SchismFormulation::METEO, "PSFC"}}, // SPFH2m - specific humidity at 2m - {"SPFH2m", SchismFormulation::METEO}, + {"SPFH2m", { SchismFormulation::METEO, "Q2D"}}, // TMP2m - temperature at 2m - {"TMP2m", SchismFormulation::METEO}, + {"TMP2m", { SchismFormulation::METEO, "T2D"}}, // UU10m, VV10m - wind velocity components at 10m - {"UU10m", SchismFormulation::METEO}, - {"VV10m", SchismFormulation::METEO}, + {"UU10m", { SchismFormulation::METEO, "U2D"}}, + {"VV10m", { SchismFormulation::METEO, "V2D"}}, /* Input Boundary Conditions */ // ETA2_bnd - water surface elevation at the boundaries - {"ETA2_bnd", SchismFormulation::OFFSHORE}, + {"ETA2_bnd", { SchismFormulation::OFFSHORE, "ETA2_bnd"}}, // Q_bnd - flows at boundaries - {"Q_bnd", SchismFormulation::INFLOW}, + {"Q_bnd", { SchismFormulation::INFLOW, "Q_bnd"}}, }; std::vector SchismFormulation::exported_output_variable_names_ = @@ -57,7 +57,7 @@ SchismFormulation::SchismFormulation( , init_config_path , /* model_time_step_fixed = */ true , s_schism_registration_function - , MPI_COMM_WORLD + , MPI_COMM_SELF ); } @@ -77,6 +77,20 @@ void SchismFormulation::initialize() input_variable_count_[name] = mesh_size(name); } + auto const& output_vars = bmi_->GetOutputVarNames(); + + for (auto const& name : output_vars) { + //if (expected_output_variables_.find(name) == expected_output_variables_.end()) { + // throw std::runtime_error("SCHISM instance requests unexpected output variable '" + name + "'"); + //} + + output_variable_units_[name] = bmi_->GetVarUnits(name); + output_variable_type_[name] = bmi_->GetVarType(name); + output_variable_count_[name] = mesh_size(name); + } + + time_step_length_ = std::chrono::seconds((long long)bmi_->GetTimeStep()); + set_inputs(); } @@ -92,9 +106,11 @@ void SchismFormulation::finalize() void SchismFormulation::set_inputs() { for (auto var : expected_input_variables_) { - auto& name = var.first; - auto selector = var.second; - auto points = MeshPointsSelector{name, current_time_, time_step_length_, input_variable_units_[name], all_points}; + auto const& name = var.first; + auto const& mapping = var.second; + auto selector = mapping.selector; + auto const& source_name = mapping.name; + auto points = MeshPointsSelector{source_name, current_time_, time_step_length_, input_variable_units_[name], all_points}; ProviderType* provider = [this, selector](){ switch(selector) { @@ -104,13 +120,15 @@ void SchismFormulation::set_inputs() default: throw std::runtime_error("Unknown SCHISM provider selector type"); } }(); - std::vector values = provider->get_values(points); - bmi_->SetValue(name, values.data()); + std::vector buffer(mesh_size(name)); + provider->get_values(points, buffer); + bmi_->SetValue(name, buffer.data()); } } void SchismFormulation::update() { + current_time_ += time_step_length_; set_inputs(); bmi_->Update(); } @@ -166,5 +184,4 @@ size_t SchismFormulation::mesh_size(std::string const& variable_name) return nbytes / itemsize; } - #endif // NGEN_WITH_BMI_FORTRAN && NGEN_WITH_MPI diff --git a/test/coastal/SchismFormulation_Test.cpp b/test/coastal/SchismFormulation_Test.cpp index 38caccd23e..e342b91047 100644 --- a/test/coastal/SchismFormulation_Test.cpp +++ b/test/coastal/SchismFormulation_Test.cpp @@ -2,9 +2,13 @@ #include #include "realizations/coastal/SchismFormulation.hpp" +#include +#include +#include const static std::string library_path = "/Users/phil/Code/noaa/BUILD/bmischism_2024-08-19-ngen/libtestbmifortranmodel.dylib"; const static std::string init_config_path = "/Users/phil/Code/noaa/SCHISM_Lake_Champlain_BMI_test/namelist.input"; +const static std::string met_forcing_netcdf_path = "/Users/phil/Code/noaa/NextGen_Forcings_Engine_SCHISM_Lake_Champlain_2015120100.nc"; #if 0 struct Schism_Formulation_IT : public ::testing::Test @@ -54,13 +58,13 @@ struct MockProvider : data_access::DataProvider size_t get_ts_index_for_time(const time_t &epoch_time) const override { return 1; } data_type get_value(const selection_type& selector, data_access::ReSampleMethod m) override { return data[0]; } - std::vector get_values(const selection_type& selector, data_access::ReSampleMethod) override + std::vector get_values(const selection_type& selector, data_access::ReSampleMethod m) override { throw ""; return data; } + void get_values(const selection_type& selector, boost::span out_data) override { auto default_value = input_variables_defaults[selector.variable_name]; - for (auto& val : data) { + for (auto& val : out_data) { val = default_value; } - return data; } }; @@ -70,17 +74,77 @@ int main(int argc, char **argv) MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); auto provider = std::make_shared(); + + std::tm start_time_tm{}; + start_time_tm.tm_year = 2015 - 1900; + start_time_tm.tm_mon = 12 - 1; + start_time_tm.tm_mday = 1; + auto start_time_t = std::mktime(&start_time_tm); + + std::tm stop_time_tm{}; + stop_time_tm.tm_year = 2015 - 1900; + stop_time_tm.tm_mon = 12 - 1; + stop_time_tm.tm_mday = 2; + auto stop_time_t = std::mktime(&stop_time_tm); + + auto netcdf_met_provider = std::make_shared(met_forcing_netcdf_path, + std::chrono::system_clock::from_time_t(start_time_t), + std::chrono::system_clock::from_time_t(stop_time_t)); auto schism = std::make_unique(/*id=*/ "test_schism_formulation", library_path, init_config_path, - provider, + netcdf_met_provider, provider, provider ); schism->initialize(); + for (int i = 0; i < 3; ++i) + schism->update(); + + using namespace std::chrono_literals; + + auto report = [](std::vector const& data, std::string name) { + double min = 10e6, max = -10e6; + for (int i = 0; i < data.size(); ++i) { + double val = data[i]; + if (std::isnan(val)) { + std::cout << "Nan found at " << i << std::endl; + break; + } + + min = std::min(val, min); + max = std::max(val, max); + } + std::cout << name << " ranges from " << min << " to " << max << std::endl; + }; + + std::vector bedlevel(278784, std::numeric_limits::quiet_NaN()); + MeshPointsSelector bedlevel_selector{"BEDLEVEL", std::chrono::system_clock::now(), 3600s, "m", all_points}; + schism->get_values(bedlevel_selector, bedlevel); + report(bedlevel, "BEDLEVEL"); + + std::vector eta2(278784, std::numeric_limits::quiet_NaN()); + MeshPointsSelector eta2_selector{"ETA2", std::chrono::system_clock::now(), 3600s, "m", all_points}; + schism->get_values(eta2_selector, eta2); + report(eta2, "ETA2"); + + std::vector vx(278784, std::numeric_limits::quiet_NaN()); + MeshPointsSelector vx_selector{"VX", std::chrono::system_clock::now(), 3600s, "m s-1", all_points}; + schism->get_values(vx_selector, vx); + report(vx, "VX"); + + std::vector vy(278784, std::numeric_limits::quiet_NaN()); + MeshPointsSelector vy_selector{"VY", std::chrono::system_clock::now(), 3600s, "m s-1", all_points}; + schism->get_values(vy_selector, vy); + report(vy, "VY"); + schism->update(); + schism->get_values(vx_selector, vx); + schism->get_values(vy_selector, vy); + report(vx, "VX"); + report(vy, "VY"); schism->finalize(); MPI_Finalize();