https://mooseframework.inl.gov
MultiSmoothSuperellipsoidIC.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 // Creates multiple superellipsoids that are positioned randomly throughout the domain
11 // each semiaxis can be varied by a uniform or normal distribution
12 
14 
15 // MOOSE includes
16 #include "MooseMesh.h"
17 #include "MooseUtils.h"
18 #include "MooseVariable.h"
19 
21 
24 {
26  params.addClassDescription("Random distribution of smooth ellipse with given minimum spacing");
27  params.addRequiredParam<std::vector<unsigned int>>("numbub",
28  "Vector of the number of bubbles to place");
29  params.addRequiredParam<std::vector<Real>>(
30  "bubspac",
31  "Vector of the minimum spacing of bubbles of one type, measured from center to center");
32  params.addParam<unsigned int>("max_num_tries", 1000, "The number of tries");
33  params.addRequiredParam<std::vector<Real>>(
34  "semiaxis_a", "Vector of mean semiaxis values in the x direction for the ellipse");
35  params.addRequiredParam<std::vector<Real>>(
36  "semiaxis_b", "Vector of mean semiaxis values in the y direction for the ellipse");
37  params.addRequiredParam<std::vector<Real>>("semiaxis_c",
38  "Vector of mean semiaxis values in the z direction "
39  "for the ellipse, must be greater than 0 even if 2D.");
40  params.addParam<std::vector<Real>>(
41  "exponent",
42  std::vector<Real>(),
43  "Vector of exponents for each superellipsoid, n=2 is a normal ellipse");
44  params.addParam<std::vector<Real>>("semiaxis_a_variation",
45  std::vector<Real>(),
46  "Vector of plus or minus fractions of random variation in the "
47  "bubble semiaxis in the x direction for uniform, standard "
48  "deviation for normal");
49  params.addParam<std::vector<Real>>("semiaxis_b_variation",
50  std::vector<Real>(),
51  "Vector of plus or minus fractions of random variation in the "
52  "bubble semiaxis in the y direction for uniform, standard "
53  "deviation for normal");
54  params.addParam<std::vector<Real>>("semiaxis_c_variation",
55  std::vector<Real>(),
56  "Vector of plus or minus fractions of random variation in the "
57  "bubble semiaxis in the z direction for uniform, standard "
58  "deviation for normal. Must be set to 0 if 2D.");
59  params.addParam<bool>("check_extremes",
60  false,
61  "Check all Superellipsoid extremes (center +- "
62  "each semiaxis) for overlap, must have "
63  "prevent_overlap set to True.");
64  params.addParam<bool>("prevent_overlap",
65  false,
66  "Check all Superellipsoid centers for overlap with other superellipsoids.");
67  params.addParam<bool>("vary_axes_independently",
68  true,
69  "If true the length of each semiaxis is randomly chosen "
70  "within the provided parameters, if false then one random "
71  "number is generated and applied to all semiaxes.");
72  MooseEnum rand_options("uniform normal none", "none");
73  params.addParam<MooseEnum>(
74  "semiaxis_variation_type",
75  rand_options,
76  "Type of distribution that random superellipsoid semiaxes will follow");
77  return params;
78 }
79 
81  : SmoothSuperellipsoidBaseIC(parameters),
82  _max_num_tries(getParam<unsigned int>("max_num_tries")),
83  _semiaxis_variation_type(getParam<MooseEnum>("semiaxis_variation_type")),
84  _prevent_overlap(getParam<bool>("prevent_overlap")),
85  _check_extremes(getParam<bool>("check_extremes")),
86  _vary_axes_independently(getParam<bool>("vary_axes_independently")),
87  _numbub(parameters.get<std::vector<unsigned int>>("numbub")),
88  _bubspac(parameters.get<std::vector<Real>>("bubspac")),
89  _exponent(parameters.get<std::vector<Real>>("exponent")),
90  _semiaxis_a(parameters.get<std::vector<Real>>("semiaxis_a")),
91  _semiaxis_b(parameters.get<std::vector<Real>>("semiaxis_b")),
92  _semiaxis_c(parameters.get<std::vector<Real>>("semiaxis_c")),
93  _semiaxis_a_variation(parameters.get<std::vector<Real>>("semiaxis_a_variation")),
94  _semiaxis_b_variation(parameters.get<std::vector<Real>>("semiaxis_b_variation")),
95  _semiaxis_c_variation(parameters.get<std::vector<Real>>("semiaxis_c_variation"))
96 {
97 }
98 
99 void
101 {
102  unsigned int nv = _numbub.size();
103 
104  if (nv != _bubspac.size() || nv != _exponent.size() || nv != _semiaxis_a.size() ||
105  nv != _semiaxis_b.size() || nv != _semiaxis_c.size())
106  mooseError("Vectors for numbub, bubspac, exponent, semiaxis_a, semiaxis_b, and semiaxis_c must "
107  "be the same size.");
108 
109  if (_semiaxis_variation_type != 2 &&
110  (nv != _semiaxis_a_variation.size() || nv != _semiaxis_b_variation.size() ||
111  nv != _semiaxis_c_variation.size()))
112  mooseError("Vectors for numbub, semiaxis_a_variation, semiaxis_b_variation, and "
113  "semiaxis_c_variation must be the same size.");
114 
115  if (_semiaxis_variation_type == 2 &&
116  (_semiaxis_a_variation.size() > 0 || _semiaxis_b_variation.size() > 0 ||
117  _semiaxis_c_variation.size() > 0))
118  mooseWarning(
119  "Values were provided for semiaxis_a/b/c_variation but semiaxis_variation_type is set "
120  "to 'none' in 'MultiSmoothSuperellipsoidIC'.");
121 
122  for (_gk = 0; _gk < nv; ++_gk)
123  {
124  // Set up domain bounds with mesh tools
125  for (const auto i : make_range(Moose::dim))
126  {
129  }
131 
133  }
134 }
135 
136 void
138 {
139  Real randnum;
140  unsigned int start = _as.size();
141  _as.resize(start + _numbub[_gk]);
142  _bs.resize(start + _numbub[_gk]);
143  _cs.resize(start + _numbub[_gk]);
144 
145  for (unsigned int i = start; i < _as.size(); i++)
146  {
147  switch (_semiaxis_variation_type)
148  {
149  case 0: // Uniform distrubtion
150  randnum = _random.rand(_tid);
151  _as[i] = _semiaxis_a[_gk] * (1.0 + (1.0 - 2.0 * randnum) * _semiaxis_a_variation[_gk]);
152  _bs[i] = _semiaxis_b[_gk] *
153  (1.0 + (1.0 - 2.0 * (_vary_axes_independently ? _random.rand(_tid) : randnum)) *
155  _cs[i] = _semiaxis_c[_gk] *
156  (1.0 + (1.0 - 2.0 * (_vary_axes_independently ? _random.rand(_tid) : randnum)) *
158  break;
159 
160  case 1: // Normal distribution
161  randnum = _random.randNormal(_tid, 0, 1);
162  _as[i] = _semiaxis_a[_gk] + (randnum * _semiaxis_a_variation[_gk]);
163  _bs[i] = _semiaxis_b[_gk] +
164  ((_vary_axes_independently ? _random.randNormal(_tid, 0, 1) : randnum) *
166  _cs[i] = _semiaxis_c[_gk] +
167  ((_vary_axes_independently ? _random.randNormal(_tid, 0, 1) : randnum) *
169  break;
170 
171  case 2: // No variation
172  _as[i] = _semiaxis_a[_gk];
173  _bs[i] = _semiaxis_b[_gk];
174  _cs[i] = _semiaxis_c[_gk];
175  }
176 
177  _as[i] = _as[i] < 0.0 ? 0.0 : _as[i];
178  _bs[i] = _bs[i] < 0.0 ? 0.0 : _bs[i];
179  _cs[i] = _cs[i] < 0.0 ? 0.0 : _cs[i];
180  }
181 }
182 
183 void
185 {
186  unsigned int start = _centers.size();
187  _centers.resize(start + _numbub[_gk]);
188 
189  for (unsigned int i = start; i < _centers.size(); i++)
190  {
191  // Vary circle center positions
192  unsigned int num_tries = 0;
193  while (num_tries < _max_num_tries)
194  {
195  num_tries++;
196 
197  RealTensorValue ran;
198  ran(0, 0) = _random.rand(_tid);
199  ran(1, 1) = _random.rand(_tid);
200  ran(2, 2) = _random.rand(_tid);
201 
202  _centers[i] = _bottom_left + ran * _range;
203 
204  for (unsigned int j = 0; j < i; ++j)
206  ellipsoidsOverlap(i, j))
207  goto fail;
208 
209  // accept the position of the new center
210  goto accept;
211 
212  // retry a new position until tries are exhausted
213  fail:
214  continue;
215  }
216 
217  if (num_tries == _max_num_tries)
218  mooseError("max_num_tries reached in 'MultiSmoothSuperellipsoidIC'.");
219 
220  accept:
221  continue;
222  }
223 }
224 
225 void
227 {
228  unsigned int start = _ns.size();
229  _ns.resize(start + _numbub[_gk]);
230 
231  for (unsigned int i = start; i < _ns.size(); ++i)
232  _ns[i] = _exponent[_gk];
233 }
234 
235 bool
237 {
238  // Check for overlap between centers
239  const Point dist_vec = _mesh.minPeriodicVector(_var.number(), _centers[i], _centers[j]);
240  const Real dist = dist_vec.norm();
241 
242  // Handle this case independently because we cannot calculate polar angles at this point
243  if (MooseUtils::absoluteFuzzyEqual(dist, 0.0))
244  return true;
245 
246  // Compute the distance r from the center of the superellipsoid to its outside edge
247  // along the vector from the center to the current point
248  // This uses the equation for a superellipse in polar coordinates and substitutes
249  // distances for sin, cos functions
250  Real rmn;
251 
252  // calculate rmn = r^(-n), replacing sin, cos functions with distances
253  rmn = (std::pow(std::abs(dist_vec(0) / dist / _as[i]), _ns[i]) +
254  std::pow(std::abs(dist_vec(1) / dist / _bs[i]), _ns[i]) +
255  std::pow(std::abs(dist_vec(2) / dist / _cs[i]), _ns[i]));
256  // calculate r2 from rmn
257  const Real r1 = std::pow(rmn, (-1.0 / _ns[i]));
258 
259  // calculate rmn = r^(-n), replacing sin, cos functions with distances
260  rmn = (std::pow(std::abs(dist_vec(0) / dist / _as[j]), _ns[j]) +
261  std::pow(std::abs(dist_vec(1) / dist / _bs[j]), _ns[j]) +
262  std::pow(std::abs(dist_vec(2) / dist / _cs[j]), _ns[j]));
263  const Real r2 = std::pow(rmn, (-1.0 / _ns[j]));
264 
265  if (dist < r1 + r2)
266  return true;
267 
268  // Check for overlap between extremes of new ellipsoid candidate and the center
269  // of accepted ellisoids if _check_extremes enabled
270  if (_check_extremes)
271  return checkExtremes(i, j) || checkExtremes(j, i);
272 
273  // otherwise no overlap has been detected
274  return false;
275 }
276 
277 bool
278 MultiSmoothSuperellipsoidIC::checkExtremes(unsigned int i, unsigned int j)
279 {
280  Point tmp_p;
281  for (unsigned int pc = 0; pc < 6; pc++)
282  {
283  tmp_p = _centers[j];
284  // Find extremes along semiaxis of candidate ellipsoids
285  if (pc == 0)
286  tmp_p(0) -= _as[j];
287  else if (pc == 1)
288  tmp_p(0) += _as[j];
289  else if (pc == 2)
290  tmp_p(1) -= _bs[j];
291  else if (pc == 3)
292  tmp_p(1) += _bs[j];
293  else if (pc == 4)
294  tmp_p(2) -= _cs[j];
295  else
296  tmp_p(2) += _cs[j];
297 
298  const Point dist_vec = _mesh.minPeriodicVector(_var.number(), _centers[i], tmp_p);
299  const Real dist = dist_vec.norm();
300 
301  // Handle this case independently because we cannot calculate polar angles at this point
302  if (MooseUtils::absoluteFuzzyEqual(dist, 0.0))
303  return true;
304 
305  // calculate rmn = r^(-n), replacing sin, cos functions with distances
306  Real rmn = (std::pow(std::abs(dist_vec(0) / dist / _as[i]), _ns[i]) +
307  std::pow(std::abs(dist_vec(1) / dist / _bs[i]), _ns[i]) +
308  std::pow(std::abs(dist_vec(2) / dist / _cs[i]), _ns[i]));
309  Real r = std::pow(rmn, (-1.0 / _ns[i]));
310 
311  if (dist < r)
312  return true;
313  }
314 
315  return false;
316 }
virtual Real getMaxInDimension(unsigned int component) const
virtual Real getMinInDimension(unsigned int component) const
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual bool checkExtremes(unsigned int i, unsigned int j)
unsigned int number() const
static InputParameters validParams()
RealVectorValue minPeriodicVector(unsigned int nonlinear_var_num, Point p, Point q) const
std::vector< unsigned int > _numbub
static constexpr std::size_t dim
SmoothSuperellipsoidBaseIC is the base class for all initial conditions that create superellipsoids...
static InputParameters validParams()
MooseVariableField< T > & _var
void mooseWarning(Args &&... args) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
Real randNormal(std::size_t i, Real mean, Real sigma)
virtual bool ellipsoidsOverlap(unsigned int i, unsigned int j)
TensorValue< Real > RealTensorValue
MultiSmoothSuperellipsoidIC(const InputParameters &parameters)
Real minPeriodicDistance(unsigned int nonlinear_var_num, Point p, Point q) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
registerMooseObject("PhaseFieldApp", MultiSmoothSuperellipsoidIC)
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
Real rand(std::size_t i)
MultismoothSuperellipsoidIC creates multiple SmoothSuperellipsoid (number = numbub) that are randomly...
MooseUnits pow(const MooseUnits &, int)
void ErrorVector unsigned int
const Elem & get(const ElemType type_in)