16 #include "libmesh/int_range.h" 18 #include <Eigen/Dense> 28 params.
addClassDescription(
"Load and manage DREAM.3D EBSD data files for running simulations on " 29 "reconstructed microstructures.");
31 "custom_columns", 0,
"Number of additional custom data columns to read from the EBSD file");
32 params.
addParam<
unsigned int>(
"bins", 20,
"Number of bins to segregate quaternions");
33 params.
addParam<
Real>(
"L_norm", 1,
"Specifies the type of average the user intends to perform");
34 params.
addParam<std::string>(
"ebsd_meshgenerator",
35 "Specify the name of the EBSDMeshGenerator. The EBSDReader can " 36 "autodetect this, if only one such MeshGenerator exists.");
42 _mesh(_fe_problem.
mesh()),
43 _nl(_fe_problem.getNonlinearSystemBase(_sys.number())),
45 _custom_columns(getParam<unsigned
int>(
"custom_columns")),
46 _time_step(_fe_problem.timeStep()),
47 _mesh_dimension(_mesh.dimension()),
48 _bins(getParam<unsigned
int>(
"bins")),
49 _L_norm(getParam<
Real>(
"L_norm")),
66 std::string ebsd_filename;
73 ebsd_filename =
mesh->getEBSDFilename();
74 geometry =
mesh->getEBSDGeometry();
78 std::string ebsd_meshgenerator_name;
80 ebsd_meshgenerator_name = getParam<std::string>(
"ebsd_meshgenerator");
84 for (
auto & mgn : meshgenerator_names)
90 if (!ebsd_meshgenerator_name.empty())
91 mooseError(
"Found multiple EBSDMeshGenerator objects (",
92 ebsd_meshgenerator_name,
95 "). Use the 'ebsd_meshgenerator' parameter to specify which one to use.");
96 ebsd_meshgenerator_name = mgn;
100 if (ebsd_meshgenerator_name.empty())
101 mooseError(
"Failed to autodetect an EBSDMeshGenerator (or a deprecated EBSDMesh object).");
108 paramError(
"ebsd_meshgenerator",
"No valid EBSDMeshGenerator object found.");
114 std::ifstream stream_in(ebsd_filename.c_str());
116 mooseError(
"Can't open EBSD file: ", ebsd_filename);
136 _data.resize(total_size);
139 while (std::getline(stream_in, line))
141 if (line.find(
"#") != 0)
147 std::istringstream iss(line);
148 iss >>
d._phi1 >>
d._Phi >>
d._phi2 >>
x >>
y >> z >>
d._feature_id >>
d._phase >>
159 if (!(iss >>
d._custom[i]))
160 mooseError(
"Unable to read in EBSD custom data column #", i);
163 (geometry.
dim == 3 && (z < _minz || z >
_maxz)))
164 mooseError(
"EBSD Data ouside of the domain declared in the header ([",
181 d._p = Point(
x,
y, z);
201 a._symmetry =
a._phase =
a._n = 0;
206 b.phi1 =
b.Phi =
b.phi2 = 0.0;
210 std::vector<std::vector<Eigen::Quaternion<Real>>> quat(
_grain_num);
218 angles.
phi1 =
j._phi1;
220 angles.
phi2 =
j._phi2;
228 else if (
a._phase !=
j._phase)
229 mooseError(
"An EBSD feature needs to have a uniform phase.");
232 a._symmetry =
j._symmetry;
233 else if (
a._symmetry !=
j._symmetry)
234 mooseError(
"An EBSD feature needs to have a uniform symmetry parameter.");
237 a._custom[i] +=
j._custom[i];
240 a._feature_id =
j._feature_id;
255 std::map<std::tuple<int, int, int, int>,
unsigned int> feature_weights;
258 for (
const auto & q : quat[i])
260 const auto bin = std::make_tuple<int, int, int, int>(std::floor(q.w() * 0.5 *
_bins),
261 std::floor(q.x() * 0.5 *
_bins),
262 std::floor(q.y() * 0.5 *
_bins),
263 std::floor(q.z() * 0.5 *
_bins));
264 feature_weights[bin]++;
277 typedef Eigen::Matrix<Real, 4, 4> Matrix4x4;
278 Matrix4x4 quat_mat = Matrix4x4::Zero();
279 typedef Eigen::Matrix<Real, 4, 1> Vector4;
281 bool data_quality_ok =
false;
283 for (
const auto & q : quat[i])
285 Vector4
v(q.w(), q.x(), q.y(), q.z());
287 const auto bin = std::make_tuple<int, int, int, int>(std::floor(q.w() * 0.5 *
_bins),
288 std::floor(q.x() * 0.5 *
_bins),
289 std::floor(q.y() * 0.5 *
_bins),
290 std::floor(q.z() * 0.5 *
_bins));
291 const auto bin_size = feature_weights[bin];
295 quat_mat +=
v *
weight *
v.transpose();
302 if (bin_size * 2 > quat[i].size())
303 data_quality_ok =
true;
309 if (!data_quality_ok)
310 _console << COLOR_YELLOW <<
"EBSD orientation data may not be reliable for grain " << i
312 << COLOR_DEFAULT << std::flush;
315 Eigen::EigenSolver<Matrix4x4> EigenSolver(quat_mat);
316 Vector4 eigen_values = EigenSolver.eigenvalues().real();
317 Matrix4x4 eigen_vectors = EigenSolver.eigenvectors().real();
320 Vector4::Index max_index = 0;
321 eigen_values.maxCoeff(&max_index);
322 const auto max_vec = eigen_vectors.col(max_index);
323 const Eigen::Quaternion<Real> q(max_vec(0), max_vec(1), max_vec(2), max_vec(3));
340 a._custom[i] /=
Real(
a._n);
390 unsigned int x_index, y_index, z_index, global_index;
395 mooseError(
"Data points must be on the interior of the mesh elements. In EBSDReader ",
name());
400 global_index = z_index *
_ny;
402 mooseError(
"Data points must be on the interior of the mesh elements. In EBSDReader ",
410 global_index = (global_index + y_index) *
_nx + x_index;
413 mooseAssert(global_index <
_data.size(),
414 "global_index " << global_index <<
" points out of _data range: " <<
_data.size());
424 unsigned avg_index = var;
428 mooseError(
"Error! Index out of range in EBSDReader::indexFromIndex(), index: ",
436 const std::map<dof_id_type, std::vector<Real>> &
442 const std::map<dof_id_type, std::vector<Real>> &
471 const std::map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map =
476 for (
const auto & node :
as_range(
mesh.active_nodes_begin(),
mesh.active_nodes_end()))
487 const auto & node_to_elem_pair = node_to_elem_map.find(node_id);
488 if (node_to_elem_pair != node_to_elem_map.end())
490 unsigned int n_elems =
491 node_to_elem_pair->second
494 for (
unsigned int ne = 0; ne < n_elems; ++ne)
497 unsigned int elem_id = (node_to_elem_pair->second)[ne];
500 const Elem * elem =
mesh.elem_ptr(elem_id);
504 const unsigned int global_id =
getGlobalID(
d._feature_id);
514 MooseSharedPointer<EBSDAccessFunctors::EBSDPointDataFunctor>
553 mooseError(
"Error: Please input supported EBSD_param");
557 return MooseSharedPointer<EBSDPointDataFunctor>(ret_val);
560 MooseSharedPointer<EBSDAccessFunctors::EBSDAvgDataFunctor>
602 mooseError(
"Error: Please input supported EBSD_param");
606 return MooseSharedPointer<EBSDAvgDataFunctor>(ret_val);
const Geometry & getEBSDGeometry() const
const EBSDAvgData & getAvgData(unsigned int i) const
Get the requested type of average data for (global) grain number i.
unsigned indexFromPoint(const Point &p) const
Computes a global index in the _data array given an input centroid point.
const MeshGenerator & getMeshGenerator(const std::string &name) const
std::map< dof_id_type, std::vector< Real > > _node_to_phase_weight_map
Map of phase weights per node.
unsigned int _custom_columns
number of additional custom data columns
const std::map< dof_id_type, std::vector< dof_id_type > > & nodeToActiveSemilocalElemMap()
std::vector< std::string > getMeshGeneratorNames() const
Real _maxx
Maximum grid extent.
MooseSharedPointer< EBSDPointDataFunctor > getPointDataAccessFunctor(const MooseEnum &field_name) const
Factory function to return a point functor specified by name.
unsigned int _grain_num
Variables needed to determine reduced order parameter values.
const std::vector< double > y
unsigned int _L_norm
L_norm value for averaging.
unsigned _nx
The number of values in the x, y and z directions.
const EBSDPointData & getData(const Point &p) const
Get the requested type of data at the point p.
const std::string & getEBSDFilename() const
virtual const std::string & name() const
MooseMesh & _mesh
MooseMesh Variables.
Mesh generated from parameters read from a DREAM3D EBSD file.
bool isParamValid(const std::string &name) const
static InputParameters validParams()
const std::map< dof_id_type, std::vector< Real > > & getNodeToGrainWeightMap() const
Returns a map consisting of the node index followd by a vector of all grain weights for that node...
Per element EBSD data point.
const std::vector< double > x
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
std::map< unsigned int, unsigned int > _global_id_map
map from feature_id to global_id
virtual const EulerAngles & getEulerAngles(unsigned int) const
EulerAngleProvider interface implementation to fetch a triplet of Euler angles.
std::array< Real, 3 > min
Access functor base class for EBSDAvgData.
const int & _time_step
current timestep. Maps are only rebuild on mesh change during time step zero
A GeneralUserObject that reads an EBSD file and stores the centroid data in a data structure which in...
Real _dx
The spacing of the values in x, y and z directions.
void paramError(const std::string ¶m, Args... args) const
std::string stringify(const T &t)
unsigned int _mesh_dimension
Dimension of the problem domain.
virtual unsigned int getGrainNum() const
Return the total number of grains.
EBSDReader(const InputParameters ¶ms)
std::vector< EBSDAvgData > _avg_data
Averages by (global) grain ID.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string v
registerMooseObject("PhaseFieldApp", EBSDReader)
unsigned indexFromIndex(unsigned int var) const
Transfer the index into the _avg_data array from given index.
std::map< dof_id_type, std::vector< Real > > _node_to_grain_weight_map
Map of grain weights per node.
unsigned int _bins
number of bins for each quaternion component
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::array< unsigned int, 3 > n
Abstract base class for user objects that implement the Euler Angle provider interface.
const ConsoleStream _console
const std::map< dof_id_type, std::vector< Real > > & getNodeToPhaseWeightMap() const
Returns a map consisting of the node index followd by a vector of all phase weights for that node...
static InputParameters validParams()
std::vector< EulerAngles > _avg_angles
Euler Angles by (global) grain ID.
void buildNodeWeightMaps()
Build grain and phase weight maps.
virtual unsigned int getPhaseNum() const
Return the total number of phases.
MooseSharedPointer< EBSDAvgDataFunctor > getAvgDataAccessFunctor(const MooseEnum &field_name) const
Factory function to return a average functor specified by name.
Mesh generated from parameters.
void meshChanged()
Maps need to be updated when the mesh changes.
MooseUnits pow(const MooseUnits &, int)
void ErrorVector unsigned int
std::vector< std::vector< unsigned int > > _global_id
global ID for given phases and grains
Access functor base class for EBSDPointData.
std::vector< EBSDPointData > _data
Logically three-dimensional data indexed by geometric points in a 1D vector.
Eigen::Quaternion< Real > toQuaternion()
virtual unsigned int getGlobalID(unsigned int phase, unsigned int local_id) const
Return the (global) grain id for a given phase and (local) grain number.