Preserve all trial preparation and disposition counts in reports
This commit is contained in:
@@ -151,6 +151,8 @@ def build_rows(audits):
|
||||
for key in ("normalized_unbordered_residual", "central_border", "normalized_border_action"):
|
||||
row["final_" + key] = finite(physical18[key], "final " + key, nonnegative=key != "central_border")
|
||||
line_search = case["line_search"]
|
||||
row["line_search_counts"] = {key: line_search[key] for key in
|
||||
("total_trials", "counts_by_source", "counts_by_disposition", "source_disposition_counts")}
|
||||
for key in ("pressure_force_rejections", "residual_metric_rejections"):
|
||||
row[key] = finite(line_search[key], key, True)
|
||||
row["minimum_accepted_alpha"] = line_search["minimum_accepted_alpha"]
|
||||
@@ -178,6 +180,24 @@ def build_rows(audits):
|
||||
return frozen, coupled
|
||||
|
||||
|
||||
def trial_stage_rows(coupled):
|
||||
table = []
|
||||
for row in coupled:
|
||||
counts = row["line_search_counts"]
|
||||
total = 0
|
||||
for stage in counts["source_disposition_counts"]:
|
||||
count = finite(stage["count"], "stage count", True)
|
||||
require(count > 0 and int(count) == count, "Invalid integer stage count")
|
||||
code = finite(stage["disposition_code"], "disposition code", True)
|
||||
require(int(code) == code and code <= 5, "Invalid disposition code")
|
||||
total += count
|
||||
table.append({key: row[key] for key in ("case", "n", "J", "density_degree", "campaign")} |
|
||||
{"source": stage["source"], "disposition": stage["disposition"], "disposition_code": code,
|
||||
"rejected": code != 0, "count": count})
|
||||
require(total == counts["total_trials"], "Joint stage counts do not cover all recorded trials")
|
||||
return table
|
||||
|
||||
|
||||
def comparisons(frozen, coupled):
|
||||
result = []
|
||||
for kind, table in (("frozen", frozen), ("coupled", coupled)):
|
||||
@@ -315,6 +335,20 @@ def plot_figure(frozen, coupled, output):
|
||||
|
||||
|
||||
class Tests(unittest.TestCase):
|
||||
def test_distinct_preparation_stage_counts(self):
|
||||
row = {"case": "sample", "n": 3., "J": 0., "density_degree": 4, "campaign": "recorded",
|
||||
"line_search_counts": {"total_trials": 4, "source_disposition_counts": [
|
||||
{"source": "barotropic closure", "disposition": "inadmissible_state", "disposition_code": 1, "count": 2},
|
||||
{"source": "pressure force", "disposition": "inadmissible_state", "disposition_code": 1, "count": 1},
|
||||
{"source": "", "disposition": "accepted", "disposition_code": 0, "count": 1}]}}
|
||||
table = trial_stage_rows([row])
|
||||
self.assertEqual({r["source"]: r["count"] for r in table}, {"barotropic closure": 2, "pressure force": 1, "": 1})
|
||||
self.assertTrue(table[0]["rejected"])
|
||||
self.assertFalse(table[-1]["rejected"])
|
||||
row["line_search_counts"]["total_trials"] = 5
|
||||
with self.assertRaisesRegex(ValueError, "cover all recorded trials"):
|
||||
trial_stage_rows([row])
|
||||
|
||||
def test_cross_audit_non_density_layout(self):
|
||||
def case(density_size, gravity_size=23):
|
||||
return {"n": 1.5, "J": 0., "block_sizes": {"value/density": density_size,
|
||||
@@ -385,7 +419,13 @@ class Tests(unittest.TestCase):
|
||||
"final_residual": .01, "threshold": 1e-8, "accepted_steps": 1, "linear_iterations": 7,
|
||||
"iteration_seconds": 10., "iterations": [{"linear_seconds": 6.}]},
|
||||
"observer_timings": {"observer_total": 200.}, "run": {"seconds": 215., "utc_minus_monotonic_seconds": .01},
|
||||
"line_search": {"pressure_force_rejections": 4, "residual_metric_rejections": 1, "minimum_accepted_alpha": 1/32},
|
||||
"line_search": {"pressure_force_rejections": 4, "residual_metric_rejections": 1, "minimum_accepted_alpha": 1/32,
|
||||
"total_trials": 6, "counts_by_source": {"pressure force": 4, "residual metric": 1, "": 1},
|
||||
"counts_by_disposition": {"inadmissible_state": 4, "insufficient_decrease": 1, "accepted": 1},
|
||||
"source_disposition_counts": [
|
||||
{"source": "pressure force", "disposition": "inadmissible_state", "disposition_code": 1, "count": 4},
|
||||
{"source": "residual metric", "disposition": "insufficient_decrease", "disposition_code": 4, "count": 1},
|
||||
{"source": "", "disposition": "accepted", "disposition_code": 0, "count": 1}]},
|
||||
"physical": {"14": {"metrics": metrics}, "18": {"metrics": metrics}}}
|
||||
audit = {"artifact_passed": True, "campaigns": {"/recorded/campaign": {
|
||||
"producer_commit": "test", "mesh_sha256": "test", "cases": {"sample": case}}}}
|
||||
@@ -405,6 +445,8 @@ class Tests(unittest.TestCase):
|
||||
self.assertEqual(row["pressure_force_rejections"], 4)
|
||||
self.assertEqual(row["residual_metric_rejections"], 1)
|
||||
self.assertEqual(row["minimum_accepted_alpha"], 1/32)
|
||||
self.assertEqual(row["line_search_counts"], {key: case["line_search"][key] for key in
|
||||
("total_trials", "counts_by_source", "counts_by_disposition", "source_disposition_counts")})
|
||||
|
||||
|
||||
def main():
|
||||
@@ -426,6 +468,7 @@ def main():
|
||||
frozen, coupled = build_rows(inputs)
|
||||
require(frozen or coupled, "No cases in input audits")
|
||||
relative = comparisons(frozen, coupled)
|
||||
stages = trial_stage_rows(coupled)
|
||||
args.output.mkdir(parents=True, exist_ok=False)
|
||||
write_csv(args.output / "frozen_projection.csv", frozen, ["case", "n", "J", "density_degree", "density_dofs",
|
||||
"negative_mass_over_abs_mass", "negative_volume_fraction", "negative_classification", "negative_mass_over_uncertainty_scale",
|
||||
@@ -439,6 +482,8 @@ def main():
|
||||
"h_energy_virial_q14", "h_force_virial_q14", "negative_mass_over_abs_mass", "negative_volume_fraction",
|
||||
"negative_classification", "eos_l2_q30", "eos_rms_q30"])
|
||||
write_csv(args.output / "relative_to_Q2.csv", relative)
|
||||
write_csv(args.output / "trial_stages.csv", stages,
|
||||
["case", "n", "J", "density_degree", "campaign", "source", "disposition", "disposition_code", "rejected", "count"])
|
||||
if not args.tables_only:
|
||||
plot_figure(frozen, coupled, args.output)
|
||||
digest = lambda path: hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
@@ -452,11 +497,12 @@ def main():
|
||||
"Newton seconds sum reported nonlinear-iteration times, excluding observer and setup costs; total elapsed time is kept separately.",
|
||||
"Final unbordered residual, signed central border and normalized border action come from q18 physical diagnostics; bordered convergence does not imply that these vanish.",
|
||||
"Pressure-force and residual-metric rejection counts retain the recorded stage distinction; residual-metric counts include any nonfinite metric failures as well as insufficient decrease.",
|
||||
"All source/disposition counts, including accepted trials, are preserved in trial_stages.csv and JSON; preparation-stage counts alone do not establish where a candidate would fail if processing continued.",
|
||||
"Ratios to Q2 compare recorded endpoints and do not imply equal convergence or error tolerances were attained.",
|
||||
"Undefined values are null/blank; zero is kept exactly. No logarithmic plot floor is inserted.",
|
||||
"Uncertain-only negative observations retain exact table values and appear as separate plot annotations; resolved trends do not connect through them. Colors are stable by (n,J).",
|
||||
"P(h) virial milestones do not establish pointwise density validity; density-based virials are retained separately."],
|
||||
"frozen_projection": frozen, "coupled_outcomes": coupled, "relative_to_Q2": relative,
|
||||
"frozen_projection": frozen, "coupled_outcomes": coupled, "relative_to_Q2": relative, "trial_stages": stages,
|
||||
"artifacts_sha256": {path.name: digest(path) for path in args.output.iterdir() if path.is_file()}}
|
||||
(args.output / "summary.json").write_text(json.dumps(summary, indent=2, allow_nan=False) + "\n")
|
||||
print("Wrote", args.output)
|
||||
|
||||
Reference in New Issue
Block a user