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 : // MOOSE includes 11 : #include "BoundaryElemIntegrityCheckThread.h" 12 : #include "AuxiliarySystem.h" 13 : #include "NonlinearSystemBase.h" 14 : #include "FEProblemBase.h" 15 : #include "SideUserObject.h" 16 : #include "MooseMesh.h" 17 : #include "IntegratedBCBase.h" 18 : #include "MooseObjectTagWarehouse.h" 19 : 20 : #include "libmesh/threads.h" 21 : #include "libmesh/elem.h" 22 : #include "libmesh/mesh_base.h" 23 : 24 : #include <vector> 25 : 26 55047 : BoundaryElemIntegrityCheckThread::BoundaryElemIntegrityCheckThread( 27 55047 : FEProblemBase & fe_problem, const TheWarehouse::Query & query) 28 55047 : : _fe_problem(fe_problem), 29 55047 : _aux_sys(fe_problem.getAuxiliarySystem()), 30 55047 : _elem_aux(_aux_sys.elemAuxWarehouse()), 31 55047 : _elem_vec_aux(_aux_sys.elemVectorAuxWarehouse()), 32 55047 : _elem_array_aux(_aux_sys.elemArrayAuxWarehouse()), 33 55047 : _query(query) 34 : { 35 55047 : } 36 : 37 : // Splitting Constructor 38 5066 : BoundaryElemIntegrityCheckThread::BoundaryElemIntegrityCheckThread( 39 5066 : BoundaryElemIntegrityCheckThread & x, Threads::split) 40 5066 : : _fe_problem(x._fe_problem), 41 5066 : _aux_sys(x._aux_sys), 42 5066 : _elem_aux(x._elem_aux), 43 5066 : _elem_vec_aux(x._elem_vec_aux), 44 5066 : _elem_array_aux(x._elem_array_aux), 45 5066 : _query(x._query) 46 : { 47 5066 : } 48 : 49 : void 50 60113 : BoundaryElemIntegrityCheckThread::operator()(const ConstBndElemRange & range) 51 : { 52 60113 : ParallelUniqueId puid; 53 60113 : const auto tid = puid.id; 54 : 55 1907378 : for (const auto & belem : range) 56 : { 57 1869565 : const Elem * elem = belem->_elem; 58 1869565 : const auto boundary_id = belem->_bnd_id; 59 1869565 : const auto side = belem->_side; 60 : 61 : // We can distribute work just as the actual execution code will 62 1869565 : if (elem->processor_id() != _fe_problem.processor_id()) 63 22285 : return; 64 : 65 1847280 : auto & mesh = _fe_problem.mesh(); 66 : 67 1847280 : const auto & bnd_name = mesh.getBoundaryName(boundary_id); 68 : 69 : // uo check 70 1847280 : std::vector<SideUserObject *> objs; 71 1847280 : _query.clone() 72 1847280 : .condition<AttribThread>(tid) 73 1847280 : .condition<AttribInterfaces>(Interfaces::SideUserObject) 74 3694560 : .condition<AttribBoundaries>(boundary_id, true) 75 1847280 : .queryInto(objs); 76 1966398 : for (const auto & uo : objs) 77 119125 : if (uo->checkVariableBoundaryIntegrity()) 78 : { 79 119125 : auto leftover_vars = uo->checkAllVariables(*elem); 80 119125 : if (!leftover_vars.empty()) 81 : { 82 120 : const auto neighbor = elem->neighbor_ptr(side); 83 120 : const bool upwind_elem = !neighbor || elem->id() < neighbor->id(); 84 : const Elem * lower_d_elem = 85 120 : upwind_elem ? mesh.getLowerDElem(elem, side) 86 12 : : mesh.getLowerDElem(neighbor, neighbor->which_neighbor_am_i(elem)); 87 120 : if (lower_d_elem) 88 116 : leftover_vars = uo->checkVariables(*lower_d_elem, leftover_vars); 89 : } 90 119125 : boundaryIntegrityCheckError(*uo, leftover_vars, bnd_name); 91 119118 : } 92 : 93 7807549 : auto check = [elem, boundary_id, &bnd_name, tid, &mesh, side](const auto & warehouse) 94 : { 95 7349254 : if (!warehouse.hasBoundaryObjects(boundary_id, tid)) 96 7211513 : return; 97 : 98 137741 : const auto & bnd_objects = warehouse.getBoundaryObjects(boundary_id, tid); 99 298234 : for (const auto & bnd_object : bnd_objects) 100 : // Skip if this object uses geometric search because coupled variables may be defined on 101 : // paired boundaries instead of the boundary this elem is on 102 160501 : if (!bnd_object->requiresGeometricSearch() && bnd_object->checkVariableBoundaryIntegrity()) 103 : { 104 : // First check the higher-dimensional element 105 157247 : auto leftover_vars = bnd_object->checkAllVariables(*elem); 106 157247 : if (!leftover_vars.empty()) 107 : { 108 3030 : const auto neighbor = elem->neighbor_ptr(side); 109 3030 : const bool upwind_elem = !neighbor || elem->id() < neighbor->id(); 110 3030 : const Elem * lower_d_elem = 111 3030 : upwind_elem ? mesh.getLowerDElem(elem, side) 112 0 : : mesh.getLowerDElem(neighbor, neighbor->which_neighbor_am_i(elem)); 113 3030 : if (lower_d_elem) 114 3022 : leftover_vars = bnd_object->checkVariables(*lower_d_elem, leftover_vars); 115 : } 116 : 117 157247 : boundaryIntegrityCheckError(*bnd_object, leftover_vars, bnd_name); 118 157239 : } 119 1847273 : }; 120 : 121 1847273 : check(_elem_aux); 122 1847269 : check(_elem_vec_aux); 123 1847269 : check(_elem_array_aux); 124 3654708 : for (const auto i : make_range(_fe_problem.numNonlinearSystems())) 125 1807443 : check(_fe_problem.getNonlinearSystemBase(i).getIntegratedBCWarehouse()); 126 1847265 : } 127 60098 : } 128 : 129 : void 130 5063 : BoundaryElemIntegrityCheckThread::join(const BoundaryElemIntegrityCheckThread & /*y*/) 131 : { 132 5063 : } 133 : 134 : void 135 1186593 : boundaryIntegrityCheckError(const MooseObject & object, 136 : const std::set<MooseVariableFieldBase *> & variables, 137 : const BoundaryName & boundary_name) 138 : { 139 1186593 : if (variables.empty()) 140 1186554 : return; 141 : 142 39 : std::vector<std::string> names; 143 39 : names.reserve(variables.size()); 144 78 : for (const auto * const var : variables) 145 39 : names.push_back(var->name()); 146 : 147 78 : mooseError("'", 148 39 : object.name(), 149 : "' of type '", 150 39 : object.type(), 151 : "' depends on variable(s) '", 152 39 : MooseUtils::join(names, ","), 153 : "'. However, that variable does not appear to be defined on (all of) boundary '", 154 : boundary_name, 155 : "'."); 156 0 : }