Reading Outputs

A pipeline run writes each output as an XDMF+H5 pair. This page shows the four things you typically do with them: open them in ParaView, load a timeseries into pandas, export to CSV, quick-plot, and round-trip the embedded reproducibility metadata. The examples assume the Cp output from Getting Started (out/cp.time_series.h5 and out/cp.stats.h5).

Open in ParaView

Open the .xdmf sidecar, not the .h5:

paraview out/cp.stats.xdmf

ParaView reads the geometry and the per-triangle fields (mean / rms / min / max for a stats file; the per-timestep Cp for a time-series file) directly through the XDMF description; the .h5 next to it supplies the arrays.

Into a pandas DataFrame

cfdmod.read_timeseries_df() flattens a coefficient timeseries into a wide-form DataFrame indexed by normalized time, one column per triangle:

from cfdmod import read_timeseries_df

df = read_timeseries_df("out/cp.time_series.h5", "cp", triangles=[0, 1, 2])
#   index   -> time_normalized
#   columns -> triangle indices 0, 1, 2
#   values  -> Cp(t, triangle)

The second argument is the coefficient group inside the file: "cp" in a Cp file, "cf_x" / "cf_y" / "cf_z" in a Cf file, "cm_x" / "cm_y" / "cm_z" in a Cm file.

Because a per-triangle Cp file can be tens of thousands of columns wide, read_timeseries_df refuses to return more than max_columns (200 by default) unless you narrow it:

  • triangles=[...] – keep an explicit subset of triangle indices.

  • regions=True – for Cf / Cm files, where every triangle in a region carries the same value, deduplicate to one representative column per region. Do not use this on per-triangle Cp.

  • timestep_range=(t_min, t_max) – restrict to a raw-time window before building the frame.

# Cf: one column per body/region, windowed in time
cf = read_timeseries_df(
    "out/cf_x.time_series.h5", "cf_x",
    regions=True, timestep_range=(0.0, 5.0),
)

Export to CSV

cfdmod.to_csv() writes the wide-form frame (first column time_normalized, one column per retained triangle/region) – it drops straight into a spreadsheet. Extra keyword arguments pass through to pandas.DataFrame.to_csv:

from cfdmod import to_csv

to_csv(df, "out/cp_selected.csv")

Quick plot

cfdmod.plot_timeseries() is a one-line matplotlib plot of the frame, returning the Axes so you can keep styling it:

from cfdmod import plot_timeseries

ax = plot_timeseries(df, title="Cp on selected triangles", ylabel="Cp")
ax.figure.savefig("out/cp_selected.png", dpi=150)

Reproducibility metadata

You can embed the parameters that produced a result as HDF5 attributes plus a YAML string dataset under /{group}/processing_metadata, so the file records how it was made. cfdmod.write_processing_metadata() attaches the record to an existing output group; cfdmod.read_processing_metadata() reads it back:

from cfdmod import write_processing_metadata, read_processing_metadata

write_processing_metadata(
    "out/cp.stats.h5", "stats",
    {"note": "galpao Cp demo", "dynamic_pressure_factor": 800.0},
)

meta = read_processing_metadata("out/cp.stats.h5", "stats")
meta["config"]          # -> {'note': 'galpao Cp demo', 'dynamic_pressure_factor': 800.0}
meta["cfdmod_version"]  # package version that wrote the record
meta["produced_at"]     # ISO-8601 UTC timestamp

The config dict is free-form – record whatever parameters you want to reproduce. Both helpers live in cfdmod.io.xdmf.