Skip to content

Commit c1e0609

Browse files
Merge pull request #13 from donald-e-boyce/job-keys-arg
added job_keys command line argument and updated `linear_single_crystal` demo.
2 parents 432dcd1 + e726829 commit c1e0609

File tree

7 files changed

+128
-96
lines changed

7 files changed

+128
-96
lines changed

demo/linear_single_crystal/README.md

Lines changed: 42 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,60 @@
11
# Linear Single Crystal
22

3-
This example uses simple test problems to illustrate how to set up a single job or a suite of jobs. The problems are single crystal, meaning there is just one material and a single orientation, so it's easy to set up problems where you know the answer.
4-
5-
## Inputs
6-
The first inputs are `suite` and `process`. The suite is the name for the whole group of simulations, `linear_single_crystal`. The process is the name of the process model; here it is `linear-elasticity`.
3+
This example uses simple test problems to illustrate how to set up a single job or a suite of jobs. The problems here are single crystal, meaning there is just one material and one orientation, so it's easy to set up problems where you know the answer.
4+
5+
## Jobs
6+
To run a simulation, you will need to define a `inputs.Job` instance. A `Job` has six components.
7+
```
8+
job = inputs.job.Job(
9+
suite = suite,
10+
process = process,
11+
mesh_input = mesh_input,
12+
material_input = material_input,
13+
polycrystal_input = polycrystal_input,
14+
deformation_input = deformation_input
15+
)
16+
```
17+
The `suite` and the `process` are simple strings. They give the name of the suite of simulations and the name of the material process being modeled. In this example, we have:
18+
```
19+
suite = "linear_single_crystal"
20+
process = "linear-elasticity"
21+
```
22+
The other four components describe the mesh, the material, the polycrystal (microstructure) and the applied deformation. Each of these components will have `key` (hashable type) that can be used to generate the input. The key may be a string, a number or a tuple, or some combination of these. Each input is then built from the key.
723

824
### Materials
9-
In the `data` module, there is a dictionary of materials. It defines two isotropic materials and three cubic materials. All are abstract and do not reflect actual materials.
25+
In the `data` module, there is a dictionary of elastic materials. It defines two
26+
isotropic materials and three cubic materials. In this example, the materials are very simple and do not reflect actual materials. The material `key` is simply the name of the material. In this example, we set moduli that gives the identity stiffness matrix.
27+
```
28+
matl_key = "identity-iso"
29+
```
1030

1131
### Polycrystal
12-
A simple polycrystal is set up. It has one crystal and so one orientation. For the isotropic materials, the orientation doesn't matter at all (as long as it's a rotation matrix), but it does matter for the cubic materials. At this point, only the identity is used, but the mechanism to add more single orientaitons is there. The tuple `(axis, angle)` is the key to generate a rotation through a given angle about one of the coordinate axes. As mentioned above, only `(0, 0)`, representing the identity, is used currently.
13-
32+
In this example, we use a very simple polycrystal. In face, it is a single crystal. The only thing we need to assign is the crystal orientation. We chose to use a rotation through somae angle about one of the coordinate axes. The polycrystal key is a pair of numbers, the first being the axis of rotation: 0, 1, or 2. The second is the angle of rotation. So for example, if the key were `(1, 45)`, that would represent a single crystal rotated 45 degrees about the y-axis. In this example, the material is isotropic so the orientation doesn't matter. This gives an orientation matrix of the identity.
33+
```
34+
poly_key = (0, 0)
35+
```
1436
### Meshes
15-
These are simple box meshes, and the tuple of divsions is used to generate the mesh. These are purposely small since we are running problems with an exact answer.
16-
17-
### Deformations
18-
For the test problems, we set up the problem data to have exact solutions of the for `u = Ax`. We use nine choices for `A`; each one has zeros in all positions except for 1 spot, which has value 1. Body forces are zero. We apply several types of boundary conditions:
19-
* full displacement (Dirichlet) boundary conditions on the whole boundary
20-
* traction boundary conditions on the top surface and displacement everywhere else
21-
* traction boundary conditions on the top in the z-component only, and displacements everywhere else
22-
* traction boundary conditions on the top in the `xy` directions only, and displacements everywhere else.
23-
24-
## Single Job
25-
26-
To set up a single job, you just create `Job` instance named `job`. It takes the names of the suite and the process. Then there are the four inputs described above. To run the single job:
27-
28-
```mpirun -n 2 pxx_job linear_single_crystal```
29-
30-
## Batch Job
31-
To run in batch, use the `pxx_suite` script. In the `batch` module, an iterator is set up to generate various combinations of the various inputs. The iterator generates keys that are used to create the job, and a `get_job(key)` function is used by the processing script to generate the actual job. Run like this:
32-
33-
```pxx_suite -n 2 linear_single_crystal.batch```
34-
# Linear Single Crystal
35-
36-
This example uses simple test problems to illustrate how to set up a single job or a suite of jobs. The problems are single crystal, meaning there is just one
37-
material and one orientation, so it's easy to set up problems where you know
38-
the answer.
39-
40-
## Inputs
41-
The first inputs are `suite` and `process`. The suite is the name for the
42-
whole group of simulations, `linear_single_crystal`. The process is the name
43-
of the process model; here it is `linear-elasticity`.
44-
45-
### Materials
46-
In the `data` module, there is a dictionary of materials. It defines two
47-
isotropic materials and three cubic materials. All are abstract and do not
48-
reflect actual materials.
49-
50-
### Polycrystal
51-
A simple polycrystal is set up. It has one crystal and so one orientation. For
52-
the isotropic materials, the orientation doesn't matter at all (as long as
53-
it's a rotation matrix), but it does matter for the cubic materials. At this point, only the identity is used, but the mechanism to add more single orientaitons is there. The tuple `(axis, angle)` is the key to generate a
54-
rotation through a given angle about one of the coordinate axes. As mentioned
55-
above, only `(0, 0)`, representing the identity, is used currently.
56-
57-
### Meshes
58-
These are simple box meshes, and the tuple of divsions is used to generate
59-
the mesh. These are purposely small since we are running problems with an
60-
exact answer.
61-
37+
These are simple box meshes, and the `mesh key` is the tuple of divsions is used to generate the mesh. These are purposely small since we are running problems with an
38+
exact answer. Here the mesh is a box with 40 subdivisions in each direction.
39+
```
40+
mesh_key = (40, 40, 40)
41+
```
6242
### Deformations
6343
For the test problems, we set up the problem data to have exact solutions of
64-
the for `u = Ax`. We use nine choices for `A`; each one has zeros in all
65-
positions except for 1 spot, which has value 1. Body forces are zero. We apply
44+
the form `u = Ax`. We use nine choices for `A`; each one has zeros in all
45+
positions except for 1 spot, which has value 1.0. Body forces are zero. We apply
6646
several types of boundary conditions:
6747
* full displacement (Dirichlet) boundary conditions on the whole boundary
6848
* traction boundary conditions on the top surface and displacement everywhere else
6949
* traction boundary conditions on the top in the z-component only, and displacements everywhere else
7050
* traction boundary conditions on the top in the `xy` directions only, and displacements everywhere else.
7151

72-
## Single Job
73-
74-
To set up a single job, you just create `Job` instance named `job`. It takes
75-
the names of the suite and the process. Then there are the four inputs
76-
described above. To run the single job:
52+
In this example, we apply traction on the top surface, and the strain will be zero except for the xx-component.
53+
```
54+
defm_key = ("zmax-traction", 1, 1)
55+
```e
56+
## Running a Single Job
57+
To run a single job, use the `pxx_job` script.
7758
7859
```mpirun -n 2 pxx_job linear_single_crystal```
7960
Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
"""Inputs Module for lienar single crystal"""
2-
import numpy as np
32

4-
from polycrystalx import inputs
3+
from . import batch
54

6-
from .batch import suite, process, get_job
5+
# Material has identity for stiffness matrix.
6+
matl_key = "identity-iso"
77

8+
# Single crystal with no rotation.
9+
poly_key = (0, 0)
810

9-
matl = "identity-iso"
10-
poly = (0, 0)
11-
mesh = (20, 20, 20)
12-
defm = ("full", 1, 1)
11+
# Mesh is a box with 40 divisions in each directon.
12+
mesh_key = (40, 40, 40)
1313

14-
job = get_job((matl, poly, mesh, defm))
14+
# The applied deformation is a traction on the top and a displacement field
15+
# u = Ax where
16+
# [1 0 0]
17+
# A = [0 0 0]
18+
# [0 0 0]
19+
defm_key = ("zmax-traction", 1, 1)
20+
21+
job_key = (matl_key, poly_key, mesh_key, defm_key)
22+
23+
job = batch.get_job(job_key)

demo/linear_single_crystal/batch.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
suite = "linear_single_crystal"
1212
process = "linear-elasticity"
1313

14-
# The `get_job` function is required for running batch jobs.
1514

1615
def get_job(key):
1716
matl, poly, mesh, defm = key
@@ -30,20 +29,31 @@ def get_job(key):
3029
)
3130

3231

33-
# Next, we set up the iterator for job keys.
32+
# Below are some job suites.
3433

35-
all_matl_keys = matl_dict.keys()
36-
matl_keys = ("identity-iso",)
34+
matl_keys = list(matl_dict.keys())
3735
poly_keys = [(0, 0)]
38-
mesh_keys = ((10, 20, 30),)
39-
all_defm_keys = itertools.product(
40-
("full", "zmax-traction", "zmax-traction-z", "zmax-traction-xy"),
41-
range(3), range(3)
42-
)
36+
mesh_keys = [(10, 20, 30)]
37+
defm_keys = [("full", 1, 1)]
38+
39+
# This suite runs all materials on the same mesh with displacements
40+
# corresponding to an xx-strain field.
41+
all_materials_xx = itertools.product(matl_keys, poly_keys, mesh_keys, defm_keys)
42+
43+
44+
matl_keys = ["cubic-211"]
45+
poly_keys = [(0, 0)]
46+
mesh_keys = [(10, 20, 30)]
47+
defm_keys = [
48+
("zmax-traction", 3, 3),
49+
("zmax-traction-z", 3, 3),
50+
("zmax-traction-xy", 3, 3)
51+
]
52+
53+
# This suite runs various traction boundary conditions on the top surface with a
54+
# fixed mesh and a cubic material.
55+
cubic_traction_z = itertools.product(matl_keys, poly_keys, mesh_keys, defm_keys)
4356

44-
identity_all_bcs = itertools.product(matl_keys, [(0, 0)], [(10, 20, 30)], all_defm_keys)
45-
all_matls_full_bcs = itertools.product(
46-
all_matl_keys, [(0, 0)], [(20, 20, 20)], [("full", 0, 0)]
47-
)
4857

49-
job_keys = itertools.chain(identity_all_bcs, all_matls_full_bcs)
58+
# This is the default job suite.
59+
job_keys = cubic_traction_z

demo/linear_single_crystal/data.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,23 @@ def cubic_from_KGdGs(K, Gd, Gs):
3939
# Polycrystal Data
4040

4141
def get_polycrystal_input(ax, ang_d):
42-
"""return polycrystal input for single crystal rotated about axis `ax`"""
42+
"""Return polycrystal input for single crystal
43+
44+
Parameters
45+
----------
46+
ax: array(3)
47+
axis of rotation
48+
ang_d: float
49+
angle of rotation in degrees
50+
51+
Returns
52+
-------
53+
inp: inputs.polycrystal.Polycrystal
54+
the polycrystal input
55+
"""
4356
ms = get_micro(ax, ang_d)
4457
name = "-".join(("single-crystal", "xyz"[ax] + str(ang_d)))
58+
4559
return inputs.polycrystal.Polycrystal(
4660
name=name,
4761
polycrystal=ms

demo/linear_single_crystal/defm_data.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from polycrystalx import inputs
55
from polycrystalx.inputs.tools import interpolate
6-
from polycrystal.utils.tensordata import TensorData
6+
from polycrystal.utils.tensor_data.mandel_system import MandelSystem
77

88

99
X_COMP, Y_COMP, Z_COMP = 0, 1, 2
@@ -127,8 +127,22 @@ def get_input(key, matl):
127127

128128
def traction(matl, ori, A, n):
129129
"""Traction on surface with normal n of def with grad u = A for matl"""
130-
C = matl.sample_stiffness(ori)
131-
eps = TensorData(A.reshape(1, 3, 3))
132-
sig6 = C @ eps.symm6[0]
133-
sig = TensorData.from_parts(symm6=sig6.reshape((1,6))).matrices[0]
130+
matl.output_system = "MANDEL"
131+
132+
"""The following section of code computes the stress in the sample frame:
133+
1. Convert strain from sample to crystal
134+
2. Create the Mandel 6-vector for the crystal strain
135+
3. Apply the 6x6 stiffness to obtain the stress in the crystal frame
136+
4. Convert the stress 6-vector to a matrix, still in crystal frame
137+
5. Convert the stress matrix from crystal to sample
138+
6. Then you can apply the stress to the normal vector to get the traction.
139+
"""
140+
C_c = matl.stiffness # crystal frame
141+
eps_s = A
142+
eps_c = ori @ A @ ori.T
143+
eps_c6 = MandelSystem(eps_c).symm
144+
sig_c6 = C_c @ eps_c6.T
145+
sig_c = MandelSystem.from_parts(symm=sig_c6.T).matrices[0]
146+
sig = ori.T @ A @ ori
147+
134148
return sig @ n

polycrystalx/scripts/run_suite.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,22 @@ def main():
1515
"""run a suite of jobs"""
1616
p = argparser(*sys.argv)
1717
args = p.parse_args()
18+
print("job keys: ", args.keys)
1819

1920
user_module = get_input_module(args.input_module)
20-
if not hasattr(user_module, "job_keys"):
21-
raise AttributeError('module has no "job_keys" attribute')
21+
if not hasattr(user_module, args.keys):
22+
emsg = f"job keys attribute '{args.keys}' was not found"
23+
raise AttributeError(emsg)
2224

23-
24-
for job in user_module.job_keys:
25+
for job in getattr(user_module, args.keys):
2526
# Pickle to a temp file.
2627
fp = tempfile.NamedTemporaryFile(delete=False)
2728

2829
with open(fp.name, "wb") as f:
2930
pickle.dump(job, f)
3031

3132
print("\n===== New Job Starting", flush=True)
33+
3234
# Now run MPI job.
3335
cmd = [
3436
"mpirun", "-np", str(args.n),
@@ -52,5 +54,10 @@ def argparser(*args):
5254
default=2,
5355
help="number of processes"
5456
)
57+
p.add_argument(
58+
'-k', '--keys', type=str,
59+
default="job_keys",
60+
help="name of attribute with job keys"
61+
)
5562

5663
return p

tests/test_inputs.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ def test_check_inputs(self):
3535
)
3636

3737

38-
39-
40-
4138
class TestDeformationInputs:
4239

4340
def test_linear_elasticity(self):

0 commit comments

Comments
 (0)