https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
13#include "RotationTensor.h"
14#include "SystemBase.h"
15
17
20{
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
50void
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];
73
74 RealGradient torque = _grain_torque.getTorqueValues()[i];
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
167const EulerAngles &
169{
170 mooseAssert(i < getGrainNum(), "Requesting Euler angles for an invalid grain id");
171 return _angles_old[i];
172}
registerMooseObject("PhaseFieldApp", EulerAngleUpdater)
const double R
void ErrorVector unsigned int
Abstract base class for user objects that implement the Euler Angle provider interface.
std::vector< EulerAngles > & _angles
virtual const EulerAngles & getEulerAngles(unsigned int i) const
static InputParameters validParams()
virtual unsigned int getGrainNum() const
Update Euler angles of each grains after rigid body rotation This class estimates the rotation of pri...
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.
EulerAngleUpdater(const InputParameters &parameters)
std::vector< EulerAngles > & _angles_old
bool _first_time_recovered
Whether the simulation has recovered once.
const EulerAngleProvider & _euler
const GrainForceAndTorqueInterface & _grain_torque
virtual const EulerAngles & getEulerAnglesOld(unsigned int) const
virtual void initialize() override
const GrainTrackerInterface & _grain_tracker
static InputParameters validParams()
const VectorPostprocessorValue & _grain_volumes
Euler angle triplet.
Definition EulerAngles.h:25
This class provides interface for extracting the forces and torques computed in other UserObjects.
virtual const std::vector< RealGradient > & getTorqueValues() const =0
This class defines the interface for the GrainTracking objects.
virtual std::size_t getTotalFeatureCount() const =0
Returns a number large enough to contain the largest ID for all grains in use.
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void mooseError(Args &&... args) const
This is a RealTensor version of a rotation matrix It is instantiated with the Euler angles,...
virtual bool converged(const unsigned int sys_num)
unsigned int number() const
FEProblemBase & _fe_problem
SystemBase & _sys
const Real pi