"""Summarize accuracy, contact phases and repeated cost for isolated variants.""" import argparse import json from pathlib import Path import statistics import numpy as np def read(path):return json.loads(path.read_bytes()) def main(): parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('directory',type=Path) args=parser.parse_args();out=args.directory runs=read(out/'summary.json');rows=[];branches=[];groups=[] for profile,variants in runs.items(): baseline=variants['off'] base_force=baseline['groups']['force']['worstAbsolute']['maxAbsoluteError'] base_time=baseline['timing']['medianSeconds'] base_curves=np.load(out/profile/'off/curves.npz') for mode,r in variants.items(): data=np.load(out/profile/mode/'curves.npz') contacts=[] for key in data.files: if key.startswith('platform|') and key.endswith('.gap'): expected='amesim|'+key.split('|',1)[1] mismatch=data['phaseMatched'] & ((data[key]<0)!=(data[expected]<0)) contacts.extend(dict(key=key.split('|',1)[1],time=float(data['time'][i])) for i in np.flatnonzero(mismatch)) equal=all(np.array_equal(data[k],base_curves[k],equal_nan=True) for k in data.files if k.startswith('platform|')) worst=r['groups']['force']['worstAbsolute'];timing=r['timing'];native=r['nativeRun'] report=read(out/profile/mode/'comparison.json') branches.extend(dict(profile=profile,mode=mode,**c) for c in report['curves'] if c['quantity']=='force') groups.extend(dict(profile=profile,mode=mode,quantity=q,**g) for q,g in r['groups'].items()) counter_keys=('nfev','acceptedSteps','rejectedSteps','solverStarts','stateTransitions','njev','nlu','experimentalEvents') counters=[{k:t.get(k) for k in counter_keys} for t in timing['runs']] row=dict(profile=profile,mode=mode,medianSolveSeconds=timing['medianSeconds'], minimumSolveSeconds=timing['minimumSeconds'],maximumSolveSeconds=timing['maximumSeconds'], timingRepeats=timing['repeats'],repeatCountersStable=all(c==counters[0] for c in counters), medianCpuSeconds=statistics.median(t['solveCpuSeconds'] for t in timing['runs']), solveChangePercent=100*(timing['medianSeconds']/base_time-1), forceMaxError=worst['maxAbsoluteError'],forceWorstTime=worst['worstTime'],forceWorstKey=worst['key'], forceErrorChangePercent=100*(worst['maxAbsoluteError']/base_force-1), forceQuietMax=max(c['quietMaxAbsolute'] for c in report['curves'] if c['quantity']=='force'), pressureMaxError=r['groups']['pressure']['worstAbsolute']['maxAbsoluteError'], temperatureMaxError=r['groups']['temperature']['worstAbsolute']['maxAbsoluteError'], above5PercentCount=r['above5PercentCount'],phaseUnpairedCount=r['phaseUnpairedGridCount'], contactPhaseMismatches=contacts,gridTrajectoryEqualsOff=equal, rawPeakContactForce=r['extraEventPointMaxContactForce'], acceptedSteps=native['acceptedSteps'],rejectedSteps=native['rejectedSteps'], nfev=native['nfev'],solverStarts=native['solverStarts'],njev=native['njev'],nlu=native['nlu'], stateTransitions=native['stateTransitions'], experimentalEvents=native.get('experimentalEvents',{}),jacobianMode=native['jacobianMode']) rows.append(row) print(json.dumps(row,ensure_ascii=False)) (out/'effect-summary.json').write_text(json.dumps(rows,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') (out/'branch-force-summary.json').write_text(json.dumps(branches,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') (out/'group-summary.json').write_text(json.dumps(groups,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') if __name__=='__main__':main()