21#include "libmesh/parallel_algebra.h"
22#include "libmesh/meshfree_interpolation.h"
23#include "libmesh/system.h"
24#include "libmesh/radial_basis_interpolation.h"
28 MultiAppInterpolationTransfer,
37 "Transfers the value to the target domain from a combination/interpolation of the values on "
38 "the nearest nodes in the source domain, using coefficients based on the distance to each "
41 "num_points", 3,
"The number of nearest points to use for interpolation.");
43 "power", 2,
"The polynomial power to use for calculation of the decay in the interpolation.");
45 MooseEnum interp_type(
"inverse_distance radial_basis",
"inverse_distance");
46 params.
addParam<
MooseEnum>(
"interp_type", interp_type,
"The algorithm to use for interpolation.");
50 "Radius to use for radial_basis interpolation. If negative "
51 "then the radius is taken as the max distance between "
56 "gap width with which we want to temporarily shrink mesh in transfering solution");
58 MooseEnum shrink_type(
"SOURCE TARGET",
"SOURCE");
59 params.
addParam<
MooseEnum>(
"shrink_mesh", shrink_type,
"Which mesh we want to shrink");
61 params.
addParam<std::vector<SubdomainName>>(
64 "Gap subdomains we want to exclude when constructing/using virtually translated points");
66 params.
addParam<Real>(
"distance_tol",
68 "If the distance between two points is smaller than distance_tol, two "
69 "points will be considered as identical");
77 _num_points(getParam<unsigned
int>(
"num_points")),
78 _power(getParam<Real>(
"power")),
79 _interp_type(getParam<
MooseEnum>(
"interp_type")),
80 _radius(getParam<Real>(
"radius")),
81 _shrink_gap_width(getParam<Real>(
"shrink_gap_width")),
82 _shrink_mesh(getParam<
MooseEnum>(
"shrink_mesh")),
83 _exclude_gap_blocks(getParam<
std::vector<SubdomainName>>(
"exclude_gap_blocks")),
84 _distance_tol(getParam<Real>(
"distance_tol"))
90 paramError(
"variable",
" Support single to-variable only ");
93 paramError(
"source_variable",
" Support single from-variable only ");
99 std::set<subdomain_id_type> & subdomainids)
104 auto & node_to_elem =
mesh.nodeToElemMap();
105 auto node_to_elem_pair = node_to_elem.find(node.id());
107 if (node_to_elem_pair == node_to_elem.end())
108 mooseError(
"Can not find elements for node ", node.id());
110 subdomainids.clear();
112 for (
auto element : node_to_elem_pair->second)
114 auto & elem =
mesh.getMesh().elem_ref(element);
115 auto subdomain = elem.subdomain_id();
117 subdomainids.insert(subdomain);
129 const auto & from_mesh = from_moose_mesh.
getMesh();
134 const System & from_sys = from_system_base.
system();
137 auto from_sys_num = from_sys.
number();
138 auto from_var_num = from_sys.variable_number(from_var.
name());
141 const auto & fe_type = from_sys.variable_type(from_var_num);
142 bool from_is_constant = fe_type.order == CONSTANT;
143 bool from_is_nodal = fe_type.family == LAGRANGE;
146 if (fe_type.order > FIRST && !from_is_nodal)
147 mooseError(
"We don't currently support second order or higher elemental variable ");
151 std::vector<Point> & src_pts(idi->get_source_points());
152 std::vector<Number> & src_vals(idi->get_source_vals());
155 std::unordered_map<dof_id_type, Point> from_tranforms;
156 std::set<subdomain_id_type> exclude_block_ids;
161 exclude_block_ids.insert(exclude_subdomainids.begin(), exclude_subdomainids.end());
165 const NumericVector<Number> & from_solution = *from_sys.solution;
167 std::set<subdomain_id_type> subdomainids;
168 std::vector<subdomain_id_type> include_block_ids;
171 for (
const auto *
const from_node : from_mesh.local_node_ptr_range())
174 if (from_node->n_comp(from_sys_num, from_var_num) == 0)
179 if (from_tranforms.size() > 0)
184 include_block_ids.clear();
185 include_block_ids.resize(std::max(subdomainids.size(), exclude_block_ids.size()));
186 auto it = std::set_difference(subdomainids.begin(),
188 exclude_block_ids.begin(),
189 exclude_block_ids.end(),
190 include_block_ids.begin());
192 include_block_ids.resize(it - include_block_ids.begin());
194 if (include_block_ids.size())
195 translate = from_tranforms[*include_block_ids.begin()];
201 dof_id_type from_dof = from_node->dof_number(from_sys_num, from_var_num, 0);
202 src_vals.push_back(from_solution(from_dof));
203 src_pts.push_back(from_app_transform(*from_node) + translate);
208 std::vector<Point> points;
209 for (
const auto *
const from_elem :
210 as_range(from_mesh.local_elements_begin(), from_mesh.local_elements_end()))
213 if (from_elem->n_dofs(from_sys_num, from_var_num) < 1)
217 if (from_is_constant)
218 points.push_back(from_elem->vertex_average());
220 for (
const auto & node : from_elem->node_ref_range())
221 points.push_back(node);
223 unsigned int n_comp = from_elem->n_comp(from_sys_num, from_var_num);
224 auto n_points = points.size();
226 if (n_points != n_comp)
229 " does not equal to number of variable components ",
232 unsigned int offset = 0;
236 if (from_tranforms.size() > 0)
238 auto subdomain = from_elem->subdomain_id();
241 mooseError(
"subdomain id does not make sense", subdomain);
244 if (exclude_block_ids.find(subdomain) == exclude_block_ids.end())
245 translate = from_tranforms[subdomain];
250 for (
const auto & point : points)
252 dof_id_type from_dof = from_elem->dof_number(from_sys_num, from_var_num, offset++);
253 src_vals.push_back(from_solution(from_dof));
254 src_pts.push_back(from_app_transform(point) + translate);
264 NumericVector<Real> & to_solution,
271 System & to_sys = to_system_base.
system();
274 auto to_sys_num = to_sys.
number();
275 auto to_var_num = to_sys.variable_number(to_var.
name());
278 const MeshBase & to_mesh = to_moose_mesh.
getMesh();
281 std::unordered_map<dof_id_type, Point> to_tranforms;
282 std::set<subdomain_id_type> exclude_block_ids;
287 exclude_block_ids.insert(exclude_subdomainids.begin(), exclude_subdomainids.end());
290 const auto & to_fe_type = to_sys.variable_type(to_var_num);
291 bool to_is_constant = to_fe_type.order == CONSTANT;
292 bool to_is_nodal = to_fe_type.family == LAGRANGE;
294 if (to_fe_type.order > FIRST && !to_is_nodal)
295 mooseError(
"We don't currently support second order or higher elemental variable ");
297 std::set<subdomain_id_type> subdomainids;
298 std::vector<subdomain_id_type> include_block_ids;
299 std::vector<Point> pts;
300 std::vector<Number> vals;
303 for (
const auto *
const node : to_mesh.local_node_ptr_range())
305 if (node->n_dofs(to_sys_num, to_var_num) <= 0)
309 if (to_tranforms.size() > 0)
314 include_block_ids.clear();
315 include_block_ids.resize(std::max(subdomainids.size(), exclude_block_ids.size()));
316 auto it = std::set_difference(subdomainids.begin(),
318 exclude_block_ids.begin(),
319 exclude_block_ids.end(),
320 include_block_ids.begin());
321 include_block_ids.resize(it - include_block_ids.begin());
322 if (include_block_ids.size())
323 translate = to_tranforms[*include_block_ids.begin()];
329 pts.push_back(to_app_transform(*node) + translate);
333 dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0);
334 to_solution.set(dof, vals.front());
339 std::vector<Point> points;
340 for (
const auto *
const elem :
341 as_range(to_mesh.local_elements_begin(), to_mesh.local_elements_end()))
344 if (elem->n_dofs(to_sys_num, to_var_num) < 1)
349 points.push_back(elem->vertex_average());
351 for (
const auto & node : elem->node_ref_range())
352 points.push_back(node);
354 auto n_points = points.size();
355 unsigned int n_comp = elem->n_comp(to_sys_num, to_var_num);
357 if (n_points != n_comp)
360 " does not equal to number of variable components ",
365 if (to_tranforms.size() > 0)
367 auto subdomain = elem->subdomain_id();
370 mooseError(
"subdomain id does not make sense", subdomain);
372 if (exclude_block_ids.find(subdomain) == exclude_block_ids.end())
373 translate = to_tranforms[subdomain];
378 unsigned int offset = 0;
379 for (
const auto & point : points)
382 pts.push_back(to_app_transform(point) + translate);
386 dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, offset++);
387 to_solution.set(dof, vals.front());
399 TIME_SECTION(
"MultiAppGeometricInterpolationTransfer::execute()",
401 "Transferring variables based on node interpolation");
405 std::unique_ptr<libMesh::InverseDistanceInterpolation<LIBMESH_DIM>> idi;
409 idi = std::make_unique<libMesh::InverseDistanceInterpolation<LIBMESH_DIM>>(
413 idi = std::make_unique<libMesh::RadialBasisInterpolation<LIBMESH_DIM>>(fe_problem.
comm(),
434 idi->prepare_for_use();
436 for (
unsigned int i = 0; i <
getToMultiApp()->numGlobalApps(); i++)
442 auto & to_var = to_problem.getVariable(0,
464 const auto & from_var = from_problem.getVariable(0,
473 idi->prepare_for_use();
496 const MooseMesh & mesh, std::unordered_map<dof_id_type, Point> & transformation)
498 auto & libmesh_mesh =
mesh.getMesh();
500 auto & subdomainids =
mesh.meshSubdomains();
502 subdomain_id_type max_subdomain_id = 0;
505 for (
auto subdomain_id : subdomainids)
507 max_subdomain_id = max_subdomain_id > subdomain_id ? max_subdomain_id : subdomain_id;
510 max_subdomain_id += 1;
512 std::unordered_map<dof_id_type, Point> subdomain_centers;
513 std::unordered_map<dof_id_type, dof_id_type> nelems;
516 as_range(libmesh_mesh.local_elements_begin(), libmesh_mesh.local_elements_end()))
519 subdomain_centers[max_subdomain_id] += elem->vertex_average();
520 nelems[max_subdomain_id] += 1;
522 auto subdomain = elem->subdomain_id();
528 subdomain_centers[subdomain] += elem->vertex_average();
530 nelems[subdomain] += 1;
537 subdomain_centers[max_subdomain_id] /= nelems[max_subdomain_id];
539 for (
auto subdomain_id : subdomainids)
541 subdomain_centers[subdomain_id] /= nelems[subdomain_id];
546 transformation.clear();
547 for (
auto subdomain_id : subdomainids)
549 transformation[subdomain_id] =
550 subdomain_centers[max_subdomain_id] - subdomain_centers[subdomain_id];
552 auto norm = transformation[subdomain_id].norm();
557 transformation[subdomain_id] /= norm;
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
registerMooseObjectRenamed("MooseApp", MultiAppInterpolationTransfer, "12/31/2023 24:00", MultiAppGeometricInterpolationTransfer)
registerMooseObject("MooseApp", MultiAppGeometricInterpolationTransfer)
void ErrorVector unsigned int
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
virtual const MooseVariableFieldBase & getVariable(const THREAD_ID tid, const std::string &var_name, Moose::VarKindType expected_var_type=Moose::VarKindType::VAR_ANY, Moose::VarFieldType expected_var_field_type=Moose::VarFieldType::VAR_FIELD_ANY) const override
Returns the variable reference for requested variable which must be of the expected_var_type (Nonline...
virtual MooseMesh & mesh() override
const std::string & name() const
Get the name of the class.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
std::vector< SubdomainID > getSubdomainIDs(const std::vector< SubdomainName > &subdomain_names) const
Get the associated subdomainIDs for the subdomain names that are passed in.
void errorIfDistributedMesh(std::string name) const
Generate a unified error message if the underlying libMesh mesh is a DistributedMesh.
SystemBase & sys()
Get the system this variable is part of.
This class provides an interface for common operations on field variables of both FE and FV types wit...
Transfers variables on possibly different meshes while conserving a user defined property (Postproces...
VariableName _from_var_name
This values are used if a derived class only supports one variable.
const std::vector< VariableName > _from_var_names
Name of variables transferring from.
const std::vector< AuxVariableName > _to_var_names
Name of variables transferring to.
static InputParameters validParams()
AuxVariableName _to_var_name
Interpolate variable values using geometry/mesh-based coefficients.
std::vector< SubdomainName > _exclude_gap_blocks
static InputParameters validParams()
void interpolateTargetPoints(FEProblemBase &to_problem, MooseVariableFieldBase &to_var, NumericVector< Real > &to_solution, const MultiAppCoordTransform &to_app_transform, const std::unique_ptr< libMesh::InverseDistanceInterpolation< Moose::dim > > &idi)
void computeTransformation(const MooseMesh &mesh, std::unordered_map< dof_id_type, Point > &transformation)
void fillSourceInterpolationPoints(FEProblemBase &from_problem, const MooseVariableFieldBase &from_var, const MultiAppCoordTransform &from_app_transform, std::unique_ptr< libMesh::InverseDistanceInterpolation< Moose::dim > > &idi)
void subdomainIDsNode(MooseMesh &mesh, const Node &node, std::set< subdomain_id_type > &subdomainids)
virtual void execute() override
Execute the transfer.
MultiAppGeometricInterpolationTransfer(const InputParameters ¶meters)
bool _displaced_source_mesh
True if displaced mesh is used for the source mesh, otherwise false.
std::vector< std::unique_ptr< MultiAppCoordTransform > > _from_transforms
bool _displaced_target_mesh
True if displaced mesh is used for the target mesh, otherwise false.
const std::shared_ptr< MultiApp > getToMultiApp() const
Get the MultiApp to transfer data to.
const std::shared_ptr< MultiApp > getFromMultiApp() const
Get the MultiApp to transfer data from.
std::vector< std::unique_ptr< MultiAppCoordTransform > > _to_transforms
bool hasFromMultiApp() const
Whether the transfer owns a non-null from_multi_app.
Base class for a system (of equations)
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
FEProblemBase & _fe_problem
MooseEnum _current_direction
const Parallel::Communicator & comm() const
std::unique_ptr< NumericVector< Number > > solution
unsigned int number() const
const SubdomainID INVALID_BLOCK_ID