Deterministic CFD diagnostics¶
NAVIER-CFD 1.1.0 introduces a focused diagnostic foundation for field summaries, conditioned errors, multiphase interface analysis, and worst-case ranking.
These functions are deterministic NumPy operations. They do not rely on language-model numerical reasoning.
Available functions¶
| Function | Purpose |
|---|---|
field_summary |
Summarize finite values, optionally within a mask. |
conditioned_rmse |
Compute RMSE inside a declared condition mask. |
gradient_interface_mask |
Create a high-gradient phase-fraction diagnostic mask. |
analyze_interface_error |
Compare interface and bulk errors. |
rank_worst_cases |
Rank cases by RMSE and report MAE and maximum error. |
Diagnostic workflow¶
flowchart LR
PRED[Predictions]
TRUTH[Targets]
META[Axes, units, masks, normalization]
ALIGN[Shape and semantic alignment]
GLOBAL[Global metrics]
CASE[Worst-case ranking]
COND[Condition masks]
LOCAL[Conditioned diagnostics]
FIND[Evidence-linked findings]
PRED --> ALIGN
TRUTH --> ALIGN
META --> ALIGN
ALIGN --> GLOBAL
ALIGN --> CASE
ALIGN --> COND --> LOCAL
GLOBAL --> FIND
CASE --> FIND
LOCAL --> FIND
Always verify:
- prediction and target shapes;
- case, time, spatial, and channel axes;
- physical units and inverse normalization;
- validity masks;
- geometry correspondence;
- field mapping.
field_summary¶
import numpy as np
from navier_cfd import field_summary
report = field_summary(
velocity_y,
mask=fluid_cells,
)
Output:
{
"count": 18540,
"finite_fraction": 1.0,
"min": -0.82,
"max": 1.47,
"mean": 0.13,
"std": 0.32,
"rms": 0.35
}
Semantics¶
finite_fractionis calculated over the full input array.- Summary statistics use finite values remaining after mask application.
- A mask is broadcast over trailing dimensions.
- Empty finite selection raises a
ValueError.
Uses¶
- detect non-finite values;
- identify impossible ranges;
- compare field scales;
- check inverse normalization;
- report target and prediction distributions.
conditioned_rmse¶
from navier_cfd import conditioned_rmse
boundary_rmse = conditioned_rmse(
prediction,
target,
boundary_mask,
)
The function:
- verifies matching prediction and target shapes;
- broadcasts the condition mask;
- combines it with finite-value masks;
- calculates RMSE only on selected values.
Use it for:
- boundary regions;
- bubble interfaces;
- high-vorticity cells;
- late-time windows;
- specified operating regimes;
- sensor neighborhoods;
- uncertainty quantiles.
The scientific validity depends on how the mask was defined.
gradient_interface_mask¶
from navier_cfd import gradient_interface_mask
interface_mask = gradient_interface_mask(
gas_volume_fraction,
percentile=85.0,
spatial_axes=(1, 2),
)
The function calculates gradients along the declared spatial axes, forms a gradient magnitude, and selects positive finite values at or above the chosen percentile.
flowchart LR
ALPHA[Phase fraction]
GRAD[Spatial gradients]
MAG[Gradient magnitude]
THR[Positive-value percentile]
MASK[Interface proxy mask]
ALPHA --> GRAD --> MAG --> THR --> MASK
Important interpretation¶
The result is a high-gradient diagnostic proxy, not a guaranteed physical interface classifier.
Its meaning depends on:
- grid spacing;
- smoothing and numerical diffusion;
- selected spatial axes;
- percentile;
- phase-fraction noise;
- temporal alignment;
- geometry masks.
For nonuniform grids, derivative-aware methods using physical coordinates should be preferred in future versions.
Failure cases¶
- percentile outside 0–100;
- all gradients equal to zero;
- incorrect axes;
- inclusion of time or channel axes as spatial axes.
analyze_interface_error¶
from navier_cfd import analyze_interface_error
report = analyze_interface_error(
prediction,
target,
gas_volume_fraction,
percentile=85.0,
spatial_axes=(1, 2),
)
Output fields:
| Field | Meaning |
|---|---|
interface_percentile |
Percentile used to construct the mask. |
interface_fraction |
Fraction of phase-fraction array selected. |
interface_rmse |
RMSE within interface-mask cells. |
bulk_rmse |
RMSE outside the interface mask. |
interface_to_bulk_rmse_ratio |
Interface RMSE divided by bulk RMSE. |
interface_squared_error_fraction |
Fraction of total squared error localized in the interface mask. |
Interpretation example¶
interface_fraction = 0.15
interface_squared_error_fraction = 0.62
interface_to_bulk_rmse_ratio = 2.4
This means 15% of the phase-fraction locations contain 62% of the squared error, and RMSE in that region is 2.4 times the bulk RMSE.
It does not prove the model fails because of a particular physical mechanism. It provides evidence for an interface-error hypothesis.
rank_worst_cases¶
from navier_cfd import rank_worst_cases
rows = rank_worst_cases(
predictions,
targets,
case_ids=("vgas_070", "vgas_098", "vgas_139"),
mask=fluid_cells,
top_k=3,
)
for row in rows:
print(row.case_id, row.rmse, row.mae, row.max_abs_error)
The first axis is interpreted as the case axis.
Each CaseError contains:
case_id;rmse;mae;max_abs_error.
Cases with no finite selected values are skipped.
Mask behavior¶
A mask matching the full prediction shape is indexed per case. Otherwise it is broadcast to each case.
Be explicit about whether the mask is:
- common geometry;
- per-case geometry;
- per-time validity;
- per-channel validity.
BubbleNet example¶
import numpy as np
from navier_cfd import (
analyze_interface_error,
field_summary,
rank_worst_cases,
)
pred = np.load("pred_u_g_y.npy")
true = np.load("true_u_g_y.npy")
alpha_g = np.load("ep_g.npy")
case_ids = np.load("case_ids.npy").astype(str)
print("Target:", field_summary(true))
print("Prediction:", field_summary(pred))
worst = rank_worst_cases(
pred,
true,
case_ids=case_ids,
top_k=5,
)
interface = analyze_interface_error(
pred,
true,
alpha_g,
percentile=85,
spatial_axes=(1, 2),
)
A suitable finding would be:
“The five largest-RMSE cases occur at the two highest held-out gas velocities. A gradient-derived mask covering 15% of the domain contains 62% of total squared error.”
A stronger causal statement requires additional experiments.
Diagnostic decision tree¶
flowchart TD
START[High test error]
ALIGN{Arrays and normalization correct?}
FIX[Fix data alignment]
CASE[Rank worst cases]
CLUSTER{Errors cluster by regime?}
COND[Calculate conditioned errors]
PROFILE{Profiles preserved?}
SPECT{High-frequency loss?}
PHYS{Physics metrics valid and passed?}
OOD{Outside validated domain?}
NEXT[Propose smallest discriminating experiment]
START --> ALIGN
ALIGN -- no --> FIX
ALIGN -- yes --> CASE --> CLUSTER
CLUSTER -- yes --> COND
CLUSTER -- no --> PROFILE
COND --> PROFILE
PROFILE --> SPECT --> PHYS --> OOD --> NEXT
Relationship to metric suites¶
The diagnostic functions complement, rather than replace, NAVIER-CFD metric suites.
Use metric suites for standardized comparisons:
data_standard;the_well;realpdebench;fluid_standard.
Use diagnostics to localize and explain performance:
- worst cases;
- selected regions;
- interfaces;
- regimes;
- boundaries;
- time windows.
Current limitations¶
v1.1.0 does not yet include deterministic functions for:
- arbitrary nonuniform-grid derivatives;
- vortex-core detection;
- boundary-layer thickness;
- shock detection;
- particle-cluster statistics;
- spectral conditioned errors;
- uncertainty calibration;
- automatic regime classification;
- connected-component bubble tracking.
These are planned extensions and should not be implied by the current API.