Line data Source code
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 "EBSDMeshGenerator.h"
11 : #include "MooseApp.h"
12 : #include "MathUtils.h"
13 :
14 : #include "libmesh/int_range.h"
15 : #include "libmesh/mesh_refinement.h"
16 :
17 : #include <fstream>
18 :
19 : registerMooseObject("PhaseFieldApp", EBSDMeshGenerator);
20 :
21 : InputParameters
22 344 : EBSDMeshGenerator::validParams()
23 : {
24 344 : InputParameters params = MeshGenerator::validParams();
25 344 : params.addClassDescription("Mesh generated from a specified DREAM.3D EBSD data file.");
26 688 : params.addRequiredParam<FileName>("filename", "The name of the file containing the EBSD data");
27 :
28 688 : params.addDeprecatedParam<unsigned int>("uniform_refine",
29 : "Deprecated. Use `pre_refine` instead.",
30 : "Deprecated. Use `pre_refine` instead.");
31 688 : params.addParam<unsigned int>(
32 : "pre_refine",
33 688 : 0,
34 : "Number of coarsening levels available in adaptive mesh refinement. The resulting mesh will "
35 : "have one mesh element per EBSD data cell, but will be based on a refined coarser mesh with "
36 : "'pre_refine' levels of refinement. This requires all dimension of the EBSD data to be "
37 : "divisible by 2^pre_refine.(this parameter was formerly called 'uniform_refine')");
38 :
39 688 : params.addParam<processor_id_type>(
40 : "num_cores_for_partition",
41 : "Number of cores for partitioning the graph (dafaults to the number of MPI ranks)");
42 344 : return params;
43 0 : }
44 :
45 176 : EBSDMeshGenerator::EBSDMeshGenerator(const InputParameters & parameters)
46 : : MeshGenerator(parameters),
47 352 : _distributed(_mesh->isDistributedMesh()),
48 352 : _filename(getParam<FileName>("filename")),
49 704 : _pre_refine(isParamValid("pre_refine") ? getParam<unsigned int>("pre_refine")
50 176 : : getParam<unsigned int>("uniform_refine")),
51 352 : _base(buildMeshSubgenerator())
52 : {
53 168 : }
54 :
55 : std::unique_ptr<MeshBase> &
56 176 : EBSDMeshGenerator::buildMeshSubgenerator()
57 : {
58 176 : readEBSDHeader();
59 :
60 : const auto generator_type =
61 170 : _distributed ? "DistributedRectilinearMeshGenerator" : "GeneratedMeshGenerator";
62 170 : auto params = _app.getFactory().getValidParams(generator_type);
63 :
64 342 : params.set<MooseEnum>("dim") = (_geometry.dim == 1 ? "1" : (_geometry.dim == 2 ? "2" : "3"));
65 :
66 : std::array<unsigned int, 3> nr;
67 170 : nr[0] = _geometry.n[0];
68 170 : nr[1] = _geometry.n[1];
69 170 : nr[2] = _geometry.n[2];
70 :
71 : // set min/max box length
72 170 : params.set<Real>("xmin") = _geometry.min[0];
73 170 : params.set<Real>("xmax") = nr[0] * _geometry.d[0] + _geometry.min[0];
74 170 : params.set<Real>("ymin") = _geometry.min[1];
75 170 : params.set<Real>("ymax") = nr[1] * _geometry.d[1] + _geometry.min[1];
76 170 : params.set<Real>("zmin") = _geometry.min[2];
77 170 : params.set<Real>("zmax") = nr[2] * _geometry.d[2] + _geometry.min[2];
78 :
79 : // check if the requested uniform refine level is possible and determine initial grid size
80 506 : for (auto i : make_range(_geometry.dim))
81 : {
82 338 : auto factor = MathUtils::pow(2, _pre_refine);
83 338 : if (nr[i] % factor != 0)
84 2 : paramError("pre_refine",
85 : "EBSDMeshGenerator error. Requested levels of pre refinement not possible.");
86 336 : nr[i] /= factor;
87 : }
88 :
89 168 : if (_distributed)
90 : {
91 22 : params.set<dof_id_type>("nx") = nr[0];
92 22 : params.set<dof_id_type>("ny") = nr[1];
93 22 : params.set<dof_id_type>("nz") = nr[2];
94 22 : params.set<processor_id_type>("num_cores_for_partition") =
95 44 : isParamValid("num_cores_for_partition")
96 44 : ? getParam<processor_id_type>("num_cores_for_partition")
97 : : 0;
98 : }
99 : else
100 : {
101 146 : params.set<unsigned int>("nx") = nr[0];
102 146 : params.set<unsigned int>("ny") = nr[1];
103 146 : params.set<unsigned int>("nz") = nr[2];
104 : }
105 :
106 336 : addMeshSubgenerator(generator_type, name() + "_base_mesh", params);
107 504 : return getMeshByName(name() + "_base_mesh");
108 168 : }
109 :
110 : void
111 176 : EBSDMeshGenerator::readEBSDHeader()
112 : {
113 176 : std::ifstream stream_in(_filename.c_str());
114 :
115 176 : if (!stream_in)
116 0 : paramError("filename", "Can't open EBSD file: ", _filename);
117 :
118 : // Labels to look for in the header
119 : const std::vector<std::string> labels = {
120 176 : "x_step", "x_dim", "y_step", "y_dim", "z_step", "z_dim", "x_min", "y_min", "z_min"};
121 :
122 : // Dimension variables to store once they are found in the header
123 : // X_step, X_Dim, Y_step, Y_Dim, Z_step, Z_Dim
124 : // We use Reals even though the Dim values should all be integers...
125 176 : std::vector<Real> label_vals(labels.size(), 0.0);
126 :
127 : std::string line;
128 6150 : while (std::getline(stream_in, line))
129 : {
130 : // We need to process the comment lines that have:
131 : // X_step, X_Dim
132 : // Y_step, Y_Dim
133 : // Z_step, Z_Dim
134 : // in them. The labels are case insensitive.
135 6150 : if (line.find("#") == 0)
136 : {
137 : // Process lines that start with a comment character (comments and meta data)
138 : std::transform(line.begin(), line.end(), line.begin(), ::tolower);
139 :
140 51820 : for (unsigned i = 0; i < labels.size(); ++i)
141 47430 : if (line.find(labels[i]) != std::string::npos)
142 : {
143 : std::string dummy;
144 1584 : std::istringstream iss(line);
145 1584 : iss >> dummy >> dummy >> label_vals[i];
146 :
147 : // One label per line, break out of for loop over labels
148 : break;
149 1584 : }
150 : }
151 : else
152 : // first non comment line marks the end of the header
153 : break;
154 : }
155 :
156 : // Copy stuff out of the label_vars array into class variables
157 176 : _geometry.d[0] = label_vals[0];
158 176 : _geometry.n[0] = label_vals[1];
159 176 : _geometry.min[0] = label_vals[6];
160 :
161 176 : _geometry.d[1] = label_vals[2];
162 176 : _geometry.n[1] = label_vals[3];
163 176 : _geometry.min[1] = label_vals[7];
164 :
165 176 : _geometry.d[2] = label_vals[4];
166 176 : _geometry.n[2] = label_vals[5];
167 176 : _geometry.min[2] = label_vals[8];
168 :
169 : unsigned int dim;
170 :
171 : // determine mesh dimension
172 350 : for (dim = 3; dim > 0 && _geometry.n[dim - 1] == 0; --dim)
173 : ;
174 :
175 : // check if the data has nonzero stepsizes
176 518 : for (unsigned i = 0; i < dim; ++i)
177 : {
178 346 : if (_geometry.n[i] == 0)
179 2 : mooseError("Error reading header, EBSD grid size is zero.");
180 344 : if (_geometry.d[i] == 0.0)
181 2 : mooseError("Error reading header, EBSD data step size is zero.");
182 : }
183 :
184 172 : if (dim == 0)
185 2 : mooseError("Error reading header, EBSD data is zero dimensional.");
186 :
187 170 : _geometry.dim = dim;
188 170 : }
189 :
190 : std::unique_ptr<MeshBase>
191 132 : EBSDMeshGenerator::generate()
192 : {
193 132 : if (_pre_refine)
194 : {
195 16 : libMesh::MeshRefinement mesh_refinement(*_base);
196 16 : mesh_refinement.uniformly_refine(_pre_refine);
197 16 : }
198 132 : return std::move(_base);
199 : }
|