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(declareRestartableData<std::vector<EulerAngles>>("euler_angles")),
47  _angles_old(declareRestartableData<std::vector<EulerAngles>>("euler_angles_old"))
48 {
49 }
50 
51 void
53 {
54  const auto grain_num = _grain_tracker.getTotalFeatureCount();
55 
56  if (_first_time)
57  {
58  _angles.resize(grain_num);
59  _angles_old.resize(grain_num);
60  for (unsigned int i = 0; i < grain_num; ++i)
61  _angles[i] = _euler.getEulerAngles(i); // Read initial euler angles
62  }
63 
64  unsigned int angle_size = _angles.size();
65  for (unsigned int i = angle_size; i < grain_num; ++i) // if new grains are created
66  _angles.push_back(_euler.getEulerAngles(i)); // Assign initial euler angles
67 
68  for (unsigned int i = 0; i < grain_num; ++i)
69  {
70  // We dont want to use old angles on recovery
72  _angles[i] = _angles_old[i];
73  _first_time_recovered = false;
74 
76 
77  if (i <= angle_size && _t_step > _t_step_old) // if new grains are created
78  _angles_old[i] = _angles[i];
79  else if (i > angle_size)
80  _angles_old.push_back(_angles[i]);
81 
82  RotationTensor R0(_angles_old[i]); // RotationTensor as per old euler angles
83  RealVectorValue torque_rotated =
84  R0 * torque; // Applied torque is rotated to allign with old grain axes
85  RealVectorValue omega =
86  _mr / _grain_volumes[i] * torque_rotated; // Angular velocity as per old grain axes
96  RealVectorValue angle_change;
97  angle_change(0) = omega(2) * _dt;
98  angle_change(1) =
99  (omega(0) * std::cos(angle_change(0)) + omega(1) * std::sin(angle_change(0))) * _dt;
100  angle_change(2) = (omega(0) * std::sin(angle_change(0)) * std::sin(angle_change(1)) -
101  omega(1) * std::cos(angle_change(0)) * std::sin(angle_change(1)) +
102  omega(2) * std::cos(angle_change(1))) *
103  _dt;
104  angle_change *= (180.0 / libMesh::pi);
105 
106  RotationTensor R1(angle_change); // Rotation matrix due to torque
113  RealTensorValue R = R1 * R0;
114 
115  if (R(2, 2) != 1.0 && R(2, 2) != -1.0) // checks if cos(Phi) = 1 or -1
116  {
117  _angles[i].phi1 = std::atan2(R(2, 0), -R(2, 1)) * (180.0 / libMesh::pi);
118  _angles[i].Phi = std::acos(R(2, 2)) * (180.0 / libMesh::pi);
119  _angles[i].phi2 = std::atan2(R(0, 2), R(1, 2)) * (180.0 / libMesh::pi);
120  }
121  else if (R(2, 2) == 1.0) // special case for Phi = 0.0
122  {
123  if (R0(2, 2) == 1.0)
124  // when Phi_old = 0.0; all the rotations are about z axis and angles accumulates after each
125  // rotation
126  _angles[i].phi1 = _angles_old[i].phi1 + _angles_old[i].phi2 + angle_change(0);
127  else
128  _angles[i].phi1 = angle_change(0);
129  // Comply with bunge euler angle definitions, 0.0 <= phi1 <= 360.0
130  if (std::abs(_angles[i].phi1) > 360.0)
131  {
132  int laps = _angles[i].phi1 / 360.0;
133  _angles[i].phi1 -= laps * 360.0;
134  }
135  _angles[i].Phi = 0.0;
136  _angles[i].phi2 = -_angles[i].phi1 + std::atan2(R(0, 1), R(1, 1)) * (180.0 / libMesh::pi);
137  }
138  else
139  {
140  if (R0(2, 2) == 1.0)
141  _angles[i].phi1 = _angles_old[i].phi1 + _angles_old[i].phi2 + angle_change(0);
142  else
143  _angles[i].phi1 = angle_change(0);
144  // Comply with bunge euler angle definitions, 0.0 <= phi1 <= 360.0
145  if (std::abs(_angles[i].phi1) > 360.0)
146  {
147  int laps = _angles[i].phi1 / 360.0;
148  _angles[i].phi1 -= laps * 360.0;
149  }
150  _angles[i].Phi = 180.0;
151  _angles[i].phi2 = _angles[i].phi1 - std::atan2(-R(0, 1), -R(1, 1)) * (180.0 / libMesh::pi);
152  }
153 
154  // Following checks and updates are done only to comply with bunge euler angle definitions, 0.0
155  // <= phi1/phi2 <= 360.0
156  if (_angles[i].phi1 < 0.0)
157  _angles[i].phi1 += 360.0;
158  if (_angles[i].phi2 < 0.0)
159  _angles[i].phi2 += 360.0;
160  if (_angles[i].Phi < 0.0)
161  mooseError("Euler angle out of range.");
162  }
163 
164  _first_time = false;
166 }
167 
168 unsigned int
170 {
171  return _angles.size();
172 }
173 
174 const EulerAngles &
176 {
177  mooseAssert(i < getGrainNum(), "Requesting Euler angles for an invalid grain id");
178  return _angles[i];
179 }
180 
181 const EulerAngles &
183 {
184  mooseAssert(i < getGrainNum(), "Requesting Euler angles for an invalid grain id");
185  return _angles_old[i];
186 }
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 unsigned int getGrainNum() const override
virtual const std::vector< RealGradient > & getTorqueValues() const =0
std::vector< EulerAngles > & _angles_old
Previous set of Euler angles, used when the time step failed to reset the angles (pre-update) ...
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.
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()
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:162
EulerAngleUpdater(const InputParameters &parameters)
virtual void initialize() override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const EulerAngles & getEulerAngles(unsigned int) const =0
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.
FEProblemBase & _fe_problem
Euler angle triplet.
Definition: EulerAngles.h:24
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
std::vector< EulerAngles > & _angles
Current set of Euler angles (one per grain), updated on initialize()
Abstract base class for user objects that implement the Euler Angle provider interface.
void ErrorVector unsigned int
const Real pi