www.mooseframework.org
EulerAngleUpdater.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
10 #include "EulerAngleUpdater.h"
11 #include "GrainTrackerInterface.h"
13 #include "RotationTensor.h"
14 #include "SystemBase.h"
15 
16 registerMooseObject("PhaseFieldApp", EulerAngleUpdater);
17 
20 {
22  params.addClassDescription(
23  "Provide updated euler angles after rigid body rotation of the grains.");
24  params.addRequiredParam<UserObjectName>("grain_tracker_object",
25  "The FeatureFloodCount UserObject to get values from.");
26  params.addRequiredParam<UserObjectName>("euler_angle_provider",
27  "Name of Euler angle provider user object");
28  params.addRequiredParam<UserObjectName>("grain_torques_object",
29  "Name of Euler angle provider user object");
30  params.addRequiredParam<VectorPostprocessorName>("grain_volumes",
31  "The feature volume VectorPostprocessorValue.");
32  params.addParam<Real>("rotation_constant", 1.0, "Constant value characterizing grain rotation");
33  return params;
34 }
35 
37  : EulerAngleProvider(params),
38  _grain_tracker(getUserObject<GrainTrackerInterface>("grain_tracker_object")),
39  _euler(getUserObject<EulerAngleProvider>("euler_angle_provider")),
40  _grain_torque(getUserObject<GrainForceAndTorqueInterface>("grain_torques_object")),
41  _grain_volumes(getVectorPostprocessorValue("grain_volumes", "feature_volumes")),
42  _mr(getParam<Real>("rotation_constant")),
43  _first_time(true)
44 {
45 }
46 
47 void
49 {
50  const auto grain_num = _grain_tracker.getTotalFeatureCount();
51 
52  if (_first_time)
53  {
54  _angles.resize(grain_num);
55  _angles_old.resize(grain_num);
56  for (unsigned int i = 0; i < grain_num; ++i)
57  _angles[i] = _euler.getEulerAngles(i); // Read initial euler angles
58  }
59 
60  unsigned int angle_size = _angles.size();
61  for (unsigned int i = angle_size; i < grain_num; ++i) // if new grains are created
62  _angles.push_back(_euler.getEulerAngles(i)); // Assign initial euler angles
63 
64  for (unsigned int i = 0; i < grain_num; ++i)
65  {
67  _angles[i] = _angles_old[i];
68 
70 
71  if (i <= angle_size) // if new grains are created
72  _angles_old[i] = _angles[i];
73  else
74  _angles_old.push_back(_angles[i]);
75 
76  RotationTensor R0(_angles_old[i]); // RotationTensor as per old euler angles
77  RealVectorValue torque_rotated =
78  R0 * torque; // Applied torque is rotated to allign with old grain axes
79  RealVectorValue omega =
80  _mr / _grain_volumes[i] * torque_rotated; // Angular velocity as per old grain axes
90  RealVectorValue angle_change;
91  angle_change(0) = omega(2) * _dt;
92  angle_change(1) =
93  (omega(0) * std::cos(angle_change(0)) + omega(1) * std::sin(angle_change(0))) * _dt;
94  angle_change(2) = (omega(0) * std::sin(angle_change(0)) * std::sin(angle_change(1)) -
95  omega(1) * std::cos(angle_change(0)) * std::sin(angle_change(1)) +
96  omega(2) * std::cos(angle_change(1))) *
97  _dt;
98  angle_change *= (180.0 / libMesh::pi);
99 
100  RotationTensor R1(angle_change); // Rotation matrix due to torque
107  RealTensorValue R = R1 * R0;
108 
109  if (R(2, 2) != 1.0 && R(2, 2) != -1.0) // checks if cos(Phi) = 1 or -1
110  {
111  _angles[i].phi1 = std::atan2(R(2, 0), -R(2, 1)) * (180.0 / libMesh::pi);
112  _angles[i].Phi = std::acos(R(2, 2)) * (180.0 / libMesh::pi);
113  _angles[i].phi2 = std::atan2(R(0, 2), R(1, 2)) * (180.0 / libMesh::pi);
114  }
115  else if (R(2, 2) == 1.0) // special case for Phi = 0.0
116  {
117  if (R0(2, 2) == 1.0)
118  // when Phi_old = 0.0; all the rotations are about z axis and angles accumulates after each
119  // rotation
120  _angles[i].phi1 = _angles_old[i].phi1 + _angles_old[i].phi2 + angle_change(0);
121  else
122  _angles[i].phi1 = angle_change(0);
123  // Comply with bunge euler angle definitions, 0.0 <= phi1 <= 360.0
124  if (std::abs(_angles[i].phi1) > 360.0)
125  {
126  int laps = _angles[i].phi1 / 360.0;
127  _angles[i].phi1 -= laps * 360.0;
128  }
129  _angles[i].Phi = 0.0;
130  _angles[i].phi2 = -_angles[i].phi1 + std::atan2(R(0, 1), R(1, 1)) * (180.0 / libMesh::pi);
131  }
132  else
133  {
134  if (R0(2, 2) == 1.0)
135  _angles[i].phi1 = _angles_old[i].phi1 + _angles_old[i].phi2 + angle_change(0);
136  else
137  _angles[i].phi1 = angle_change(0);
138  // Comply with bunge euler angle definitions, 0.0 <= phi1 <= 360.0
139  if (std::abs(_angles[i].phi1) > 360.0)
140  {
141  int laps = _angles[i].phi1 / 360.0;
142  _angles[i].phi1 -= laps * 360.0;
143  }
144  _angles[i].Phi = 180.0;
145  _angles[i].phi2 = _angles[i].phi1 - std::atan2(-R(0, 1), -R(1, 1)) * (180.0 / libMesh::pi);
146  }
147 
148  // Following checks and updates are done only to comply with bunge euler angle definitions, 0.0
149  // <= phi1/phi2 <= 360.0
150  if (_angles[i].phi1 < 0.0)
151  _angles[i].phi1 += 360.0;
152  if (_angles[i].phi2 < 0.0)
153  _angles[i].phi2 += 360.0;
154  if (_angles[i].Phi < 0.0)
155  mooseError("Euler angle out of range.");
156  }
157 
158  _first_time = false;
159 }
160 
161 unsigned int
163 {
164  return _angles.size();
165 }
166 
167 const EulerAngles &
169 {
170  mooseAssert(i < getGrainNum(), "Requesting Euler angles for an invalid grain id");
171  return _angles[i];
172 }
173 
174 const EulerAngles &
176 {
177  mooseAssert(i < getGrainNum(), "Requesting Euler angles for an invalid grain id");
178  return _angles_old[i];
179 }
const GrainTrackerInterface & _grain_tracker
const GrainForceAndTorqueInterface & _grain_torque
This class defines the interface for the GrainTracking objects.
virtual bool converged(const unsigned int nl_sys_num)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
This class provides interface for extracting the forces and torques computed in other UserObjects...
const VectorPostprocessorValue & _grain_volumes
virtual unsigned int getGrainNum() const override
virtual const std::vector< RealGradient > & getTorqueValues() const =0
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual std::size_t getTotalFeatureCount() const =0
Returns a number large enough to contain the largest ID for all grains in use.
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
TensorValue< Real > RealTensorValue
static InputParameters validParams()
const EulerAngleProvider & _euler
registerMooseObject("PhaseFieldApp", EulerAngleUpdater)
virtual const EulerAngles & getEulerAnglesOld(unsigned int) const
static InputParameters validParams()
SystemBase & _sys
unsigned int number() const
Update Euler angles of each grains after rigid body rotation This class estimates the rotation of pri...
virtual const EulerAngles & getEulerAngles(unsigned int) const override
This is a RealTensor version of a rotation matrix It is instantiated with the Euler angles...
static const std::string R
Definition: NS.h:147
EulerAngleUpdater(const InputParameters &parameters)
virtual void initialize() override
std::vector< EulerAngles > _angles_old
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const EulerAngles & getEulerAngles(unsigned int) const =0
FEProblemBase & _fe_problem
Euler angle triplet.
Definition: EulerAngles.h:24
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
Abstract base class for user objects that implement the Euler Angle provider interface.
std::vector< EulerAngles > _angles
const Real pi