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
28
31{
34 "Samples the value of a variable within the main application at each sub-application "
35 "position and transfers the value to a postprocessor on the sub-application(s) when "
36 "performing the to-multiapp transfer. Reconstructs the value of a CONSTANT MONOMIAL "
37 "variable associating the value of each element to the value of the postprocessor "
38 "in the closest sub-application whem performing the from-multiapp transfer.");
39 params.addRequiredParam<PostprocessorName>(
40 "postprocessor",
41 "The name of the postprocessor in the MultiApp to transfer the value to. "
42 "This should most likely be a Reciever Postprocessor.");
43 params.addRequiredParam<VariableName>("source_variable", "The variable to transfer from.");
44 params.addParam<unsigned int>(
45 "source_variable_component",
46 0,
47 "The component of source variable, may be non-zero for array variables.");
48 params.addParam<bool>(
49 "map_array_variable_components_to_child_apps",
50 false,
51 "When true, groups of sub-applications will be associated with different components of the "
52 "supplied array variable in 'source_variable'. For instance, if there are 9 sub-applications "
53 "and 3 components in the variable, sub-apps 0-2 will go to component 0, 3-5 will go to 1, "
54 "and 6-8 will go to 2.");
55
56 // Sibling transfers not supported
57 params.suppressParameter<bool>("execute_after_from_multiapp");
58
59 return params;
60}
61
63 const InputParameters & parameters)
64 : MultiAppTransfer(parameters),
65 MeshChangedInterface(parameters),
66 _postprocessor_name(getParam<PostprocessorName>("postprocessor")),
67 _var_name(getParam<VariableName>("source_variable")),
68 _comp(getParam<unsigned int>("source_variable_component")),
69 _var(_fe_problem.getVariable(0, _var_name)),
70 _map_comp_to_child(getParam<bool>("map_array_variable_components_to_child_apps"))
71{
72 if (_directions.size() != 1)
73 paramError("direction", "This transfer is only unidirectional");
74
75 if (_directions.isValueSet("from_multiapp"))
76 {
77 // Check that the variable is a CONSTANT MONOMIAL.
78 auto & fe_type = _var.feType();
79 if (fe_type.order != CONSTANT || fe_type.family != MONOMIAL)
80 paramError("source_variable",
81 "Variable must be in CONSTANT MONOMIAL when transferring from a postprocessor "
82 "from sub-apps.");
83
85 paramError("source_variable", "Variable must be an auxiliary variable");
86 }
87 else if (_directions.isValueSet("between_multiapp"))
88 mooseError("MultiAppVariableValueSamplePostprocessorTransfer has not been made to support "
89 "sibling transfers");
90
92 paramError("map_array_variable_components_to_child_apps",
93 "'source_variable' must be an array variable when mapping array variable components "
94 "to child applications.");
95 if (_map_comp_to_child && parameters.isParamSetByUser("source_variable_component"))
96 paramError("map_array_variable_components_to_child_apps",
97 "'source_variable_component' is invalid when mapping array variable components to "
98 "child applications.");
99}
100
101void
103{
104 if (!_directions.isValueSet("from_multiapp"))
105 return;
106
107 const auto num_global_apps = getFromMultiApp()->numGlobalApps();
108
109 // Setup the communication pattern
110 _postprocessor_to_processor_id.resize(num_global_apps,
111 std::numeric_limits<processor_id_type>::max());
112 for (const auto i : make_range(num_global_apps))
113 if (getFromMultiApp()->hasLocalApp(i))
115
117#ifdef DEBUG
118 for (const auto i : make_range(num_global_apps))
119 {
120 mooseAssert(_postprocessor_to_processor_id[i] != std::numeric_limits<processor_id_type>::max(),
121 "Every element in the vector should have been set.");
122 if (getFromMultiApp()->hasLocalApp(i))
123 mooseAssert(_postprocessor_to_processor_id[i] == this->processor_id(),
124 "If I owned this app, then the processor id value should be my own");
125 }
126#endif
127}
128
129void
131{
132 if (!_directions.isValueSet("from_multiapp"))
133 return;
134
135 // Cache the Multiapp position ID for every element.
136 auto & mesh = _fe_problem.mesh().getMesh();
137 unsigned int multiapp_pos_id = 0;
138 for (auto & elem : as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
139 // Exclude the elements without dofs.
140 if (_var.hasBlocks(elem->subdomain_id()))
141 {
142 // The next two loops will loop through all the sub-applications
143 // The first loop is over each component of the source variable we are transferring to/from
144 unsigned int j = 0; // Indicates sub-app index
145 for (unsigned int g = 0; g < getFromMultiApp()->numGlobalApps() / _apps_per_component; ++g)
146 {
147 Real distance = std::numeric_limits<Real>::max();
148 unsigned int count = 0;
149 // The second loop is over all the sub-apps the given component is associated with
150 for (unsigned int c = 0; c < _apps_per_component; ++c, ++j)
151 {
152 Real current_distance = (getFromMultiApp()->position(j) - elem->true_centroid()).norm();
153 if (MooseUtils::absoluteFuzzyLessThan(current_distance, distance))
154 {
155 distance = current_distance;
156 multiapp_pos_id = j;
157 count = 0;
158 }
159 else if (MooseUtils::absoluteFuzzyEqual(current_distance, distance))
160 ++count;
161 }
162 if (count > 0)
164 "The distances of an element to more than one sub-applications are too close "
165 " in transfer '",
166 name(),
167 "'. The code chooses the sub-application with the smallest ID to set "
168 "the variable on the element, which may created undesired variable solutions."
169 "\nHaving different positions for sub-applications, "
170 "a centroid-based MultiApp or adding block restriction to the variable can "
171 "be used to resolve this warning.");
172
173 // Note: in case of count>0, the sub-application with smallest id will be used for the
174 // transfer.
175 _cached_multiapp_pos_ids.push_back(multiapp_pos_id);
176 _needed_postprocessors.insert(multiapp_pos_id);
177 }
178 }
179}
180
181void
183{
185
186 unsigned int num_apps = _directions.isValueSet("from_multiapp")
187 ? getFromMultiApp()->numGlobalApps()
188 : getToMultiApp()->numGlobalApps();
189 if (_map_comp_to_child && num_apps % _var.count() != 0)
190 paramError("map_array_variable_components_to_child_apps",
191 "The number of sub-applications (",
192 num_apps,
193 ") is not divisible by the number of components in '",
194 _var_name,
195 "' (",
196 _var.count(),
197 ").");
198 _apps_per_component = _map_comp_to_child ? num_apps / _var.count() : num_apps;
199
202}
203
204void
209
210void
212{
213 TIME_SECTION("MultiAppVariableValueSamplePostprocessorTransfer::execute()",
214 5,
215 "Transferring a variable to a postprocessor through sampling");
216
217 switch (_current_direction)
218 {
219 case TO_MULTIAPP:
220 {
221 const ArrayMooseVariable * array_var = nullptr;
222 const MooseVariableField<Real> * standard_var = nullptr;
223 if (_var.isArray())
224 array_var = &_fe_problem.getArrayVariable(0, _var_name);
225 else if (!_var.isVector())
226 standard_var = cast_ptr<MooseVariableField<Real> *>(&_var);
227 else
228 mooseError("MultiAppVariableValueSamplePostprocessorTransfer does not support transfer of "
229 "vector variables");
230
231 auto active_tags = _fe_problem.getActiveFEVariableCoupleableVectorTags(/*thread_id=*/0);
232 std::set<unsigned int> solution_tag = {_fe_problem.getVectorTagID(Moose::SOLUTION_TAG)};
233
234 _fe_problem.setActiveFEVariableCoupleableVectorTags(solution_tag, /*thread_id=*/0);
235
236 MooseMesh & from_mesh = _fe_problem.mesh();
237
238 std::unique_ptr<PointLocatorBase> pl = from_mesh.getPointLocator();
239
240 pl->enable_out_of_mesh_mode();
241
242 for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
243 {
244 Real value = -std::numeric_limits<Real>::max();
245
246 { // Get the value of the variable at the point where this multiapp is in the master domain
247
248 Point multi_app_position = getToMultiApp()->position(i);
249
250 std::vector<Point> point_vec(1, multi_app_position);
251
252 // First find the element the hit lands in
253 const Elem * elem = (*pl)(multi_app_position);
254
255 if (elem && elem->processor_id() == from_mesh.processor_id())
256 {
258 _fe_problem.reinitElemPhys(elem, point_vec, 0);
259
260 if (array_var)
261 {
262 value = array_var->sln()[0](getVariableComponent(i));
263 mooseAssert(
264 getVariableComponent(i) < array_var->count(),
265 "Component must be smaller than the number of components of array variable!");
266 mooseAssert(array_var->sln().size() == 1, "No values in u!");
267 }
268 else
269 {
270 value = standard_var->sln()[0];
271 mooseAssert(standard_var->sln().size() == 1, "No values in u!");
272 }
273 }
274
275 _communicator.max(value);
276 }
277
278 if (getToMultiApp()->hasLocalApp(i))
279 getToMultiApp()->appProblemBase(i).setPostprocessorValueByName(_postprocessor_name,
280 value);
281 }
282
283 _fe_problem.setActiveFEVariableCoupleableVectorTags(active_tags, /*thread_id=*/0);
284
285 break;
286 }
287 case FROM_MULTIAPP:
288 {
289 auto & mesh = _fe_problem.mesh().getMesh();
290 auto & solution = _var.sys().solution();
291
292 // Get the required postprocessor values
293 const unsigned int n_subapps = getFromMultiApp()->numGlobalApps();
294 std::vector<Real> pp_values(n_subapps, std::numeric_limits<Real>::max());
295 for (const auto i : make_range(n_subapps))
296 if (getFromMultiApp()->hasLocalApp(i))
297 pp_values[i] = getFromMultiApp()->appPostprocessorValue(i, _postprocessor_name);
298
299 // Gather all the multiapps postprocessor values that we need
300 std::unordered_map<processor_id_type, std::vector<unsigned int>> postprocessor_queries;
301 for (const auto needed_postprocessor : _needed_postprocessors)
302 {
303 const auto proc_id = _postprocessor_to_processor_id[needed_postprocessor];
304 if (proc_id != this->processor_id())
305 postprocessor_queries[proc_id].push_back(needed_postprocessor);
306 }
307
308 auto gather_data = [&pp_values
309#ifndef NDEBUG
310 ,
311 this
312#endif
313 ](processor_id_type libmesh_dbg_var(pid),
314 const std::vector<unsigned int> & postprocessor_ids,
315 std::vector<Real> & postprocessor_values)
316 {
317 mooseAssert(pid != this->processor_id(), "Should not be pulling from self");
318 postprocessor_values.resize(postprocessor_ids.size());
319 for (const auto i : index_range(postprocessor_ids))
320 {
321 const auto pp_id = postprocessor_ids[i];
322 const auto pp_value = pp_values[pp_id];
323 mooseAssert(
324 pp_value != std::numeric_limits<Real>::max(),
325 "If we are getting queried for postprocessor data, then we better have a valid"
326 "postprocesor value.");
327 postprocessor_values[i] = pp_value;
328 }
329 };
330
331 auto act_on_data = [&pp_values
332#ifndef NDEBUG
333 ,
334 this
335#endif
336 ](processor_id_type libmesh_dbg_var(pid),
337 const std::vector<unsigned int> & postprocessor_ids,
338 const std::vector<Real> & postprocessor_values)
339 {
340 mooseAssert(pid != this->processor_id(), "Should not be returning a query from self");
341 mooseAssert(postprocessor_ids.size() == postprocessor_values.size(),
342 "should be a 1-to-1 query-to-response");
343 for (const auto i : index_range(postprocessor_ids))
344 {
345 const auto pp_id = postprocessor_ids[i];
346 const auto pp_value = postprocessor_values[i];
347 mooseAssert(pp_value != std::numeric_limits<Real>::max(),
348 "If we are returning postprocessor data, then we better have a valid"
349 "postprocesor value.");
350 pp_values[pp_id] = pp_value;
351 }
352 };
353
354 constexpr Real example = 0;
356 _communicator, postprocessor_queries, gather_data, act_on_data, &example);
357
358 // Assign the multiapps postprocessor values to the local elements.
359 unsigned int i = 0;
360 for (auto & elem :
361 as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
362 {
363 // Exclude the elements without dofs
364 if (_var.hasBlocks(elem->subdomain_id()))
365 {
366 std::vector<dof_id_type> dof_indices;
367 _var.getDofIndices(elem, dof_indices);
368 mooseAssert(dof_indices.size() == _var.count(),
369 "The variable must be a constant monomial with one DoF on an element per "
370 "component.");
371 mooseAssert(pp_values[_cached_multiapp_pos_ids[i]] != std::numeric_limits<Real>::max(),
372 "We should have pulled all the data we needed.");
373 for (unsigned int c = 0; c < n_subapps / _apps_per_component; ++c)
374 {
375 solution.set(dof_indices[getVariableComponent(_cached_multiapp_pos_ids[i])],
376 pp_values[_cached_multiapp_pos_ids[i]]);
377 ++i;
378 }
379 }
380 }
381 solution.close();
382 break;
383 }
384 }
385}
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.
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn't required or valid in the derived class...
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:3557
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:3846
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:202
const std::set< TagID > & getActiveFEVariableCoupleableVectorTags(const THREAD_ID tid) const
Definition SubProblem.C:395
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:113
FEProblemBase & _fe_problem
Definition Transfer.h:100
MooseEnum _current_direction
Definition Transfer.h:109
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)
Real distance(const Point &p)