Improvements to VTU output - #631
Conversation
…iles to be greater than 0
There was a problem hiding this comment.
Pull request overview
This PR improves VTK/VTU output usability and correctness when visualizing solver results (e.g., in ParaView) by exporting physical time metadata, aligning timestep indexing with viewers by optionally exporting the initial condition, and providing a switch to persist Domain_ID across all saved frames.
Changes:
- Add VTK
TimeValuefield-data output for VTU/VTP writers and set it on VTU outputs (and URIS outputs) to expose physical time in viewers. - Export the initial condition as
*_000.vtuwhenStart_saving_after_time_step == 0(non-restart path), and ensure CEP ionic-model initial membrane potential is copied into the initial solution state. - Add
Save_domain_ID_in_every_fileparameter (default off) and thread it throughComMod/MPI distribution to optionally exportDomain_IDevery timestep; also validate VTK/restart save increments are>= 1and fix defaults.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Code/Source/solver/VtkData.h | Adds set_time_value() API to VTK writer abstraction. |
| Code/Source/solver/VtkData.cpp | Implements writing TimeValue field data for VTP/VTU outputs. |
| Code/Source/solver/vtk_xml.cpp | Sets TimeValue on VTU output (non-averaged) and extends Domain_ID emission conditions. |
| Code/Source/solver/uris.cpp | Sets TimeValue on URIS VTU outputs. |
| Code/Source/solver/Simulation.cpp | Wires new Save_domain_ID_in_every_file parameter into ComMod. |
| Code/Source/solver/Parameters.h | Adds save_domain_id_in_every_file to general simulation parameters. |
| Code/Source/solver/Parameters.cpp | Sets valid default save increments (1) and enforces >= 1; registers new domain ID toggle parameter. |
| Code/Source/solver/main.cpp | Writes initial-condition VTU before entering the time loop when configured. |
| Code/Source/solver/initialize.cpp | Updates CEP initialization call to provide solution state for initialization consistency. |
| Code/Source/solver/distribute.cpp | Broadcasts alwaysSaveDomainID across MPI ranks. |
| Code/Source/solver/ComMod.h | Adds alwaysSaveDomainID flag; removes unused sepOutput. |
| Code/Source/solver/ComMod.cpp | Initializes new alwaysSaveDomainID member; removes sepOutput init. |
| Code/Source/solver/cep_ion.h | Updates cep_init() signature and documents behavior. |
| Code/Source/solver/cep_ion.cpp | Copies initialized action potential into the initial solution velocity so initial exports reflect ionic model state. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #631 +/- ##
==========================================
+ Coverage 72.86% 73.11% +0.25%
==========================================
Files 258 259 +1
Lines 39486 39445 -41
Branches 6724 6672 -52
==========================================
+ Hits 28771 28841 +70
+ Misses 10472 10361 -111
Partials 243 243 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
mrp089
left a comment
There was a problem hiding this comment.
Thank you, @michelebucelli! Looks good. Only idea I would have is add TimeValue to some of the integration tests as a check.
|
@mrp089 That's a good idea! I have updated the integration tests (in this commit) so that they all check the computed TimeValue against an expected one. The expected one is not read from the reference solution, but rather determined based on time step size and number of timesteps from the simulation. |
There was a problem hiding this comment.
🟡 Changes recommended
The VtkData refactor introduces concrete correctness issues in VTP writing (cell insertion/array selection and tuple-count validation) that can crash or break existing output paths.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
Code/Source/solver/VtkData.cpp:635
- VtkVtpData::insert_cell() always inserts into vtkPolyData::Polys and never initializes the underlying vtkCellArray. This can crash (GetPolys() may be null) and also produces incorrect output for 1D faces where cell_type() returns VTK_LINE (those should be stored in Lines, not Polys).
void VtkVtpData::insert_cell(int vtk_cell_type,
vtkSmartPointer<vtkIdList> elem_nodes) {
// A vtkPolyData derives the type of a polygon from its number of points, so
// vtk_cell_type is not needed here.
vtk_polydata->GetPolys()->InsertNextCell(elem_nodes);
}
Code/Source/solver/VtkData.cpp:63
- get_connectivity() allocates the output array using num_points_per_elem_ (from the first cell), but then iterates up to each cell's actual number of points without validation. If a file contains mixed cell types (or corrupt data), this will write past the allocated row count. Validate that all cells have the expected number of points (and use a smart pointer to avoid leaking vtkGenericCell).
Array<int> VtkData::get_connectivity() const {
Array<int> connectivity(num_points_per_elem_, num_elems_);
auto cell = vtkGenericCell::New();
for (int i = 0; i < num_elems_; i++) {
vtk_data->GetCell(i, cell);
const int num_cell_pts = cell->GetNumberOfPoints();
for (int j = 0; j < num_cell_pts; ++j) {
connectivity(j, i) = cell->PointIds->GetId(j);
}
- Files reviewed: 18/18 changed files
- Comments generated: 3
- Review effort level: Lite
…ay GlobalElementID
Fixes #618.
Current situation
Release Notes
Major
TimeValuefield attribute containing the time, which viewers such as ParaView use to properly show the physical time in the UI.Start_saving_after_time_step == 0, then the initial condition is exported toresult_000.vtu. This improves the alignment between timestep indices in the simulation and viewers (on top of allowing to view the initial solution). This can be disabled by settingStart_saving_after_time_stepto anything strictly greater than 0.General_simulation_parameters/Save_domain_ID_in_every_filetoggles exporting theDomain_IDfield to every timestep, instead of just the first. It is disabled by default (meaning that the default is the same as the current state). If enabled, it allows e.g. thresholding the simulation results based on subdomains.Minor
Increment_in_saving_VTK_filesandIncrement_in_saving_restart_filesdefaulted to the invalid value 0, and there was no check that they are>= 1. I changed the default value to1, and introduced those assertions.ComMod::sepOutput.Documentation
Newly added or modified variables and functions have been given Doxygen documentation.
Testing
Automatic tests all pass after the changes.
Code of Conduct & Contributing Guidelines