https://mooseframework.inl.gov
ComputeBlockOrientationByRotation.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 
11 #include "MooseMesh.h"
12 
13 #include "libmesh/mesh_tools.h"
14 
16 
19 {
21  params.addParam<unsigned int>("bins", 20, "Number of bins to segregate quaternions");
22  params.addParam<Real>("L_norm", 1, "Specifies the type of average the user intends to perform");
23  params.addClassDescription(
24  "This object determines the orientation of each grain (block) by identifying the most common "
25  "orientation direction among the material points within the grain.");
26  return params;
27 }
28 
30  const InputParameters & parameters)
31  : ComputeBlockOrientationBase(parameters),
32  _updated_rotation(getMaterialProperty<RankTwoTensor>("updated_rotation")),
33  _bins(getParam<unsigned int>("bins")),
34  _L_norm(getParam<Real>("L_norm"))
35 {
36 }
37 
38 void
40 {
42 
43  _block_ea_values.clear();
44  _quat.clear();
45 }
46 
47 void
49 {
50  RankTwoTensor rot;
52 
53  for (unsigned int _qp = 0; _qp < _qrule->n_points(); _qp++)
54  rot += _JxW[_qp] * _coord[_qp] * _updated_rotation[_qp];
55  rot /= _current_elem_volume;
56 
57  // transform RankTwoTensor to Eigen::Matrix
58  Eigen::Matrix<Real, 3, 3> rot_mat;
59 
60  for (unsigned int i = 0; i < 3; ++i)
61  for (unsigned int j = 0; j < 3; ++j)
62  rot_mat(i, j) = rot(i, j);
63 
64  // SVD-based projection to SO(3)
65  Eigen::JacobiSVD<Eigen::Matrix<Real, 3, 3>> svd(rot_mat,
66  Eigen::ComputeFullU | Eigen::ComputeFullV);
67 
68  Eigen::Matrix<Real, 3, 3> U = svd.matrixU();
69  Eigen::Matrix<Real, 3, 3> V = svd.matrixV();
70 
71  // Enforce proper rotation (det = +1)
72  Eigen::Matrix<Real, 3, 3> R = U * V.transpose();
73  if (R.determinant() < 0.0)
74  {
75  Eigen::Matrix<Real, 3, 3> D = Eigen::Matrix<Real, 3, 3>::Identity();
76  D(2, 2) = -1.0;
77  R = U * D * V.transpose();
78  }
79 
80  // compute Quaternion from rotation matrix
81  Eigen::Quaternion<Real> q(R);
82  // store quaternion values for the current element
83  _quat[_current_elem->subdomain_id()].push_back(std::make_tuple(q.w(), q.x(), q.y(), q.z()));
84 }
85 
86 void
88 {
89  for (const auto & block : _fe_problem.mesh().meshSubdomains())
90  {
91  // Use allgather to sync data from all processors
94  }
95 }
96 
99 {
100  // creating a map to store the quaternion count for each bin index
101  std::map<std::tuple<int, int, int, int>, unsigned int> feature_weights;
102 
103  // precompute the scaling from the bins once and reuse
104  const Real bin_scale = 0.5 * _bins;
105 
106  for (const auto & [w, x, y, z] : _quat[sid])
107  {
108  const auto bin = std::make_tuple<int, int, int, int>(std::floor(w * bin_scale),
109  std::floor(x * bin_scale),
110  std::floor(y * bin_scale),
111  std::floor(z * bin_scale));
112  feature_weights[bin]++;
113  }
114 
115  // quaternion average matrix Q*w*Q^T
116  typedef Eigen::Matrix<Real, 4, 4> Matrix4x4;
117  Matrix4x4 quat_mat = Matrix4x4::Zero();
118  typedef Eigen::Matrix<Real, 4, 1> Vector4;
119 
120  Real total_weight = 0.0;
121 
122  for (const auto & [w, x, y, z] : _quat[sid])
123  {
124  Vector4 v(w, x, y, z);
125 
126  const auto bin = std::make_tuple<int, int, int, int>(std::floor(w * bin_scale),
127  std::floor(x * bin_scale),
128  std::floor(y * bin_scale),
129  std::floor(z * bin_scale));
130  const auto bin_size = feature_weights[bin];
131  const auto weight = std::pow(bin_size, _L_norm);
132  total_weight += weight;
133 
134  quat_mat += v * weight * v.transpose();
135  }
136 
137  quat_mat *= 1.0 / total_weight;
138 
139  // compute eigenvalues and eigenvectors
140  Eigen::EigenSolver<Matrix4x4> EigenSolver(quat_mat);
141  Vector4 eigen_values = EigenSolver.eigenvalues().real();
142  Matrix4x4 eigen_vectors = EigenSolver.eigenvectors().real();
143 
144  // Selecting eigenvector corresponding to max eigenvalue to compute average Euler angle
145  Vector4::Index max_index = 0;
146  eigen_values.maxCoeff(&max_index);
147  const auto max_vec = eigen_vectors.col(max_index) / eigen_vectors.col(max_index).norm();
148  const Eigen::Quaternion<Real> q(max_vec(0), max_vec(1), max_vec(2), max_vec(3));
149 
150  return EulerAngles(q);
151 }
std::map< SubdomainID, EulerAngles > _block_ea_values
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
void mooseSetToZero(T &v)
const MaterialProperty< RankTwoTensor > & _updated_rotation
static InputParameters validParams()
const MooseArray< Real > & _coord
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
registerMooseObject("SolidMechanicsApp", ComputeBlockOrientationByRotation)
virtual void initialize() override
Clear internal Euler angle and misorientationdata.
const double v
unsigned int _bins
number of bins for each quaternion component
const std::vector< double > y
const Parallel::Communicator & _communicator
const double R
const Real & _current_elem_volume
EulerAngles computeSubdomainEulerAngles(const SubdomainID &sid)
Compute Quaternion for each subdomain (block), following Markley, F.
Real _L_norm
parameter used to compute the weighting function for the average quaternion calculation ...
FEProblemBase & _fe_problem
virtual void execute() override
Compute the average of the rotation matrix in this element.
const std::vector< double > x
Computes the average value of a variable on each block.
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Computes the average value of a variable on each block.
virtual void initialize() override
This is called before execute so you can reset any internal data.
ComputeBlockOrientationByRotation(const InputParameters &parameters)
dof_id_type total_weight(const MeshBase &mesh)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const QBase *const & _qrule
const Elem *const & _current_elem
const MooseArray< Real > & _JxW
Euler angle triplet.
Definition: EulerAngles.h:24
virtual MooseMesh & mesh() override
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::unordered_map< SubdomainID, std::vector< std::tuple< Real, Real, Real, Real > > > _quat
virtual void finalize() override
Gather all Euler angles from this block.
MooseUnits pow(const MooseUnits &, int)
void ErrorVector unsigned int
const std::set< SubdomainID > & meshSubdomains() const