Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
create_figures.py
Go to the documentation of this file.
1"""Reproducible manual illustrations; analytical curves are not simulation results."""
2from pathlib import Path
3import numpy as np
4import matplotlib
5matplotlib.use('Agg')
6import matplotlib.pyplot as plt
7from matplotlib.patches import FancyBboxPatch, FancyArrowPatch, Polygon
8from mpl_toolkits.mplot3d.art3d import Line3DCollection
9ROOT=Path(__file__).resolve().parents[1]
10OUT=ROOT/'figures'
11OUT.mkdir(exist_ok=True)
12plt.rcParams.update({'font.size':11,'font.family':'DejaVu Sans','axes.spines.top':False,'axes.spines.right':False,'pdf.fonttype':42})
13blue='#176b91'; orange='#d27a30'; dark='#203547'; pale='#edf4f8'
14def save(fig,name):
15 fig.savefig(OUT/(name+'.pdf'),bbox_inches='tight')
16 fig.savefig(OUT/(name+'.png'),dpi=150,bbox_inches='tight')
17 plt.close(fig)
18def box(ax,x,y,w,h,text,color=pale):
19 ax.add_patch(FancyBboxPatch((x,y),w,h,boxstyle='round,pad=0.02',fc=color,ec=blue,lw=1.3))
20 ax.text(x+w/2,y+h/2,text,ha='center',va='center',fontsize=10,color=dark)
21def arrow(ax,a,b):
22 ax.add_patch(FancyArrowPatch(a,b,arrowstyle='-|>',mutation_scale=13,color=blue,lw=1.5))
23# Mesh illustration reads the actual repository fixture, no synthetic tetrahedra.
24lines=(ROOT.parent/'Library/Meshes/unitCube24.msh').read_text().splitlines()
25k=lines.index('$Nodes'); nn=int(lines[k+1]); pts={int(s.split()[0]):np.array(list(map(float,s.split()[1:4]))) for s in lines[k+2:k+2+nn]}
26k=lines.index('$Elements'); ne=int(lines[k+1]); tets=[]
27for s in lines[k+2:k+2+ne]:
28 a=list(map(int,s.split()))
29 if a[1]==4:tets.append(a[3+a[2]:])
30edges=set()
31for tet in tets:
32 for i in range(4):
33 for j in range(i):edges.add(tuple(sorted((tet[i],tet[j]))))
34fig=plt.figure(figsize=(10,4.3))
35for idx,title in enumerate(['Simplicial volume: 24 tetrahedra','Polyhedral boundary: cube faces']):
36 ax=fig.add_subplot(1,2,idx+1,projection='3d')
37 if idx==0: segs=[[pts[a],pts[b]] for a,b in edges]
38 else:
39 corners=[v for v in pts.values() if np.all(np.abs(v)==.5)]
40 segs=[[a,b] for i,a in enumerate(corners) for b in corners[:i] if np.sum(a!=b)==1]
41 ax.add_collection3d(Line3DCollection(segs,colors=blue,linewidths=.8 if idx==0 else 2))
42 ax.set(xlim=(-.55,.55),ylim=(-.55,.55),zlim=(-.55,.55),title=title)
43 ax.set_box_aspect((1,1,1));ax.set_axis_off();ax.view_init(22,32)
44fig.text(.5,.02,'Same domain; volume interpolation and boundary traversal use different representations.',ha='center',fontsize=10)
45save(fig,'mesh_views')
46fig,ax=plt.subplots(figsize=(10,4));ax.axis('off');ax.set(xlim=(0,10),ylim=(0,4))
47box(ax,.1,2.7,2.6,.9,'Material file\nscales, crystal type, laws')
48box(ax,3.65,2.7,2.7,.9,'Polycrystal\nshared material + grains')
49box(ax,7.2,2.7,2.6,.9,'Mesh regions\ngeometric partition')
50arrow(ax,(2.7,3.15),(3.65,3.15));arrow(ax,(7.2,3.15),(6.35,3.15))
51for x,txt in [(1.4,'Grain 1: C2G1\nlattice + slip systems'),(6,'Grain 2: C2G2\nlattice + slip systems')]:box(ax,x,.7,2.7,1,txt)
52arrow(ax,(4.4,2.7),(2.75,1.7));arrow(ax,(5.6,2.7),(7.35,1.7));arrow(ax,(4.1,1.2),(6,1.2));ax.text(5.05,.55,'grain boundary',ha='center',fontsize=9)
53save(fig,'polycrystal')
54fig,(ax,bx)=plt.subplots(1,2,figsize=(10,3.6));x=np.linspace(0,1,300)
55for y,l,c in [(2*(x-.5)*(x-1),'N₀',blue),(4*x*(1-x),'N₁/₂',orange),(2*x*(x-.5),'N₁','#668f52')]:ax.plot(x,y,label=l,color=c)
56ax.set(title='Quadratic Lagrange edge basis',xlabel='Edge coordinate',ylabel='Shape function');ax.legend(frameon=False);ax.grid(alpha=.15)
57bx.set(xlim=(0,5),ylim=(0,4));bx.axis('off')
58for y,t in [(3,'Mesh + LagrangeElement'),(1.8,'TrialFunction + weak forms'),(.6,'WeakProblem: constraints + solve')]:box(bx,.2,y,4.6,.7,t)
59arrow(bx,(2.5,3),(2.5,2.5));arrow(bx,(2.5,1.8),(2.5,1.3));fig.tight_layout();save(fig,'fem')
60fig,ax=plt.subplots(figsize=(10,4.2));ax.set(xlim=(0,10),ylim=(0,4.5));ax.axis('off')
61box(ax,.3,3.4,9.4,.7,'DefectiveCrystalBase: mesh, polycrystal, periodic lattice, optional FEM')
62for x,t in [(.3,'DDD'),(2.7,'Elastic deformation'),(5.1,'Inclusions'),(7.5,'Cluster dynamics')]:
63 box(ax,x,1.8,2.2,.8,t);arrow(ax,(x+1.1,3.4),(x+1.1,2.6))
64box(ax,.3,.25,9.4,.8,'MicrostructureContainer: solve / reSolve → minimum dt → output → update')
65for x in [.3,2.7,5.1,7.5]:arrow(ax,(x+1.1,1.8),(x+1.1,1.05))
66save(fig,'multiphysics')
67
68fig=plt.figure(figsize=(6,4));ax=fig.add_subplot(111,projection='3d');t=np.linspace(0,2*np.pi,120)
69ax.plot(np.cos(t),np.sin(t),0*t,color=blue);ax.plot(np.cos(t),0*t,np.sin(t),color=blue,alpha=.3)
70v=np.array([.55,.45,.7]);v/=np.linalg.norm(v)
71for p,l in [(np.array([0,0,1.3]),'e₃ = R / R'),(v,'κ(θ, φ)')]:ax.quiver(0,0,0,*p,color=orange);ax.text(*p,l,fontsize=10)
72ax.set_axis_off();ax.set_box_aspect((1,1,1));ax.view_init(20,30);save(fig,'fourier_sphere')
73# Standalone plots place each illustration next to the physics that uses it.
74fig,ax=plt.subplots(figsize=(7,2.8));a=np.logspace(-4,4,400)
75ax.semilogx(a,1/(1+a),label='Applied stress weight',color=blue)
76ax.semilogx(a,a/(1+a),label='Imposed strain weight',color=orange)
77ax.set(xlabel='Scalar stiffness ratio α',ylabel='Weight');ax.legend(frameon=False,fontsize=10);ax.grid(alpha=.15);fig.tight_layout();save(fig,'controller_weights')
78fig,ax=plt.subplots(figsize=(7,2.8));x=np.linspace(-3,3,500)
79ax.plot(x,np.sqrt(x*x+.3**2),color=orange,label='a = 0.3');ax.plot(x,np.abs(x),color=blue,ls='--',label='a = 0')
80ax.set(xlabel='Signed separation along a line',ylabel='Regularized distance Rₐ');ax.legend(frameon=False);ax.grid(alpha=.15);fig.tight_layout();save(fig,'regularized_distance')
81
82# Regenerate the polycrystalline comparison used in Figure 1.1.
83import runpy
84runpy.run_path(str(ROOT / "scripts/create_polycrystal_figure.py"))
85
86# Geometric entity hierarchies.
87runpy.run_path(str(ROOT / "scripts/create_entity_figures.py"))
88
89runpy.run_path(str(ROOT / "scripts/create_periodicity_figure.py"))
90
91runpy.run_path(str(ROOT / "scripts/create_mesh_library_figure.py"))
box(ax, x, y, w, h, text, color=pale)
save(fig, name)