https://mooseframework.inl.gov
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"
20 #include "MooseAppCoordTransform.h"
21 
22 #include "libmesh/meshfree_interpolation.h"
23 #include "libmesh/system.h"
24 
25 #include "timpi/parallel_sync.h"
26 
27 using namespace libMesh;
28 
30 
33 {
35  params.addClassDescription(
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 
99 void
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,
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  {
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 
127 void
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  {
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)
161  mooseWarning(
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 
179 void
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 
202 void
204 {
206 }
207 
208 void
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  {
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 
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() == 1,
367  "The variable must be a constant monomial with one DoF on an element");
368  mooseAssert(pp_values[_cached_multiapp_pos_ids[i]] != std::numeric_limits<Real>::max(),
369  "We should have pulled all the data we needed.");
370  for (unsigned int c = 0; c < n_subapps / _apps_per_component; ++c)
371  {
372  solution.set(dof_indices[0] + getVariableComponent(_cached_multiapp_pos_ids[i]),
373  pp_values[_cached_multiapp_pos_ids[i]]);
374  ++i;
375  }
376  }
377  }
378  solution.close();
379  break;
380  }
381  }
382 }
virtual TagID getVectorTagID(const TagName &tag_name) const
Get a TagID from a TagName.
Definition: SubProblem.C:203
void pull_parallel_vector_data(const Communicator &comm, const MapToVectors &queries, GatherFunctor &gather_data, const ActionFunctor &act_on_data, const datum *example)
const libMesh::FEType & feType() const
Get the type of finite element object.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
Definition: MooseUtils.h:380
const std::shared_ptr< MultiApp > getFromMultiApp() const
Get the MultiApp to transfer data from.
void meshChanged() override
Called on this object when the mesh changes.
NumericVector< Number > & solution()
Definition: SystemBase.h:195
MooseEnum _current_direction
Definition: Transfer.h:106
registerMooseObject("MooseApp", MultiAppVariableValueSamplePostprocessorTransfer)
const std::set< TagID > & getActiveFEVariableCoupleableVectorTags(const THREAD_ID tid) const
Definition: SubProblem.C:396
unsigned int count() const
Get the number of components Note: For standard and vector variables, the number is one...
MeshBase & mesh
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
virtual void getDofIndices(const Elem *, std::vector< dof_id_type > &) const
FEProblemBase & _fe_problem
Definition: Transfer.h:97
const std::shared_ptr< MultiApp > getToMultiApp() const
Get the MultiApp to transfer data to.
const Parallel::Communicator & _communicator
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
virtual void initialSetup() override
Method called at the beginning of the simulation for checking integrity or doing one-time setup...
Real distance(const Point &p)
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:57
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
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...
auto max(const L &left, const R &right)
std::vector< processor_id_type > _postprocessor_to_processor_id
Entries in this vector correspond to the processor ID that owns the application/postprocessor corresp...
Samples a variable&#39;s value in the parent application domain at the point where the MultiApp (for each...
const bool _map_comp_to_child
Whether or not to map groups of child applications to each component of an array variable.
uint8_t processor_id_type
virtual bool isVector() const =0
CONSTANT
unsigned int size() const
The number of elements that can currently be stored in the array.
Definition: MooseArray.h:259
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...
Interface for notifications that the mesh has changed.
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3443
void min(const T &r, T &o, Request &req) const
void initialSetup() override
Method called at the beginning of the simulation for checking integrity or doing one-time setup...
const FieldVariableValue & sln() const override
element solutions
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
std::unordered_set< unsigned int > _needed_postprocessors
The postprocessors that this process needs for its active local elements.
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
virtual bool isArray() const
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is less than another variable within an absolute tolerance...
Definition: MooseUtils.h:475
PostprocessorName _postprocessor_name
the name of the postprocessor on the sub-applications
AuxVariableName _var_name
the name of the variable on the main-application
void setupPostprocessorCommunication()
Sets up the postprocessor to processor ID communication pattern data member _postprocessor_to_process...
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 ...
bool isValueSet(const std::string &value) const
Methods for seeing if a value is set in the MultiMooseEnum.
auto norm(const T &a) -> decltype(std::abs(a))
unsigned int getVariableComponent(unsigned int index) const
Maps the child application index to the parent application variable component.
AuxiliarySystem & getAuxiliarySystem()
static InputParameters validParams()
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition: SystemBase.C:834
virtual void setCurrentSubdomainID(const Elem *elem, const THREAD_ID tid) override
MONOMIAL
void cacheElemToPostprocessorData()
Method that caches data regarding the element to postprocess relationship.
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const FieldVariableValue & sln() const =0
MultiMooseEnum _directions
The directions this Transfer is to be executed on.
Definition: Transfer.h:110
void max(const T &r, T &o, Request &req) const
Base class for all MultiAppTransfer objects.
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
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...
const InputParameters & parameters() const
Get the parameters of the object.
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...
const TagName SOLUTION_TAG
Definition: MooseTypes.C:25
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:3728
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...
bool hasBlocks(const SubdomainName &name) const
Test if the supplied block name is valid for this object.
virtual void setActiveFEVariableCoupleableVectorTags(std::set< TagID > &vtags, const THREAD_ID tid) override
processor_id_type processor_id() const
unsigned int _apps_per_component
The number of applications associated with a component of the variable when doing array variable samp...
SystemBase & sys()
Get the system this variable is part of.
processor_id_type processor_id() const
virtual void reinitElemPhys(const Elem *elem, const std::vector< Point > &phys_points_in_elem, const THREAD_ID tid) override
void ErrorVector unsigned int
auto index_range(const T &sizable)