Skip to content

Comments

Update ngen to generate catchment output variables in a combined netCDF file (NGWPC-9011)#106

Draft
sivasankkar wants to merge 15 commits intodevelopmentfrom
ssn_9011_netcdf_for_catchments
Draft

Update ngen to generate catchment output variables in a combined netCDF file (NGWPC-9011)#106
sivasankkar wants to merge 15 commits intodevelopmentfrom
ssn_9011_netcdf_for_catchments

Conversation

@sivasankkar
Copy link

@sivasankkar sivasankkar commented Dec 18, 2025

Enable functionality in ngen to write all catchment outputs to a netcdf file.

Additions

  • NetCDFCreator.hpp - header file for creating a class that can handle all netcdf operations.
  • NetCDFCreator.cpp - class file for methods/functions to handle all netcdf operations.
  • NetCDFCreatorTest.cpp - class containing two unit tests - one for the catchment and another for the output values.

Removals

Changes

  • NetCDFCreator.hpp and cpp: Functions to create and write catchment output variables to netcdf file.
  • Bmi_Formulation.hpp: Added get_output_variable_units and set_output_variable_units function to obtain the output variable units to write to netcdf attributes.
  • Bmi_Module_Formulation.cpp and Bmi_Multi_Formulation.cpp: Set the output variable units read from realization config.
  • NgenSimulation.hpp: Included netcdfcreator header and pointer for that class.
  • NgenSimulation.cpp: Added a function call to write the output variable values to netcdf after every time step.
  • Formulation_Manager.hpp: Added a function to retrieve all catchment formulations for iterating through for netcdf creation.
  • Layer.hpp and cpp: Added a function to gather catchment outputs to a vector for each timestep.
  • NGen.cpp: Added a message for MPI runs and a function call to create the NetCDF writer/creator instance for non-MPI runs.
  • CMakeFiles for ngen and test - Created a library for the NetCDFCreator and set up target link libraries appropriately.

Testing

  1. Tested with CNF data with 67 catchments. The NetCDF output file was created successfully for non-MPI runs.
  2. Appropriate log message was added for MPI runs.
  3. Appropriate log message was added when no output variables were mentioned in the realization config.
  4. Unit tests

Screenshots

Notes

Todos

Checklist

  • PR has an informative and human-readable title
  • Changes are limited to a single goal (no scope creep)
  • Code can be automatically merged (no conflicts)
  • Code follows project standards (link if applicable)
  • Passes all existing automated tests
  • Any change in functionality is tested
  • New functions are documented (with a description, list of inputs, and expected output)
  • Placeholder code is flagged / future todos are captured in comments
  • Project documentation has been updated (including the "Unreleased" section of the CHANGELOG)
  • Reviewers requested with the Reviewers tool ➡️

Testing checklist (automated report can be put here)

Target Environment support

  • Linux


NetCDFCreator::NetCDFCreator(std::shared_ptr<realization::Formulation_Manager> manager,
const std::string& output_name,Simulation_Time const& sim_time)
:catchmentNcFile_(manager->get_output_root() + output_name + ".nc",NcFile::replace)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating the file in an initializer means that we can't catch and report errors that might arise.


NetCDFCreator::NetCDFCreator(std::shared_ptr<realization::Formulation_Manager> manager,
const std::string& output_name,Simulation_Time const& sim_time)
:catchmentNcFile_(manager->get_output_root() + output_name + ".nc",NcFile::replace)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file creation (and subsequent writing) needs to be coordinated across MPI processes. One process will do the creation, and then every other process will open the already-created file.

That would be a reason to not do any of the file initialization in the constructor. Instead, from main():

  • Every process constructs an instance of the NetCDFWriter
  • Process with rank == 0 calls the creation/initialization method
  • Every process calls MPI_Barrier
  • Every process (maybe, rank != 0) calls the open method to get the NcFile handle
  • Maybe they all load the NcVars for each variable to be written.

They then later use the open NcFile to putVar individual catchment variables, presumably using the same indexes established for t-route. Maybe the initialization method mentioned above writes a catchment_labels variable to ensure they can be identified later.

std::shared_ptr<Simulation_Time> sim_time_;
NcDim timeDim;
NcDim catchmentsDim;
std::map<std::string, std::shared_ptr<realization::Catchment_Formulation>> formulations;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what Formulation_Manager already owns. Why it is being duplicated?

std::string catchment_id = catchment_val.first;

//iterate through catchment dimension to find the index of the catchment for writing.
//also split the comma separated outputs string to a vector of double values

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this feature designed as taking the string formatted outputs, and then re-parsing them to numeric values? Why are the numeric values not carried from the calculation straight to this output?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants