#!/usr/bin/env python3 """Generate manuscript tables solely from saved numerical summaries.""" import argparse import json from pathlib import Path ROOT = Path(__file__).resolve().parent RESULTS = ROOT / 'experiment' / 'results' TABLES = ROOT / 'tables' def read(name): return json.loads((RESULTS / name / 'summary.json').read_text()) def sci(value, precision=4): if value == 0: return '$0$' mantissa, exponent = f'{value:.{precision}e}'.split('e') return f'${mantissa}\\times10^{{{int(exponent)}}}$' def write_table(name, alignment, header, rows): lines = [r'\begingroup', r'\small', r'\setlength{\tabcolsep}{4pt}', r'\begin{tabular}{' + alignment + '}', r'\toprule', ' & '.join(header) + r'\\', r'\midrule'] lines.extend(' & '.join(row) + r'\\' for row in rows) lines.extend([r'\bottomrule', r'\end{tabular}', r'\endgroup', '']) (TABLES / name).write_text('\n'.join(lines)) def main(): global RESULTS, TABLES parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--results", default="experiment/results") parser.add_argument("--output", default="tables") args = parser.parse_args() RESULTS = (ROOT / args.results).resolve() TABLES = (ROOT / args.output).resolve() TABLES.mkdir(parents=True, exist_ok=True) conv = read('convergence')['rows'] write_table('convergence_table.tex', 'rrrrrr', ['$J$', '$h$', r'$L_h^2$', r'$H_h^1$', 'Time difference', 'Order'], [[str(r['sites']), f"{r['h']:.5f}", sci(r['max_l2'], 3), sci(r['max_h1'], 3), sci(r['max_time_difference_l2'], 3), '--' if r['order_h1'] is None else f"{r['order_h1']:.3f}"] for r in conv]) speeds = read('spectroscopy')['speeds'] write_table('speed_table.tex', 'rcrrr', ['$J$', 'Branch', '$m_{\\rm fit}^2$', '$c_{\\rm fit}$', 'Max. rel. error'], [[str(r['sites']), '$' + r['branch'] + '$', f"{r['mass_sq_fit']:.8f}", f"{r['speed_fit']:.8f}", sci(r['max_relative_continuum_error'], 3)] for r in speeds]) coll = read('collision') principal = next(r for r in coll['runs'] if r['label'] == coll['principal_label']) rows = sorted((r for r in coll['runs'] if r['sites'] == principal['sites'] and r['content'] == 'both' and not r['linear'] and r['epsilon'] >= 0), key=lambda r: r['epsilon']) cross = {(r['sites'], r['epsilon']): r['max_v_excess'] for r in coll['cross_excess']} write_table('epsilon_table.tex', 'rrrr', [r'$\varepsilon$', r'$\max\|v\|_h$', r'$\max E_{v,\mathrm{quad}}$', r'$\max C_v$'], [[f"{r['epsilon']:.3f}", sci(r['max_v_l2']), sci(r['max_v_quadratic_energy']), sci(cross.get((r['sites'], r['epsilon']), 0.0))] for r in rows]) write_table('collision_refinement_table.tex', 'crrr', ['Grid pair', 'Full field', '$v$ field', '$v$ excess field'], [[f"{r['coarse']} / {r['fine']}", sci(r['max_field_difference']), sci(r['max_v_difference']), sci(r['max_v_cross_excess_difference'])] for r in coll['refinement']]) source = read('source_check')['rows'] write_table('source_response_table.tex', 'rrr', [r'$\varepsilon$', r'$\max\|v_\varepsilon/\varepsilon-v_1\|_h$', r'$\max\|v_{h,\varepsilon}-v_\varepsilon\|_h$'], [[f"{r['epsilon']:.3f}", sci(r['max_v_over_epsilon_minus_v1_l2']), sci(r['max_automaton_v_minus_continuum_v_l2'])] for r in source]) print('Generated 5 manuscript tables from saved summaries.') if __name__ == '__main__': main()