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 "MultiAppGeneralFieldShapeEvaluationTransfer.h" 11 : 12 : // MOOSE includes 13 : #include "DisplacedProblem.h" 14 : #include "FEProblem.h" 15 : #include "MooseMesh.h" 16 : #include "MooseTypes.h" 17 : #include "MooseVariableFE.h" 18 : #include "Positions.h" 19 : 20 : #include "libmesh/system.h" 21 : #include "libmesh/mesh_function.h" 22 : 23 : registerMooseObject("MooseApp", MultiAppGeneralFieldShapeEvaluationTransfer); 24 : 25 : InputParameters 26 18735 : MultiAppGeneralFieldShapeEvaluationTransfer::validParams() 27 : { 28 18735 : InputParameters params = MultiAppGeneralFieldTransfer::validParams(); 29 18735 : params.addClassDescription( 30 : "Transfers field data at the MultiApp position using the finite element shape " 31 : "functions from the origin application."); 32 : 33 : // Blanket ban on origin boundary restriction. Most shape functions have their support extend 34 : // outside the boundary. For a true face variable, this parameter would make sense again 35 18735 : params.suppressParameter<std::vector<BoundaryName>>("from_boundaries"); 36 : // Shape function evaluations return an invalid value outside an app's domain anyway 37 18735 : params.suppressParameter<bool>("from_app_must_contain_point"); 38 : 39 18735 : return params; 40 0 : } 41 : 42 2237 : MultiAppGeneralFieldShapeEvaluationTransfer::MultiAppGeneralFieldShapeEvaluationTransfer( 43 2237 : const InputParameters & parameters) 44 2237 : : MultiAppGeneralFieldTransfer(parameters) 45 : { 46 : // Nearest point isn't well defined for sending app-based data from main app to a multiapp 47 2233 : if (_nearest_positions_obj && isParamValid("to_multi_app") && !isParamValid("from_multi_app")) 48 0 : paramError("use_nearest_position", 49 : "Cannot use nearest-position algorithm when sending from the main application"); 50 : 51 : // There's not much use for matching cell divisions when the locations have to match exactly 52 : // to get a valid source variable value anyway 53 4466 : if (_from_mesh_division_behavior == MeshDivisionTransferUse::MATCH_DIVISION_INDEX || 54 2233 : _to_mesh_division_behavior == MeshDivisionTransferUse::MATCH_DIVISION_INDEX) 55 0 : paramError("from_mesh_division_usage", 56 : "Matching division index is disabled for shape evaluation transfers"); 57 2233 : } 58 : 59 : void 60 5050 : MultiAppGeneralFieldShapeEvaluationTransfer::prepareEvaluationOfInterpValues( 61 : const unsigned int var_index) 62 : { 63 5050 : _local_bboxes.clear(); 64 5050 : if (_use_bounding_boxes) 65 5050 : extractLocalFromBoundingBoxes(_local_bboxes); 66 : 67 5050 : _local_meshfuns.clear(); 68 5050 : buildMeshFunctions(var_index, _local_meshfuns); 69 5050 : } 70 : 71 : void 72 5050 : MultiAppGeneralFieldShapeEvaluationTransfer::buildMeshFunctions( 73 : const unsigned int var_index, std::vector<libMesh::MeshFunction> & local_meshfuns) 74 : { 75 5050 : local_meshfuns.reserve(_from_problems.size()); 76 : 77 : // Construct a local mesh function for each origin problem 78 11457 : for (unsigned int i_from = 0; i_from < _from_problems.size(); ++i_from) 79 : { 80 6407 : FEProblemBase & from_problem = *_from_problems[i_from]; 81 : MooseVariableFieldBase & from_var = 82 6407 : from_problem.getVariable(0, 83 6407 : _from_var_names[var_index], 84 : Moose::VarKindType::VAR_ANY, 85 : Moose::VarFieldType::VAR_FIELD_ANY); 86 : 87 6407 : System & from_sys = from_var.sys().system(); 88 6407 : unsigned int from_var_num = from_sys.variable_number(getFromVarName(var_index)); 89 : 90 12814 : local_meshfuns.emplace_back(getEquationSystem(from_problem, _displaced_source_mesh), 91 6407 : *from_sys.current_local_solution, 92 : from_sys.get_dof_map(), 93 : from_var_num); 94 6407 : local_meshfuns.back().init(); 95 6407 : local_meshfuns.back().enable_out_of_mesh_mode(GeneralFieldTransfer::BetterOutOfMeshValue); 96 : } 97 5050 : } 98 : 99 : void 100 7202 : MultiAppGeneralFieldShapeEvaluationTransfer::evaluateInterpValues( 101 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 102 : std::vector<std::pair<Real, Real>> & outgoing_vals) 103 : { 104 7202 : evaluateInterpValuesWithMeshFunctions( 105 7202 : _local_bboxes, _local_meshfuns, incoming_points, outgoing_vals); 106 7202 : } 107 : 108 : void 109 7202 : MultiAppGeneralFieldShapeEvaluationTransfer::evaluateInterpValuesWithMeshFunctions( 110 : const std::vector<BoundingBox> & local_bboxes, 111 : std::vector<libMesh::MeshFunction> & local_meshfuns, 112 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 113 : std::vector<std::pair<Real, Real>> & outgoing_vals) 114 : { 115 7202 : dof_id_type i_pt = 0; 116 797269 : for (auto & [pt, mesh_div] : incoming_points) 117 : { 118 790067 : bool point_found = false; 119 790067 : outgoing_vals[i_pt].second = GeneralFieldTransfer::BetterOutOfMeshValue; 120 : 121 : // Loop on all local origin problems until: 122 : // - we've found the point in an app and the value at that point is valid 123 : // - or if looking for conflicts between apps, we must check them all 124 : // - or if looking for the nearest app, we also check them all 125 1688157 : for (MooseIndex(_from_problems.size()) i_from = 0; 126 2595910 : i_from < _from_problems.size() && 127 907753 : (!point_found || _search_value_conflicts || _nearest_positions_obj); 128 : ++i_from) 129 : { 130 : // Check spatial restrictions 131 898090 : Real distance = 0; 132 898090 : if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance)) 133 618514 : continue; 134 : else 135 : { 136 : // Use mesh function to compute interpolation values 137 290935 : const auto from_global_num = getGlobalSourceAppIndex(i_from); 138 290935 : const auto local_pt = _from_transforms[from_global_num]->mapBack(pt); 139 290935 : auto val = (local_meshfuns[i_from])(local_pt); 140 : 141 : // Look for overlaps. The check is not active outside of overlap search because in that 142 : // case we accept the first value from the lowest ranked process 143 : // NOTE: There is no guarantee this will be the final value used among all problems 144 : // but for shape evaluation we really do expect only one value to even be valid 145 290935 : if (detectConflict(val, outgoing_vals[i_pt].first, distance, outgoing_vals[i_pt].second)) 146 : { 147 : // In the nearest-position/app mode, we save conflicts in the reference frame 148 74 : if (_nearest_positions_obj) 149 32 : registerConflict(i_from, 0, pt, distance, true); 150 : else 151 42 : registerConflict(i_from, 0, local_pt, distance, true); 152 : } 153 : 154 : // No need to consider decision factors if value is invalid 155 290935 : if (val == GeneralFieldTransfer::BetterOutOfMeshValue) 156 11359 : continue; 157 : else 158 279576 : point_found = true; 159 : 160 : // Assign value and the distance from the target point to the origin data 161 : // distance only matters if multiple applications are providing a valid value 162 : // which would mean they overlap in the reference space. The distance can help 163 : // lift the indetermination on which value to select 164 279576 : if (distance < outgoing_vals[i_pt].second) 165 : { 166 279506 : outgoing_vals[i_pt].first = val; 167 279506 : outgoing_vals[i_pt].second = distance; 168 : } 169 : } 170 : } 171 : 172 790067 : if (!point_found) 173 510565 : outgoing_vals[i_pt] = {GeneralFieldTransfer::BetterOutOfMeshValue, 174 1021130 : GeneralFieldTransfer::BetterOutOfMeshValue}; 175 : 176 : // Move to next point 177 790067 : i_pt++; 178 : } 179 7202 : }