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 18413 : MultiAppGeneralFieldShapeEvaluationTransfer::validParams() 27 : { 28 18413 : InputParameters params = MultiAppGeneralFieldTransfer::validParams(); 29 18413 : 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 18413 : params.suppressParameter<std::vector<BoundaryName>>("from_boundaries"); 36 : // Shape function evaluations return an invalid value outside an app's domain anyway 37 18413 : params.suppressParameter<bool>("from_app_must_contain_point"); 38 : 39 18413 : return params; 40 0 : } 41 : 42 2076 : MultiAppGeneralFieldShapeEvaluationTransfer::MultiAppGeneralFieldShapeEvaluationTransfer( 43 2076 : const InputParameters & parameters) 44 2076 : : MultiAppGeneralFieldTransfer(parameters) 45 : { 46 : // Nearest point isn't well defined for sending app-based data from main app to a multiapp 47 2072 : 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 4144 : if (_from_mesh_division_behavior == MeshDivisionTransferUse::MATCH_DIVISION_INDEX || 54 2072 : _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 2072 : } 58 : 59 : void 60 4620 : MultiAppGeneralFieldShapeEvaluationTransfer::prepareEvaluationOfInterpValues( 61 : const unsigned int var_index) 62 : { 63 4620 : _local_bboxes.clear(); 64 4620 : if (_use_bounding_boxes) 65 4620 : extractLocalFromBoundingBoxes(_local_bboxes); 66 : 67 4620 : _local_meshfuns.clear(); 68 4620 : buildMeshFunctions(var_index, _local_meshfuns); 69 4620 : } 70 : 71 : void 72 4620 : MultiAppGeneralFieldShapeEvaluationTransfer::buildMeshFunctions( 73 : const unsigned int var_index, std::vector<libMesh::MeshFunction> & local_meshfuns) 74 : { 75 4620 : local_meshfuns.reserve(_from_problems.size()); 76 : 77 : // Construct a local mesh function for each origin problem 78 10396 : for (unsigned int i_from = 0; i_from < _from_problems.size(); ++i_from) 79 : { 80 5776 : FEProblemBase & from_problem = *_from_problems[i_from]; 81 : MooseVariableFieldBase & from_var = 82 5776 : from_problem.getVariable(0, 83 5776 : _from_var_names[var_index], 84 : Moose::VarKindType::VAR_ANY, 85 : Moose::VarFieldType::VAR_FIELD_ANY); 86 : 87 5776 : System & from_sys = from_var.sys().system(); 88 5776 : unsigned int from_var_num = from_sys.variable_number(getFromVarName(var_index)); 89 : 90 11552 : local_meshfuns.emplace_back(getEquationSystem(from_problem, _displaced_source_mesh), 91 5776 : *from_sys.current_local_solution, 92 : from_sys.get_dof_map(), 93 : from_var_num); 94 5776 : local_meshfuns.back().init(); 95 5776 : local_meshfuns.back().enable_out_of_mesh_mode(GeneralFieldTransfer::BetterOutOfMeshValue); 96 : } 97 4620 : } 98 : 99 : void 100 6772 : MultiAppGeneralFieldShapeEvaluationTransfer::evaluateInterpValues( 101 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 102 : std::vector<std::pair<Real, Real>> & outgoing_vals) 103 : { 104 6772 : evaluateInterpValuesWithMeshFunctions( 105 6772 : _local_bboxes, _local_meshfuns, incoming_points, outgoing_vals); 106 6772 : } 107 : 108 : void 109 6772 : 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 6772 : dof_id_type i_pt = 0; 116 727030 : for (auto & [pt, mesh_div] : incoming_points) 117 : { 118 720258 : bool point_found = false; 119 720258 : 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 1532957 : for (MooseIndex(_from_problems.size()) i_from = 0; 126 2353927 : i_from < _from_problems.size() && 127 820970 : (!point_found || _search_value_conflicts || _nearest_positions_obj); 128 : ++i_from) 129 : { 130 : // Check spatial restrictions 131 812699 : Real distance = 0; 132 812699 : if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance)) 133 565492 : continue; 134 : else 135 : { 136 : // Use mesh function to compute interpolation values 137 258558 : const auto from_global_num = getGlobalSourceAppIndex(i_from); 138 258558 : const auto local_pt = _from_transforms[from_global_num]->mapBack(pt); 139 258558 : 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 258558 : 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 258558 : if (val == GeneralFieldTransfer::BetterOutOfMeshValue) 156 11351 : continue; 157 : else 158 247207 : 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 247207 : if (distance < outgoing_vals[i_pt].second) 165 : { 166 247137 : outgoing_vals[i_pt].first = val; 167 247137 : outgoing_vals[i_pt].second = distance; 168 : } 169 : } 170 : } 171 : 172 720258 : if (!point_found) 173 473125 : outgoing_vals[i_pt] = {GeneralFieldTransfer::BetterOutOfMeshValue, 174 946250 : GeneralFieldTransfer::BetterOutOfMeshValue}; 175 : 176 : // Move to next point 177 720258 : i_pt++; 178 : } 179 6772 : }