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 "MultiAppPostprocessorInterpolationTransfer.h"
11 :
12 : // MOOSE includes
13 : #include "FEProblem.h"
14 : #include "MooseMesh.h"
15 : #include "MooseTypes.h"
16 : #include "MultiApp.h"
17 : #include "MooseAppCoordTransform.h"
18 :
19 : #include "libmesh/meshfree_interpolation.h"
20 : #include "libmesh/numeric_vector.h"
21 : #include "libmesh/system.h"
22 : #include "libmesh/radial_basis_interpolation.h"
23 :
24 : using namespace libMesh;
25 :
26 : registerMooseObject("MooseApp", MultiAppPostprocessorInterpolationTransfer);
27 :
28 : InputParameters
29 14541 : MultiAppPostprocessorInterpolationTransfer::validParams()
30 : {
31 14541 : InputParameters params = MultiAppTransfer::validParams();
32 14541 : params.addClassDescription("Transfer postprocessor data from sub-application into field data on "
33 : "the parent application.");
34 14541 : params.addRequiredParam<AuxVariableName>(
35 : "variable", "The auxiliary variable to store the transferred values in.");
36 14541 : params.addRequiredParam<PostprocessorName>("postprocessor", "The Postprocessor to interpolate.");
37 43623 : params.addParam<unsigned int>(
38 29082 : "num_points", 3, "The number of nearest points to use for interpolation.");
39 43623 : params.addParam<Real>(
40 29082 : "power", 2, "The polynomial power to use for calculation of the decay in the interpolation.");
41 :
42 14541 : MooseEnum interp_type("inverse_distance radial_basis", "inverse_distance");
43 :
44 14541 : params.addParam<MooseEnum>("interp_type", interp_type, "The algorithm to use for interpolation.");
45 :
46 43623 : params.addParam<Real>("radius",
47 29082 : -1,
48 : "Radius to use for radial_basis interpolation. If negative "
49 : "then the radius is taken as the max distance between "
50 : "points.");
51 29082 : return params;
52 14541 : }
53 :
54 144 : MultiAppPostprocessorInterpolationTransfer::MultiAppPostprocessorInterpolationTransfer(
55 144 : const InputParameters & parameters)
56 : : MultiAppTransfer(parameters),
57 144 : _postprocessor(getParam<PostprocessorName>("postprocessor")),
58 144 : _to_var_name(getParam<AuxVariableName>("variable")),
59 144 : _num_points(getParam<unsigned int>("num_points")),
60 144 : _power(getParam<Real>("power")),
61 144 : _interp_type(getParam<MooseEnum>("interp_type")),
62 144 : _radius(getParam<Real>("radius")),
63 144 : _nodal(false)
64 : {
65 144 : if (isParamValid("to_multi_app"))
66 4 : paramError("to_multi_app", "Unused parameter; only from-MultiApp transfers are implemented");
67 :
68 : auto & to_fe_type =
69 140 : getFromMultiApp()->problemBase().getStandardVariable(0, _to_var_name).feType();
70 348 : if ((to_fe_type.order != CONSTANT || to_fe_type.family != MONOMIAL) &&
71 212 : (to_fe_type.order != FIRST || to_fe_type.family != LAGRANGE))
72 4 : paramError("variable", "Must be either CONSTANT MONOMIAL or FIRST LAGRANGE");
73 :
74 132 : _nodal = to_fe_type.family == LAGRANGE;
75 132 : }
76 :
77 : void
78 578 : MultiAppPostprocessorInterpolationTransfer::execute()
79 : {
80 578 : TIME_SECTION("MultiAppPostprocessorInterpolationTransfer::execute()",
81 : 5,
82 : "Transferring/interpolating postprocessors");
83 :
84 578 : switch (_current_direction)
85 : {
86 0 : case TO_MULTIAPP:
87 : {
88 0 : mooseError("Interpolation from a variable to a MultiApp postprocessors has not been "
89 : "implemented. Use MultiAppVariableValueSamplePostprocessorTransfer!");
90 : break;
91 : }
92 578 : case FROM_MULTIAPP:
93 : {
94 578 : errorIfObjectExecutesOnTransferInSourceApp(_postprocessor);
95 578 : std::unique_ptr<InverseDistanceInterpolation<LIBMESH_DIM>> idi;
96 :
97 578 : switch (_interp_type)
98 : {
99 565 : case 0:
100 565 : idi = std::make_unique<InverseDistanceInterpolation<LIBMESH_DIM>>(
101 565 : _communicator, _num_points, _power);
102 565 : break;
103 13 : case 1:
104 13 : idi = std::make_unique<RadialBasisInterpolation<LIBMESH_DIM>>(_communicator, _radius);
105 13 : break;
106 0 : default:
107 0 : mooseError("Unknown interpolation type!");
108 : }
109 :
110 578 : std::vector<Point> & src_pts(idi->get_source_points());
111 578 : std::vector<Number> & src_vals(idi->get_source_vals());
112 :
113 1156 : std::vector<std::string> field_vars;
114 578 : field_vars.push_back(_to_var_name);
115 578 : idi->set_field_variables(field_vars);
116 :
117 : {
118 : mooseAssert(_to_transforms.size() == 1, "There should only be one transform here");
119 578 : const auto & to_coord_transform = *_to_transforms[0];
120 3226 : for (unsigned int i = 0; i < getFromMultiApp()->numGlobalApps(); i++)
121 : {
122 2648 : if (getFromMultiApp()->hasLocalApp(i) && getFromMultiApp()->isRootProcessor())
123 : {
124 : // Evaluation of the _from_transform at the origin yields the transformed position of
125 : // the from multi-app
126 2000 : if (!getFromMultiApp()->runningInPosition())
127 1568 : src_pts.push_back(to_coord_transform.mapBack((*_from_transforms[i])(Point(0))));
128 : else
129 : // if running in position, the subapp mesh has been transformed so the translation
130 : // is no longer applied by the transform
131 432 : src_pts.push_back(to_coord_transform.mapBack(
132 864 : (*_from_transforms[i])(getFromMultiApp()->position(i))));
133 2000 : src_vals.push_back(getFromMultiApp()->appPostprocessorValue(i, _postprocessor));
134 : }
135 : }
136 : }
137 :
138 : // We have only set local values - prepare for use by gathering remote data
139 578 : idi->prepare_for_use();
140 :
141 : // Loop over the parent app nodes and set the value of the variable
142 : {
143 578 : System * to_sys = find_sys(getFromMultiApp()->problemBase().es(), _to_var_name);
144 :
145 578 : unsigned int sys_num = to_sys->number();
146 578 : unsigned int var_num = to_sys->variable_number(_to_var_name);
147 :
148 578 : NumericVector<Real> & solution = *to_sys->solution;
149 :
150 578 : MooseMesh & mesh = getFromMultiApp()->problemBase().mesh();
151 :
152 578 : std::vector<std::string> vars;
153 :
154 578 : vars.push_back(_to_var_name);
155 :
156 578 : if (_nodal)
157 : {
158 : // handle linear lagrange shape functions
159 100473 : for (const auto & node : as_range(mesh.localNodesBegin(), mesh.localNodesEnd()))
160 : {
161 49960 : if (node->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this node
162 : {
163 49960 : std::vector<Point> pts;
164 49960 : std::vector<Number> vals;
165 :
166 49960 : pts.push_back(*node);
167 49960 : vals.resize(1);
168 :
169 49960 : idi->interpolate_field_data(vars, pts, vals);
170 :
171 49960 : Real value = vals.front();
172 :
173 : // The zero only works for LAGRANGE!
174 49960 : dof_id_type dof = node->dof_number(sys_num, var_num, 0);
175 :
176 49960 : solution.set(dof, value);
177 49960 : }
178 553 : }
179 : }
180 : else
181 : {
182 : // handle constant monomial shape functions
183 25 : for (const auto & elem :
184 2158 : as_range(mesh.getMesh().local_elements_begin(), mesh.getMesh().local_elements_end()))
185 : {
186 : // Exclude the elements without dofs
187 1054 : if (elem->n_dofs(sys_num, var_num) > 0)
188 : {
189 1054 : std::vector<Point> pts;
190 1054 : std::vector<Number> vals;
191 :
192 1054 : pts.push_back(elem->vertex_average());
193 1054 : vals.resize(1);
194 :
195 1054 : idi->interpolate_field_data(vars, pts, vals);
196 :
197 1054 : Real value = vals.front();
198 :
199 1054 : dof_id_type dof = elem->dof_number(sys_num, var_num, 0);
200 1054 : solution.set(dof, value);
201 1054 : }
202 25 : }
203 : }
204 :
205 578 : solution.close();
206 578 : }
207 :
208 578 : getFromMultiApp()->problemBase().es().update();
209 :
210 578 : break;
211 578 : }
212 : }
213 578 : }
|