www.mooseframework.org
MultiAppVariableValueSamplePostprocessorTransfer.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
28 
31 {
33  params.addClassDescription(
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  return params;
56 }
57 
59  const InputParameters & parameters)
60  : MultiAppTransfer(parameters),
61  MeshChangedInterface(parameters),
62  _postprocessor_name(getParam<PostprocessorName>("postprocessor")),
63  _var_name(getParam<VariableName>("source_variable")),
64  _comp(getParam<unsigned int>("source_variable_component")),
65  _var(_fe_problem.getVariable(0, _var_name)),
66  _map_comp_to_child(getParam<bool>("map_array_variable_components_to_child_apps"))
67 {
68  if (_directions.size() != 1)
69  paramError("direction", "This transfer is only unidirectional");
70 
71  if (_directions.contains("from_multiapp"))
72  {
73  // Check that the variable is a CONSTANT MONOMIAL.
74  auto & fe_type = _var.feType();
75  if (fe_type.order != CONSTANT || fe_type.family != MONOMIAL)
76  paramError("source_variable",
77  "Variable must be in CONSTANT MONOMIAL when transferring from a postprocessor "
78  "from sub-apps.");
79 
81  paramError("source_variable", "Variable must be an auxiliary variable");
82  }
83  else if (_directions.contains("between_multiapp"))
84  mooseError("MultiAppVariableValueSamplePostprocessorTransfer has not been made to support "
85  "sibling transfers");
86 
88  paramError("map_array_variable_components_to_child_apps",
89  "'source_variable' must be an array variable when mapping array variable components "
90  "to child applications.");
91  if (_map_comp_to_child && parameters.isParamSetByUser("source_variable_component"))
92  paramError("map_array_variable_components_to_child_apps",
93  "'source_variable_component' is invalid when mapping array variable components to "
94  "child applications.");
95 }
96 
97 void
99 {
100  if (!_directions.contains("from_multiapp"))
101  return;
102 
103  const auto num_global_apps = getFromMultiApp()->numGlobalApps();
104 
105  // Setup the communication pattern
106  _postprocessor_to_processor_id.resize(num_global_apps,
108  for (const auto i : make_range(num_global_apps))
109  if (getFromMultiApp()->hasLocalApp(i))
111 
113 #ifdef DEBUG
114  for (const auto i : make_range(num_global_apps))
115  {
117  "Every element in the vector should have been set.");
118  if (getFromMultiApp()->hasLocalApp(i))
119  mooseAssert(_postprocessor_to_processor_id[i] == this->processor_id(),
120  "If I owned this app, then the processor id value should be my own");
121  }
122 #endif
123 }
124 
125 void
127 {
128  if (!_directions.contains("from_multiapp"))
129  return;
130 
131  // Cache the Multiapp position ID for every element.
132  auto & mesh = _fe_problem.mesh().getMesh();
133  unsigned int multiapp_pos_id = 0;
134  for (auto & elem : as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
135  // Exclude the elements without dofs.
136  if (_var.hasBlocks(elem->subdomain_id()))
137  {
138  // The next two loops will loop through all the sub-applications
139  // The first loop is over each component of the source variable we are transferring to/from
140  unsigned int j = 0; // Indicates sub-app index
141  for (unsigned int g = 0; g < getFromMultiApp()->numGlobalApps() / _apps_per_component; ++g)
142  {
144  unsigned int count = 0;
145  // The second loop is over all the sub-apps the given component is associated with
146  for (unsigned int c = 0; c < _apps_per_component; ++c, ++j)
147  {
148  Real current_distance = (getFromMultiApp()->position(j) - elem->true_centroid()).norm();
149  if (MooseUtils::absoluteFuzzyLessThan(current_distance, distance))
150  {
151  distance = current_distance;
152  multiapp_pos_id = j;
153  count = 0;
154  }
155  else if (MooseUtils::absoluteFuzzyEqual(current_distance, distance))
156  ++count;
157  }
158  if (count > 0)
159  mooseWarning(
160  "The distances of an element to more than one sub-applications are too close "
161  " in transfer '",
162  name(),
163  "'. The code chooses the sub-application with the smallest ID to set "
164  "the variable on the element, which may created undesired variable solutions."
165  "\nHaving different positions for sub-applications, "
166  "a centroid-based MultiApp or adding block restriction to the variable can "
167  "be used to resolve this warning.");
168 
169  // Note: in case of count>0, the sub-application with smallest id will be used for the
170  // transfer.
171  _cached_multiapp_pos_ids.push_back(multiapp_pos_id);
172  _needed_postprocessors.insert(multiapp_pos_id);
173  }
174  }
175 }
176 
177 void
179 {
181 
182  unsigned int num_apps = _directions.contains("from_multiapp") ? getFromMultiApp()->numGlobalApps()
183  : getToMultiApp()->numGlobalApps();
184  if (_map_comp_to_child && num_apps % _var.count() != 0)
185  paramError("map_array_variable_components_to_child_apps",
186  "The number of sub-applications (",
187  num_apps,
188  ") is not divisible by the number of components in '",
189  _var_name,
190  "' (",
191  _var.count(),
192  ").");
193  _apps_per_component = _map_comp_to_child ? num_apps / _var.count() : num_apps;
194 
197 }
198 
199 void
201 {
203 }
204 
205 void
207 {
208  TIME_SECTION("MultiAppVariableValueSamplePostprocessorTransfer::execute()",
209  5,
210  "Transferring a variable to a postprocessor through sampling");
211 
212  switch (_current_direction)
213  {
214  case TO_MULTIAPP:
215  {
216  const ArrayMooseVariable * array_var = nullptr;
217  const MooseVariableField<Real> * standard_var = nullptr;
218  if (_var.isArray())
219  array_var = &_fe_problem.getArrayVariable(0, _var_name);
220  else if (!_var.isVector())
221  standard_var = static_cast<MooseVariableField<Real> *>(&_var);
222  else
223  mooseError("MultiAppVariableValueSamplePostprocessorTransfer does not support transfer of "
224  "vector variables");
225 
226  auto active_tags = _fe_problem.getActiveFEVariableCoupleableVectorTags(/*thread_id=*/0);
227  std::set<unsigned int> solution_tag = {_fe_problem.getVectorTagID(Moose::SOLUTION_TAG)};
228 
229  _fe_problem.setActiveFEVariableCoupleableVectorTags(solution_tag, /*thread_id=*/0);
230 
231  MooseMesh & from_mesh = _fe_problem.mesh();
232 
233  std::unique_ptr<PointLocatorBase> pl = from_mesh.getPointLocator();
234 
235  pl->enable_out_of_mesh_mode();
236 
237  for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
238  {
240 
241  { // Get the value of the variable at the point where this multiapp is in the master domain
242 
243  Point multi_app_position = getToMultiApp()->position(i);
244 
245  std::vector<Point> point_vec(1, multi_app_position);
246 
247  // First find the element the hit lands in
248  const Elem * elem = (*pl)(multi_app_position);
249 
250  if (elem && elem->processor_id() == from_mesh.processor_id())
251  {
253  _fe_problem.reinitElemPhys(elem, point_vec, 0);
254 
255  if (array_var)
256  {
257  value = array_var->sln()[0](getVariableComponent(i));
258  mooseAssert(
259  getVariableComponent(i) < array_var->count(),
260  "Component must be smaller than the number of components of array variable!");
261  mooseAssert(array_var->sln().size() == 1, "No values in u!");
262  }
263  else
264  {
265  value = standard_var->sln()[0];
266  mooseAssert(standard_var->sln().size() == 1, "No values in u!");
267  }
268  }
269 
271  }
272 
273  if (getToMultiApp()->hasLocalApp(i))
274  getToMultiApp()->appProblemBase(i).setPostprocessorValueByName(_postprocessor_name,
275  value);
276  }
277 
278  _fe_problem.setActiveFEVariableCoupleableVectorTags(active_tags, /*thread_id=*/0);
279 
280  break;
281  }
282  case FROM_MULTIAPP:
283  {
284  auto & mesh = _fe_problem.mesh().getMesh();
285  auto & solution = _var.sys().solution();
286 
287  // Get the required postprocessor values
288  const unsigned int n_subapps = getFromMultiApp()->numGlobalApps();
289  std::vector<Real> pp_values(n_subapps, std::numeric_limits<Real>::max());
290  for (const auto i : make_range(n_subapps))
291  if (getFromMultiApp()->hasLocalApp(i))
292  pp_values[i] = getFromMultiApp()->appPostprocessorValue(i, _postprocessor_name);
293 
294  // Gather all the multiapps postprocessor values that we need
295  std::unordered_map<processor_id_type, std::vector<unsigned int>> postprocessor_queries;
296  for (const auto needed_postprocessor : _needed_postprocessors)
297  {
298  const auto proc_id = _postprocessor_to_processor_id[needed_postprocessor];
299  if (proc_id != this->processor_id())
300  postprocessor_queries[proc_id].push_back(needed_postprocessor);
301  }
302 
303  auto gather_data = [&pp_values
304 #ifndef NDEBUG
305  ,
306  this
307 #endif
308  ](processor_id_type libmesh_dbg_var(pid),
309  const std::vector<unsigned int> & postprocessor_ids,
310  std::vector<Real> & postprocessor_values)
311  {
312  mooseAssert(pid != this->processor_id(), "Should not be pulling from self");
313  postprocessor_values.resize(postprocessor_ids.size());
314  for (const auto i : index_range(postprocessor_ids))
315  {
316  const auto pp_id = postprocessor_ids[i];
317  const auto pp_value = pp_values[pp_id];
318  mooseAssert(
319  pp_value != std::numeric_limits<Real>::max(),
320  "If we are getting queried for postprocessor data, then we better have a valid"
321  "postprocesor value.");
322  postprocessor_values[i] = pp_value;
323  }
324  };
325 
326  auto act_on_data = [&pp_values
327 #ifndef NDEBUG
328  ,
329  this
330 #endif
331  ](processor_id_type libmesh_dbg_var(pid),
332  const std::vector<unsigned int> & postprocessor_ids,
333  const std::vector<Real> & postprocessor_values)
334  {
335  mooseAssert(pid != this->processor_id(), "Should not be returning a query from self");
336  mooseAssert(postprocessor_ids.size() == postprocessor_values.size(),
337  "should be a 1-to-1 query-to-response");
338  for (const auto i : index_range(postprocessor_ids))
339  {
340  const auto pp_id = postprocessor_ids[i];
341  const auto pp_value = postprocessor_values[i];
342  mooseAssert(pp_value != std::numeric_limits<Real>::max(),
343  "If we are returning postprocessor data, then we better have a valid"
344  "postprocesor value.");
345  pp_values[pp_id] = pp_value;
346  }
347  };
348 
349  constexpr Real example = 0;
351  _communicator, postprocessor_queries, gather_data, act_on_data, &example);
352 
353  // Assign the multiapps postprocessor values to the local elements.
354  unsigned int i = 0;
355  for (auto & elem :
356  as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
357  {
358  // Exclude the elements without dofs
359  if (_var.hasBlocks(elem->subdomain_id()))
360  {
361  std::vector<dof_id_type> dof_indices;
362  _var.getDofIndices(elem, dof_indices);
363  mooseAssert(dof_indices.size() == 1,
364  "The variable must be a constant monomial with one DoF on an element");
365  mooseAssert(pp_values[_cached_multiapp_pos_ids[i]] != std::numeric_limits<Real>::max(),
366  "We should have pulled all the data we needed.");
367  for (unsigned int c = 0; c < n_subapps / _apps_per_component; ++c)
368  {
369  solution.set(dof_indices[0] + getVariableComponent(_cached_multiapp_pos_ids[i]),
370  pp_values[_cached_multiapp_pos_ids[i]]);
371  ++i;
372  }
373  }
374  }
375  solution.close();
376  break;
377  }
378  }
379 }
virtual TagID getVectorTagID(const TagName &tag_name) const
Get a TagID from a TagName.
Definition: SubProblem.C:180
void pull_parallel_vector_data(const Communicator &comm, const MapToVectors &queries, GatherFunctor &gather_data, const ActionFunctor &act_on_data, const datum *example)
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:346
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:176
MooseEnum _current_direction
Definition: Transfer.h:106
registerMooseObject("MooseApp", MultiAppVariableValueSamplePostprocessorTransfer)
const std::set< TagID > & getActiveFEVariableCoupleableVectorTags(const THREAD_ID tid) const
Definition: SubProblem.C:362
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
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:56
const FEType & feType() const
Get the type of finite element object.
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...
virtual bool isArray() const =0
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
bool contains(const std::string &value) const
Contains methods for seeing if a value is in the MultiMooseEnum.
CONSTANT
unsigned int size() const
The number of elements that can currently be stored in the array.
Definition: MooseArray.h:256
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:3198
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
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:437
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 ...
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:800
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 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 option parameter and a documentation string to the InputParameters object...
const TagName SOLUTION_TAG
Definition: MooseTypes.C:27
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.
virtual std::unique_ptr< PointLocatorBase > getPointLocator() const
Proxy function to get a (sub)PointLocator from either the underlying libMesh mesh (default)...
Definition: MooseMesh.C:3479
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)