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 "MultiAppGeneralFieldUserObjectTransfer.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 "UserObject.h" 19 : #include "Positions.h" 20 : 21 : #include "libmesh/system.h" 22 : #include "libmesh/mesh_function.h" 23 : 24 : registerMooseObject("MooseApp", MultiAppGeneralFieldUserObjectTransfer); 25 : 26 : InputParameters 27 5485 : MultiAppGeneralFieldUserObjectTransfer::validParams() 28 : { 29 5485 : InputParameters params = MultiAppGeneralFieldTransfer::validParams(); 30 5485 : params.addClassDescription( 31 : "Transfers user object spatial evaluations from an origin app onto a variable in the target " 32 : "application."); 33 : 34 16455 : params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{}; 35 10970 : params.suppressParameter<std::vector<VariableName>>("source_variable"); 36 16455 : params.addRequiredParam<UserObjectName>("source_user_object", 37 : "The UserObject you want to transfer values from. " 38 : "It must implement the SpatialValue() class routine"); 39 : 40 5485 : MultiAppTransfer::addUserObjectExecutionCheckParam(params); 41 : 42 : // Blanket ban on origin boundary restriction. User objects tend to extend beyond boundaries, 43 : // and be able to be evaluated within a volume rather than only on a boundary 44 : // This could be re-enabled for spatial user objects that are only defined on boundaries 45 5485 : params.suppressParameter<std::vector<BoundaryName>>("from_boundaries"); 46 5485 : return params; 47 0 : } 48 : 49 1215 : MultiAppGeneralFieldUserObjectTransfer::MultiAppGeneralFieldUserObjectTransfer( 50 1215 : const InputParameters & parameters) 51 : : MultiAppGeneralFieldTransfer(parameters), 52 3627 : _user_object_name(getParam<UserObjectName>("source_user_object")) 53 : { 54 1206 : if (_to_var_names.size() > 1) 55 6 : paramError("variable", "Only one variable at a time is supported by this transfer"); 56 : 57 : // Block restriction does not make sense if we're ok with extrapolating 58 5067 : if (isParamValid("from_blocks") && !_source_app_must_contain_point && 59 1713 : !parameters.isParamSetByUser("extrapolation_constant")) 60 6 : paramError("from_app_must_contain_point", 61 : "Source block restriction cannot be used at the same type as allowing extrapolation" 62 : " of values for a user object transfer (with 'from_app_must_contain_point=false') " 63 : " unless an extrapolation constant is provided (with 'extrapolation_constant')"); 64 : 65 : // Nearest point isn't well defined for sending app-based data from main app to a multiapp 66 1500 : if (_nearest_positions_obj && isParamValid("to_multi_app") && !isParamValid("from_multi_app")) 67 0 : paramError("use_nearest_position", 68 : "Cannot use nearest-position algorithm when sending from the main application"); 69 1200 : } 70 : 71 : void 72 1212 : MultiAppGeneralFieldUserObjectTransfer::execute() 73 : { 74 : // Execute the user object if it was specified to execute on TRANSFER 75 1212 : switch (_current_direction) 76 : { 77 472 : case TO_MULTIAPP: 78 : { 79 472 : checkParentAppUserObjectExecuteOn(_user_object_name); 80 472 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name); 81 472 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name); 82 472 : break; 83 : } 84 520 : case FROM_MULTIAPP: 85 520 : errorIfObjectExecutesOnTransferInSourceApp(_user_object_name); 86 : } 87 : 88 : // Perfom the actual transfer 89 1212 : MultiAppGeneralFieldTransfer::execute(); 90 1206 : } 91 : 92 : void 93 1212 : MultiAppGeneralFieldUserObjectTransfer::prepareEvaluationOfInterpValues( 94 : const unsigned int /* var_index */) 95 : { 96 1212 : _local_bboxes.clear(); 97 1212 : if (_use_bounding_boxes) 98 1212 : extractLocalFromBoundingBoxes(_local_bboxes); 99 1212 : } 100 : 101 : void 102 1762 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValues( 103 : const unsigned int /*var_index*/, 104 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 105 : std::vector<std::pair<Real, Real>> & outgoing_vals) 106 : { 107 1762 : evaluateInterpValuesWithUserObjects(_local_bboxes, incoming_points, outgoing_vals); 108 1762 : } 109 : 110 : void 111 1762 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValuesWithUserObjects( 112 : const std::vector<BoundingBox> & local_bboxes, 113 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 114 : std::vector<std::pair<Real, Real>> & outgoing_vals) 115 : { 116 1762 : dof_id_type i_pt = 0; 117 751567 : for (auto & [pt, mesh_div] : incoming_points) 118 : { 119 749805 : bool point_found = false; 120 749805 : outgoing_vals[i_pt].second = GeneralFieldTransfer::OutOfMeshValue; 121 : 122 : // Loop on all local origin problems until: 123 : // - we've found the point in an app and the value at that point is valid 124 : // - or if looking for conflicts between apps, we must check them all 125 1842708 : for (MooseIndex(_from_problems.size()) i_from = 0; 126 2944939 : i_from < _from_problems.size() && 127 1102231 : (!point_found || _search_value_conflicts || _nearest_positions_obj); 128 : ++i_from) 129 : { 130 : // User object spatialValue() evaluations do not provide a distance 131 1092903 : Real distance = 1; 132 : // Check spatial restrictions 133 1092903 : if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance)) 134 990728 : continue; 135 : else 136 : { 137 : // Get user object from the local problem 138 : const UserObject & user_object = 139 102175 : _from_problems[i_from]->getUserObjectBase(_user_object_name); 140 : 141 : // Use spatial value routine to compute the origin value to transfer 142 : const auto local_pt = 143 204350 : getPointInSourceAppFrame(pt, i_from, "User object spatial value evaluation"); 144 102175 : auto val = user_object.spatialValue(local_pt); 145 : 146 : // Look for overlaps. The check is not active outside of overlap search because in that 147 : // case we accept the first value from the lowest ranked process 148 : // NOTE: There is no guarantee this will be the final value used among all problems 149 : // but we register an overlap as soon as two values are possible from this rank 150 102175 : if (detectConflict(val, outgoing_vals[i_pt].first, distance, outgoing_vals[i_pt].second)) 151 : { 152 9 : if (_nearest_positions_obj) 153 0 : registerConflict(i_from, 0, pt, distance, true); 154 : else 155 9 : registerConflict(i_from, 0, local_pt, distance, true); 156 : } 157 : 158 : // No need to consider decision factors if value is invalid 159 102175 : if (val == GeneralFieldTransfer::OutOfMeshValue) 160 0 : continue; 161 : else 162 102175 : point_found = true; 163 : 164 : // Assign value 165 102175 : if (distance < outgoing_vals[i_pt].second) 166 : { 167 102157 : outgoing_vals[i_pt].first = val; 168 102157 : outgoing_vals[i_pt].second = distance; 169 : } 170 : } 171 : } 172 : 173 749805 : if (!point_found) 174 647648 : outgoing_vals[i_pt] = {GeneralFieldTransfer::OutOfMeshValue, 175 1295296 : GeneralFieldTransfer::OutOfMeshValue}; 176 : 177 : // Move to next point 178 749805 : i_pt++; 179 : } 180 1762 : } 181 : 182 : std::string 183 3 : MultiAppGeneralFieldUserObjectTransfer::getDataSourceName(unsigned int /*var_index*/) const 184 : { 185 3 : return "user object '" + _user_object_name + "'"; 186 : }