NEML2 1.4.0
Loading...
Searching...
No Matches
CrystalGeometry.cxx
1// Copyright 2023, UChicago Argonne, LLC
2// All Rights Reserved
3// Software Name: NEML2 -- the New Engineering material Model Library, version 2
4// By: Argonne National Laboratory
5// OPEN SOURCE LICENSE (MIT)
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to deal
9// in the Software without restriction, including without limitation the rights
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in
15// all copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23// THE SOFTWARE.
24
25#include "neml2/models/crystallography/CrystalGeometry.h"
26
27#include "neml2/models/crystallography/crystallography.h"
28#include "neml2/tensors/tensors.h"
29
30using namespace torch::indexing;
31
32namespace neml2
33{
34namespace crystallography
35{
36
37register_NEML2_object(CrystalGeometry);
38
41{
43
44 options.doc() =
45 "A Data object storing basic crystallographic information for a given crystal system.";
46
47 options.set<CrossRef<R2>>("crystal_class");
48 options.set("crystal_class").doc() = "The set of symmetry operations defining the crystal class.";
49
50 options.set<CrossRef<Vec>>("lattice_vectors");
51 options.set("lattice_vectors").doc() =
52 "The three lattice vectors defining the crystal translational symmetry";
53
54 options.set<CrossRef<MillerIndex>>("slip_directions");
55 options.set("slip_directions").doc() = "A list of Miller indices defining the slip directions";
56
57 options.set<CrossRef<MillerIndex>>("slip_planes");
58 options.set("slip_planes").doc() = "A list of Miller indices defining the slip planes";
59
60 return options;
61}
62
64 : CrystalGeometry(options,
65 options.get<CrossRef<R2>>("crystal_class"),
66 options.get<CrossRef<Vec>>("lattice_vectors"),
67 setup_schmid_tensors(options.get<CrossRef<Vec>>("lattice_vectors"),
68 options.get<CrossRef<R2>>("crystal_class"),
69 options.get<CrossRef<MillerIndex>>("slip_directions"),
70 options.get<CrossRef<MillerIndex>>("slip_planes")))
71{
72}
73
75 const R2 & cclass,
76 const Vec & lattice_vectors)
77 : CrystalGeometry(options,
78 cclass,
80 setup_schmid_tensors(lattice_vectors,
81 cclass,
82 options.get<CrossRef<MillerIndex>>("slip_directions"),
83 options.get<CrossRef<MillerIndex>>("slip_planes")))
84{
85}
86
87Vec
89{
90 return _lattice_vectors.batch_index({0});
91}
92
93Vec
95{
96 return _lattice_vectors.batch_index({1});
97}
98
99Vec
101{
102 return _lattice_vectors.batch_index({2});
103}
104
105Vec
107{
108 return _reciprocal_lattice_vectors.batch_index({0});
109}
110
111Vec
113{
114 return _reciprocal_lattice_vectors.batch_index({1});
115}
116
117Vec
119{
120 return _reciprocal_lattice_vectors.batch_index({2});
121}
122
125{
126 return _slip_offsets.back();
127}
128
131{
132 return _slip_offsets.size() - 1;
133}
134
137{
139 return _slip_offsets[i + 1] - _slip_offsets[i];
140}
141
143 const R2 & cclass,
144 const Vec & lattice_vectors,
145 std::tuple<Vec, Vec, Scalar, std::vector<TorchSize>> slip_data)
146 : Data(options),
147 _sym_ops(cclass),
148 _lattice_vectors(declare_buffer<Vec>("lattice_vectors", lattice_vectors)),
149 _reciprocal_lattice_vectors(declare_buffer<Vec>("reciprocal_lattice_vectors",
150 make_reciprocal_lattice(_lattice_vectors))),
151 _slip_directions(declare_buffer<MillerIndex>("slip_directions", "slip_directions")),
152 _slip_planes(declare_buffer<MillerIndex>("slip_planes", "slip_planes")),
153 _cartesian_slip_directions(
154 declare_buffer<Vec>("cartesian_slip_directions", std::get<0>(slip_data))),
155 _cartesian_slip_planes(declare_buffer<Vec>("cartesian_slip_planes", std::get<1>(slip_data))),
156 _burgers(declare_buffer<Scalar>("burgers", std::get<2>(slip_data))),
157 _slip_offsets(std::get<3>(slip_data)),
158 _A(declare_buffer<R2>("schmid_tensors",
159 (_cartesian_slip_directions / _cartesian_slip_directions.norm())
160 .outer(_cartesian_slip_planes / _cartesian_slip_planes.norm()))),
161 _M(declare_buffer<SR2>("symmetric_schmid_tensors", SR2(_A))),
162 _W(declare_buffer<WR2>("skew_symmetric_schmid_tensors", WR2(_A)))
163{
164}
165
166Vec
167CrystalGeometry::make_reciprocal_lattice(const Vec & lattice_vectors)
168{
169 auto a1 = lattice_vectors.batch_index({0});
170 auto a2 = lattice_vectors.batch_index({1});
171 auto a3 = lattice_vectors.batch_index({2});
172
173 Vec rl = Vec(torch::stack({a2.cross(a3) / a1.dot(a2.cross(a3)),
174 a3.cross(a1) / a2.dot(a3.cross(a1)),
175 a1.cross(a2) / a3.dot(a1.cross(a2))}));
176
177 return rl;
178}
179
180Vec
181CrystalGeometry::miller_to_cartesian(const Vec & A, const MillerIndex & d)
182{
183 // Take advantage that a collection of 3 vectors is a R2
184 return R2(torch::Tensor(A)) * d.reduce().to_vec();
185}
186
187std::tuple<Vec, Vec, Scalar, std::vector<TorchSize>>
188CrystalGeometry::setup_schmid_tensors(const Vec & A,
189 const R2 & cls,
190 const MillerIndex & slip_directions,
191 const MillerIndex & slip_planes)
192{
193 // We need the reciprocol lattice
194 Vec B = make_reciprocal_lattice(A);
195
196 // List of slip directions and planes needs to be consistent
197 if (slip_directions.batch_sizes() != slip_planes.batch_sizes())
198 neml_assert("Input slip directions and planes must have the same batch sizes");
199
200 auto bshape = slip_planes.batch_sizes();
201 auto nbatch = slip_planes.batch_dim();
202
203 // Loop over each slip system
204 std::vector<torch::Tensor> cartesian_slip_directions;
205 std::vector<torch::Tensor> cartesian_slip_planes;
206 std::vector<torch::Tensor> burgers_vectors;
207 std::vector<TorchSize> offsets = {0};
208
209 for (TorchSize i = 0; i < bshape[nbatch - 1]; i++)
210 {
211 // Get the cartesian slip plane and direction
212 auto cmd = slip_directions.batch_index({torch::indexing::Ellipsis, i});
213 auto cmp = slip_planes.batch_index({torch::indexing::Ellipsis, i});
214
215 // Get the families of symmetry-equivalent planes and directions
216 auto direction_options = unique_bidirectional(cls, miller_to_cartesian(A, cmd));
217 auto plane_options = unique_bidirectional(cls, miller_to_cartesian(B, cmp));
218
219 // Accept the ones that are perpendicular
220 // We could do this in a vectorized manner, but I don't think it's worth it as
221 // this code only runs once
222 TorchSize last = offsets.back();
223 for (TorchSize j = 0; j < direction_options.batch_sizes()[direction_options.batch_dim() - 1];
224 j++)
225 {
226 auto di = direction_options.batch_index({torch::indexing::Ellipsis, j});
227 auto dps = plane_options.dot(di);
228 auto inds =
229 torch::where(torch::isclose(torch::abs(dps), torch::tensor(0.0, dps.dtype()))).front();
230 // We could very easily vectorize this loop, but again whatever
231 for (TorchSize kk = 0; kk < inds.sizes()[0]; kk++)
232 {
233 TorchSize k = inds.index({kk}).item<TorchSize>();
234 auto pi = plane_options.batch_index({torch::indexing::Ellipsis, k});
235 cartesian_slip_directions.push_back(di / di.norm());
236 cartesian_slip_planes.push_back(pi / pi.norm());
237 burgers_vectors.push_back(di.norm());
238 last += 1;
239 }
240 }
241 offsets.push_back(last);
242 }
243
244 return std::make_tuple(Vec(torch::stack(cartesian_slip_directions)),
245 Vec(torch::stack(cartesian_slip_planes)),
246 Scalar(torch::stack(burgers_vectors)),
247 offsets);
248}
249
250} // namespace crystallography
251} // namespace neml2
Derived batch_index(TorchSlice indices) const
Get a batch.
Definition BatchTensorBase.cxx:184
The wrapper (decorator) for cross-referencing unresolved values at parse time.
Definition CrossRef.h:52
Definition Data.h:36
static OptionSet expected_options()
Definition Data.cxx:30
Represention of a crystal direction or plane a Miller Index.
Definition MillerIndex.h:38
A custom map-like data structure. The keys are strings, and the values can be nonhomogeneously typed.
Definition OptionSet.h:59
const std::string & doc() const
A readonly reference to the option set's docstring.
Definition OptionSet.h:91
T & set(const std::string &)
Definition OptionSet.h:436
A basic R2.
Definition R2.h:42
The (logical) symmetric second order tensor.
Definition SR2.h:46
The (logical) scalar.
Definition Scalar.h:38
Derived cross(const VecBase< Derived2 > &v) const
cross product
Definition VecBase.h:106
Scalar dot(const VecBase< Derived2 > &v) const
dot product
Definition VecBase.h:96
The (logical) vector.
Definition Vec.h:42
A skew rank 2, represented as an axial vector.
Definition WR2.h:43
Defines the geometry of a crystal system This includes a basic definition of the crystal lattice,...
Definition CrystalGeometry.h:48
Vec b3() const
accessor for the third reciprocal lattice vector
Definition CrystalGeometry.cxx:118
const R2 & A() const
Accessor for the full Schmid tensors.
Definition CrystalGeometry.h:88
const Vec & cartesian_slip_directions() const
Accessor for the slip directions.
Definition CrystalGeometry.h:81
Vec a1() const
accessor for the first lattice vector
Definition CrystalGeometry.cxx:88
const Vec & cartesian_slip_planes() const
Accessor for the slip planes.
Definition CrystalGeometry.h:83
CrystalGeometry(const OptionSet &options)
Setup from parameter set.
Definition CrystalGeometry.cxx:63
Vec a3() const
accessor for the third lattice vector
Definition CrystalGeometry.cxx:100
Vec b2() const
accessor for the second reciprocal lattice vector
Definition CrystalGeometry.cxx:112
TorchSize nslip_groups() const
Number of slip groups.
Definition CrystalGeometry.cxx:130
TorchSize nslip() const
Total number of slip systems.
Definition CrystalGeometry.cxx:124
static OptionSet expected_options()
Input options.
Definition CrystalGeometry.cxx:40
Vec a2() const
accessor for the second lattice vector
Definition CrystalGeometry.cxx:94
Vec b1() const
accessor for the first reciprocal lattice vector
Definition CrystalGeometry.cxx:106
TorchSize nslip_in_group(TorchSize i) const
Number of slip systems in a given group.
Definition CrystalGeometry.cxx:136
Vec unique_bidirectional(const R2 &ops, const Vec &inp)
Helper to return all symmetrically-equivalent directions from a cartesian vector.
Definition crystallography.cxx:147
Definition CrossRef.cxx:32
void neml_assert_dbg(bool assertion, Args &&... args)
Definition error.h:85
int64_t TorchSize
Definition types.h:35
void neml_assert(bool assertion, Args &&... args)
Definition error.h:73