#!/usr/bin/env python3 """Read completed/partial pressure diagnostics; never launch a solver or modify inputs.""" import argparse import csv import json import math from pathlib import Path ROOT = Path(__file__).resolve().parent ITERATIONS = (2, 3, 4, 7, 11) def rows(path): if not path.exists(): return [] with path.open() as stream: return [r for r in csv.DictReader(stream) if None not in r and all(v is not None for v in r.values())] def metrics(path): return {r['metric']: float(r['value']) for r in rows(path)} def metadata(path): if not path.exists(): return {} return dict(line.split('=', 1) for line in path.read_text().splitlines() if '=' in line) def numeric(row): result = {} for key, value in row.items(): try: result[key] = float(value) except ValueError: result[key] = value return result def negative_h_rejection(row): # Enums at source9e1b65d: thermodynamic_domain=2, pressure_force=6, # outside_domain=5. The prepared pressure operator emits this for h<0. return all(float(row.get(k, -999)) == v for k, v in [('admissible', 0), ('reason', 2), ('stage', 6), ('eos_code', 5)]) def sanitize(value): if isinstance(value, float) and not math.isfinite(value): return None if isinstance(value, dict): return {k: sanitize(v) for k, v in value.items()} if isinstance(value, list): return [sanitize(v) for v in value] return value def case(iteration): folder = ROOT / 'focused' / f'n1_J0p10_iteration_{iteration}' capture = metadata(ROOT / 'captures/n1_J0p10_capture' / f'capture_{iteration}/capture.txt') bound = metrics(folder / 'frozen_enthalpy_bound.csv') inputs = metrics(folder / 'frozen_input_checks.csv') replay = rows(folder / 'replayed_candidate.csv') trial_rows = rows(folder / 'pressure_obstruction_trials.csv') limits = [numeric(r) for r in rows(folder / 'pressure_obstruction_limits.csv')] summary = metrics(folder / 'pressure_obstruction_summary.csv') live = next((r for r in rows(ROOT / 'captures/n1_J0p10_capture/newton.csv') if int(r['iteration']) == iteration), None) result = {'iteration': iteration, 'folder': str(folder), 'capture': capture, 'bounds': bound, 'input_checks': inputs, 'limits': limits, 'exact_candidate': numeric(replay[0]) if replay else None, 'exact_candidate_confirms_pressure_negative_h': negative_h_rejection(replay[0]) if replay else None, 'restoration_completed': 'final_restoration_residual_difference' in inputs, 'pressure_trials_completed': len(trial_rows), 'pressure_trials_expected': summary.get('candidate_trial_count'), 'trial_checks': [], 'live_newton_step': numeric(live) if live else None} result['pressure_grid_complete'] = (summary.get('candidate_trial_count') is not None and len(trial_rows) == summary['candidate_trial_count']) if capture: result['direction_roundoff_relative_estimate'] = ( float(capture['direction_roundoff_scale_estimate']) / float(capture['direction_norm'])) if bound: result['closure_to_pressure_bound_ratio'] = bound['closure_alpha_h'] / bound['pressure_alpha_h'] result['exact_first_trial_over_pressure_bound'] = float(capture['first_trial_alpha']) / bound['pressure_alpha_h'] if live: result['accepted_alpha_over_union_bound'] = float(live['alpha']) / bound['alpha_thermodynamic'] result['tightest_sampled_family'] = ('closure' if bound['closure_alpha_h'] < bound['pressure_alpha_h'] else 'pressure' if bound['pressure_alpha_h'] < bound['closure_alpha_h'] else 'tie') midpoint = .5 * (bound['closure_alpha_h'] + bound['pressure_alpha_h']) result['between_bounds_midpoint'] = { 'alpha': midpoint, 'closure_limiting_h_prediction': bound['limiting_h'] + midpoint * bound['limiting_dh'], 'pressure_limiting_h_prediction': bound['pressure_limiting_h'] + midpoint * bound['pressure_limiting_dh'], } for row in trial_rows: r = numeric(row) errors = [abs(r[f'{family}_limiting_h_evaluated'] - r[f'{family}_limiting_h_prediction']) for family in ('pressure', 'closure')] sign_checks = [((r[f'{family}_limiting_h_evaluated'] < 0) == (r[f'{family}_limiting_h_prediction'] < 0)) for family in ('pressure', 'closure')] ratio = r['alpha_over_union_bound'] r['maximum_limiting_h_evaluation_prediction_absolute_difference'] = max(errors) r['both_limiting_point_signs_match_prediction'] = all(sign_checks) r['confirms_pressure_negative_h'] = negative_h_rejection(row) # Descriptive expectation check for these fixed cases, not a general # assertion that h>=0 guarantees preparation or merit acceptance. expected = (r['direction'] == 'shape_only' or ratio < 1) r['admissibility_matches_enthalpy_only_prediction'] = bool(r['admissible']) == expected result['trial_checks'].append(r) if trial_rows: result['all_limiting_sign_predictions_match'] = all(r['both_limiting_point_signs_match_prediction'] for r in result['trial_checks']) result['all_admissibility_matches_enthalpy_only_prediction'] = all( r['admissibility_matches_enthalpy_only_prediction'] for r in result['trial_checks']) result['mapping_rejections'] = sum(r['admissible'] == 0 and r['reason'] in (0, 1) for r in result['trial_checks']) result['maximum_limiting_h_absolute_disagreement'] = max( r['maximum_limiting_h_evaluation_prediction_absolute_difference'] for r in result['trial_checks']) shape_rows = [r for r in result['trial_checks'] if r['direction'] == 'shape_only'] h_crossing_rows = [r for r in result['trial_checks'] if r['direction'] == 'enthalpy_only' and r['alpha_over_union_bound'] > 1] result['shape_only_all_prepared'] = all(r['admissible'] == 1 for r in shape_rows) if len(shape_rows) == 4 else None result['enthalpy_only_crossing_failures_all_pressure_negative_h'] = ( all(r['confirms_pressure_negative_h'] for r in h_crossing_rows) if len(h_crossing_rows) == 2 else None) return result def fmt(value): return 'pending' if value is None else f'{value:.9g}' def vector_entries(path, indices): """Read only selected zero-based entries; reject an incompatible saved vector.""" if not path.exists(): return None selected = set(indices) found = {} with path.open() as stream: size = int(next(stream).strip()) if not selected or min(selected) < 0 or max(selected) >= size: raise ValueError(f'Carrier indices incompatible with {path}') count = 0 for index, line in enumerate(stream): value = float(line) count += 1 if index in selected: found[index] = value if count != size or len(found) != len(selected): raise ValueError(f'Incomplete vector {path}') return [found[index] for index in indices] def extrema(values): return {'count': len(values), 'minimum': min(values), 'maximum': max(values), 'maximum_absolute': max(abs(x) for x in values), 'l2_norm': math.sqrt(math.fsum(x*x for x in values)), 'negative_count': sum(x < 0 for x in values), 'nonzero_count': sum(x != 0 for x in values)} def supplemental(cases): """Find the two supplemental case IDs without imposing an output-parent name.""" result = {'cases': [], 'offline_surface_checks': []} case_ids = [('n1_J0p10_onset_between_bounds', 2), ('n1_J0p10_late_surface_trace', 11)] reference_rows = None for name, iteration in case_ids: candidates = [path.parent for path in ROOT.glob(f'**/{name}/surface_trace_summary.csv')] if len(candidates) > 1: raise ValueError(f'Ambiguous duplicate supplemental case: {name}') if not candidates: result['cases'].append({'id': name, 'iteration': iteration, 'available': False}) continue folder = candidates[0] carrier_rows = [numeric(r) for r in rows(folder / 'surface_trace_rows.csv')] summary = metrics(folder / 'surface_trace_summary.csv') if 'pressure_alpha_h' not in summary: result['cases'].append({'id': name, 'iteration': iteration, 'available': False}) continue contribution_rows = [numeric(r) for r in rows(folder / 'surface_trace_limits.csv')] node_rows = [numeric(r) for r in rows(folder / 'surface_trace_nodes.csv')] replay_rows = rows(folder / 'replayed_candidate.csv') source_case = next(c for c in cases if c['iteration'] == iteration) details = {'id': name, 'iteration': iteration, 'available': True, 'folder': str(folder), 'summary': summary, 'contributions': contribution_rows, 'replayed_candidate': numeric(replay_rows[0]) if replay_rows else None, 'carrier_rows_complete': len(carrier_rows) == summary.get('surface_row_count'), 'nodal_checks': [], 'restoration': metrics(folder / 'frozen_input_checks.csv')} provenance = folder.parent / 'provenance.json' if provenance.exists(): p = json.loads(provenance.read_text()) details['provenance'] = {key: p.get(key) for key in ('commit', 'branch', 'mesh_sha256')} if carrier_rows and details['carrier_rows_complete']: indices = [int(r['root_index']) for r in carrier_rows] if len(set(indices)) != len(indices): raise ValueError(f'Duplicate surface indices in {folder}') if reference_rows is not None and indices != reference_rows: raise ValueError('Supplemental surface carrier maps differ') reference_rows = indices for family in ('closure', 'pressure'): nodal = [r for r in node_rows if r['family'] == family] if not nodal: continue if len(nodal) != nodal[0]['node_count']: continue # A live CSV may not yet have all nodal rows. union = nodal[0]['alpha_union'] factors = [('base', 0), ('near_below_union', .99*union), ('near_above_union', 1.01*union), ('unit_step', 1)] if source_case['capture']: factors.append(('captured_first_alpha', float(source_case['capture']['first_trial_alpha']))) if source_case['live_newton_step']: factors.append(('accepted_alpha', source_case['live_newton_step']['alpha'])) scale = max(abs(r[k]) for r in nodal for k in ('h', 'dh')) tolerance = 64 * math.ulp(1.0) * scale limit = next((r for r in contribution_rows if r['family'] == family), None) if limit is None: continue for label, alpha in factors: values = [r['h'] + alpha*r['dh'] for r in nodal] stats = extrema(values) stats.update({'family': family, 'element': nodal[0]['element'], 'fe_order': nodal[0]['fe_order'], 'label': label, 'alpha': alpha, 'roundoff_scale_estimate': tolerance, 'negative_beyond_roundoff_count': sum(v < -tolerance for v in values), 'limiting_point_h': limit['full_h'] + alpha*limit['full_dh']}) details['nodal_checks'].append(stats) if name.endswith('between_bounds') and details['replayed_candidate']: r = details['replayed_candidate'] details['replay_confirms_closure_outside_domain'] = all(r.get(k) == v for k, v in [('admissible', 0), ('reason', 2), ('stage', 3), ('eos_code', 5)]) details['candidate_derivation'] = json.loads((ROOT / 'supplemental_inputs/between_bounds_derivation.json').read_text()) result['cases'].append(details) if reference_rows is not None: result['surface_root_indices'] = reference_rows for c in cases: folder = ROOT / 'captures/n1_J0p10_capture' / f"capture_{c['iteration']}" base = vector_entries(folder / 'physical_base.txt', reference_rows) candidate = vector_entries(folder / 'physical_candidate.txt', reference_rows) if base is None or candidate is None: continue alpha = float(c['capture']['first_trial_alpha']) dh = [(v-b)/alpha for b, v in zip(base, candidate)] result['offline_surface_checks'].append({'iteration': c['iteration'], 'first_trial_alpha': alpha, 'base_h': extrema(base), 'exact_candidate_h': extrema(candidate), 'reconstructed_direction_dh': extrema(dh), 'base_and_exact_candidate_entire_surface_identically_zero': all(v == 0 for v in base + candidate)}) return result def main(): global ROOT parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('campaign_root', nargs='?', type=Path, default=ROOT, help='Campaign artifact directory (default: directory containing this script).') ROOT = parser.parse_args().campaign_root.expanduser().resolve() if not ROOT.is_dir(): parser.error(f'Campaign directory does not exist: {ROOT}') cases = [case(i) for i in ITERATIONS] transitions = [] for first, second in zip(cases, cases[1:]): if second['iteration'] != first['iteration'] + 1 or not first['bounds'] or not second['bounds']: continue alpha = first['live_newton_step']['alpha'] for family, prefix in [('closure', ''), ('pressure', 'pressure_')]: b, c = first['bounds'], second['bounds'] same = all(b[prefix + key] == c[prefix + key] for key in ['limiting_element', 'limiting_point']) predicted = b[prefix + 'limiting_h'] + alpha * b[prefix + 'limiting_dh'] observed = c[prefix + 'limiting_h'] transitions.append({'from_iteration': first['iteration'], 'to_iteration': second['iteration'], 'family': family, 'same_limiting_point': same, 'accepted_alpha': alpha, 'predicted_next_h': predicted, 'observed_next_h': observed, 'absolute_disagreement': abs(predicted - observed) if same else None}) supplements = supplemental(cases) provenance_file = ROOT / 'focused/provenance.json' source_revision = json.loads(provenance_file.read_text()).get('commit', '9e1b65d') if provenance_file.exists() else '9e1b65d' report = {'schema_version': 2, 'source_revision': source_revision, 'interpretation': 'Exact candidate replay is authoritative; direction probes include reconstruction roundoff.', 'cases': cases, 'consecutive_captured_step_checks': transitions, 'supplemental': supplements} polynomial_path = ROOT / 'pressure_polynomial_checks.json' polynomial = json.loads(polynomial_path.read_text()) if polynomial_path.exists() else None if polynomial: report['offline_polynomial_artifacts'] = ['pressure_polynomial_checks.json', 'pressure_polynomial_analysis.md'] (ROOT / 'pressure_checks.json').write_text(json.dumps(sanitize(report), indent=2, allow_nan=False) + '\n') lines = ['# Pressure obstruction analysis', '', 'Read-only analysis of the frozen n=1, J=.1 direction captures. This script launches no solver and does not modify case data. ' f'The original focused source is {source_revision}; iteration numbers are zero-based. ' 'Supplemental source revisions are recorded per case in pressure_checks.json. Partial cases are explicitly pending.', '', '| Iteration | Exact first alpha | Pressure bound | Closure bound | Limiting pressure h | dh | Element / point | Exact replay |', '|---:|---:|---:|---:|---:|---:|---|---|'] for c in cases: b = c['bounds'] loc = f"{int(b['pressure_limiting_element'])} / {int(b['pressure_limiting_point'])}" if b else 'pending' replay = ('pressure negative h' if c['exact_candidate_confirms_pressure_negative_h'] else ('other; inspect JSON' if c['exact_candidate'] else 'pending')) alpha = float(c['capture']['first_trial_alpha']) if c['capture'] else None lines.append(f"| {c['iteration']} | {fmt(alpha)} | {fmt(b.get('pressure_alpha_h'))} | " f"{fmt(b.get('closure_alpha_h'))} | {fmt(b.get('pressure_limiting_h'))} | " f"{fmt(b.get('pressure_limiting_dh'))} | {loc} | {replay} |") if all(c['exact_candidate_confirms_pressure_negative_h'] for c in cases): lines += ['', '**All five exact saved first candidates reproduce finite negative enthalpy in pressure preparation.** ' 'These failures are thermodynamic-domain rejections, not geometry rejections. The saved candidates are ' 'replayed directly, so this conclusion does not depend on reconstructing the Newton direction.'] populated = [c for c in cases if c['bounds']] if populated: lines += ['', 'The family attaining the smaller sampled bound is ' + ', '.join( f"iteration {c['iteration']}: {c['tightest_sampled_family']}" for c in populated) + '.', '', '| Iteration | Live accepted alpha | Accepted alpha / union bound |', '|---:|---:|---:|'] for c in populated: lines.append(f"| {c['iteration']} | {fmt(c['live_newton_step']['alpha'])} | {fmt(c['accepted_alpha_over_union_bound'])} |") if cases[-1]['bounds'] and cases[0]['bounds']: first, last = cases[0]['bounds'], cases[-1]['bounds'] lines += ['', f"From iteration 2 to 11 the pressure bound shrinks by " f"{first['pressure_alpha_h']/last['pressure_alpha_h']:.6g} times. The limiting pressure sample remains " f"element {int(last['pressure_limiting_element'])}, point {int(last['pressure_limiting_point'])}; " 'its h approaches zero while dh remains negative. ' f"At iteration 11 the closure bound is {last['closure_alpha_h']/last['pressure_alpha_h']:.6g} times larger. " 'The mechanism of the step-length collapse is established along these directions; why the Newton ' 'directions continue to decrease this h remains unresolved.'] if transitions: maximum = max(r['absolute_disagreement'] for r in transitions if r['absolute_disagreement'] is not None) lines += ['', f"For consecutive captured states at the same limiting point, h_next = h + alpha_accepted*dh " f"agrees with the independently scanned next base to at most {maximum:.3g} absolute. " 'The pointwise approach to the enthalpy boundary is therefore directly tied to the accepted steps.'] lines += ['', '## Crossing controls', '', '| Iteration | Candidate rows / expected | Shape-only all prepared | h-only crossing rejects negative h | Geometry rejections | Max h prediction/evaluation difference | Restored |', '|---:|---:|---|---|---:|---:|---|'] for c in cases: if c['iteration'] not in (2, 11): continue lines.append(f"| {c['iteration']} | {c['pressure_trials_completed']} / {fmt(c['pressure_trials_expected'])} | " f"{c.get('shape_only_all_prepared') if c.get('shape_only_all_prepared') is not None else 'pending'} | " f"{c.get('enthalpy_only_crossing_failures_all_pressure_negative_h') if c.get('enthalpy_only_crossing_failures_all_pressure_negative_h') is not None else 'pending'} | " f"{c.get('mapping_rejections', 'pending')} | {fmt(c.get('maximum_limiting_h_absolute_disagreement'))} | " f"{c['restoration_completed']} |") onset = cases[0] if onset['bounds']: b = onset['bounds'] midpoint = onset['between_bounds_midpoint'] midpoint_case = next(c for c in supplements['cases'] if c['iteration'] == 2) measured_midpoint = midpoint_case.get('replay_confirms_closure_outside_domain') midpoint_outcome = ('The supplemental candidate reproduces thermodynamic-domain rejection at the closure stage ' '(reason=2, stage=3, EOS code=5), confirming pressure preparation passes at this alpha before closure fails.' if measured_midpoint is True else 'The supplemental replay has a different outcome; inspect pressure_checks.json.' if measured_midpoint is False else 'Its production outcome is pending; the supplemental replay can separate closure from pressure.') lines += ['', '## Onset interpretation', '', f"The onset has a tighter **{onset['tightest_sampled_family']}** bound: closure {b['closure_alpha_h']:.12g}, " f"pressure {b['pressure_alpha_h']:.12g}. The original alpha=1 trial crosses both. " 'Pressure is prepared before closure, so the recorded pressure-stage rejection identifies the first failing stage at that alpha; ' 'it does not establish the pressure quadrature as the tightest restriction.', '', f"A midpoint alpha={midpoint['alpha']:.12g} predicts closure h=" f"{midpoint['closure_limiting_h_prediction']:.9g} and pressure h=" f"{midpoint['pressure_limiting_h_prediction']:.9g} at the respective limiting points. " 'This midpoint is outside the original probe grid. ' + midpoint_outcome, ''] populated_limits = [c for c in cases if c['limits']] if populated_limits: lines += ['', '## Limiting-point locations', '', '| Iteration | Family | Surface-adjacent element | Reference radius | Physical base (x, y, z) |', '|---:|---|---|---:|---|'] for c in populated_limits: for r in c['limits']: xyz = ', '.join(fmt(r[f'physical_{d}']) for d in 'xyz') lines.append(f"| {c['iteration']} | {r['family']} | {int(r['element'])}; " f"{bool(r['element_touches_stellar_surface'])} | {fmt(r['reference_radius'])} | ({xyz}) |") lines += ['', '## Surface trace is an enforced equation', '', 'The runtime isobaric condition is not absent merely because the field registry has no essential constraint. ' 'The root constructs an enthalpy boundary map on StellarSurface (prepared_stellar_equilibrium.cpp:407), ' 'replaces surface hydrostatic residual rows (lines 809–810), and replaces their Jacobian rows (904–908). ' 'The compiled constraint is h−h(P_surface), with identity h Jacobian for fixed pressure ' '(surface/compiled.cppm:47–59). At P_surface=0 the polytropic EOS gives h=0. ' 'The radial seed explicitly sets these boundary coefficients to zero ' '(seed/stellar_equilibrium_projection.cppm:203–208).', '', 'This is algebraic enforcement, not a per-trial coefficient projection. Source inspection alone does not ' 'establish exact zero in every captured iterate under an inexact linear solve. Even a zero polynomial ' 'boundary trace does not guarantee nonnegative enthalpy within the adjacent high-order element. ' 'The observed near-surface wall therefore does not establish a missing boundary condition or interpolation ' 'as the cause of the Newton direction.'] trace_cases = [c for c in supplements['cases'] if c['available']] if trace_cases: lines += ['', '## Supplemental surface carrier and nodal checks', '', 'The actual surface carrier indices come from GetPressureSurfaceRows(), then select entries in each ' 'saved physical state. Boundary-only fields retain those coefficients and zero every other enthalpy ' 'coefficient; evaluating this field at a limiting interior point gives the boundary contribution to ' 'that polynomial value, not a separate trace sample on the stellar surface.', '', '| Iteration | Carrier rows | Base max abs h | Direction max abs dh | Unit-step max abs h |', '|---:|---:|---:|---:|---:|'] for c in trace_cases: m = c['summary'] lines.append(f"| {c['iteration']} | {fmt(m.get('surface_row_count'))} | {fmt(m.get('base_h_maximum_absolute'))} | " f"{fmt(m.get('direction_dh_maximum_absolute'))} | {fmt(m.get('h_plus_dh_maximum_absolute'))} |") offline = supplements['offline_surface_checks'] if len(offline) == len(ITERATIONS) and all(c['base_and_exact_candidate_entire_surface_identically_zero'] for c in offline): lines += ['', '**All actual surface enthalpy coefficients are exactly zero in all five saved bases and all ' 'five exact first candidates.** Their reconstructed boundary directions are therefore also zero. ' 'Boundary-row leakage is ruled out for these captured directions, independently of the inexact ' 'linear-solve possibility from source inspection.'] else: lines += ['', 'Offline surface checks (including nonzero and negative counts) are recorded per capture in ' 'pressure_checks.json; inspect them before inferring exact trace enforcement in captured states.'] lines += ['', '| Iteration | Family | Full h | Boundary contribution h | Full dh | Boundary contribution dh |', '|---:|---|---:|---:|---:|---:|'] for c in trace_cases: for r in c['contributions']: lines.append(f"| {c['iteration']} | {r['family']} | {fmt(r['full_h'])} | {fmt(r['boundary_h'])} | " f"{fmt(r['full_dh'])} | {fmt(r['boundary_dh'])} |") lines += ['', 'Full physical fields are scattered through the production field adapter, then evaluated at FE ' 'GetNodes() coordinates. These values do not assume that raw signed local DOF indices are nodal values. ' 'The same element is intentionally exported separately for each limiting rule family.', '', '| Iteration | Family | Step | Nodal minimum h | Negative nodes | Limiting interior-point h |', '|---:|---|---|---:|---:|---:|'] for c in trace_cases: for r in c['nodal_checks']: if r['label'] in ('base', 'near_above_union', 'unit_step'): lines.append(f"| {c['iteration']} | {r['family']} | {r['label']} | {fmt(r['minimum'])} | " f"{r['negative_count']} | {fmt(r['limiting_point_h'])} |") undershoots = [(c['iteration'], r['family']) for c in trace_cases for r in c['nodal_checks'] if r['label'] == 'near_above_union' and r['minimum'] >= 0 and r['limiting_point_h'] < 0] if undershoots: lines += ['', 'At 1.01 times the union bound, nonnegative values at every FE node coexist with negative ' 'enthalpy at the limiting interior point in ' + ', '.join(f'iteration {i} {family}' for i, family in undershoots) + '. This demonstrates an interior polynomial undershoot in these trial directions. It does not ' 'establish an interpolation implementation error or explain why Newton selects this direction.'] lines += ['', 'Nodal nonnegativity is not a certificate of positivity between nodes. The JSON includes strict ' 'negative counts and a separate 64-epsilon times nodal-value-scale estimate, which is descriptive ' 'rather than a certified rounding bound. Equality exactly at the union bound is deliberately not ' 'used to decide a crossing. The production quadrature union bound also does not certify positivity ' 'at unsampled points; these results do not establish the minimum enthalpy over an entire element.'] if polynomial: lines += ['', '## Offline interior polynomial check', '', 'A separate independently validated tensor-Q3 reconstruction samples 495,264 strictly interior ' 'reference points in each exported limiting element, including logarithmic distances to its zero ' 'face. It reconstructs all 64 nodes exactly and both production limit points to roundoff.'] for c in polynomial['cases']: minimum = c['sampled_extrema']['base']['minimum'] if minimum < -c['roundoff_scale_estimate']: point = ', '.join(fmt(x) for x in c['sampled_extrema']['base']['minimum_reference_point']) lines += ['', f"**The saved iteration {c['iteration']} base already has negative enthalpy between " f"production quadrature points:** sampled h={minimum:.9g} at reference ({point}). " 'This base-state finding is independent of Newton-direction reconstruction. The surface ' 'coefficients and all 64 FE node values remain nonnegative; production quadrature positivity ' 'therefore misses a real polynomial undershoot in this accepted state.'] else: lines += ['', f"Iteration {c['iteration']} has no negative base samples on this grid; its sampled " f"directional bound {c['directional_bound']['sampled_admissible_step_bound']:.12g} is tighter " f"than the production bound {c['union_production_bound']:.12g}. Absence of negative samples " 'does not certify positivity everywhere.'] lines += ['', 'See pressure_polynomial_analysis.md and pressure_polynomial_checks.json for interpolation ' 'validation, minima, locations and limitations. No solver or preparation rule was changed.'] lines += ['', '## Scope and interpretation', '', 'A replay with reason=2, stage=6, EOS code=5 is the production pressure operator’s finite h<0 branch. ' 'It resolves the old CSV ambiguity with inverted geometry. Missing determinant/F data on rejection are not measured nonfinite residuals.', '', 'The bound scans the exact production pressure/closure quadrature points using pointwise polynomial contractions. ' 'The independently re-evaluated h values in the crossing table concern the two frozen limiting points, not a full search for each trial’s most negative point. ' 'Optimized tensor contractions can differ at roundoff; .99/1.01 factors deliberately avoid equality at the crossing.', '', 'Element-to-surface adjacency, when available in pressure_obstruction_limits.csv, is an exact topology flag. ' 'It is not distance to the surface. Physical/reference Cartesian coordinates and element-local integration coordinates are distinct.', '', 'At iteration 11 the supplied direction is reconstructed from a first-trial difference at alpha=1.9073486328125e-6; ' 'its relative subtraction-roundoff scale estimate is approximately 4.88e-7, not a certified error bound. ' 'The exact saved candidate is replayed without that reconstruction and is authoritative for the observed rejection.', '', 'Preparation success in a frozen probe does not establish line-search merit acceptance, physical equilibrium, or eventual Newton convergence. ' 'No requested stopping test, enthalpy admissibility rule, or solver was changed. ' 'The evolving bound is directional: a falling h/dh bound does not by itself identify why the nonlinear correction keeps pointing outward from the admissible set.', '', 'Machine-readable evidence and all individual trial checks: pressure_checks.json. ' 'Reproduce this analysis with `python3 analyze_pressure.py /path/to/campaign_artifacts`; ' 'the optional campaign path defaults to the script directory.'] (ROOT / 'pressure_analysis.md').write_text('\n'.join(lines) + '\n') print(json.dumps({'cases_with_exact_replay': sum(c['exact_candidate'] is not None for c in cases), 'cases_fully_restored': sum(c['restoration_completed'] for c in cases), 'supplemental_available': sum(c['available'] for c in supplements['cases']), 'supplemental_fully_restored': sum('final_restoration_residual_difference' in c.get('restoration', {}) for c in supplements['cases']), 'candidate_rows': {c['iteration']: c['pressure_trials_completed'] for c in cases}}, sort_keys=True)) if __name__ == '__main__': main()