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