OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
Default2DOutputPlugin.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2//
3// Copyright 2026 Caleb Buahin
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
34
35#pragma once
36
37#ifdef OPENSWMM_HAS_2D
38
40
43#include <string>
44#include <memory>
45#include <mutex>
46#include <unordered_map>
47#include <vector>
48#include <hdf5.h>
49
50namespace openswmm {
51class SWMMEngine;
52}
53namespace openswmm::twoD {
54
55struct InertialEdges;
57struct MeshData; // forward declaration
58struct SolverOptions2D; // forward declaration
60
140class Default2DOutputPlugin final : public IOutputPlugin {
141public:
146 explicit Default2DOutputPlugin(std::string h5_path);
147 ~Default2DOutputPlugin() override;
148
149 // Non-copyable
150 Default2DOutputPlugin(const Default2DOutputPlugin&) = delete;
151 Default2DOutputPlugin& operator=(const Default2DOutputPlugin&) = delete;
152
153 // -----------------------------------------------------------------------
154 // IOutputPlugin interface
155 // -----------------------------------------------------------------------
156
163 PluginState state() const noexcept override { return state_; }
164
173 int initialize(const std::vector<std::string>& init_args,
174 const IPluginComponentInfo* info) override;
175
183 int validate(const SimulationContext& ctx) override;
184
199 int prepare(const SimulationContext& ctx) override;
200
210 int update(const SimulationSnapshot& snapshot) override;
211
224 int finalize(const SimulationContext& ctx) override;
225
232 const char* last_error_message() const noexcept override { return last_error_.c_str(); }
233
251 void prepareMeshAndDatasets(const MeshData& mesh);
252
269 void setMeshCoordinateScale(double metres_per_model_unit);
270
291 std::string configureOutput(const SolverOptions2D& opts, double report_step_sec);
292
300 unsigned reportVariables() const noexcept { return report_vars_; }
301
316 void enqueueSourceHistory(std::shared_ptr<const SourceResultHistory> history);
317
318private:
319 friend class openswmm::SWMMEngine;
320 // Internal single-file, water-only continuation. IO must be idle.
321 bool checkpoint_fresh_ = false;
322 bool checkpoint_write_failed_ = false;
323 void checkpointWriteStatus(herr_t);
324 std::string checkpoint_header_;
325 struct PreparedCheckpoint;
326 std::string checkpointBytes(const SimulationContext&, double next_report_ms,
327 const SimulationSnapshot&);
328 std::shared_ptr<PreparedCheckpoint> prepareCheckpoint(const SimulationContext&,
329 double next_report_ms,
330 const SimulationSnapshot&,
331 const SourceResultHistory*, std::string);
332 void installCheckpoint(PreparedCheckpoint&);
333 io::CheckpointOutputPublication::Output checkpointPublication(const PreparedCheckpoint&) const;
334 void adoptCheckpoint(PreparedCheckpoint&) noexcept;
335 void validateCheckpoint(hid_t, const SimulationContext&, double, const SimulationSnapshot&,
336 hsize_t, double, bool) const;
337 std::vector<hid_t*> checkpointDatasets();
338 void closeDatasets() noexcept;
339 std::string fileBytes() const;
340 std::string captureFileCheckpoint(const SimulationContext&, double, const SimulationSnapshot&,
341 const std::filesystem::path&,
342 std::shared_ptr<io::OwnedCheckpointFile>&);
343 std::shared_ptr<PreparedCheckpoint>
344 prepareFileCheckpoint(const SimulationContext&, double, const SimulationSnapshot&, std::string);
345 void resolveCheckpointDatasets(PreparedCheckpoint&, const SimulationSnapshot&);
346 std::mutex source_mutex_;
347 std::vector<std::shared_ptr<const SourceResultHistory>> source_pending_;
348 std::shared_ptr<const SourceResultHistory> source_written_;
349 int writePendingSourceHistory();
350 // ---- results-file size controls (configureOutput) ----
351 hid_t storage_type_ = H5T_NATIVE_DOUBLE;
352 int compression_ = 4;
353 unsigned report_vars_ = 0x7FFu;
354 std::vector<std::string> species_filter_;
355 std::vector<int> species_rows_;
356 double report_2d_step_days_ = 0.0;
357 double next_due_days_ = -1.0;
365 bool want(unsigned bit) const noexcept { return (report_vars_ & bit) != 0; }
378 void writeSpeciesRows(const double* all, hsize_t n_species_in);
379
380 std::string h5_path_;
381 PluginState state_ = PluginState::UNLOADED;
382 std::string last_error_;
383
384 std::unordered_map<std::string, std::string>
385 native_species_units_; // keyed by identity, not surface row
386 std::string model_crs_;
387 double metres_per_model_unit_ = 1.0;
388
389 hid_t file_id_ = H5I_INVALID_HID;
390
391 // Dataset handles for time-varying fields (unlimited time dimension)
392 hid_t ds_time_ = H5I_INVALID_HID;
393 hid_t ds_face_depth_ = H5I_INVALID_HID;
394 hid_t ds_face_head_ = H5I_INVALID_HID;
395 hid_t ds_face_grad_hx_ = H5I_INVALID_HID;
396 hid_t ds_face_grad_hy_ = H5I_INVALID_HID;
397 hid_t ds_face_grad_hx_lim_ = H5I_INVALID_HID;
398 hid_t ds_face_grad_hy_lim_ = H5I_INVALID_HID;
399 hid_t ds_face_rainfall_ = H5I_INVALID_HID;
400 hid_t ds_face_coupling_flux_ = H5I_INVALID_HID;
401 hid_t ds_face_net_source_ = H5I_INVALID_HID;
402 hid_t ds_face_infil_rate_ = H5I_INVALID_HID;
403 hid_t ds_face_infil_cum_ = H5I_INVALID_HID;
404 hid_t ds_face_rain_cum_ = H5I_INVALID_HID;
405 std::array<hid_t, meshSnowFields.size()> ds_snow_ = [] {
406 std::array<hid_t, meshSnowFields.size()> ids;
407 ids.fill(H5I_INVALID_HID);
408 return ids;
409 }();
410 void createSnowDatasets(const SimulationSnapshot&);
411
415 hid_t ds_face_species_conc_ = H5I_INVALID_HID;
416 hsize_t n_species_ = 0;
420 hid_t ds_face_buildup_ = H5I_INVALID_HID;
421 hsize_t n_buildup_ = 0;
428 static constexpr int kGwFaceFields = 27; // G-X3: + Mesh2_face_gw_link_seepage
429 static constexpr hsize_t kGwLedgerTerms = 15; // G-X3: + link (LED 10), residual last
430 hid_t ds_gw_face_[kGwFaceFields] = {
431 H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID,
432 H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID,
433 H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID,
434 H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID,
435 H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID,
436 H5I_INVALID_HID, H5I_INVALID_HID};
437 hid_t ds_gw_ledger_ = H5I_INVALID_HID;
440 static constexpr hsize_t kGwSpeciesLedgerTerms = 15;
441 hid_t ds_gw_sat_conc_ = H5I_INVALID_HID;
442 hid_t ds_gw_unsat_conc_ = H5I_INVALID_HID;
443 hid_t ds_gw_species_ledger_ = H5I_INVALID_HID;
444 hsize_t n_gw_species_ = 0;
445 hid_t ds_gw_bed_exchange_ = H5I_INVALID_HID;
446 hid_t ds_gw_theta_ = H5I_INVALID_HID;
447 hsize_t n_gw_beds_ = 0;
448 hsize_t n_gw_layers_ = 0;
449 hid_t ds_gw_layer_mass_ = H5I_INVALID_HID, ds_gw_layer_conc_ = H5I_INVALID_HID;
450 hid_t ds_gw_boundary_water_ = H5I_INVALID_HID, ds_gw_boundary_species_ = H5I_INVALID_HID;
451 hid_t ds_gw_transport_ledger_ = H5I_INVALID_HID;
452 hsize_t n_gw_transport_layers_ = 0, n_gw_boundaries_ = 0;
453 bool gw_created_ = false;
454 void createGroundwaterDatasets(const SimulationSnapshot& snap);
455 bool heat_created_ = false;
456 hsize_t n_heat_layers_ = 0;
457 hsize_t n_heat_lid_layers_ = 0;
458 hid_t ds_heat_water_temp_ = H5I_INVALID_HID;
459 hid_t ds_heat_bed_temp_ = H5I_INVALID_HID;
460 hid_t ds_heat_bed_energy_ = H5I_INVALID_HID;
461 hid_t ds_heat_bed_initial_energy_ = H5I_INVALID_HID;
462 hid_t ds_heat_bed_capacity_ = H5I_INVALID_HID;
463 hid_t ds_heat_bed_pore_volume_ = H5I_INVALID_HID;
464 hid_t ds_heat_bed_species_conc_ = H5I_INVALID_HID;
465 hid_t ds_heat_bed_species_initial_amount_ = H5I_INVALID_HID;
466 hid_t ds_heat_bed_species_exchange_ = H5I_INVALID_HID;
467 hid_t ds_heat_bed_age_generation_ = H5I_INVALID_HID;
468 hsize_t n_heat_bed_species_ = 0;
469 hid_t ds_heat_surface_budget_ = H5I_INVALID_HID;
470 hid_t ds_heat_evaporation_ = H5I_INVALID_HID;
471 hid_t ds_heat_ground_temp_ = H5I_INVALID_HID;
472 hid_t ds_heat_ground_energy_ = H5I_INVALID_HID;
473 hid_t ds_heat_ground_capacity_ = H5I_INVALID_HID;
474 hid_t ds_heat_layer_temp_ = H5I_INVALID_HID;
475 hid_t ds_heat_layer_energy_ = H5I_INVALID_HID;
476 hid_t ds_heat_layer_capacity_ = H5I_INVALID_HID;
477 hid_t ds_heat_ground_budget_ = H5I_INVALID_HID;
478 hid_t ds_heat_lid_temp_ = H5I_INVALID_HID;
479 hid_t ds_heat_lid_energy_ = H5I_INVALID_HID;
480 hid_t ds_heat_lid_capacity_ = H5I_INVALID_HID;
481 hid_t ds_heat_lid_ground_contact_ = H5I_INVALID_HID;
482 void createThermalDatasets(const SimulationSnapshot& snap);
483 const MeshData* mixing_mesh_ = nullptr; // borrowed immutable prepared geometry
484 std::unique_ptr<InertialEdges> mixing_edges_;
485 std::unique_ptr<MomentumPhysics2D> mixing_diagnostics_;
486 bool mixing_enabled_ = false, momentum_velocity_ = false;
487 double mixing_cs_ = .1, mixing_background_ = 0, mixing_depth_coefficient_ = 0, mixing_dry_ = .001,
488 coriolis_f_ = 0;
489 const char* turbulence_name_ = "NONE";
490 hid_t ds_face_eddy_viscosity_ = H5I_INVALID_HID;
491 hid_t ds_face_strain_rate_ = H5I_INVALID_HID;
492 hid_t ds_face_vx_ = H5I_INVALID_HID;
493 hid_t ds_face_vy_ = H5I_INVALID_HID;
494 hid_t ds_face_continuity_err_ = H5I_INVALID_HID;
495 hid_t ds_edge_flux_ = H5I_INVALID_HID;
496 hid_t ds_node_head_ = H5I_INVALID_HID;
497 hid_t ds_node_depth_ = H5I_INVALID_HID;
498
499 // Cumulative envelopes — fixed [nFace], overwritten in place each update()
500 hid_t ds_face_max_depth_ = H5I_INVALID_HID;
501 hid_t ds_face_max_velocity_ = H5I_INVALID_HID;
502 hid_t ds_face_max_continuity_err_ = H5I_INVALID_HID;
503
504 hsize_t n_faces_ = 0;
505 hsize_t n_nodes_ = 0;
506 hsize_t edge_stride_ = 3;
507 hsize_t n_steps_ = 0;
508
509 // Helpers
517 void writeMeshTopology(const SimulationContext& ctx);
527 void writeCrsVariable();
549 hid_t createUnlimitedDataset(const char* name, int rank, const hsize_t* dims,
550 const hsize_t* chunk_dims, hid_t type = -1);
564 void writeStringAttr(hid_t loc, const char* name, const char* value);
574 void writeDoubleAttr(hid_t loc, const char* name, double value);
589 void extendAndWrite2D(hid_t ds, const double* data, hsize_t n_cols);
608 void extendAndWrite4D(hid_t ds, const double* data, hsize_t a, hsize_t b, hsize_t c);
625 void extendAndWrite3D(hid_t ds, const double* data, hsize_t dim1, hsize_t dim2);
639 hid_t createFaceEnvelopeDataset(const char* name, const char* long_name, const char* units);
651 void writeFaceEnvelope(hid_t ds, const double* data);
652};
653
654} // namespace openswmm::twoD
655
656#endif // OPENSWMM_HAS_2D
Versioned checkpoint file serialization and integrity checks.
Publication of outputs associated with restored checkpoint sessions.
Interface for output-writing plugins.
Definition MomentumPhysics2D.hpp:25
Definition SourceResultHistory.hpp:41
PluginState
Plugin lifecycle states.
Definition PluginState.hpp:86
State state(const FvClosure &table, const Jet &h, const Jet &velocity, uint8_t press)
Construct a differentiated wet face state from depth and velocity.
Definition ImplicitWetKernels.hpp:234
StmtPtr prepare(sqlite3 *db, const std::string &sql)
Prepare the first SQL statement without stepping it.
Definition GpkgUtils.hpp:171
void initialize(SimulationContext &ctx)
Build node-LID hydraulic cells and initial retained/mobile water state.
Definition LidNode.cpp:517
void validate(SimulationContext &ctx)
Validate node-LID model references, layers, supported physics and anchored geometry.
Definition LidNode.cpp:271
Definition ExchangeLaw.hpp:60
Definition ExchangeLaw.hpp:60
constexpr std::array< SnowResultField, 23 > meshSnowFields
Definition SnowResults.hpp:24
Canonical unique interior-edge layout + per-cell incidence for the local-inertial scheme.
Definition InertialEdges.hpp:60
SoA storage for 2D mixed triangle/quad mesh geometry and topology.
Definition MeshData.hpp:65
Definition SolverOptions2D.hpp:257