https://mooseframework.inl.gov
ComputeGBMisorientationType.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 #include "SolutionUserObject.h"
12 
14 
17 {
19  params.addClassDescription("Calculate types of grain boundaries in a polycrystalline sample");
20  params.addRequiredParam<UserObjectName>("grain_tracker",
21  "The GrainTracker UserObject to get values from.");
22  params.addRequiredParam<UserObjectName>("ebsd_reader", "The EBSDReader GeneralUserObject");
24  "v", "var_name_base", "op_num", "Array of coupled variables");
25  params.addParam<Real>("angle_threshold", 15, "Max LAGB Misorientation angle");
26  return params;
27 }
28 
30  : Material(parameters),
31  _grain_tracker(getUserObject<GrainTracker>("grain_tracker")),
32  _ebsd_reader(getUserObject<EBSDReader>("ebsd_reader")),
33  _op_num(coupledComponents("v")),
34  _vals(coupledValues("v")),
35  _angle_threshold(getParam<Real>("angle_threshold")),
36  _gb_type(declareADProperty<Real>("gb_type"))
37 {
39 }
40 
41 void
43 {
44  // Find out the number of boundary unique_id and save them
45  _gb_pairs.clear();
46  _gb_op_pairs.clear();
47 
48  const auto & op_to_grains = _grain_tracker.getVarToFeatureVector(_current_elem->id());
49  for (auto i : index_range(op_to_grains))
50  {
51  if (op_to_grains[i] == FeatureFloodCount::invalid_id)
52  continue;
53 
54  _gb_pairs.push_back(_ebsd_reader.getFeatureID(op_to_grains[i]));
55  _gb_op_pairs.push_back((*_vals[i])[_qp]);
56  }
57 
58  // Compute GB type by the number of id
59  _gb_type[_qp] = 0;
60  switch (_gb_pairs.size())
61  {
62  case 0:
63  break;
64  case 1:
65  break;
66  case 2:
67  // get type by Misorientation angle
68  _gb_type[_qp] =
70  : 2);
71  break;
72  default:
73  // get continuous type at triple junction
75  }
76 }
77 
78 // Function to output total line number of Misorientation angle file
79 unsigned int
81 {
82  return _misorientation_angles.size();
83 }
84 
85 // Function to output specific line number in Misorientation angle file
86 unsigned int
87 ComputeGBMisorientationType::getLineNum(unsigned int grain_i, unsigned int grain_j)
88 {
89  if (grain_i > grain_j)
90  return grain_j + (grain_i - 1) * grain_i / 2;
91  else
92  return grain_i + (grain_j - 1) * grain_j / 2;
93 }
94 
95 // Function to calculate the GB type in Triple junction
96 Real
98 {
99  unsigned int lagb_num = 0;
100  unsigned int hagb_num = 0;
101  Real ratio_base = 0.0;
102  Real ratio_lagb = 0.0;
103  for (unsigned int i = 1; i < _gb_pairs.size(); ++i)
104  {
105  for (unsigned int j = 0; j < i; ++j)
106  {
107  ratio_base += (_gb_op_pairs[i] * _gb_op_pairs[i] * _gb_op_pairs[j] * _gb_op_pairs[j]);
109  {
110  lagb_num += 1;
111  ratio_lagb += (_gb_op_pairs[i] * _gb_op_pairs[i] * _gb_op_pairs[j] * _gb_op_pairs[j]);
112  }
113  else
114  hagb_num += 1;
115  }
116  }
117  if (lagb_num == 0)
118  return 2;
119  else if (hagb_num == 0)
120  return 1;
121  else
122  return 2 - ratio_lagb / ratio_base;
123 }
124 
125 // Function to convert symmetry matrix to quaternion form
126 void
128  Eigen::Quaternion<Real> & q)
129 {
130  double q4 = 0;
131  if ((1 + O[0][0] + O[1][1] + O[2][2]) > 0)
132  {
133  q4 = sqrt(1 + O[0][0] + O[1][1] + O[2][2]) / 2;
134  q.w() = q4;
135  q.x() = (O[2][1] - O[1][2]) / (4 * q4);
136  q.y() = (O[0][2] - O[2][0]) / (4 * q4);
137  q.z() = (O[1][0] - O[0][1]) / (4 * q4);
138  }
139  else if ((1 + O[0][0] - O[1][1] - O[2][2]) > 0)
140  {
141  q4 = sqrt(1 + O[0][0] - O[1][1] - O[2][2]) / 2;
142  q.w() = (O[2][1] - O[1][2]) / (4 * q4);
143  q.x() = q4;
144  q.y() = (O[1][0] + O[0][1]) / (4 * q4);
145  q.z() = (O[0][2] + O[2][0]) / (4 * q4);
146  }
147  else if ((1 - O[0][0] + O[1][1] - O[2][2]) > 0)
148  {
149  q4 = sqrt(1 - O[0][0] + O[1][1] - O[2][2]) / 2;
150  q.w() = (O[0][2] - O[2][0]) / (4 * q4);
151  q.x() = (O[1][0] + O[0][1]) / (4 * q4);
152  q.y() = q4;
153  q.z() = (O[2][1] + O[1][2]) / (4 * q4);
154  }
155  else if ((1 - O[0][0] - O[1][1] + O[2][2]) > 0)
156  {
157  q4 = sqrt(1 - O[0][0] - O[1][1] + O[2][2]) / 2;
158  q.w() = (O[1][0] - O[0][1]) / (4 * q4);
159  q.x() = (O[0][2] + O[2][0]) / (4 * q4);
160  q.y() = (O[2][1] + O[1][2]) / (4 * q4);
161  q.z() = q4;
162  }
163 }
164 
165 // Function to define the symmetry operator
166 void
168 {
169  // grow by number of symmetric operators
170  _sym_quat.resize(_o_sym);
171 
172  // cubic symmetry
173  double sym_rotation[24][3][3] = {
174  {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
175  {{1, 0, 0}, {0, 0, -1}, {0, 1, 0}}, {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}},
176  {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}}, {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
177  {{-1, 0, 0}, {0, 0, -1}, {0, -1, 0}}, {{-1, 0, 0}, {0, 0, 1}, {0, 1, 0}},
178  {{0, 1, 0}, {-1, 0, 0}, {0, 0, 1}}, {{0, 1, 0}, {0, 0, -1}, {-1, 0, 0}},
179  {{0, 1, 0}, {1, 0, 0}, {0, 0, -1}}, {{0, 1, 0}, {0, 0, 1}, {1, 0, 0}},
180  {{0, -1, 0}, {1, 0, 0}, {0, 0, 1}}, {{0, -1, 0}, {0, 0, -1}, {1, 0, 0}},
181  {{0, -1, 0}, {-1, 0, 0}, {0, 0, -1}}, {{0, -1, 0}, {0, 0, 1}, {-1, 0, 0}},
182  {{0, 0, 1}, {0, 1, 0}, {-1, 0, 0}}, {{0, 0, 1}, {1, 0, 0}, {0, 1, 0}},
183  {{0, 0, 1}, {0, -1, 0}, {1, 0, 0}}, {{0, 0, 1}, {-1, 0, 0}, {0, -1, 0}},
184  {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}}, {{0, 0, -1}, {-1, 0, 0}, {0, 1, 0}},
185  {{0, 0, -1}, {0, -1, 0}, {-1, 0, 0}}, {{0, 0, -1}, {1, 0, 0}, {0, -1, 0}}};
186 
187  // initialize global operator
188  for (int o = 0; o < _o_sym; o++)
189  rotationSymmetryToQuaternion(sym_rotation[o], _sym_quat[o]);
190 }
191 
192 // Function to return the misorientation of two quaternions
193 double
195  const Eigen::Quaternion<Real> qj)
196 {
197  Real miso0, misom = 2.0 * libMesh::pi;
198  Eigen::Quaternion<Real> q, qib, qjb, qmin;
199  qmin.w() = 0;
200  qmin.x() = 0;
201  qmin.y() = 0;
202  qmin.z() = 0;
203 
204  for (int o1 = 0; o1 < _o_sym; o1++)
205  {
206  for (int o2 = 0; o2 < _o_sym; o2++)
207  {
208  qib = _sym_quat[o1] * qi;
209  qjb = _sym_quat[o2] * qj;
210 
211  // j-grain conjugate quaternion
212  qjb.x() = -qjb.x();
213  qjb.y() = -qjb.y();
214  qjb.z() = -qjb.z();
215  q = qib * qjb;
216  miso0 = round(2 * std::acos(q.w()) * 1e5) / 1e5;
217 
218  if (miso0 > libMesh::pi)
219  miso0 = miso0 - 2 * libMesh::pi;
220  if (std::abs(miso0) < misom)
221  {
222  misom = std::abs(miso0);
223  qmin = q;
224  }
225  }
226  }
227 
228  miso0 = 2 * std::acos(qmin.w());
229  if (miso0 > libMesh::pi)
230  miso0 = miso0 - 2 * libMesh::pi;
231 
232  return std::abs(miso0);
233 }
234 
235 // Get the Misorientation angle
236 void
238 {
239  // Initialize symmetry operator as quaternion vectors
241  // Initialize parameters to calculate misorientation
242  const auto grain_num = _ebsd_reader.getGrainNum();
243  _euler_angle.resize(grain_num);
244  _quat_angle.resize(grain_num);
245 
246  // Get Euler Angle of Orientation
247  for (const auto i : make_range(grain_num))
248  {
249  auto grain_id = _ebsd_reader.getFeatureID(i);
250  mooseAssert(grain_id < grain_num, "Feature ids cannot exceed max grain number");
252  _quat_angle[grain_id] = _euler_angle[grain_id].toQuaternion();
253  }
254 
255  for (const auto j : make_range(std::make_unsigned_t<int>(1), grain_num))
256  {
257  for (const auto i : make_range(j))
258  {
260  _misorientation_angles.push_back(theta / libMesh::pi * 180);
261  }
262  }
263 }
double getMisorientationFromQuaternion(const Eigen::Quaternion< Real > qi, const Eigen::Quaternion< Real > qj)
Function to return the misorientation of two quaternions.
const Real _angle_threshold
the max value of LAGB
ComputeGBMisorientationType(const InputParameters &parameters)
virtual unsigned int getLineNum(unsigned int grain_i, unsigned int grain_j)
Function to obtain line number for a given grain pair.
void defineSymmetryOperator()
Function to define the symmetry operator.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void rotationSymmetryToQuaternion(const double O[3][3], Eigen::Quaternion< Real > &q)
Function to convert symmetry matrix to quaternion form.
registerMooseObject("PhaseFieldApp", ComputeGBMisorientationType)
virtual Real getTripleJunctionType()
Function to get the GB type for triple junctions.
std::vector< EulerAngles > _euler_angle
void addRequiredParam(const std::string &name, const std::string &doc_string)
unsigned int getFeatureID(unsigned int phase, unsigned int local_id) const
Return the EBSD feature id for a given phase and phase (local) grain number.
Definition: EBSDReader.h:81
unsigned int _qp
virtual const std::vector< unsigned int > & getVarToFeatureVector(dof_id_type elem_id) const override
Returns a list of active unique feature ids for a particular element.
Definition: GrainTracker.C:130
std::vector< double > _misorientation_angles
Parameters to calculate the Misorientation angle file.
static InputParameters validParams()
virtual void computeQpProperties() override
Necessary override. This is where the property values are set.
T round(T x)
const std::vector< const VariableValue * > _vals
const GrainTracker & _grain_tracker
Grain tracker object.
virtual const EulerAngles & getEulerAngles(unsigned int) const
EulerAngleProvider interface implementation to fetch a triplet of Euler angles.
Definition: EBSDReader.C:362
A GeneralUserObject that reads an EBSD file and stores the centroid data in a data structure which in...
Definition: EBSDReader.h:31
static const unsigned int invalid_id
std::vector< unsigned int > _gb_pairs
parameters to store the EBSD id and corresponding value on GB
std::vector< Eigen::Quaternion< Real > > _sym_quat
The parameters to calculate the misorientation.
virtual unsigned int getGrainNum() const
Return the total number of grains.
Definition: EBSDReader.C:374
std::vector< Eigen::Quaternion< Real > > _quat_angle
static InputParameters validParams()
virtual unsigned int getTotalLineNum() const
Function to obtain the total line number in misorientation angle file.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void addRequiredCoupledVarWithAutoBuild(const std::string &name, const std::string &base_name, const std::string &num_name, const std::string &doc_string)
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
IntRange< T > make_range(T beg, T end)
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
Visualize the location of grain boundaries in a polycrystalline simulation.
ADMaterialProperty< Real > & _gb_type
precalculated element value
auto index_range(const T &sizable)
const Elem *const & _current_elem
void getMisorientationAngles()
Get the Misorientation angle.
const EBSDReader & _ebsd_reader
EBSD reader user object.
const Real pi