https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PolycrystalVoronoi.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 "PolycrystalVoronoi.h"
11#include "IndirectSort.h"
12#include "MooseRandom.h"
13#include "MooseMesh.h"
14#include "MooseVariable.h"
15#include "NonlinearSystemBase.h"
16#include "DelimitedFileReader.h"
17
19
22{
25 "Random Voronoi tessellation polycrystal (used by PolycrystalVoronoiAction)");
26 params.addParam<unsigned int>(
27 "grain_num", 0, "Number of grains being represented by the order parameters");
28 params.addParam<unsigned int>("rand_seed", 0, "The random seed");
29 params.addParam<bool>(
30 "columnar_3D", false, "3D microstructure will be columnar in the z-direction?");
31 params.addParam<bool>(
32 "use_kdtree", false, "Whether or not to use a KD tree to speedup grain search");
33 params.addRangeCheckedParam<unsigned int>("point_patch_size",
34 1,
35 "point_patch_size > 0",
36 "How many nearest points KDTree should return");
37 params.addRangeCheckedParam<unsigned int>("grain_patch_size",
38 10,
39 "grain_patch_size > 0",
40 "How many nearest grains KDTree should return");
41 params.addParam<FileName>(
42 "file_name",
43 "",
44 "File containing grain centroids, if file_name is provided, the centroids "
45 "from the file will be used.");
46 params.addParam<Real>("int_width", 0.0, "Width of diffuse interfaces");
47 return params;
48}
49
51 : PolycrystalUserObjectBase(parameters),
52 _grain_num(getParam<unsigned int>("grain_num")),
53 _columnar_3D(getParam<bool>("columnar_3D")),
54 _rand_seed(getParam<unsigned int>("rand_seed")),
55 _int_width(getParam<Real>("int_width")),
56 _file_name(getParam<FileName>("file_name")),
57 _kd_tree(nullptr),
58 _use_kdtree(getParam<bool>("use_kdtree")),
59 _point_patch_size(getParam<unsigned int>("point_patch_size")),
60 _grain_patch_size(getParam<unsigned int>("grain_patch_size"))
61{
62 if (_file_name == "" && _grain_num == 0)
63 mooseError("grain_num must be provided if the grain centroids are not read from a file");
64
65 if (_file_name != "" && _grain_num > 0)
66 mooseWarning("grain_num is ignored and will be determined from the file.");
67}
68
69void
71 std::vector<unsigned int> & grains) const
72{
73 grains.resize(0);
74 Real d_min = _range.norm();
75 Real distance;
76 auto n_grains = _centerpoints.size();
77 auto min_index = n_grains;
78
79 if (_use_kdtree)
80 {
81 mooseAssert(_kd_tree, "KD tree is not constructed yet");
82 mooseAssert(_grain_gtl_ids.size() == _new_points.size(),
83 "The number of grain global IDs does not match that of new center points");
84
85 std::vector<std::size_t> return_index(_point_patch_size);
86 std::vector<Real> return_dist_sqr(_point_patch_size);
87
88 _kd_tree->neighborSearch(point, _point_patch_size, return_index, return_dist_sqr);
89
90 min_index = _grain_gtl_ids[return_index[0]];
91
92 d_min = return_dist_sqr[0];
93
94 // By default, _point_patch_size is one. A larger _point_patch_size
95 // may be useful if nearest nodes are not unique, and
96 // we want to select the node that has the smallest ID
97 for (unsigned int i = 1; i < _point_patch_size; i++)
98 {
99 if (d_min > return_dist_sqr[i])
100 {
101 min_index = _grain_gtl_ids[return_index[i]];
102 d_min = return_dist_sqr[i];
103 }
104 else if (d_min == return_dist_sqr[i])
105 {
106 min_index = min_index > _grain_gtl_ids[return_index[i]] ? _grain_gtl_ids[return_index[i]]
107 : min_index;
108 }
109 }
110 }
111 else
112 {
113 // Find the closest centerpoint to the current point
114 for (MooseIndex(_centerpoints) grain = 0; grain < n_grains; ++grain)
115 {
117 if (distance < d_min)
118 {
119 d_min = distance;
120 min_index = grain;
121 }
122 }
123 }
124
125 mooseAssert(min_index < n_grains, "Couldn't find closest Voronoi cell");
126 Point current_grain = _centerpoints[min_index];
127 grains.push_back(min_index); // closest centerpoint always gets included
128
129 if (_int_width > 0.0)
130 {
131 if (_use_kdtree)
132 {
133 mooseAssert(_grain_patch_size < _grain_gtl_ids.size(),
134 "Number of neighboring grains should not exceed number of global grains");
135
136 std::vector<std::size_t> return_index(_grain_patch_size);
137 _kd_tree->neighborSearch(current_grain, _grain_patch_size, return_index);
138
139 std::set<dof_id_type> neighbor_grains;
140 for (unsigned int i = 0; i < _grain_patch_size; i++)
141 if (_grain_gtl_ids[return_index[i]] != min_index)
142 neighbor_grains.insert(_grain_gtl_ids[return_index[i]]);
143
144 for (auto it = neighbor_grains.begin(); it != neighbor_grains.end(); ++it)
145 if ((*it) != min_index)
146 {
147 Point next_grain = _centerpoints[*it];
148 Point N = findNormalVector(point, current_grain, next_grain);
149 Point cntr = findCenterPoint(point, current_grain, next_grain);
150 distance = N * (cntr - point);
151 if (distance < _int_width)
152 grains.push_back(*it); // also include all grains with nearby boundaries
153 }
154 }
155 else
156 {
157 for (MooseIndex(_centerpoints) grain = 0; grain < n_grains; ++grain)
158 if (grain != min_index)
159 {
160 Point next_grain = _centerpoints[grain];
161 Point N = findNormalVector(point, current_grain, next_grain);
162 Point cntr = findCenterPoint(point, current_grain, next_grain);
163 distance = N * (cntr - point);
164 if (distance < _int_width)
165 grains.push_back(grain); // also include all grains with nearby boundaries
166 }
167 }
168 }
169}
170
171Real
172PolycrystalVoronoi::getVariableValue(unsigned int op_index, const Point & p) const
173{
174 std::vector<unsigned int> grain_ids;
175 getGrainsBasedOnPoint(p, grain_ids);
176
177 // Now see if any of those grains are represented by the passed in order parameter
178 unsigned int active_grain_on_op = invalid_id;
179 for (auto grain_id : grain_ids)
180 if (op_index == _grain_to_op.at(grain_id))
181 {
182 active_grain_on_op = grain_id;
183 break;
184 }
185
186 Real profile_val = 0.0;
187 if (active_grain_on_op != invalid_id)
188 profile_val = computeDiffuseInterface(p, active_grain_on_op, grain_ids);
189
190 return profile_val;
191}
192
193void
195{
196 // Set up domain bounds with mesh tools
197 for (const auto i : make_range(Moose::dim))
198 {
201 }
203
204 if (!_file_name.empty())
205 {
207
208 txt_reader.read();
209 std::vector<std::string> col_names = txt_reader.getNames();
210 std::vector<std::vector<Real>> data = txt_reader.getData();
211 _grain_num = data[0].size();
213
214 for (unsigned int i = 0; i < col_names.size(); ++i)
215 {
216 // Check vector lengths
217 if (data[i].size() != _grain_num)
218 paramError("Columns in ", _file_name, " do not have uniform lengths.");
219 }
220
221 for (unsigned int grain = 0; grain < _grain_num; ++grain)
222 {
223 _centerpoints[grain](0) = data[0][grain];
224 _centerpoints[grain](1) = data[1][grain];
225 if (col_names.size() > 2)
226 _centerpoints[grain](2) = data[2][grain];
227 else
228 _centerpoints[grain](2) = 0.0;
229 }
230 }
231 else
232 {
234
235 // Randomly generate the centers of the individual grains represented by the Voronoi
236 // tessellation
238 std::vector<Real> distances(_grain_num);
239
240 for (auto grain = decltype(_grain_num)(0); grain < _grain_num; grain++)
241 {
242 for (const auto i : make_range(Moose::dim))
243 _centerpoints[grain](i) = _bottom_left(i) + _range(i) * MooseRandom::rand();
244 if (_columnar_3D)
245 _centerpoints[grain](2) = _bottom_left(2) + _range(2) * 0.5;
246 }
247 }
248
249 // Build a KDTree that is used to speedup point search
251}
252
253void
255{
256 if (!_use_kdtree)
257 return;
258
259 auto midplane = _bottom_left + _range / 2.0;
260 dof_id_type local_grain_id = 0;
261 _grain_gtl_ids.clear();
262 _grain_gtl_ids.reserve(_centerpoints.size() * std::pow(2.0, _mesh.dimension()));
263 _new_points.clear();
264 // Use more memory. Factor is 2^dim
265 _new_points.reserve(_centerpoints.size() * std::pow(2.0, _mesh.dimension()));
266 // Domain will be extended along the periodic directions
267 // For each direction, a half domain is constructed
268 std::vector<std::vector<Real>> xyzs(LIBMESH_DIM);
269 const auto & periodic_dims = _mesh.queryPeriodicDimensions(*_vars[0]);
270 for (auto & point : _centerpoints)
271 {
272 // Cear up
273 for (unsigned int i = 0; i < LIBMESH_DIM; i++)
274 xyzs[i].clear();
275
276 // Have at least the original point
277 for (unsigned int i = 0; i < LIBMESH_DIM; i++)
278 xyzs[i].push_back(point(i));
279
280 // Add new coords when there exists periodic boundary conditions
281 // We extend half domain
282 for (unsigned int i = 0; i < _mesh.dimension(); i++)
283 if (periodic_dims[i])
284 xyzs[i].push_back(point(i) <= midplane(i) ? point(i) + _range(i) : point(i) - _range(i));
285
286 // Construct all combinations
287 for (auto x : xyzs[0])
288 for (auto y : xyzs[1])
289 for (auto z : xyzs[2])
290 {
291 _new_points.push_back(Point(x, y, z));
292 _grain_gtl_ids.push_back(local_grain_id);
293 }
294
295 local_grain_id++;
296 }
297
298 // Build a KDTree that is used to speedup point search
299 // We should not destroy _new_points after the tree is contributed
300 // KDTree use a reference to "_new_points"
301 _kd_tree = std::make_unique<KDTree>(_new_points, _mesh.getMaxLeafSize());
302}
303
304Real
306 const unsigned int & gr_index,
307 const std::vector<unsigned int> & grain_ids) const
308{
309 Real val = 1.0;
310 Point current_grain = _centerpoints[gr_index];
311 for (auto i : grain_ids)
312 if (i != gr_index)
313 {
314 Point next_grain = _centerpoints[i];
315 Point N = findNormalVector(point, current_grain, next_grain);
316 Point cntr = findCenterPoint(point, current_grain, next_grain);
317 for (unsigned int vcomp = 0; vcomp < 3; ++vcomp)
318 if (N(vcomp) != 0.0)
319 {
320 Real L = findLinePoint(point, N, cntr, vcomp);
321 val *= 0.5 * (1.0 - std::tanh(2.0 * (point(vcomp) - L) * N(vcomp) / _int_width));
322 break;
323 }
324 }
325 return val;
326}
327
328Point
329PolycrystalVoronoi::findNormalVector(const Point & point, const Point & p1, const Point & p2) const
330{
331 Point pa = point + _mesh.minPeriodicVector(*_vars[0], point, p1);
332 Point pb = point + _mesh.minPeriodicVector(*_vars[0], point, p2);
333 Point N = pb - pa;
334 return N / N.norm();
335}
336
337Point
338PolycrystalVoronoi::findCenterPoint(const Point & point, const Point & p1, const Point & p2) const
339{
340 Point pa = point + _mesh.minPeriodicVector(*_vars[0], point, p1);
341 Point pb = point + _mesh.minPeriodicVector(*_vars[0], point, p2);
342 return 0.5 * (pa + pb);
343}
344
345Real
347 const Point & N,
348 const Point & cntr,
349 const unsigned int vcomp) const
350{
351 const Real l_sum = N((vcomp + 1) % 3) * (point((vcomp + 1) % 3) - cntr((vcomp + 1) % 3)) +
352 N((vcomp + 2) % 3) * (point((vcomp + 2) % 3) - cntr((vcomp + 2) % 3));
353
354 return cntr(vcomp) - l_sum / N(vcomp);
355}
const std::vector< double > y
const std::vector< double > x
const Real p
sideset clear()
registerMooseObject("PhaseFieldApp", PolycrystalVoronoi)
void ErrorVector unsigned int
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
static const unsigned int invalid_id
MooseMesh & _mesh
A reference to the mesh.
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 addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
RealVectorValue minPeriodicVector(const unsigned int sys_num, const unsigned int var_num, Point p, Point q) const
Real minPeriodicDistance(const unsigned int sys_num, const unsigned int var_num, const Point &p, const Point &q) const
virtual unsigned int dimension() const
unsigned int getMaxLeafSize() const
virtual Real getMaxInDimension(unsigned int component) const
const std::array< bool, 3 > & queryPeriodicDimensions(const unsigned int sys_num, const unsigned int var_num) const
virtual Real getMinInDimension(unsigned int component) const
static Real rand()
void seed(std::size_t i, unsigned int seed)
const std::vector< std::string > & getNames() const
const std::vector< std::vector< T > > & getData() const
This object provides the base capability for creating proper polycrystal ICs.
std::map< unsigned int, unsigned int > _grain_to_op
A map of the grain_id to op.
static InputParameters validParams()
unsigned int _grain_num
The number of grains to create.
Real findLinePoint(const Point &point, const Point &N, const Point &cntr, const unsigned int dim) const
Point findCenterPoint(const Point &point, const Point &p1, const Point &p2) const
const unsigned int _rand_seed
virtual void precomputeGrainStructure() override
This callback is triggered after the object is initialized and may be optionally overridden to do pre...
std::vector< Point > _new_points
Original grain center points and duplicated grain center points.
unsigned int _point_patch_size
The number of nearest points.
static InputParameters validParams()
const FileName _file_name
Real computeDiffuseInterface(const Point &point, const unsigned int &gr_index, const std::vector< unsigned int > &grain_ids) const
PolycrystalVoronoi(const InputParameters &parameters)
bool _use_kdtree
Whether or not to use a KD tree to speedup grain search.
std::vector< dof_id_type > _grain_gtl_ids
The domain is extended to consider periodic boundary conditions.
Point findNormalVector(const Point &point, const Point &p1, const Point &p2) const
std::vector< Point > _centerpoints
std::unique_ptr< KDTree > _kd_tree
KD tree that is used to speedup grain search.
virtual void getGrainsBasedOnPoint(const Point &point, std::vector< unsigned int > &grains) const override
Method for retrieving active grain IDs based on some point in the mesh.
virtual Real getVariableValue(unsigned int op_index, const Point &p) const override
Returns the variable value for a given op_index and mesh point.
unsigned int _grain_patch_size
The number of neighboring grains.
const Parallel::Communicator & _communicator
static constexpr std::size_t dim
Real distance(const Point &p)