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 16919 : MultiAppGeneralFieldUserObjectTransfer::validParams() 28 : { 29 16919 : InputParameters params = MultiAppGeneralFieldTransfer::validParams(); 30 16919 : params.addClassDescription( 31 : "Transfers user object spatial evaluations from an origin app onto a variable in the target " 32 : "application."); 33 : 34 50757 : params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{}; 35 33838 : params.suppressParameter<std::vector<VariableName>>("source_variable"); 36 50757 : 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 16919 : 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 16919 : params.suppressParameter<std::vector<BoundaryName>>("from_boundaries"); 46 16919 : return params; 47 0 : } 48 : 49 1331 : MultiAppGeneralFieldUserObjectTransfer::MultiAppGeneralFieldUserObjectTransfer( 50 1331 : const InputParameters & parameters) 51 : : MultiAppGeneralFieldTransfer(parameters), 52 3969 : _user_object_name(getParam<UserObjectName>("source_user_object")) 53 : { 54 1319 : if (_to_var_names.size() > 1) 55 8 : 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 5540 : if (isParamValid("from_blocks") && !_source_app_must_contain_point && 59 1875 : !parameters.isParamSetByUser("extrapolation_constant")) 60 8 : 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 1639 : 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 1311 : } 70 : 71 : void 72 1323 : MultiAppGeneralFieldUserObjectTransfer::execute() 73 : { 74 : // Execute the user object if it was specified to execute on TRANSFER 75 1323 : switch (_current_direction) 76 : { 77 515 : case TO_MULTIAPP: 78 : { 79 515 : checkParentAppUserObjectExecuteOn(_user_object_name); 80 515 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name); 81 515 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name); 82 515 : break; 83 : } 84 568 : case FROM_MULTIAPP: 85 568 : errorIfObjectExecutesOnTransferInSourceApp(_user_object_name); 86 : } 87 : 88 : // Perfom the actual transfer 89 1323 : MultiAppGeneralFieldTransfer::execute(); 90 1315 : } 91 : 92 : void 93 1323 : MultiAppGeneralFieldUserObjectTransfer::prepareEvaluationOfInterpValues( 94 : const unsigned int /* var_index */) 95 : { 96 1323 : _local_bboxes.clear(); 97 1323 : if (_use_bounding_boxes) 98 1323 : extractLocalFromBoundingBoxes(_local_bboxes); 99 1323 : } 100 : 101 : void 102 1873 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValues( 103 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 104 : std::vector<std::pair<Real, Real>> & outgoing_vals) 105 : { 106 1873 : evaluateInterpValuesWithUserObjects(_local_bboxes, incoming_points, outgoing_vals); 107 1873 : } 108 : 109 : void 110 1873 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValuesWithUserObjects( 111 : const std::vector<BoundingBox> & local_bboxes, 112 : const std::vector<std::pair<Point, unsigned int>> & incoming_points, 113 : std::vector<std::pair<Real, Real>> & outgoing_vals) 114 : { 115 1873 : dof_id_type i_pt = 0; 116 816776 : for (auto & [pt, mesh_div] : incoming_points) 117 : { 118 814903 : bool point_found = false; 119 814903 : 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 2029779 : for (MooseIndex(_from_problems.size()) i_from = 0; 125 3255509 : i_from < _from_problems.size() && 126 1225730 : (!point_found || _search_value_conflicts || _nearest_positions_obj); 127 : ++i_from) 128 : { 129 : // User object spatialValue() evaluations do not provide a distance 130 1214876 : Real distance = 1; 131 : // Check spatial restrictions 132 1214876 : if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance)) 133 1100939 : continue; 134 : else 135 : { 136 113937 : const auto from_global_num = getGlobalSourceAppIndex(i_from); 137 : 138 : // Get user object from the local problem 139 : const UserObject & user_object = 140 113937 : _from_problems[i_from]->getUserObjectBase(_user_object_name); 141 : 142 : // Use spatial value routine to compute the origin value to transfer 143 113937 : const auto local_pt = _from_transforms[from_global_num]->mapBack(pt); 144 113937 : 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 113937 : if (detectConflict(val, outgoing_vals[i_pt].first, distance, outgoing_vals[i_pt].second)) 151 : { 152 12 : if (_nearest_positions_obj) 153 0 : registerConflict(i_from, 0, pt, distance, true); 154 : else 155 12 : registerConflict(i_from, 0, local_pt, distance, true); 156 : } 157 : 158 : // No need to consider decision factors if value is invalid 159 113937 : if (val == GeneralFieldTransfer::BetterOutOfMeshValue) 160 0 : continue; 161 : else 162 113937 : point_found = true; 163 : 164 : // Assign value 165 113937 : if (distance < outgoing_vals[i_pt].second) 166 : { 167 113913 : outgoing_vals[i_pt].first = val; 168 113913 : outgoing_vals[i_pt].second = distance; 169 : } 170 : } 171 : } 172 : 173 814903 : if (!point_found) 174 700990 : outgoing_vals[i_pt] = {GeneralFieldTransfer::BetterOutOfMeshValue, 175 1401980 : GeneralFieldTransfer::BetterOutOfMeshValue}; 176 : 177 : // Move to next point 178 814903 : i_pt++; 179 : } 180 1873 : }