LCOV - code coverage report
Current view: top level - src/ics - MultiSmoothSuperellipsoidIC.C (source / functions) Hit Total Coverage
Test: idaholab/moose phase_field: #31405 (292dce) with base fef103 Lines: 133 155 85.8 %
Date: 2025-09-04 07:55:36 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          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             : // Creates multiple superellipsoids that are positioned randomly throughout the domain
      11             : // each semiaxis can be varied by a uniform or normal distribution
      12             : 
      13             : #include "MultiSmoothSuperellipsoidIC.h"
      14             : 
      15             : // MOOSE includes
      16             : #include "MooseMesh.h"
      17             : #include "MooseUtils.h"
      18             : #include "MooseVariable.h"
      19             : 
      20             : registerMooseObject("PhaseFieldApp", MultiSmoothSuperellipsoidIC);
      21             : 
      22             : InputParameters
      23          46 : MultiSmoothSuperellipsoidIC::validParams()
      24             : {
      25          46 :   InputParameters params = SmoothSuperellipsoidBaseIC::validParams();
      26          46 :   params.addClassDescription("Random distribution of smooth ellipse with given minimum spacing");
      27          92 :   params.addRequiredParam<std::vector<unsigned int>>("numbub",
      28             :                                                      "Vector of the number of bubbles to place");
      29          92 :   params.addRequiredParam<std::vector<Real>>(
      30             :       "bubspac",
      31             :       "Vector of the minimum spacing of bubbles of one type, measured from center to center");
      32          92 :   params.addParam<unsigned int>("max_num_tries", 1000, "The number of tries");
      33          92 :   params.addRequiredParam<std::vector<Real>>(
      34             :       "semiaxis_a", "Vector of mean semiaxis values in the x direction for the ellipse");
      35          92 :   params.addRequiredParam<std::vector<Real>>(
      36             :       "semiaxis_b", "Vector of mean semiaxis values in the y direction for the ellipse");
      37          92 :   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          46 :   params.addParam<std::vector<Real>>(
      41             :       "exponent",
      42          46 :       std::vector<Real>(),
      43             :       "Vector of exponents for each superellipsoid, n=2 is a normal ellipse");
      44          46 :   params.addParam<std::vector<Real>>("semiaxis_a_variation",
      45          46 :                                      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          46 :   params.addParam<std::vector<Real>>("semiaxis_b_variation",
      50          46 :                                      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          46 :   params.addParam<std::vector<Real>>("semiaxis_c_variation",
      55          46 :                                      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          92 :   params.addParam<bool>("check_extremes",
      60          92 :                         false,
      61             :                         "Check all Superellipsoid extremes (center +- "
      62             :                         "each semiaxis) for overlap, must have "
      63             :                         "prevent_overlap set to True.");
      64          92 :   params.addParam<bool>("prevent_overlap",
      65          92 :                         false,
      66             :                         "Check all Superellipsoid centers for overlap with other superellipsoids.");
      67          92 :   params.addParam<bool>("vary_axes_independently",
      68          92 :                         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          92 :   MooseEnum rand_options("uniform normal none", "none");
      73          92 :   params.addParam<MooseEnum>(
      74             :       "semiaxis_variation_type",
      75             :       rand_options,
      76             :       "Type of distribution that random superellipsoid semiaxes will follow");
      77          46 :   return params;
      78          46 : }
      79             : 
      80          24 : MultiSmoothSuperellipsoidIC::MultiSmoothSuperellipsoidIC(const InputParameters & parameters)
      81             :   : SmoothSuperellipsoidBaseIC(parameters),
      82          24 :     _max_num_tries(getParam<unsigned int>("max_num_tries")),
      83          48 :     _semiaxis_variation_type(getParam<MooseEnum>("semiaxis_variation_type")),
      84          48 :     _prevent_overlap(getParam<bool>("prevent_overlap")),
      85          48 :     _check_extremes(getParam<bool>("check_extremes")),
      86          48 :     _vary_axes_independently(getParam<bool>("vary_axes_independently")),
      87          24 :     _numbub(parameters.get<std::vector<unsigned int>>("numbub")),
      88          24 :     _bubspac(parameters.get<std::vector<Real>>("bubspac")),
      89          24 :     _exponent(parameters.get<std::vector<Real>>("exponent")),
      90          24 :     _semiaxis_a(parameters.get<std::vector<Real>>("semiaxis_a")),
      91          24 :     _semiaxis_b(parameters.get<std::vector<Real>>("semiaxis_b")),
      92          24 :     _semiaxis_c(parameters.get<std::vector<Real>>("semiaxis_c")),
      93          24 :     _semiaxis_a_variation(parameters.get<std::vector<Real>>("semiaxis_a_variation")),
      94          24 :     _semiaxis_b_variation(parameters.get<std::vector<Real>>("semiaxis_b_variation")),
      95          48 :     _semiaxis_c_variation(parameters.get<std::vector<Real>>("semiaxis_c_variation"))
      96             : {
      97          24 : }
      98             : 
      99             : void
     100          18 : MultiSmoothSuperellipsoidIC::initialSetup()
     101             : {
     102          18 :   unsigned int nv = _numbub.size();
     103             : 
     104          18 :   if (nv != _bubspac.size() || nv != _exponent.size() || nv != _semiaxis_a.size() ||
     105          36 :       nv != _semiaxis_b.size() || nv != _semiaxis_c.size())
     106           0 :     mooseError("Vectors for numbub, bubspac, exponent, semiaxis_a, semiaxis_b, and semiaxis_c must "
     107             :                "be the same size.");
     108             : 
     109          18 :   if (_semiaxis_variation_type != 2 &&
     110          18 :       (nv != _semiaxis_a_variation.size() || nv != _semiaxis_b_variation.size() ||
     111             :        nv != _semiaxis_c_variation.size()))
     112           0 :     mooseError("Vectors for numbub, semiaxis_a_variation, semiaxis_b_variation, and "
     113             :                "semiaxis_c_variation must be the same size.");
     114             : 
     115          18 :   if (_semiaxis_variation_type == 2 &&
     116           0 :       (_semiaxis_a_variation.size() > 0 || _semiaxis_b_variation.size() > 0 ||
     117             :        _semiaxis_c_variation.size() > 0))
     118           0 :     mooseWarning(
     119             :         "Values were provided for semiaxis_a/b/c_variation but semiaxis_variation_type is set "
     120             :         "to 'none' in 'MultiSmoothSuperellipsoidIC'.");
     121             : 
     122          54 :   for (_gk = 0; _gk < nv; ++_gk)
     123             :   {
     124             :     // Set up domain bounds with mesh tools
     125         144 :     for (const auto i : make_range(Moose::dim))
     126             :     {
     127         108 :       _bottom_left(i) = _mesh.getMinInDimension(i);
     128         108 :       _top_right(i) = _mesh.getMaxInDimension(i);
     129             :     }
     130          36 :     _range = _top_right - _bottom_left;
     131             : 
     132          36 :     SmoothSuperellipsoidBaseIC::initialSetup();
     133             :   }
     134          18 : }
     135             : 
     136             : void
     137          36 : MultiSmoothSuperellipsoidIC::computeSuperellipsoidSemiaxes()
     138             : {
     139             :   Real randnum;
     140          36 :   unsigned int start = _as.size();
     141          36 :   _as.resize(start + _numbub[_gk]);
     142          36 :   _bs.resize(start + _numbub[_gk]);
     143          36 :   _cs.resize(start + _numbub[_gk]);
     144             : 
     145         216 :   for (unsigned int i = start; i < _as.size(); i++)
     146             :   {
     147         180 :     switch (_semiaxis_variation_type)
     148             :     {
     149         180 :       case 0: // Uniform distrubtion
     150         180 :         randnum = _random.rand(_tid);
     151         180 :         _as[i] = _semiaxis_a[_gk] * (1.0 + (1.0 - 2.0 * randnum) * _semiaxis_a_variation[_gk]);
     152         360 :         _bs[i] = _semiaxis_b[_gk] *
     153         180 :                  (1.0 + (1.0 - 2.0 * (_vary_axes_independently ? _random.rand(_tid) : randnum)) *
     154         180 :                             _semiaxis_b_variation[_gk]);
     155         360 :         _cs[i] = _semiaxis_c[_gk] *
     156         180 :                  (1.0 + (1.0 - 2.0 * (_vary_axes_independently ? _random.rand(_tid) : randnum)) *
     157         180 :                             _semiaxis_c_variation[_gk]);
     158         180 :         break;
     159             : 
     160           0 :       case 1: // Normal distribution
     161           0 :         randnum = _random.randNormal(_tid, 0, 1);
     162           0 :         _as[i] = _semiaxis_a[_gk] + (randnum * _semiaxis_a_variation[_gk]);
     163           0 :         _bs[i] = _semiaxis_b[_gk] +
     164           0 :                  ((_vary_axes_independently ? _random.randNormal(_tid, 0, 1) : randnum) *
     165           0 :                   _semiaxis_b_variation[_gk]);
     166           0 :         _cs[i] = _semiaxis_c[_gk] +
     167           0 :                  ((_vary_axes_independently ? _random.randNormal(_tid, 0, 1) : randnum) *
     168           0 :                   _semiaxis_c_variation[_gk]);
     169           0 :         break;
     170             : 
     171           0 :       case 2: // No variation
     172           0 :         _as[i] = _semiaxis_a[_gk];
     173           0 :         _bs[i] = _semiaxis_b[_gk];
     174           0 :         _cs[i] = _semiaxis_c[_gk];
     175             :     }
     176             : 
     177         360 :     _as[i] = _as[i] < 0.0 ? 0.0 : _as[i];
     178         360 :     _bs[i] = _bs[i] < 0.0 ? 0.0 : _bs[i];
     179         360 :     _cs[i] = _cs[i] < 0.0 ? 0.0 : _cs[i];
     180             :   }
     181          36 : }
     182             : 
     183             : void
     184          36 : MultiSmoothSuperellipsoidIC::computeSuperellipsoidCenters()
     185             : {
     186          36 :   unsigned int start = _centers.size();
     187          36 :   _centers.resize(start + _numbub[_gk]);
     188             : 
     189         216 :   for (unsigned int i = start; i < _centers.size(); i++)
     190             :   {
     191             :     // Vary circle center positions
     192             :     unsigned int num_tries = 0;
     193         252 :     while (num_tries < _max_num_tries)
     194             :     {
     195         252 :       num_tries++;
     196             : 
     197             :       RealTensorValue ran;
     198         252 :       ran(0, 0) = _random.rand(_tid);
     199         252 :       ran(1, 1) = _random.rand(_tid);
     200         252 :       ran(2, 2) = _random.rand(_tid);
     201             : 
     202         252 :       _centers[i] = _bottom_left + ran * _range;
     203             : 
     204        1305 :       for (unsigned int j = 0; j < i; ++j)
     205        2241 :         if (_mesh.minPeriodicDistance(_var.number(), _centers[i], _centers[j]) < _bubspac[_gk] ||
     206        1116 :             ellipsoidsOverlap(i, j))
     207          72 :           goto fail;
     208             : 
     209             :       // accept the position of the new center
     210         180 :       goto accept;
     211             : 
     212             :     // retry a new position until tries are exhausted
     213             :     fail:
     214             :       continue;
     215             :     }
     216             : 
     217           0 :     if (num_tries == _max_num_tries)
     218           0 :       mooseError("max_num_tries reached in 'MultiSmoothSuperellipsoidIC'.");
     219             : 
     220           0 :   accept:
     221             :     continue;
     222         180 :   }
     223          36 : }
     224             : 
     225             : void
     226          36 : MultiSmoothSuperellipsoidIC::computeSuperellipsoidExponents()
     227             : {
     228          36 :   unsigned int start = _ns.size();
     229          36 :   _ns.resize(start + _numbub[_gk]);
     230             : 
     231         216 :   for (unsigned int i = start; i < _ns.size(); ++i)
     232         180 :     _ns[i] = _exponent[_gk];
     233          36 : }
     234             : 
     235             : bool
     236        1116 : MultiSmoothSuperellipsoidIC::ellipsoidsOverlap(unsigned int i, unsigned int j)
     237             : {
     238             :   // Check for overlap between centers
     239        1116 :   const Point dist_vec = _mesh.minPeriodicVector(_var.number(), _centers[i], _centers[j]);
     240        1116 :   const Real dist = dist_vec.norm();
     241             : 
     242             :   // Handle this case independently because we cannot calculate polar angles at this point
     243        1116 :   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        1116 :   rmn = (std::pow(std::abs(dist_vec(0) / dist / _as[i]), _ns[i]) +
     254        1116 :          std::pow(std::abs(dist_vec(1) / dist / _bs[i]), _ns[i]) +
     255        1116 :          std::pow(std::abs(dist_vec(2) / dist / _cs[i]), _ns[i]));
     256             :   // calculate r2 from rmn
     257        1116 :   const Real r1 = std::pow(rmn, (-1.0 / _ns[i]));
     258             : 
     259             :   // calculate rmn = r^(-n), replacing sin, cos functions with distances
     260        1116 :   rmn = (std::pow(std::abs(dist_vec(0) / dist / _as[j]), _ns[j]) +
     261        1116 :          std::pow(std::abs(dist_vec(1) / dist / _bs[j]), _ns[j]) +
     262        1116 :          std::pow(std::abs(dist_vec(2) / dist / _cs[j]), _ns[j]));
     263        1116 :   const Real r2 = std::pow(rmn, (-1.0 / _ns[j]));
     264             : 
     265        1116 :   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        1053 :   if (_check_extremes)
     271         459 :     return checkExtremes(i, j) || checkExtremes(j, i);
     272             : 
     273             :   // otherwise no overlap has been detected
     274             :   return false;
     275             : }
     276             : 
     277             : bool
     278         918 : MultiSmoothSuperellipsoidIC::checkExtremes(unsigned int i, unsigned int j)
     279             : {
     280             :   Point tmp_p;
     281        6426 :   for (unsigned int pc = 0; pc < 6; pc++)
     282             :   {
     283        5508 :     tmp_p = _centers[j];
     284             :     // Find extremes along semiaxis of candidate ellipsoids
     285             :     if (pc == 0)
     286         918 :       tmp_p(0) -= _as[j];
     287             :     else if (pc == 1)
     288         918 :       tmp_p(0) += _as[j];
     289             :     else if (pc == 2)
     290         918 :       tmp_p(1) -= _bs[j];
     291             :     else if (pc == 3)
     292         918 :       tmp_p(1) += _bs[j];
     293             :     else if (pc == 4)
     294         918 :       tmp_p(2) -= _cs[j];
     295             :     else
     296         918 :       tmp_p(2) += _cs[j];
     297             : 
     298        5508 :     const Point dist_vec = _mesh.minPeriodicVector(_var.number(), _centers[i], tmp_p);
     299        5508 :     const Real dist = dist_vec.norm();
     300             : 
     301             :     // Handle this case independently because we cannot calculate polar angles at this point
     302        5508 :     if (MooseUtils::absoluteFuzzyEqual(dist, 0.0))
     303           0 :       return true;
     304             : 
     305             :     // calculate rmn = r^(-n), replacing sin, cos functions with distances
     306        5508 :     Real rmn = (std::pow(std::abs(dist_vec(0) / dist / _as[i]), _ns[i]) +
     307        5508 :                 std::pow(std::abs(dist_vec(1) / dist / _bs[i]), _ns[i]) +
     308        5508 :                 std::pow(std::abs(dist_vec(2) / dist / _cs[i]), _ns[i]));
     309        5508 :     Real r = std::pow(rmn, (-1.0 / _ns[i]));
     310             : 
     311        5508 :     if (dist < r)
     312             :       return true;
     313             :   }
     314             : 
     315             :   return false;
     316             : }

Generated by: LCOV version 1.14