#!/usr/bin/env python3 """Read-only, standard-library summary of geometry_quality_experiment artifacts.""" import argparse import csv import math from pathlib import Path def rows(path): if not path.exists(): return [] with path.open(newline="") as stream: return list(csv.DictReader(stream)) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("directory", type=Path) args = parser.parse_args() root = args.directory print("GEOMETRY (boundaries are censored at alpha=1)") for path in sorted(root.glob("*_geometry_elements.csv")): data = rows(path) limited = [r for r in data if r["limited"] == "1"] if not limited: print(path.stem, "no sampled boundary <=1") continue first = limited[0] boundary = float(first["boundary_step"]) ties = [r["element"] for r in limited if float(r["boundary_step"]) <= boundary * (1 + 1e-6)] print(path.stem, f"boundary={boundary:.10g}", f"limiter={first['element']}", f"attr={first['attribute']}", f"ties_1ppm={','.join(ties)}", f"radial_gradient={float(first['limiter_radial_gradient']):.7g}") for key in first: if "reference" in key and ("sigma" in key or "det" in key): print(" ", key, first[key]) print("\nLINEAR SOLVES") for row in rows(root / "solves.csv"): print(row) print("\nSURFACE (unweighted nodal fractional changes)") for row in rows(root / "surface_summary.csv"): print(row) surface_rows = rows(root / "surface.csv") for case in sorted({r["case"] for r in surface_rows}): groups = {} for row in surface_rows: if row["case"] != case: continue radius = float(row["radius"]) key = tuple(sorted(round(abs(float(row[c]) / radius), 8) for c in ("x", "y", "z"))) groups.setdefault(key, []).append(float(row["correction_fraction"])) print(case, "cubic_symmetry_groups=", len(groups), "max_within_group_spread=", max((max(v) - min(v) for v in groups.values()), default=math.nan)) print("\nACCEPTED RESIDUAL BLOCKS") for row in rows(root / "blocks.csv"): if row["case"] == "accepted" and row["kind"] == "residual": print(row["block"], "normalized_l2=" + row["normalized_l2"]) print("\nFINITE DIFFERENCES") for row in rows(root / "finite_differences.csv"): if float(row["action_norm"]) > 1e-12: print(row["epsilon"], row["row"], "relative_error=" + row["relative_error"]) print("\nMAPPING CHECKS") for path in sorted(root.glob("*_geometry_mapping_checks.csv")): data = rows(path) errors = [float(r["relative_mapping_matrix_error"]) for r in data] errors = [v for v in errors if math.isfinite(v)] print(path.stem, "max_matrix_error=", max(errors, default=math.nan), "invalid_samples=", sum(not math.isfinite(float(r["direct_det"])) for r in data)) print("\nEXTENSION CHECKS") for row in rows(root / "extension_checks.csv"): print(row) print("\nCORE DIAGONAL AT NEWTON LIMITER") steps = {r["case"]: float(r["safe_step"]) for r in rows(root / "solves.csv")} for path in sorted(root.glob("*_core_diagonal.csv")): data = rows(path) for row in data: if abs(float(row["s"]) - 0.010885670926971493) < 1e-12: print(path.stem, "actual_u=", row["actual_radial_displacement"], "desired_u=", row["desired_radial_displacement"], "actual_gradient=", row["actual_radial_gradient"], "desired_gradient=", row["desired_radial_gradient"]) case = path.stem.removesuffix("_core_diagonal") for alpha in sorted({1.0, steps.get(case, 1.0)}): determinants = [] for row in data: if "relative_det_coefficient_0" not in row: continue c = [float(row[f"relative_det_coefficient_{i}"]) for i in range(4)] det = ((c[3] * alpha + c[2]) * alpha + c[1]) * alpha + c[0] determinants.append((det, float(row["s"]))) if determinants: print(" ", case, "alpha=", alpha, "min_diagonal_det_and_s=", min(determinants)) if __name__ == "__main__": main()