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 "BimodalSuperellipsoidsIC.h"
11 :
12 : // MOOSE includes
13 : #include "MooseMesh.h"
14 : #include "MooseVariable.h"
15 :
16 : registerMooseObject("PhaseFieldApp", BimodalSuperellipsoidsIC);
17 :
18 : InputParameters
19 22 : BimodalSuperellipsoidsIC::validParams()
20 : {
21 22 : InputParameters params = SpecifiedSmoothSuperellipsoidIC::validParams();
22 22 : params.addClassDescription("Bimodal size distribution of large particles (specified in input "
23 : "file) and small particles (placed randomly outside the larger "
24 : "particles)");
25 44 : params.addRequiredParam<unsigned int>("npart", "The number of random (small) particles to place");
26 44 : params.addRequiredParam<Real>(
27 : "small_spac",
28 : "minimum spacing between small particles, measured from closest edge to closest edge");
29 44 : params.addRequiredParam<Real>("large_spac",
30 : "minimum spacing between large and small particles, "
31 : "measured from closest edge to closest edge");
32 44 : params.addRequiredParam<Real>(
33 : "small_a", "Mean semiaxis a value for the randomly placed (small) superellipsoids");
34 44 : params.addRequiredParam<Real>(
35 : "small_b", "Mean semiaxis b value for the randomly placed (small) superellipsoids");
36 44 : params.addRequiredParam<Real>(
37 : "small_c", "Mean semiaxis c value for the randomly placed (small) superellipsoids");
38 44 : params.addRequiredParam<Real>("small_n",
39 : "Exponent n for the randomly placed (small) superellipsoids");
40 44 : params.addParam<Real>("size_variation",
41 44 : 0.0,
42 : "Plus or minus fraction of random variation in the "
43 : "semiaxes for uniform, standard deviation for "
44 : "normal");
45 44 : MooseEnum rand_options("uniform normal none", "none");
46 44 : params.addParam<MooseEnum>(
47 : "size_variation_type", rand_options, "Type of distribution that random semiaxes will follow");
48 44 : params.addParam<unsigned int>(
49 44 : "numtries", 1000, "The number of tries to place the random particles");
50 22 : return params;
51 22 : }
52 :
53 12 : BimodalSuperellipsoidsIC::BimodalSuperellipsoidsIC(const InputParameters & parameters)
54 : : SpecifiedSmoothSuperellipsoidIC(parameters),
55 12 : _npart(getParam<unsigned int>("npart")),
56 24 : _small_spac(getParam<Real>("small_spac")),
57 24 : _large_spac(getParam<Real>("large_spac")),
58 24 : _small_a(getParam<Real>("small_a")),
59 24 : _small_b(getParam<Real>("small_b")),
60 24 : _small_c(getParam<Real>("small_c")),
61 24 : _small_n(getParam<Real>("small_n")),
62 24 : _size_variation(getParam<Real>("size_variation")),
63 24 : _size_variation_type(getParam<MooseEnum>("size_variation_type")),
64 36 : _max_num_tries(getParam<unsigned int>("numtries"))
65 : {
66 12 : }
67 :
68 : void
69 12 : BimodalSuperellipsoidsIC::initialSetup()
70 : {
71 : // Set up domain bounds with mesh tools
72 48 : for (const auto i : make_range(Moose::dim))
73 : {
74 36 : _bottom_left(i) = _mesh.getMinInDimension(i);
75 36 : _top_right(i) = _mesh.getMaxInDimension(i);
76 : }
77 12 : _range = _top_right - _bottom_left;
78 :
79 12 : if (_size_variation_type == 2 && _size_variation > 0.0)
80 0 : mooseError("If size_variation > 0.0, you must pass in a size_variation_type in "
81 : "BimodalSuperellipsoidsIC");
82 :
83 12 : SmoothSuperellipsoidBaseIC::initialSetup();
84 12 : }
85 :
86 : void
87 12 : BimodalSuperellipsoidsIC::computeSuperellipsoidSemiaxes()
88 : {
89 12 : _as.resize(_input_as.size() + _npart);
90 12 : _bs.resize(_input_bs.size() + _npart);
91 12 : _cs.resize(_input_cs.size() + _npart);
92 :
93 : // First fill in the specified (large) superellipsoids from the input file
94 30 : for (unsigned int i = 0; i < _input_as.size(); ++i)
95 : {
96 18 : _as[i] = _input_as[i];
97 18 : _bs[i] = _input_bs[i];
98 18 : _cs[i] = _input_cs[i];
99 : }
100 :
101 : // Then fill in the randomly positioned (small) superellipsoids
102 90 : for (unsigned int i = _input_as.size(); i < _input_as.size() + _npart; ++i)
103 : {
104 : // Vary semiaxes
105 78 : switch (_size_variation_type)
106 : {
107 0 : case 0: // Random distrubtion, maintaining constant shape
108 : {
109 0 : Real rand_num = _random.rand(_tid);
110 0 : _as[i] = _small_a * (1.0 + (1.0 - 2.0 * rand_num) * _size_variation);
111 0 : _bs[i] = _small_b * (1.0 + (1.0 - 2.0 * rand_num) * _size_variation);
112 0 : _cs[i] = _small_c * (1.0 + (1.0 - 2.0 * rand_num) * _size_variation);
113 0 : break;
114 : }
115 30 : case 1: // Normal distribution of semiaxis size, maintaining constant shape
116 30 : _as[i] = _random.randNormal(_tid, _small_a, _size_variation);
117 30 : _bs[i] = _as[i] * _small_b / _small_a;
118 30 : _cs[i] = _as[i] * _small_c / _small_a;
119 30 : break;
120 48 : case 2: // No variation
121 48 : _as[i] = _small_a;
122 48 : _bs[i] = _small_b;
123 48 : _cs[i] = _small_c;
124 : }
125 :
126 78 : if (_as[i] < 0.0)
127 0 : _as[i] = 0.0;
128 78 : if (_bs[i] < 0.0)
129 0 : _bs[i] = 0.0;
130 78 : if (_cs[i] < 0.0)
131 0 : _cs[i] = 0.0;
132 : }
133 12 : }
134 :
135 : void
136 12 : BimodalSuperellipsoidsIC::computeSuperellipsoidExponents()
137 : {
138 12 : _ns.resize(_input_ns.size() + _npart);
139 :
140 : // First fill in the specified (large) superellipsoids from the input file
141 30 : for (unsigned int i = 0; i < _input_ns.size(); ++i)
142 18 : _ns[i] = _input_ns[i];
143 :
144 : // Then fill in the randomly positioned (small) superellipsoids
145 : // The shape is assumed to stay constant so n does not vary
146 90 : for (unsigned int i = _input_ns.size(); i < _input_ns.size() + _npart; ++i)
147 78 : _ns[i] = _small_n;
148 12 : }
149 :
150 : void
151 6 : BimodalSuperellipsoidsIC::computeSuperellipsoidCenters()
152 : {
153 6 : _centers.resize(_x_positions.size() + _npart);
154 :
155 : // First place the specified (large) particles from the input file
156 18 : for (unsigned int i = 0; i < _x_positions.size(); ++i)
157 : {
158 12 : _centers[i](0) = _x_positions[i];
159 12 : _centers[i](1) = _y_positions[i];
160 12 : _centers[i](2) = _z_positions[i];
161 : }
162 :
163 : // Next place the randomly positioned (small) particles
164 36 : for (unsigned int i = _x_positions.size(); i < _x_positions.size() + _npart; ++i)
165 : {
166 : unsigned int num_tries = 0;
167 :
168 690 : while (num_tries < _max_num_tries)
169 : {
170 690 : num_tries++;
171 :
172 : RealTensorValue ran;
173 690 : ran(0, 0) = _random.rand(_tid);
174 690 : ran(1, 1) = _random.rand(_tid);
175 690 : ran(2, 2) = _random.rand(_tid);
176 :
177 690 : _centers[i] = _bottom_left + ran * _range;
178 :
179 : // check for collisions with the specified (large) and randomly placed small particles
180 1644 : for (unsigned int j = 0; j < i; ++j)
181 : {
182 : // Compute the distance r1 from the center of each specified superellipsoid to its
183 : // outside edge along the vector between the specified superellipsoid and the current
184 : // randomly positioned one.
185 : // This uses the equation for a superellipse in polar coordinates and substitutes
186 : // distances for sin, cos functions.
187 1614 : Point dist_vec = _mesh.minPeriodicVector(_var.number(), _centers[i], _centers[j]);
188 1614 : const Real dist = dist_vec.norm();
189 :
190 : // First calculate rmn1 = r1^(-n), replacing sin, cos functions with distances
191 1614 : Real rmn1 = (std::pow(std::abs(dist_vec(0) / dist / _as[j]), _ns[j]) +
192 1614 : std::pow(std::abs(dist_vec(1) / dist / _bs[j]), _ns[j]) +
193 1614 : std::pow(std::abs(dist_vec(2) / dist / _cs[j]), _ns[j]));
194 : // Then calculate r1 from rmn1
195 1614 : const Real r1 = std::pow(rmn1, (-1.0 / _ns[j]));
196 :
197 : // Now calculate the distance r2 from the center of the randomly placed
198 : // superellipsoid to its outside edge in the same manner
199 1614 : Real rmn2 = (std::pow(std::abs(dist_vec(0) / dist / _as[i]), _ns[i]) +
200 1614 : std::pow(std::abs(dist_vec(1) / dist / _bs[i]), _ns[i]) +
201 1614 : std::pow(std::abs(dist_vec(2) / dist / _cs[i]), _ns[i]));
202 1614 : const Real r2 = std::pow(rmn2, (-1.0 / _ns[i]));
203 :
204 : // Calculate the distance between the edges (first in the list are the large then come the
205 : // small)
206 1614 : if ((dist - r1 - r2) < (j < _x_positions.size() ? _large_spac : _small_spac))
207 660 : goto fail;
208 : }
209 :
210 : // accept the position of the new center
211 30 : goto accept;
212 :
213 : // retry a new position until tries are exhausted
214 : fail:
215 : continue;
216 : }
217 :
218 0 : if (num_tries == _max_num_tries)
219 0 : mooseError("Too many tries in MultiSmoothCircleIC");
220 :
221 0 : accept:
222 : continue;
223 30 : }
224 6 : }
|