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 "ADConvectiveHeatFluxBC.h" 11 : 12 : registerMooseObject("HeatTransferApp", ADConvectiveHeatFluxBC); 13 : 14 : InputParameters 15 321 : ADConvectiveHeatFluxBC::validParams() 16 : { 17 321 : InputParameters params = ADIntegratedBC::validParams(); 18 321 : params.addClassDescription( 19 : "Convective heat transfer boundary condition with temperature and heat " 20 : "transfer coefficient given by material properties."); 21 : // Using material properties 22 642 : params.addParam<MaterialPropertyName>("T_infinity", 23 : "Material property for far-field temperature"); 24 642 : params.addParam<MaterialPropertyName>("heat_transfer_coefficient", 25 : "Material property for heat transfer coefficient"); 26 : // Using functors 27 642 : params.addParam<MooseFunctorName>("T_infinity_functor", "Functor for far-field temperature"); 28 642 : params.addParam<MooseFunctorName>("heat_transfer_coefficient_functor", 29 : "Functor for heat transfer coefficient"); 30 : // In the case where we are coupling a FV variable (via functors) that are block restricted on the 31 : // neighboring side of boundary, we need to have two layers of ghosting to do the face 32 : // interpolation. 33 642 : params.addRelationshipManager("ElementSideNeighborLayers", 34 : Moose::RelationshipManagerType::GEOMETRIC | 35 : Moose::RelationshipManagerType::ALGEBRAIC, 36 279 : [](const InputParameters & obj_params, InputParameters & rm_params) 37 : { 38 495 : rm_params.set<unsigned short>("layers") = 39 279 : obj_params.isParamValid("T_infinity_functor") ? 2 : 1; 40 279 : }); 41 321 : return params; 42 0 : } 43 : 44 152 : ADConvectiveHeatFluxBC::ADConvectiveHeatFluxBC(const InputParameters & parameters) 45 : : ADIntegratedBC(parameters), 46 318 : _T_infinity(isParamValid("T_infinity") ? &getADMaterialProperty<Real>("T_infinity") : nullptr), 47 152 : _htc(isParamValid("heat_transfer_coefficient") 48 318 : ? &getADMaterialProperty<Real>("heat_transfer_coefficient") 49 : : nullptr), 50 152 : _T_infinity_functor( 51 442 : isParamValid("T_infinity_functor") ? &getFunctor<ADReal>("T_infinity_functor") : nullptr), 52 152 : _htc_functor(isParamValid("heat_transfer_coefficient_functor") 53 290 : ? &getFunctor<ADReal>("heat_transfer_coefficient_functor") 54 152 : : nullptr) 55 : { 56 152 : if (_T_infinity || _htc) 57 : { 58 83 : if (_T_infinity_functor) 59 0 : paramError("T_infinity_functor", 60 : "Either material properties or functors should be specified for both T_infinity " 61 : "and the heat transfer coefficient."); 62 83 : if (_htc_functor) 63 0 : paramError("heat_transfer_coefficient_functor", 64 : "Either material properties or functors should be specified for both T_infinity " 65 : "and the heat transfer coefficient"); 66 83 : if (!_htc) 67 0 : paramError("heat_transfer_coefficient", 68 : "Heat transfer coefficient material property must be specified"); 69 83 : if (!_T_infinity) 70 0 : paramError("T_infinity", "Far field temperature material property must be specified"); 71 : } 72 69 : else if (_T_infinity_functor || _htc_functor) 73 : { 74 69 : if (!_htc_functor) 75 0 : paramError("heat_transfer_coefficient_functor", 76 : "Heat transfer coefficient functor must be specified"); 77 69 : if (!_T_infinity_functor) 78 0 : paramError("T_infinity_functor", "Far field temperature functor must be specified"); 79 : } 80 : else 81 0 : paramError("T_infinity", 82 : "Far field temperature and heat transfer coefficients must be specified"); 83 152 : } 84 : 85 : void 86 151 : ADConvectiveHeatFluxBC::initialSetup() 87 : { 88 151 : if (_T_infinity) 89 83 : return; 90 : 91 : bool T_inf_can_use_neighbor = true; 92 : bool htc_can_use_neighbor = true; 93 : // Loop over elements on the primary side of all boundaries 94 1484 : for (const auto & bnd_elem : *_mesh.getBoundaryElementRange()) 95 : { 96 1416 : const auto & [elem, side, bid] = *bnd_elem; 97 : // Skip if this boundary is not part of the restriction 98 1416 : if (!hasBoundary(bid) || (elem->processor_id() != this->processor_id())) 99 1228 : continue; 100 : 101 : // Use neighbors if the functor is not defined on all primary blocks 102 188 : _T_infinity_use_neighbor = 103 188 : _T_infinity_use_neighbor || !_T_infinity_functor->hasBlocks(elem->subdomain_id()); 104 188 : _htc_use_neighbor = _htc_use_neighbor || !_htc_functor->hasBlocks(elem->subdomain_id()); 105 : 106 : // Determine if neighbor can be used, just in case 107 188 : const auto neighbor = elem->neighbor_ptr(side); 108 : if (neighbor) 109 : mooseAssert( 110 : !neighbor->is_remote(), 111 : "The neighbor best not be remote because we request at least one layer of ghosting"); 112 330 : T_inf_can_use_neighbor = T_inf_can_use_neighbor && neighbor && 113 142 : _T_infinity_functor->hasBlocks(neighbor->subdomain_id()); 114 : htc_can_use_neighbor = 115 188 : htc_can_use_neighbor && neighbor && _htc_functor->hasBlocks(neighbor->subdomain_id()); 116 : } 117 : 118 68 : _communicator.max(_T_infinity_use_neighbor); 119 68 : _communicator.max(_htc_use_neighbor); 120 : 121 : const std::string error_msg = 122 : "Functor must either be defined on all of the primary side of the boundary or on all " 123 68 : "of the secondary side."; 124 68 : if (_T_infinity_use_neighbor && !T_inf_can_use_neighbor) 125 2 : paramError("T_infinity_functor", error_msg); 126 66 : if (_htc_use_neighbor && !htc_can_use_neighbor) 127 0 : paramError("heat_transfer_coefficient_functor", error_msg); 128 : } 129 : 130 : ADReal 131 295440 : ADConvectiveHeatFluxBC::computeQpResidual() 132 : { 133 295440 : if (_T_infinity) 134 822768 : return -_test[_i][_qp] * (*_htc)[_qp] * ((*_T_infinity)[_qp] - _u[_qp]); 135 : else 136 : { 137 : // Populate neighbor information, if necessary (optimization on first qp) 138 21184 : if ((_T_infinity_use_neighbor || _htc_use_neighbor) && _qp == 0) 139 : { 140 9800 : _current_neighbor_elem = _current_elem->neighbor_ptr(_current_side); 141 : mooseAssert(_current_neighbor_elem, "Neighbor element should exist at this point."); 142 9800 : _current_neighbor_side = _current_neighbor_elem->which_neighbor_am_i(_current_elem); 143 : } 144 : 145 : // Convenience lambda for getting space argument on either element or neighbor 146 42368 : const auto get_space_arg = [this](bool use_neighbor) -> Moose::ElemSideQpArg 147 : { 148 42368 : if (!use_neighbor) 149 22768 : return {_current_elem, _current_side, _qp, _qrule, _q_point[_qp]}; 150 : else 151 19600 : return {_current_neighbor_elem, _current_neighbor_side, _qp, _qrule, _q_point[_qp]}; 152 21184 : }; 153 : 154 21184 : const auto Tinf_space_arg = get_space_arg(_T_infinity_use_neighbor); 155 21184 : const auto htc_space_arg = get_space_arg(_htc_use_neighbor); 156 21184 : const auto time_arg = Moose::currentState(); 157 21184 : return -_test[_i][_qp] * (*_htc_functor)(htc_space_arg, time_arg) * 158 42368 : ((*_T_infinity_functor)(Tinf_space_arg, time_arg) - _u[_qp]); 159 : } 160 : }