https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MultiAppVariableValueSamplePostprocessorTransfer.C
Go to the documentation of this file.
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
11
12// MOOSE includes
13#include "FEProblem.h"
14#include "MooseMesh.h"
15#include "MooseTypes.h"
16#include "MooseVariableFE.h"
17#include "MultiApp.h"
18#include "AuxiliarySystem.h"
19#include "MooseUtils.h"
21
22#include "libmesh/meshfree_interpolation.h"
23#include "libmesh/system.h"
24
25#include "timpi/parallel_sync.h"
26
27using namespace libMesh;
28
30
33{
36 "Samples the value of a variable within the main application at each sub-application "
37 "position and transfers the value to a postprocessor on the sub-application(s) when "
38 "performing the to-multiapp transfer. Reconstructs the value of a CONSTANT MONOMIAL "
39 "variable associating the value of each element to the value of the postprocessor "
40 "in the closest sub-application whem performing the from-multiapp transfer.");
41 params.addRequiredParam<PostprocessorName>(
42 "postprocessor",
43 "The name of the postprocessor in the MultiApp to transfer the value to. "
44 "This should most likely be a Reciever Postprocessor.");
45 params.addRequiredParam<VariableName>("source_variable", "The variable to transfer from.");
46 params.addParam<unsigned int>(
47 "source_variable_component",
48 0,
49 "The component of source variable, may be non-zero for array variables.");
50 params.addParam<bool>(
51 "map_array_variable_components_to_child_apps",
52 false,
53 "When true, groups of sub-applications will be associated with different components of the "
54 "supplied array variable in 'source_variable'. For instance, if there are 9 sub-applications "
55 "and 3 components in the variable, sub-apps 0-2 will go to component 0, 3-5 will go to 1, "
56 "and 6-8 will go to 2.");
57 return params;
58}
59
61 const InputParameters & parameters)
62 : MultiAppTransfer(parameters),
63 MeshChangedInterface(parameters),
64 _postprocessor_name(getParam<PostprocessorName>("postprocessor")),
65 _var_name(getParam<VariableName>("source_variable")),
66 _comp(getParam<unsigned int>("source_variable_component")),
67 _var(_fe_problem.getVariable(0, _var_name)),
68 _map_comp_to_child(getParam<bool>("map_array_variable_components_to_child_apps"))
69{
70 if (_directions.size() != 1)
71 paramError("direction", "This transfer is only unidirectional");
72
73 if (_directions.isValueSet("from_multiapp"))
74 {
75 // Check that the variable is a CONSTANT MONOMIAL.
76 auto & fe_type = _var.feType();
77 if (fe_type.order != CONSTANT || fe_type.family != MONOMIAL)
78 paramError("source_variable",
79 "Variable must be in CONSTANT MONOMIAL when transferring from a postprocessor "
80 "from sub-apps.");
81
83 paramError("source_variable", "Variable must be an auxiliary variable");
84 }
85 else if (_directions.isValueSet("between_multiapp"))
86 mooseError("MultiAppVariableValueSamplePostprocessorTransfer has not been made to support "
87 "sibling transfers");
88
90 paramError("map_array_variable_components_to_child_apps",
91 "'source_variable' must be an array variable when mapping array variable components "
92 "to child applications.");
93 if (_map_comp_to_child && parameters.isParamSetByUser("source_variable_component"))
94 paramError("map_array_variable_components_to_child_apps",
95 "'source_variable_component' is invalid when mapping array variable components to "
96 "child applications.");
97}
98
99void
101{
102 if (!_directions.isValueSet("from_multiapp"))
103 return;
104
105 const auto num_global_apps = getFromMultiApp()->numGlobalApps();
106
107 // Setup the communication pattern
108 _postprocessor_to_processor_id.resize(num_global_apps,
109 std::numeric_limits<processor_id_type>::max());
110 for (const auto i : make_range(num_global_apps))
111 if (getFromMultiApp()->hasLocalApp(i))
113
115#ifdef DEBUG
116 for (const auto i : make_range(num_global_apps))
117 {
118 mooseAssert(_postprocessor_to_processor_id[i] != std::numeric_limits<processor_id_type>::max(),
119 "Every element in the vector should have been set.");
120 if (getFromMultiApp()->hasLocalApp(i))
121 mooseAssert(_postprocessor_to_processor_id[i] == this->processor_id(),
122 "If I owned this app, then the processor id value should be my own");
123 }
124#endif
125}
126
127void
129{
130 if (!_directions.isValueSet("from_multiapp"))
131 return;
132
133 // Cache the Multiapp position ID for every element.
134 auto & mesh = _fe_problem.mesh().getMesh();
135 unsigned int multiapp_pos_id = 0;
136 for (auto & elem : as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
137 // Exclude the elements without dofs.
138 if (_var.hasBlocks(elem->subdomain_id()))
139 {
140 // The next two loops will loop through all the sub-applications
141 // The first loop is over each component of the source variable we are transferring to/from
142 unsigned int j = 0; // Indicates sub-app index
143 for (unsigned int g = 0; g < getFromMultiApp()->numGlobalApps() / _apps_per_component; ++g)
144 {
145 Real distance = std::numeric_limits<Real>::max();
146 unsigned int count = 0;
147 // The second loop is over all the sub-apps the given component is associated with
148 for (unsigned int c = 0; c < _apps_per_component; ++c, ++j)
149 {
150 Real current_distance = (getFromMultiApp()->position(j) - elem->true_centroid()).norm();
151 if (MooseUtils::absoluteFuzzyLessThan(current_distance, distance))
152 {
153 distance = current_distance;
154 multiapp_pos_id = j;
155 count = 0;
156 }
157 else if (MooseUtils::absoluteFuzzyEqual(current_distance, distance))
158 ++count;
159 }
160 if (count > 0)
162 "The distances of an element to more than one sub-applications are too close "
163 " in transfer '",
164 name(),
165 "'. The code chooses the sub-application with the smallest ID to set "
166 "the variable on the element, which may created undesired variable solutions."
167 "\nHaving different positions for sub-applications, "
168 "a centroid-based MultiApp or adding block restriction to the variable can "
169 "be used to resolve this warning.");
170
171 // Note: in case of count>0, the sub-application with smallest id will be used for the
172 // transfer.
173 _cached_multiapp_pos_ids.push_back(multiapp_pos_id);
174 _needed_postprocessors.insert(multiapp_pos_id);
175 }
176 }
177}
178
179void
181{
183
184 unsigned int num_apps = _directions.isValueSet("from_multiapp")
185 ? getFromMultiApp()->numGlobalApps()
186 : getToMultiApp()->numGlobalApps();
187 if (_map_comp_to_child && num_apps % _var.count() != 0)
188 paramError("map_array_variable_components_to_child_apps",
189 "The number of sub-applications (",
190 num_apps,
191 ") is not divisible by the number of components in '",
192 _var_name,
193 "' (",
194 _var.count(),
195 ").");
196 _apps_per_component = _map_comp_to_child ? num_apps / _var.count() : num_apps;
197
200}
201
202void
207
208void
210{
211 TIME_SECTION("MultiAppVariableValueSamplePostprocessorTransfer::execute()",
212 5,
213 "Transferring a variable to a postprocessor through sampling");
214
215 switch (_current_direction)
216 {
217 case TO_MULTIAPP:
218 {
219 const ArrayMooseVariable * array_var = nullptr;
220 const MooseVariableField<Real> * standard_var = nullptr;
221 if (_var.isArray())
222 array_var = &_fe_problem.getArrayVariable(0, _var_name);
223 else if (!_var.isVector())
224 standard_var = static_cast<MooseVariableField<Real> *>(&_var);
225 else
226 mooseError("MultiAppVariableValueSamplePostprocessorTransfer does not support transfer of "
227 "vector variables");
228
229 auto active_tags = _fe_problem.getActiveFEVariableCoupleableVectorTags(/*thread_id=*/0);
230 std::set<unsigned int> solution_tag = {_fe_problem.getVectorTagID(Moose::SOLUTION_TAG)};
231
232 _fe_problem.setActiveFEVariableCoupleableVectorTags(solution_tag, /*thread_id=*/0);
233
234 MooseMesh & from_mesh = _fe_problem.mesh();
235
236 std::unique_ptr<PointLocatorBase> pl = from_mesh.getPointLocator();
237
238 pl->enable_out_of_mesh_mode();
239
240 for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
241 {
242 Real value = -std::numeric_limits<Real>::max();
243
244 { // Get the value of the variable at the point where this multiapp is in the master domain
245
246 Point multi_app_position = getToMultiApp()->position(i);
247
248 std::vector<Point> point_vec(1, multi_app_position);
249
250 // First find the element the hit lands in
251 const Elem * elem = (*pl)(multi_app_position);
252
253 if (elem && elem->processor_id() == from_mesh.processor_id())
254 {
256 _fe_problem.reinitElemPhys(elem, point_vec, 0);
257
258 if (array_var)
259 {
260 value = array_var->sln()[0](getVariableComponent(i));
261 mooseAssert(
262 getVariableComponent(i) < array_var->count(),
263 "Component must be smaller than the number of components of array variable!");
264 mooseAssert(array_var->sln().size() == 1, "No values in u!");
265 }
266 else
267 {
268 value = standard_var->sln()[0];
269 mooseAssert(standard_var->sln().size() == 1, "No values in u!");
270 }
271 }
272
273 _communicator.max(value);
274 }
275
276 if (getToMultiApp()->hasLocalApp(i))
277 getToMultiApp()->appProblemBase(i).setPostprocessorValueByName(_postprocessor_name,
278 value);
279 }
280
281 _fe_problem.setActiveFEVariableCoupleableVectorTags(active_tags, /*thread_id=*/0);
282
283 break;
284 }
285 case FROM_MULTIAPP:
286 {
287 auto & mesh = _fe_problem.mesh().getMesh();
288 auto & solution = _var.sys().solution();
289
290 // Get the required postprocessor values
291 const unsigned int n_subapps = getFromMultiApp()->numGlobalApps();
292 std::vector<Real> pp_values(n_subapps, std::numeric_limits<Real>::max());
293 for (const auto i : make_range(n_subapps))
294 if (getFromMultiApp()->hasLocalApp(i))
295 pp_values[i] = getFromMultiApp()->appPostprocessorValue(i, _postprocessor_name);
296
297 // Gather all the multiapps postprocessor values that we need
298 std::unordered_map<processor_id_type, std::vector<unsigned int>> postprocessor_queries;
299 for (const auto needed_postprocessor : _needed_postprocessors)
300 {
301 const auto proc_id = _postprocessor_to_processor_id[needed_postprocessor];
302 if (proc_id != this->processor_id())
303 postprocessor_queries[proc_id].push_back(needed_postprocessor);
304 }
305
306 auto gather_data = [&pp_values
307#ifndef NDEBUG
308 ,
309 this
310#endif
311 ](processor_id_type libmesh_dbg_var(pid),
312 const std::vector<unsigned int> & postprocessor_ids,
313 std::vector<Real> & postprocessor_values)
314 {
315 mooseAssert(pid != this->processor_id(), "Should not be pulling from self");
316 postprocessor_values.resize(postprocessor_ids.size());
317 for (const auto i : index_range(postprocessor_ids))
318 {
319 const auto pp_id = postprocessor_ids[i];
320 const auto pp_value = pp_values[pp_id];
321 mooseAssert(
322 pp_value != std::numeric_limits<Real>::max(),
323 "If we are getting queried for postprocessor data, then we better have a valid"
324 "postprocesor value.");
325 postprocessor_values[i] = pp_value;
326 }
327 };
328
329 auto act_on_data = [&pp_values
330#ifndef NDEBUG
331 ,
332 this
333#endif
334 ](processor_id_type libmesh_dbg_var(pid),
335 const std::vector<unsigned int> & postprocessor_ids,
336 const std::vector<Real> & postprocessor_values)
337 {
338 mooseAssert(pid != this->processor_id(), "Should not be returning a query from self");
339 mooseAssert(postprocessor_ids.size() == postprocessor_values.size(),
340 "should be a 1-to-1 query-to-response");
341 for (const auto i : index_range(postprocessor_ids))
342 {
343 const auto pp_id = postprocessor_ids[i];
344 const auto pp_value = postprocessor_values[i];
345 mooseAssert(pp_value != std::numeric_limits<Real>::max(),
346 "If we are returning postprocessor data, then we better have a valid"
347 "postprocesor value.");
348 pp_values[pp_id] = pp_value;
349 }
350 };
351
352 constexpr Real example = 0;
354 _communicator, postprocessor_queries, gather_data, act_on_data, &example);
355
356 // Assign the multiapps postprocessor values to the local elements.
357 unsigned int i = 0;
358 for (auto & elem :
359 as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
360 {
361 // Exclude the elements without dofs
362 if (_var.hasBlocks(elem->subdomain_id()))
363 {
364 std::vector<dof_id_type> dof_indices;
365 _var.getDofIndices(elem, dof_indices);
366 mooseAssert(dof_indices.size() == _var.count(),
367 "The variable must be a constant monomial with one DoF on an element per "
368 "component.");
369 mooseAssert(pp_values[_cached_multiapp_pos_ids[i]] != std::numeric_limits<Real>::max(),
370 "We should have pulled all the data we needed.");
371 for (unsigned int c = 0; c < n_subapps / _apps_per_component; ++c)
372 {
373 solution.set(dof_indices[getVariableComponent(_cached_multiapp_pos_ids[i])],
374 pp_values[_cached_multiapp_pos_ids[i]]);
375 ++i;
376 }
377 }
378 }
379 solution.close();
380 break;
381 }
382 }
383}
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
unsigned int count
Definition MortarUtils.C:53
registerMooseObject("MooseApp", MultiAppVariableValueSamplePostprocessorTransfer)
void ErrorVector unsigned int
bool hasBlocks(const SubdomainName &name) const
Test if the supplied block name is valid for this object.
virtual void reinitElemPhys(const Elem *elem, const std::vector< Point > &phys_points_in_elem, const THREAD_ID tid) override
virtual ArrayMooseVariable & getArrayVariable(const THREAD_ID tid, const std::string &var_name) override
Returns the variable reference for requested ArrayMooseVariable which may be in any system.
AuxiliarySystem & getAuxiliarySystem()
virtual void setCurrentSubdomainID(const Elem *elem, const THREAD_ID tid) override
virtual MooseMesh & mesh() override
virtual void setActiveFEVariableCoupleableVectorTags(std::set< TagID > &vtags, const THREAD_ID tid) override
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
Interface for notifications that the mesh has changed.
unsigned int size() const
The number of elements that can currently be stored in the array.
Definition MooseArray.h:259
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3549
virtual std::unique_ptr< libMesh::PointLocatorBase > getPointLocator() const
Proxy function to get a (sub)PointLocator from either the underlying libMesh mesh (default),...
Definition MooseMesh.C:3838
const libMesh::FEType & feType() const
Get the type of finite element object.
virtual bool isArray() const
SystemBase & sys()
Get the system this variable is part of.
virtual void getDofIndices(const Elem *, std::vector< dof_id_type > &) const
unsigned int count() const
Get the number of components Note: For standard and vector variables, the number is one.
const FieldVariableValue & sln() const override
element solutions
virtual bool isVector() const =0
Class for stuff related to variables.
virtual const FieldVariableValue & sln() const =0
Base class for all MultiAppTransfer objects.
void initialSetup() override
Method called at the beginning of the simulation for checking integrity or doing one-time setup.
const std::shared_ptr< MultiApp > getToMultiApp() const
Get the MultiApp to transfer data to.
static InputParameters validParams()
const std::shared_ptr< MultiApp > getFromMultiApp() const
Get the MultiApp to transfer data from.
Samples a variable's value in the parent application domain at the point where the MultiApp (for each...
std::vector< processor_id_type > _postprocessor_to_processor_id
Entries in this vector correspond to the processor ID that owns the application/postprocessor corresp...
const bool _map_comp_to_child
Whether or not to map groups of child applications to each component of an array variable.
unsigned int getVariableComponent(unsigned int index) const
Maps the child application index to the parent application variable component.
void setupPostprocessorCommunication()
Sets up the postprocessor to processor ID communication pattern data member _postprocessor_to_process...
virtual void initialSetup() override
Method called at the beginning of the simulation for checking integrity or doing one-time setup.
void meshChanged() override
Called on this object when the mesh changes.
AuxVariableName _var_name
the name of the variable on the main-application
PostprocessorName _postprocessor_name
the name of the postprocessor on the sub-applications
void cacheElemToPostprocessorData()
Method that caches data regarding the element to postprocess relationship.
std::vector< unsigned int > _cached_multiapp_pos_ids
Sub-application ids of all local active elements in the main-application When _map_comp_to_child == t...
unsigned int _apps_per_component
The number of applications associated with a component of the variable when doing array variable samp...
std::unordered_set< unsigned int > _needed_postprocessors
The postprocessors that this process needs for its active local elements.
bool isValueSet(const std::string &value) const
Methods for seeing if a value is set in the MultiMooseEnum.
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
virtual TagID getVectorTagID(const TagName &tag_name) const
Get a TagID from a TagName.
Definition SubProblem.C:204
const std::set< TagID > & getActiveFEVariableCoupleableVectorTags(const THREAD_ID tid) const
Definition SubProblem.C:397
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition SystemBase.C:850
NumericVector< Number > & solution()
Definition SystemBase.h:203
void max(const T &r, T &o, Request &req) const
void min(const T &r, T &o, Request &req) const
@ FROM_MULTIAPP
Definition Transfer.h:71
@ TO_MULTIAPP
Definition Transfer.h:70
MultiMooseEnum _directions
The directions this Transfer is to be executed on.
Definition Transfer.h:110
FEProblemBase & _fe_problem
Definition Transfer.h:97
MooseEnum _current_direction
Definition Transfer.h:106
processor_id_type processor_id() const
const Parallel::Communicator & _communicator
processor_id_type processor_id() const
MeshBase & mesh
const TagName SOLUTION_TAG
Definition MooseTypes.C:25
void pull_parallel_vector_data(const Communicator &comm, const MapToVectors &queries, GatherFunctor &gather_data, const ActionFunctor &act_on_data, const datum *example)
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
auto index_range(const T &sizable)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
IntRange< T > make_range(T beg, T end)
Real distance(const Point &p)