LCOV - code coverage report
Current view: top level - src/ics - PolycrystalVoronoiVoidIC.C (source / functions) Hit Total Coverage
Test: idaholab/moose phase_field: #31405 (292dce) with base fef103 Lines: 81 93 87.1 %
Date: 2025-09-04 07:55:36 Functions: 6 7 85.7 %
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             : #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             : }

Generated by: LCOV version 1.14