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 "PolycrystalVoronoiVoidIC.h"
11 :
12 : // MOOSE includes
13 : #include "MooseMesh.h"
14 : #include "MooseVariable.h"
15 : #include "DelimitedFileReader.h"
16 : #include "GrainTrackerInterface.h"
17 : #include "PolycrystalVoronoi.h"
18 :
19 : InputParameters
20 739 : PolycrystalVoronoiVoidIC::actionParameters()
21 : {
22 739 : InputParameters params = MultiSmoothCircleIC::validParams();
23 :
24 1478 : params.addRequiredParam<unsigned int>("op_num", "Number of order parameters");
25 :
26 1478 : params.addParam<bool>(
27 1478 : "columnar_3D", false, "3D microstructure will be columnar in the z-direction?");
28 :
29 739 : return params;
30 0 : }
31 :
32 : registerMooseObject("PhaseFieldApp", PolycrystalVoronoiVoidIC);
33 :
34 : InputParameters
35 692 : PolycrystalVoronoiVoidIC::validParams()
36 : {
37 692 : InputParameters params = PolycrystalVoronoiVoidIC::actionParameters();
38 1384 : MooseEnum structure_options("grains voids");
39 1384 : params.addRequiredParam<MooseEnum>("structure_type",
40 : structure_options,
41 : "Which structure type is being initialized, grains or voids");
42 1384 : params.addParam<unsigned int>("op_index",
43 1384 : 0,
44 : "The index for the current order parameter, "
45 : "not needed if structure_type = voids");
46 1384 : params.addRequiredParam<UserObjectName>(
47 : "polycrystal_ic_uo", "UserObject for obtaining the polycrystal grain structure.");
48 1384 : params.addParam<FileName>("file_name",
49 : "",
50 : "File containing grain centroids, if file_name is provided, "
51 : "the centroids from the file will be used.");
52 692 : return params;
53 692 : }
54 :
55 372 : PolycrystalVoronoiVoidIC::PolycrystalVoronoiVoidIC(const InputParameters & parameters)
56 : : MultiSmoothCircleIC(parameters),
57 372 : _structure_type(getParam<MooseEnum>("structure_type")),
58 744 : _op_num(getParam<unsigned int>("op_num")),
59 744 : _op_index(getParam<unsigned int>("op_index")),
60 744 : _columnar_3D(getParam<bool>("columnar_3D")),
61 372 : _poly_ic_uo(getUserObject<PolycrystalVoronoi>("polycrystal_ic_uo")),
62 1116 : _file_name(getParam<FileName>("file_name"))
63 : {
64 372 : if (_invalue < _outvalue)
65 0 : mooseWarning("Detected invalue < outvalue in PolycrystalVoronoiVoidIC. Please make sure that's "
66 : "the intended usage for representing voids.");
67 372 : if (_numbub == 0)
68 0 : mooseError("PolycrystalVoronoiVoidIC requires numbub > 0. If you want no voids to "
69 : "be represented, use invalue = outvalue. In general, you should use "
70 : "PolycrystalVoronoi to represent Voronoi grain structures without "
71 : "voids.");
72 372 : }
73 :
74 : void
75 342 : PolycrystalVoronoiVoidIC::initialSetup()
76 : {
77 342 : if (_op_num <= _op_index)
78 0 : mooseError("op_index is too large in CircleGrainVoidIC");
79 :
80 : // Obtain total number and centerpoints of the grains
81 342 : _grain_num = _poly_ic_uo.getNumGrains();
82 342 : _centerpoints = _poly_ic_uo.getGrainCenters();
83 :
84 : // Call initial setup from MultiSmoothCircleIC to create _centers and _radii
85 : // for voids
86 342 : MultiSmoothCircleIC::initialSetup();
87 342 : }
88 :
89 : void
90 342 : PolycrystalVoronoiVoidIC::computeCircleCenters()
91 : {
92 342 : _centers.resize(_numbub);
93 :
94 : // This Code will place void center points on grain boundaries
95 3816 : for (unsigned int vp = 0; vp < _numbub; ++vp)
96 : {
97 : bool try_again;
98 : unsigned int num_tries = 0;
99 :
100 : do
101 : {
102 : try_again = false;
103 8964 : num_tries++;
104 :
105 8964 : if (num_tries > _max_num_tries)
106 0 : mooseError("Too many tries of assigning void centers in "
107 : "PolycrystalVoronoiVoidIC");
108 :
109 : Point rand_point;
110 :
111 35856 : for (const auto i : make_range(Moose::dim))
112 26892 : rand_point(i) = _bottom_left(i) + _range(i) * _random.rand(_tid);
113 :
114 : // Allow the vectors to be sorted based on their distance from the
115 : // rand_point
116 8964 : std::vector<PolycrystalVoronoiVoidIC::DistancePoint> diff(_grain_num);
117 :
118 113724 : for (unsigned int gr = 0; gr < _grain_num; ++gr)
119 : {
120 104760 : diff[gr].d = _mesh.minPeriodicDistance(_var.number(), rand_point, _centerpoints[gr]);
121 104760 : diff[gr].gr = gr;
122 : }
123 :
124 8964 : std::sort(diff.begin(), diff.end(), _customLess);
125 :
126 8964 : Point closest_point = _centerpoints[diff[0].gr];
127 8964 : Point next_closest_point = _centerpoints[diff[1].gr];
128 :
129 : // Find Slope of Line in the plane orthogonal to the diff_centerpoint
130 : // vector
131 8964 : Point pa = rand_point + _mesh.minPeriodicVector(_var.number(), rand_point, closest_point);
132 : Point pb =
133 8964 : rand_point + _mesh.minPeriodicVector(_var.number(), rand_point, next_closest_point);
134 : Point diff_centerpoints = pb - pa;
135 :
136 8964 : Point diff_rand_center = _mesh.minPeriodicVector(_var.number(), closest_point, rand_point);
137 8964 : Point normal_vector = diff_centerpoints.cross(diff_rand_center);
138 8964 : Point slope = normal_vector.cross(diff_centerpoints);
139 :
140 : // Midpoint position vector between two center points
141 : Point midpoint = closest_point + (0.5 * diff_centerpoints);
142 :
143 : // Solve for the scalar multiplier solution on the line
144 : Real lambda = 0;
145 8964 : Point mid_rand_vector = _mesh.minPeriodicVector(_var.number(), midpoint, rand_point);
146 :
147 : Real slope_dot = slope * slope;
148 : mooseAssert(slope_dot > 0, "The dot product of slope with itself is zero");
149 35856 : for (const auto i : make_range(Moose::dim))
150 26892 : lambda += (mid_rand_vector(i) * slope(i)) / slope_dot;
151 :
152 : // Assigning points to vector
153 8964 : _centers[vp] = slope * lambda + midpoint;
154 :
155 : // Checking to see if points are in the domain ONLY WORKS FOR PERIODIC
156 35856 : for (const auto i : make_range(Moose::dim))
157 26892 : if ((_centers[vp](i) > _top_right(i)) || (_centers[vp](i) < _bottom_left(i)))
158 : try_again = true;
159 :
160 98862 : for (unsigned int i = 0; i < vp; ++i)
161 : {
162 89898 : Real dist = _mesh.minPeriodicDistance(_var.number(), _centers[vp], _centers[i]);
163 :
164 89898 : if (dist < _bubspac)
165 : try_again = true;
166 : }
167 :
168 : // Two algorithms are available for screening bubbles falling in grain
169 : // interior. They produce
170 : // nearly identical results.
171 : // Here only one is listed. The other one is available upon request.
172 :
173 : // Use circle center for checking whether voids are at GBs
174 8964 : if (try_again == false)
175 : {
176 : Real min_rij_1, min_rij_2, rij, rij_diff_tol;
177 :
178 3552 : min_rij_1 = _range.norm();
179 3552 : min_rij_2 = _range.norm();
180 :
181 3552 : rij_diff_tol = 0.1 * _radius;
182 :
183 63858 : for (unsigned int gr = 0; gr < _grain_num; ++gr)
184 : {
185 60306 : rij = _mesh.minPeriodicDistance(_var.number(), _centers[vp], _centerpoints[gr]);
186 :
187 60306 : if (rij < min_rij_1)
188 : {
189 : min_rij_2 = min_rij_1;
190 : min_rij_1 = rij;
191 : }
192 48498 : else if (rij < min_rij_2)
193 : min_rij_2 = rij;
194 : }
195 :
196 3552 : if (std::abs(min_rij_1 - min_rij_2) > rij_diff_tol)
197 : try_again = true;
198 : }
199 :
200 8964 : } while (try_again == true);
201 : }
202 342 : }
203 :
204 : Real
205 3364560 : PolycrystalVoronoiVoidIC::value(const Point & p)
206 : {
207 : Real value = 0.0;
208 :
209 : // Determine value for voids
210 3364560 : Real void_value = MultiSmoothCircleIC::value(p);
211 :
212 : // Determine value for grains
213 3364560 : Real grain_value = _poly_ic_uo.getVariableValue(_op_index, p);
214 :
215 3364560 : switch (_structure_type)
216 : {
217 2872160 : case 0: // assigning values for grains (order parameters)
218 2872160 : if (grain_value == 0) // Not in this grain
219 : value = grain_value;
220 : else // in this grain, but might be in a void
221 520664 : if (void_value == _outvalue) // Not in a void
222 : value = grain_value;
223 60096 : else if (void_value > _outvalue && void_value < _invalue) // On void interface
224 53536 : value = grain_value * (_invalue - void_value) / (_invalue - _outvalue);
225 : else if (void_value == _invalue) // In a void, so op = 0
226 : value = 0.0;
227 : break;
228 :
229 : case 1: // assigning values for voids (concentration)
230 : value = void_value;
231 : break;
232 : }
233 :
234 3364560 : return value;
235 : }
236 :
237 : RealGradient
238 0 : PolycrystalVoronoiVoidIC::gradient(const Point & p)
239 : {
240 : RealGradient gradient;
241 0 : RealGradient void_gradient = MultiSmoothCircleIC::gradient(p);
242 :
243 : // Order parameter assignment assumes zero gradient (sharp interface)
244 0 : switch (_structure_type)
245 : {
246 0 : case 1: // assigning gradient for voids
247 0 : gradient = void_gradient;
248 0 : break;
249 : }
250 :
251 0 : return gradient;
252 : }
|