"""Original SVG figures from saved own-model records or explicit mathematical controls.""" import argparse,html,math from pathlib import Path import numpy as np from io_helpers import read_json,fixed_inputs COLORS=['#287cb4','#d45a4e','#3b936c','#9868b1'] def plot(path,curves,xlabel,ylabel,labels,width,height): left=58;right=width-18;top=22;bottom=height-72;xs=np.concatenate([np.array(a)for a,b in curves]);ys=np.concatenate([np.array(b)for a,b in curves]);xmin,xmax=float(xs.min()),float(xs.max());ymin,ymax=float(ys.min()),float(ys.max());dx=max(xmax-xmin,1e-12);dy=max(ymax-ymin,1e-12);ymin-=dy*.05;ymax+=dy*.08 X=lambda x:left+(x-xmin)/(xmax-xmin)*(right-left);Y=lambda y:bottom-(y-ymin)/(ymax-ymin)*(bottom-top) parts=[f''] for fraction in [0,.25,.5,.75,1]: x=xmin+fraction*(xmax-xmin);y=ymin+fraction*(ymax-ymin);parts.extend([f'{x:.2g}',f'{y:.2g}']) for j,(x,y)in enumerate(curves): d=' '.join(('M'if k==0 else'L')+f'{X(a):.3f},{Y(b):.3f}'for k,(a,b)in enumerate(zip(x,y)));parts.append(f'');lx=left+(j%2)*(width-left-18)/2;ly=height-23+(j//2)*16;parts.append(f'{html.escape(labels[j])}') parts.extend([f'{html.escape(xlabel)}',f'{html.escape(ylabel)}','']);path.parent.mkdir(parents=True,exist_ok=True);path.write_text(''.join(parts)) def main(): parser=argparse.ArgumentParser();parser.add_argument('--records',type=Path,default=Path('results/records'));parser.add_argument('--output',type=Path,default=Path('results/figures'));args=parser.parse_args();records=[read_json(args.records/(name+'.npz'))for name in ['renewed','rapid','extended','wind']] data={};data['tracks']=([(np.array(r['abundances'])[:,0],np.array(r['abundances'])[:,1])for r in records],'Iron abundance (dex)','Magnesium / iron (dex)',['Renewed','Rapid','Extended','Wind']) r=records[0];time=np.array(r['timeGyr']);states=np.array(r['states']);flows=np.array(r['flows']);print(r['flowFields']) # The exact saved source fields are named rather than assumed to be an unrelated yield scale. fields=r['flowFields'];fixed=fixed_inputs();prompt=flows[:,fields.index('formed')]*fixed['netCC']['fe'];delayed=flows[:,fields.index('delayedResponse')]*fixed['netIa']['fe'] data['delay']=([(time,prompt),(time,delayed)],'Elapsed time (Gyr)','New iron rate (mass unit / Gyr)',['Prompt iron','Delayed iron']) t=np.linspace(0,1,101);wind=[] for eta in [0,1]:c=.6+eta;g=1-c*.3*t;z=1e-6+.000246/c*np.log(1/g);wind.append((t,z)) data['wind']=(wind,'Elapsed time (control unit)','Iron mass fraction',['No wind','Wind loading 1']) angle=np.linspace(0,2*np.pi,201);circle=np.array([np.cos(angle),np.sin(angle)]);cov=np.array([[.01,-.01],[-.01,.0164]]);root=np.linalg.cholesky(cov);ellipse=root@circle;diag=np.diag(np.sqrt(np.diag(cov)))@circle data['covariance']=([(ellipse[0],ellipse[1]),(diag[0],diag[1])],'Iron measurement error (dex)','Ratio measurement error (dex)',['Shared Fe','Uncorrelated']) for name,(curves,x,y,labels)in data.items(): for mobile in [False,True]:plot(args.output/(name+('-mobile'if mobile else'')+'.svg'),curves,x,y,labels,360 if mobile else 820,360 if mobile else 370) print('PASS: eight own figures; no observed stars or source images') if __name__=='__main__':main()