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 "SmoothCircleBaseIC.h" 11 : #include "MooseMesh.h" 12 : #include "MooseVariable.h" 13 : #include "FEProblemBase.h" 14 : 15 : #include "libmesh/utility.h" 16 : 17 : InputParameters 18 3864 : SmoothCircleBaseIC::validParams() 19 : { 20 3864 : InputParameters params = InitialCondition::validParams(); 21 7728 : params.addRequiredParam<Real>("invalue", "The variable value inside the circle"); 22 7728 : params.addRequiredParam<Real>("outvalue", "The variable value outside the circle"); 23 7728 : params.addParam<Real>( 24 7728 : "int_width", 0.0, "The interfacial width of the void surface. Defaults to sharp interface"); 25 7728 : params.addParam<bool>("3D_spheres", true, "in 3D, whether the objects are spheres or columns"); 26 7728 : params.addParam<bool>("zero_gradient", 27 7728 : false, 28 : "Set the gradient DOFs to zero. This can avoid " 29 : "numerical problems with higher order shape " 30 : "functions and overlapping circles."); 31 7728 : params.addParam<unsigned int>("rand_seed", 12345, "Seed value for the random number generator"); 32 7728 : MooseEnum profileType("COS TANH", "COS"); 33 7728 : params.addParam<MooseEnum>( 34 : "profile", profileType, "Functional dependence for the interface profile"); 35 3864 : return params; 36 3864 : } 37 : 38 2051 : SmoothCircleBaseIC::SmoothCircleBaseIC(const InputParameters & parameters) 39 : : InitialCondition(parameters), 40 2051 : _mesh(_fe_problem.mesh()), 41 2051 : _invalue(parameters.get<Real>("invalue")), 42 2051 : _outvalue(parameters.get<Real>("outvalue")), 43 2051 : _int_width(parameters.get<Real>("int_width")), 44 2051 : _3D_spheres(parameters.get<bool>("3D_spheres")), 45 2051 : _zero_gradient(parameters.get<bool>("zero_gradient")), 46 2114 : _num_dim(_3D_spheres ? 3 : 2), 47 6153 : _profile(getParam<MooseEnum>("profile").getEnum<ProfileType>()) 48 : { 49 4102 : _random.seed(_tid, getParam<unsigned int>("rand_seed")); 50 : 51 2051 : if (_int_width <= 0.0 && _profile == ProfileType::TANH) 52 0 : paramError("int_width", 53 : "Interface width has to be strictly positive for the hyperbolic tangent profile"); 54 2051 : } 55 : 56 : void 57 1765 : SmoothCircleBaseIC::initialSetup() 58 : { 59 : // Compute radii and centers and initialize vector sizes 60 1765 : computeCircleRadii(); 61 1765 : computeCircleCenters(); 62 : 63 1765 : if (_centers.size() != _radii.size()) 64 0 : mooseError("_center and _radii vectors are not the same size in the Circle IC"); 65 : 66 1765 : if (_centers.size() < 1) 67 0 : mooseError("_center and _radii were not initialized in the Circle IC"); 68 1765 : } 69 : 70 : Real 71 11697000 : SmoothCircleBaseIC::value(const Point & p) 72 : { 73 11697000 : Real value = _outvalue; 74 : Real val2 = 0.0; 75 : 76 284538701 : for (unsigned int circ = 0; circ < _centers.size() && value != _invalue; ++circ) 77 : { 78 272841701 : val2 = computeCircleValue(p, _centers[circ], _radii[circ]); 79 272841701 : if ((val2 > value && _invalue > _outvalue) || (val2 < value && _outvalue > _invalue)) 80 : value = val2; 81 : } 82 : 83 11697000 : return value; 84 : } 85 : 86 : RealGradient 87 196690 : SmoothCircleBaseIC::gradient(const Point & p) 88 : { 89 196690 : if (_zero_gradient) 90 : return 0.0; 91 : 92 : RealGradient gradient = 0.0; 93 196690 : Real value = _outvalue; 94 : Real val2 = 0.0; 95 : 96 430880 : for (unsigned int circ = 0; circ < _centers.size(); ++circ) 97 : { 98 234190 : val2 = computeCircleValue(p, _centers[circ], _radii[circ]); 99 234190 : if ((val2 > value && _invalue > _outvalue) || (val2 < value && _outvalue > _invalue)) 100 : { 101 : value = val2; 102 63511 : gradient = computeCircleGradient(p, _centers[circ], _radii[circ]); 103 : } 104 : } 105 : 106 196690 : return gradient; 107 : } 108 : 109 : Real 110 273045891 : SmoothCircleBaseIC::computeCircleValue(const Point & p, const Point & center, const Real & radius) 111 : { 112 273045891 : Point l_center = center; 113 273045891 : Point l_p = p; 114 273045891 : if (!_3D_spheres) // Create 3D cylinders instead of spheres 115 : { 116 180240 : l_p(2) = 0.0; 117 180240 : l_center(2) = 0.0; 118 : } 119 : // Compute the distance between the current point and the center 120 273045891 : Real dist = _mesh.minPeriodicDistance(_var, l_p, l_center); 121 : 122 273045891 : switch (_profile) 123 : { 124 272997891 : case ProfileType::COS: 125 : { 126 : // Return value 127 272997891 : Real value = _outvalue; // Outside circle 128 : 129 272997891 : if (dist <= radius - _int_width / 2.0) // Inside circle 130 3474891 : value = _invalue; 131 269523000 : else if (dist < radius + _int_width / 2.0) // Smooth interface 132 : { 133 1312348 : Real int_pos = (dist - radius + _int_width / 2.0) / _int_width; 134 1312348 : value = _outvalue + (_invalue - _outvalue) * (1.0 + std::cos(int_pos * libMesh::pi)) / 2.0; 135 : } 136 : return value; 137 : } 138 : 139 48000 : case ProfileType::TANH: 140 48000 : return (_invalue - _outvalue) * 0.5 * (std::tanh(2.0 * (radius - dist) / _int_width) + 1.0) + 141 48000 : _outvalue; 142 : 143 0 : default: 144 0 : mooseError("Internal error."); 145 : } 146 : } 147 : 148 : RealGradient 149 63511 : SmoothCircleBaseIC::computeCircleGradient(const Point & p, 150 : const Point & center, 151 : const Real & radius) 152 : { 153 63511 : Point l_center = center; 154 63511 : Point l_p = p; 155 63511 : if (!_3D_spheres) // Create 3D cylinders instead of spheres 156 : { 157 0 : l_p(2) = 0.0; 158 0 : l_center(2) = 0.0; 159 : } 160 : // Compute the distance between the current point and the center 161 63511 : Real dist = _mesh.minPeriodicDistance(_var, l_p, l_center); 162 : 163 : // early return if we are probing the center of the circle 164 63511 : if (dist == 0.0) 165 : return 0.0; 166 : 167 : Real DvalueDr = 0.0; 168 63440 : switch (_profile) 169 : { 170 33440 : case ProfileType::COS: 171 33440 : if (dist < radius + _int_width / 2.0 && dist > radius - _int_width / 2.0) 172 : { 173 15486 : const Real int_pos = (dist - radius + _int_width / 2.0) / _int_width; 174 15486 : const Real Dint_posDr = 1.0 / _int_width; 175 15486 : DvalueDr = Dint_posDr * (_invalue - _outvalue) * 176 15486 : (-std::sin(int_pos * libMesh::pi) * libMesh::pi) / 2.0; 177 : } 178 : break; 179 : 180 30000 : case ProfileType::TANH: 181 30000 : DvalueDr = -(_invalue - _outvalue) * 0.5 / _int_width * libMesh::pi * 182 30000 : (1.0 - Utility::pow<2>(std::tanh(4.0 * (radius - dist) / _int_width))); 183 30000 : break; 184 : 185 0 : default: 186 0 : mooseError("Internal error."); 187 : } 188 : 189 63440 : return _mesh.minPeriodicVector(_var, center, p) * (DvalueDr / dist); 190 : }