12 #include "MooseMesh.h"
13 #include "Conversion.h"
14 #include "NonlinearSystem.h"
15 #include <Eigen/Dense>
26 params.addClassDescription(
"Load and manage DREAM.3D EBSD data files for running simulations on "
27 "reconstructed microstructures.");
28 params.addParam<
unsigned int>(
29 "custom_columns", 0,
"Number of additional custom data columns to read from the EBSD file");
30 params.addParam<
unsigned int>(
"bins", 20,
"Number of bins to segregate quaternions");
31 params.addParam<Real>(
"L_norm", 1,
"Specifies the type of average the user intends to perform");
37 _mesh(_fe_problem.mesh()),
38 _nl(_fe_problem.getNonlinearSystemBase()),
40 _custom_columns(getParam<unsigned int>(
"custom_columns")),
41 _time_step(_fe_problem.timeStep()),
42 _mesh_dimension(_mesh.dimension()),
43 _bins(getParam<unsigned int>(
"bins")),
44 _L_norm(getParam<Real>(
"L_norm")),
55 mooseError(
"One cannot have zero bins");
62 if (_app.isRecovering())
68 mooseError(
"Please use an EBSDMesh in your simulation.");
92 _data.resize(total_size);
95 while (std::getline(stream_in, line))
97 if (line.find(
"#") != 0)
103 std::istringstream iss(line);
104 iss >> d._phi1 >> d._Phi >> d._phi2 >> x >> y >> z >> d._feature_id >> d._phase >>
108 d._phi1 *= 180.0 / libMesh::pi;
109 d._Phi *= 180.0 / libMesh::pi;
110 d._phi2 *= 180.0 / libMesh::pi;
115 if (!(iss >> d._custom[i]))
116 mooseError(
"Unable to read in EBSD custom data column #", i);
119 (g.dim == 3 && (z < _minz || z >
_maxz)))
120 mooseError(
"EBSD Data ouside of the domain declared in the header ([",
137 d._p = Point(x, y, z);
144 _data[global_index] = d;
166 std::vector<std::vector<Eigen::Quaternion<Real>>> quat(
_grain_num);
169 for (
auto & j :
_data)
174 angles.
phi1 = j._phi1;
176 angles.
phi2 = j._phi2;
185 else if (a.
_phase != j._phase)
186 mooseError(
"An EBSD feature needs to have a uniform phase.");
191 mooseError(
"An EBSD feature needs to have a uniform symmetry parameter.");
204 std::map<std::tuple<unsigned int, unsigned int, unsigned int, unsigned int>,
unsigned int>>
207 std::vector<std::vector<std::tuple<unsigned int, unsigned int, unsigned int, unsigned int>>>
218 Real w_index, x_index, y_index, z_index;
220 std::vector<std::tuple<double, Eigen::VectorXd>> eigen_vectors_and_values;
223 feature_weights.push_back(
224 std::map<std::tuple<unsigned int, unsigned int, unsigned int, unsigned int>,
228 for (
unsigned int k = 0; k < quat[i].size(); k++)
230 std::tuple<unsigned int, unsigned int, unsigned int, unsigned int> bin;
231 w_index = int((quat[i][k].w() + 1) * 0.5 *
_bins);
232 x_index = int((quat[i][k].x() + 1) * 0.5 *
_bins);
233 y_index = int((quat[i][k].y() + 1) * 0.5 *
_bins);
234 z_index = int((quat[i][k].z() + 1) * 0.5 *
_bins);
236 bin = std::make_tuple(w_index, x_index, y_index, z_index);
239 quat_to_bin[i].push_back(bin);
242 auto j = feature_weights[i].find(bin);
243 if (j == feature_weights[i].end())
244 feature_weights[i].emplace_hint(j, bin, 1);
259 Eigen::MatrixXd quat_mat(4, quat[i].size());
261 Eigen::MatrixXd weight = Eigen::MatrixXd::Identity(quat[i].size(), quat[i].size());
263 unsigned int bin_size;
264 bool data_quality_ok =
false;
265 Real total_weight = 0.0;
267 for (
unsigned int j = 0; j < quat[i].size(); j++)
269 bin_size = feature_weights[i][quat_to_bin[i][j]];
276 quat_mat.col(j) << w, x, y, z;
279 total_weight += weight(j, j);
285 if (bin_size / quat[i].size() > 0.5)
286 data_quality_ok =
true;
289 weight = weight / total_weight;
292 if (!data_quality_ok)
293 _console << COLOR_YELLOW <<
"EBSD data may not be reliable"
298 Eigen::EigenSolver<Eigen::MatrixXd> EigenSolver(quat_mat * weight * quat_mat.transpose());
299 Eigen::VectorXd eigen_values = EigenSolver.eigenvalues().real();
300 Eigen::MatrixXd eigen_vectors = EigenSolver.eigenvectors().real();
303 for (
unsigned int i = 0; i < eigen_values.size(); i++)
305 std::tuple<double, Eigen::VectorXd> vec_and_val(eigen_values[i], eigen_vectors.col(i));
306 eigen_vectors_and_values.push_back(vec_and_val);
309 auto j = std::max_element(eigen_vectors_and_values.begin(),
310 eigen_vectors_and_values.end(),
311 [&](
const std::tuple<double, Eigen::VectorXd> & a,
312 const std::tuple<double, Eigen::VectorXd> & b) ->
bool {
313 return std::get<0>(a) < std::get<0>(b);
316 Eigen::Quaternion<Real> q(
317 std::get<1>(*j)(0), std::get<1>(*j)(1), std::get<1>(*j)(2), std::get<1>(*j)(3));
332 a._p *= 1.0 / Real(a._n);
335 a._custom[i] /= Real(a._n);
385 unsigned int x_index, y_index, z_index, global_index;
387 x_index = (
unsigned int)((p(0) -
_minx) /
_dx);
388 y_index = (
unsigned int)((p(1) -
_miny) /
_dy);
390 mooseError(
"Data points must be on the interior of the mesh elements. In EBSDReader ",
name());
394 z_index = (
unsigned int)((p(2) -
_minz) /
_dz);
395 global_index = z_index *
_ny;
397 mooseError(
"Data points must be on the interior of the mesh elements. In EBSDReader ",
405 global_index = (global_index + y_index) *
_nx + x_index;
408 mooseAssert(global_index <
_data.size(),
409 "global_index " << global_index <<
" points out of _data range: " <<
_data.size());
419 unsigned avg_index = var;
423 mooseError(
"Error! Index out of range in EBSDReader::indexFromIndex(), index: ",
431 const std::map<dof_id_type, std::vector<Real>> &
437 const std::map<dof_id_type, std::vector<Real>> &
448 mooseError(
"Invalid Feature ID");
466 const std::map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map =
467 _mesh.nodeToActiveSemilocalElemMap();
468 libMesh::MeshBase & mesh =
_mesh.getMesh();
471 for (
const auto & node : as_range(mesh.active_nodes_begin(), mesh.active_nodes_end()))
474 const dof_id_type node_id = node->id();
482 const auto & node_to_elem_pair = node_to_elem_map.find(node_id);
483 if (node_to_elem_pair != node_to_elem_map.end())
485 unsigned int n_elems =
486 node_to_elem_pair->second
489 for (
unsigned int ne = 0; ne < n_elems; ++ne)
492 unsigned int elem_id = (node_to_elem_pair->second)[ne];
495 const Elem * elem = mesh.elem_ptr(elem_id);
509 MooseSharedPointer<EBSDAccessFunctors::EBSDPointDataFunctor>
538 if (field_name ==
"CUSTOM" + Moose::stringify(i))
548 mooseError(
"Error: Please input supported EBSD_param");
552 return MooseSharedPointer<EBSDPointDataFunctor>(ret_val);
555 MooseSharedPointer<EBSDAccessFunctors::EBSDAvgDataFunctor>
587 if (field_name ==
"CUSTOM" + Moose::stringify(i))
597 mooseError(
"Error: Please input supported EBSD_param");
601 return MooseSharedPointer<EBSDAvgDataFunctor>(ret_val);