Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
tutorials/polycrystal/generateInputFiles.py
Go to the documentation of this file.
1"""Generate a polycrystal with random prismatic loops and 33-direction strain loading."""
2import argparse
3import os
4from pathlib import Path
5import sys
6
7repository = Path(__file__).resolve().parents[2]
8parser = argparse.ArgumentParser(description=__doc__)
9parser.add_argument("--output-dir", type=Path, default=Path(__file__).resolve().parent,
10 help="Simulation folder (defaults to this tutorial folder).")
11args = parser.parse_args()
12args.output_dir.mkdir(parents=True, exist_ok=True)
13os.chdir(args.output_dir.resolve())
14sys.path.insert(0, str(repository / "python"))
15from modlibUtils import *
16
17
18# Create folder structure
19folders=['config','F','inputFiles']
20for x in folders:
21 if not os.path.exists(x):
22 os.makedirs(x)
23
24# Make a local copy of DefectiveCrystal parameters file and modify that copy if necessary
25DCfile='DefectiveCrystal.txt'
26DCfileTemplate=str(repository)+'/Library/DefectiveCrystal/'+DCfile
27print("\033[1;32mCreating DDfile\033[0m")
28shutil.copy2(DCfileTemplate,'inputFiles/'+DCfile)
29setInputVariable('inputFiles/'+DCfile,'physics','DislocationDynamics ElasticDeformation')
30setInputVariable('inputFiles/'+DCfile,'useFEM','0')
31setInputVariable('inputFiles/'+DCfile,'Nsteps','10000') # number of simulation steps
32setInputVariable('inputFiles/'+DCfile,'maxResolveSteps','0') # number of simulation steps
33setInputVariable('inputFiles/'+DCfile,'dtMax','1e25')
34setInputVariable('inputFiles/'+DCfile,'outputFrequency','1') # output frequency
35
36setInputVariable('inputFiles/'+DCfile,'startAtTimeStep','-1')
37setInputVector('inputFiles/'+DCfile,'periodicImageSize',np.array([0,0,0]),'image counts for the active periodic directions')
38
39# Make a local copy of DD parameters file and modify that copy if necessary
40DDfile='DD.txt'
41DDfileTemplate=str(repository)+'/Library/DislocationDynamics/'+DDfile
42print("\033[1;32mCreating DDfile\033[0m")
43shutil.copy2(DDfileTemplate,'inputFiles/'+DDfile)
44setInputVariable('inputFiles/'+DDfile,'timeSteppingMethod','adaptive') # adaptive or fixed
45setInputVariable('inputFiles/'+DDfile,'dxMax','10') # max nodal displacement for when timeSteppingMethod=adaptive
46setInputVariable('inputFiles/'+DDfile,'use_velocityFilter','1') # don't filter velocity if noise is enabled
47setInputVariable('inputFiles/'+DDfile,'alphaLineTension','1.0') # dimensionless scale factor in for line tension forces
48setInputVariable('inputFiles/'+DDfile,'Lmin','25') # min segment length (in Burgers vector units)
49setInputVariable('inputFiles/'+DDfile,'Lmax','150') # max segment length (in Burgers vector units)
50setInputVariable('inputFiles/'+DDfile,'outputQuadraturePoints','1') # output quadrature data
51setInputVariable('inputFiles/'+DDfile,'glideSolverType','Galerkin') # type of glide solver, or none
52setInputVariable('inputFiles/'+DDfile,'climbSolverType','none') # type of clim solver, or none
53setInputVariable('inputFiles/'+DDfile,'crossSlipModel','0') # crossSlipModel
54
55# Make a local copy of material file, and modify that copy if necessary
56materialFile='W.txt';
57materialFileTemplate=str(repository)+'/Library/Materials/'+materialFile;
58print("\033[1;32mCreating materialFile\033[0m")
59shutil.copy2(materialFileTemplate,'inputFiles/'+materialFile)
60#setInputVariable('inputFiles/'+materialFile,'enabledSlipSystems','full<111>{110}')
61b_SI=getValueInFile('inputFiles/'+materialFile,'b_SI')
62
63# Make a local copy of ElasticDeformation file, and modify that copy if necessary
64elasticDeformatinoFile='ElasticDeformation.txt';
65elasticDeformatinoFileTemplate=str(repository)+'/Library/ElasticDeformation/'+elasticDeformatinoFile;
66print("\033[1;32mCreating elasticDeformatinoFile\033[0m")
67shutil.copy2(elasticDeformatinoFileTemplate,'inputFiles/'+elasticDeformatinoFile)
68setInputVector('inputFiles/'+elasticDeformatinoFile,'ExternalStress0',np.zeros(6),'applied stress')
69# Voigt order: 11, 22, 33, 12, 23, 13. Strain rate is per simulation time b/cs.
70strainRate33 = 1e-8
71setInputVector('inputFiles/'+elasticDeformatinoFile, 'ExternalStrainRate',
72 np.array([0.0, 0.0, strainRate33, 0.0, 0.0, 0.0]), 'applied strain rate in the global 33 direction')
73setInputVector('inputFiles/'+elasticDeformatinoFile, 'stiffnessRatio',
74 np.array([0.0, 0.0, 1e20, 0.0, 0.0, 0.0]), 'strain control in 33; zero-stress control in the other components')
75
76
77# Create polycrystal.txt using local material file
78meshFile='poly30_periodicXYZ.msh';
79meshFileTemplate=str(repository)+'/Library/Meshes/'+meshFile;
80print("\033[1;32mCreating polycrystalFile\033[0m")
81shutil.copy2(meshFileTemplate,'inputFiles/'+meshFile)
82pf=PolyCrystalFile(materialFile);
83pf.absoluteTemperature=300;
84pf.meshFile=meshFile
85# Grain 1: crystal and global coordinates aligned.
86pf.grain1globalX1 = np.array([1.0, 0.0, 0.0])
87pf.grain1globalX3 = np.array([0.0, 0.0, 1.0])
88pf.boxScaling=np.array([1e-6,1e-6,1e-6])/b_SI # scale of each mesh coordinate in Burgers vector units
89pf.X0=np.array([0,0,0]) # Mesh nodes X are mapped to x=F*(X-X0)
90pf.periodicFaceIDs=np.array([-1])
91# Explicit example orientations for all 30 grains. These rational rotations
92# are chosen for lattice-compatible periodic translations; they do not use the
93# random orientations stored in the source mesh's ElsetOrientations section.
94rx = np.array([[1., 0., 0.], [0., 0.8, -0.6], [0., 0.6, 0.8]])
95ry = np.array([[0.8, 0., 0.6], [0., 1., 0.], [-0.6, 0., 0.8]])
96rz = np.array([[0.8, -0.6, 0.], [0.6, 0.8, 0.], [0., 0., 1.]])
97grainOrientations = [np.eye(3), rx, rx.T, ry, ry.T, rz, rz.T,
98 rx @ ry, ry @ rz, rz @ rx]
99# Preserve the original first ten orientations, then add distinct products
100# of two elementary rotations. Their denominators still divide 25.
101elementaryRotations = [rx, rx.T, ry, ry.T, rz, rz.T]
102for first in elementaryRotations:
103 for second in elementaryRotations:
104 orientation = first @ second
105 if len(grainOrientations)<30 and not any(
106 np.allclose(orientation, existing, rtol=0, atol=1e-12)
107 for existing in grainOrientations):
108 grainOrientations.append(orientation)
109if len(grainOrientations)!=30:
110 raise ValueError('Expected 30 distinct grain orientations')
111# Products have denominators up to 25. Round the axial BCC repeat counts
112# to multiples of 25 so all grain orientations admit the periodic translations.
113pf.compute()
114repeatCounts = 25 * np.maximum(1, np.round(pf.boxScaling / (25 * pf.boxEdgesLatticeLengths)))
115meshScale = 2.0 # Double linear dimensions while preserving lattice-compatible repeats.
116pf.boxScaling = meshScale * repeatCounts * pf.boxEdgesLatticeLengths
117pf.write('inputFiles')
118with open('inputFiles/polycrystal.txt', 'a') as polycrystalFile:
119 for grainID, orientation in enumerate(grainOrientations[1:], start=2):
120 rows = [' '.join(f'{value:.17g}' for value in row) for row in orientation]
121 polycrystalFile.write(f'C2G{grainID}=' + '\n '.join(rows)
122 + '; # crystal-to-global rotation\n')
123
124# Random prismatic loops throughout all grains. Density is total dislocation
125# line length per unit volume; radii are in meters.
126microstructureName = 'prismaticLoopsDensity.txt'
127microstructureFile = 'inputFiles/' + microstructureName
128shutil.copy2(repository / 'Library/Microstructures/prismaticLoopsDensity.txt',
129 microstructureFile)
130setInputVariable(microstructureFile, 'targetDensity_SI', '1e13') # m^-2
131setInputVariable(microstructureFile, 'radiusDistributionMean_SI', '1e-7') # 100 nm
132setInputVariable(microstructureFile, 'radiusDistributionStd_SI', '0') # fixed radius
133setInputVector(microstructureFile, 'allowedGrainIDs', np.array([-1]), 'random placement throughout all grains')
134setInputVariable(microstructureFile, 'allowedSlipSystemIDs', '-1') # all slip systems
135with open('inputFiles/initialMicrostructure.txt', 'w') as initialMicrostructureFile:
136 initialMicrostructureFile.write('microstructureFile=' + microstructureName + ';\n')
137
138# Generate the populated frame 0 with microstructureGenerator before running DDomp.
139print('Inputs ready: ' + str(Path.cwd()))
140print('Run microstructureGenerator, then DDomp, using this simulation folder.')
setInputVector(fileName, variable, newVal, newCom)
setInputVariable(fileName, variable, newVal)