"""Scalar-history analysis plots: a single value vs. timestep."""
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
from tud_lbm.io.plotting._analysis_common import _BaseAnalysisPlot
from tud_lbm.io.plotting._analysis_common import _extract_rho_2d
from tud_lbm.io.plotting._analysis_common import _extract_u_mag_2d
from tud_lbm.io.plotting._analysis_common import _load_timesteps
from tud_lbm.io.plotting.figure_config import DEFAULT_STYLE
from tud_lbm.registry import comparison_operator
if TYPE_CHECKING:
from pathlib import Path
@comparison_operator(name="max_velocity")
[docs]
class MaxVelocityPlot(_BaseAnalysisPlot):
"""Plot maximum velocity magnitude over time."""
[docs]
title = "Maximum velocity vs timestep"
[docs]
color = DEFAULT_STYLE.colors["max_velocity"]
[docs]
def compute(self, files: list[Path]) -> dict[str, np.ndarray]:
"""Compute maximum velocity values for each timestep file."""
iters, snapshots = _load_timesteps(files, ("u",))
vals = np.asarray([float(np.max(_extract_u_mag_2d(snap["u"]))) for snap in snapshots], dtype=float)
return {"iters": iters, "values": vals}
@comparison_operator(name="density_ratio")
[docs]
class DensityRatioPlot(_BaseAnalysisPlot):
"""Plot max/min density ratio over time."""
[docs]
title = "Density ratio vs timestep"
[docs]
ylabel = "max(rho) / min(rho)"
[docs]
color = DEFAULT_STYLE.colors["density_ratio"]
[docs]
required_keys = ("rho",)
[docs]
def compute(self, files: list[Path]) -> dict[str, np.ndarray]:
"""Compute density ratio values for each timestep file."""
iters, snapshots = _load_timesteps(files, ("rho",))
vals = []
for snap in snapshots:
rho = _extract_rho_2d(snap["rho"])
min_rho = float(np.min(rho))
safe_min = min_rho if min_rho > 0 else max(min_rho, 1e-30)
vals.append(float(np.max(rho)) / safe_min if safe_min != 0 else np.inf)
return {"iters": iters, "values": np.asarray(vals, dtype=float)}
@comparison_operator(name="avg_density")
[docs]
class AvgDensityPlot(_BaseAnalysisPlot):
"""Plot average density over time."""
[docs]
title = "Average density vs timestep"
[docs]
color = DEFAULT_STYLE.colors["avg_density"]
[docs]
required_keys = ("rho",)
[docs]
def compute(self, files: list[Path]) -> dict[str, np.ndarray]:
"""Compute average density values for each timestep file."""
iters, snapshots = _load_timesteps(files, ("rho",))
vals = np.asarray([float(np.mean(_extract_rho_2d(snap["rho"]))) for snap in snapshots], dtype=float)
return {"iters": iters, "values": vals}
@comparison_operator(name="total_mass")
[docs]
class TotalMassPlot(_BaseAnalysisPlot):
"""Plot total domain mass (sum of rho) over time."""
[docs]
title = "Total mass vs timestep"
[docs]
color = DEFAULT_STYLE.colors["total_mass"]
[docs]
required_keys = ("rho",)
[docs]
def compute(self, files: list[Path]) -> dict[str, np.ndarray]:
"""Compute total mass values for each timestep file."""
iters, snapshots = _load_timesteps(files, ("rho",))
vals = np.asarray([float(np.sum(_extract_rho_2d(snap["rho"]))) for snap in snapshots], dtype=float)
return {"iters": iters, "values": vals}