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 "PolycrystalHex.h" 11 : #include "MooseRandom.h" 12 : #include "MooseMesh.h" 13 : #include "MathUtils.h" 14 : 15 : registerMooseObject("PhaseFieldApp", PolycrystalHex); 16 : 17 : InputParameters 18 76 : PolycrystalHex::validParams() 19 : { 20 76 : InputParameters params = PolycrystalVoronoi::validParams(); 21 76 : params.addClassDescription("Perturbed hexagonal polycrystal"); 22 152 : params.addParam<Real>("x_offset", 0.5, "Specifies offset of hexagon grid in x-direction"); 23 228 : params.addRangeCheckedParam<Real>( 24 : "perturbation_percent", 25 152 : 0.0, 26 : "perturbation_percent >= 0.0 & perturbation_percent <= 1.0", 27 : "The percent to randomly perturb centers of grains relative to the size of the grain"); 28 76 : return params; 29 0 : } 30 : 31 38 : PolycrystalHex::PolycrystalHex(const InputParameters & parameters) 32 : : PolycrystalVoronoi(parameters), 33 38 : _x_offset(getParam<Real>("x_offset")), 34 114 : _perturbation_percent(getParam<Real>("perturbation_percent")) 35 : { 36 38 : if (_columnar_3D == false && _dim == 3) 37 0 : mooseError( 38 : "PolycrystalHex is supported on 2D domains or 3D domains with the columnar_3D option"); 39 38 : if (_grain_num % 2 != 0) 40 0 : mooseError("PolycrystalHex requires an even square number for 2D or columnar 3D"); 41 : 42 76 : _random.seed(_tid, getParam<unsigned int>("rand_seed")); 43 38 : } 44 : 45 : void 46 29 : PolycrystalHex::precomputeGrainStructure() 47 : { 48 29 : unsigned int d = _dim; 49 : 50 29 : if (_columnar_3D && _dim == 3) 51 : d -= 1; 52 : 53 : // check if periodic boundary condition is set 54 87 : for (unsigned int j = 0; j < d; ++j) 55 : { 56 370 : for (unsigned int i = 0; i < _vars.size(); ++i) 57 312 : if (!_mesh.isTranslatedPeriodic(_vars[i]->number(), j)) 58 0 : mooseError("PolycrystalHex works only with periodic BCs"); 59 : } 60 : 61 29 : const unsigned int root = MathUtils::round(std::pow(_grain_num, 1.0 / d)); 62 : 63 : // integer power the rounded root and check if we recover the grain number 64 : unsigned int grain_pow = root; 65 58 : for (unsigned int i = 1; i < d; ++i) 66 29 : grain_pow *= root; 67 : 68 29 : if (_grain_num != grain_pow) 69 0 : mooseError( 70 : "PolycrystalHex requires a square number for 2D or columnar 3D and a cubic number for 3D"); 71 : 72 : // Set up domain bounds with mesh tools 73 116 : for (const auto i : make_range(Moose::dim)) 74 : { 75 87 : _bottom_left(i) = _mesh.getMinInDimension(i); 76 87 : _top_right(i) = _mesh.getMaxInDimension(i); 77 : } 78 29 : _range = _top_right - _bottom_left; 79 : 80 29 : _centerpoints.resize(_grain_num); 81 : 82 29 : std::vector<Real> distances(_grain_num); 83 29 : std::vector<Point> holder(_grain_num); 84 : 85 29 : const Real ndist = 1.0 / root; 86 : 87 : // Assign the relative center points positions, defining the grains according to a hexagonal 88 : // pattern 89 : unsigned int count = 0; 90 : 91 116 : for (unsigned int k = 0; k < (d == 3 ? root : 1); ++k) 92 119 : for (unsigned int j = 0; j < (d >= 2 ? root : 1); ++j) 93 462 : for (unsigned int i = 0; i < root; ++i) 94 : { 95 : // set x-coordinate 96 372 : holder[count](0) = i * ndist + (0.5 * ndist * (j % 2)) + _x_offset * ndist; 97 : 98 : // set y-coordinate 99 372 : holder[count](1) = j * ndist + (0.5 * ndist * (k % 2)); 100 : 101 : // set z-coordinate 102 372 : holder[count](2) = k * ndist; 103 : 104 : // increment counter 105 372 : count++; 106 : } 107 : 108 : // Assign center point values 109 401 : for (unsigned int grain = 0; grain < _grain_num; ++grain) 110 1488 : for (const auto i : make_range(Moose::dim)) 111 : { 112 1116 : if (_range(i) == 0) 113 352 : continue; 114 : 115 764 : Real perturbation_dist = (_range(i) / root * (_random.rand(_tid) * 2 - 1.0)) * 116 764 : _perturbation_percent; // Perturb -100 to 100% 117 764 : _centerpoints[grain](i) = _bottom_left(i) + _range(i) * holder[grain](i) + perturbation_dist; 118 : 119 764 : if (_centerpoints[grain](i) > _top_right(i)) 120 0 : _centerpoints[grain](i) = _top_right(i); 121 764 : if (_centerpoints[grain](i) < _bottom_left(i)) 122 0 : _centerpoints[grain](i) = _bottom_left(i); 123 : 124 764 : if (_columnar_3D && _dim == 3) 125 60 : _centerpoints[grain](2) = _bottom_left(2) + _range(2) * 0.5; 126 : } 127 : 128 29 : buildSearchTree(); 129 29 : }