https://mooseframework.inl.gov
EulerAngleUpdater.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 
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(declareRestartableData<bool>("first_time_euler_update", true)),
44  _first_time_recovered(_app.isRecovering()),
45  _t_step_old(declareRestartableData<int>("euler_update_tstep_old", -1)),
46  _angles_old(declareRestartableData<std::vector<EulerAngles>>("euler_angles_old"))
47 {
48 }
49 
50 void
52 {
53  const auto grain_num = _grain_tracker.getTotalFeatureCount();
54 
55  if (_first_time)
56  {
57  _angles.resize(grain_num);
58  _angles_old.resize(grain_num);
59  for (unsigned int i = 0; i < grain_num; ++i)
60  _angles[i] = _euler.getEulerAngles(i); // Read initial euler angles
61  }
62 
63  unsigned int angle_size = _angles.size();
64  for (unsigned int i = angle_size; i < grain_num; ++i) // if new grains are created
65  _angles.push_back(_euler.getEulerAngles(i)); // Assign initial euler angles
66 
67  for (unsigned int i = 0; i < grain_num; ++i)
68  {
69  // We dont want to use old angles on recovery
71  _angles[i] = _angles_old[i];
72  _first_time_recovered = false;
73 
75 
76  if (i <= angle_size && _t_step > _t_step_old) // if new grains are created
77  _angles_old[i] = _angles[i];
78  else if (i > angle_size)
79  _angles_old.push_back(_angles[i]);
80 
81  RotationTensor R0(_angles_old[i]); // RotationTensor as per old euler angles
82  RealVectorValue torque_rotated =
83  R0 * torque; // Applied torque is rotated to allign with old grain axes
84  RealVectorValue omega =
85  _mr / _grain_volumes[i] * torque_rotated; // Angular velocity as per old grain axes
95  RealVectorValue angle_change;
96  angle_change(0) = omega(2) * _dt;
97  angle_change(1) =
98  (omega(0) * std::cos(angle_change(0)) + omega(1) * std::sin(angle_change(0))) * _dt;
99  angle_change(2) = (omega(0) * std::sin(angle_change(0)) * std::sin(angle_change(1)) -
100  omega(1) * std::cos(angle_change(0)) * std::sin(angle_change(1)) +
101  omega(2) * std::cos(angle_change(1))) *
102  _dt;
103  angle_change *= (180.0 / libMesh::pi);
104 
105  RotationTensor R1(angle_change); // Rotation matrix due to torque
112  RealTensorValue R = R1 * R0;
113 
114  if (R(2, 2) != 1.0 && R(2, 2) != -1.0) // checks if cos(Phi) = 1 or -1
115  {
116  _angles[i].phi1 = std::atan2(R(2, 0), -R(2, 1)) * (180.0 / libMesh::pi);
117  _angles[i].Phi = std::acos(R(2, 2)) * (180.0 / libMesh::pi);
118  _angles[i].phi2 = std::atan2(R(0, 2), R(1, 2)) * (180.0 / libMesh::pi);
119  }
120  else if (R(2, 2) == 1.0) // special case for Phi = 0.0
121  {
122  if (R0(2, 2) == 1.0)
123  // when Phi_old = 0.0; all the rotations are about z axis and angles accumulates after each
124  // rotation
125  _angles[i].phi1 = _angles_old[i].phi1 + _angles_old[i].phi2 + angle_change(0);
126  else
127  _angles[i].phi1 = angle_change(0);
128  // Comply with bunge euler angle definitions, 0.0 <= phi1 <= 360.0
129  if (std::abs(_angles[i].phi1) > 360.0)
130  {
131  int laps = _angles[i].phi1 / 360.0;
132  _angles[i].phi1 -= laps * 360.0;
133  }
134  _angles[i].Phi = 0.0;
135  _angles[i].phi2 = -_angles[i].phi1 + std::atan2(R(0, 1), R(1, 1)) * (180.0 / libMesh::pi);
136  }
137  else
138  {
139  if (R0(2, 2) == 1.0)
140  _angles[i].phi1 = _angles_old[i].phi1 + _angles_old[i].phi2 + angle_change(0);
141  else
142  _angles[i].phi1 = angle_change(0);
143  // Comply with bunge euler angle definitions, 0.0 <= phi1 <= 360.0
144  if (std::abs(_angles[i].phi1) > 360.0)
145  {
146  int laps = _angles[i].phi1 / 360.0;
147  _angles[i].phi1 -= laps * 360.0;
148  }
149  _angles[i].Phi = 180.0;
150  _angles[i].phi2 = _angles[i].phi1 - std::atan2(-R(0, 1), -R(1, 1)) * (180.0 / libMesh::pi);
151  }
152 
153  // Following checks and updates are done only to comply with bunge euler angle definitions, 0.0
154  // <= phi1/phi2 <= 360.0
155  if (_angles[i].phi1 < 0.0)
156  _angles[i].phi1 += 360.0;
157  if (_angles[i].phi2 < 0.0)
158  _angles[i].phi2 += 360.0;
159  if (_angles[i].Phi < 0.0)
160  mooseError("Euler angle out of range.");
161  }
162 
163  _first_time = false;
165 }
166 
167 const EulerAngles &
169 {
170  mooseAssert(i < getGrainNum(), "Requesting Euler angles for an invalid grain id");
171  return _angles_old[i];
172 }
const GrainTrackerInterface & _grain_tracker
const GrainForceAndTorqueInterface & _grain_torque
This class defines the interface for the GrainTracking objects.
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
bool _first_time_recovered
Whether the simulation has recovered once.
virtual const std::vector< RealGradient > & getTorqueValues() const =0
std::vector< EulerAngles > & _angles_old
std::vector< EulerAngles > & _angles
const double R
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.
FEProblemBase & _fe_problem
TensorValue< Real > RealTensorValue
static InputParameters validParams()
virtual bool converged(const unsigned int sys_num)
const EulerAngleProvider & _euler
registerMooseObject("PhaseFieldApp", EulerAngleUpdater)
virtual const EulerAngles & getEulerAnglesOld(unsigned int) const
static InputParameters validParams()
unsigned int number() const
virtual unsigned int getGrainNum() const
Update Euler angles of each grains after rigid body rotation This class estimates the rotation of pri...
This is a RealTensor version of a rotation matrix It is instantiated with the Euler angles...
EulerAngleUpdater(const InputParameters &parameters)
virtual void initialize() override
SystemBase & _sys
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool & _first_time
Whether this is the first time updating angles, in which case the initial euler angle provider should...
int & _t_step_old
Used to determine whether a timestep is being repeated.
Euler angle triplet.
Definition: EulerAngles.h:24
virtual const EulerAngles & getEulerAngles(unsigned int i) const
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.
void ErrorVector unsigned int
const Real pi