Skip to content

Commit

Permalink
We could conditionally skip gap blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
fdkong authored and milljm committed Jul 15, 2020
1 parent 7b4cc27 commit fac1439
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 105 deletions.
6 changes: 0 additions & 6 deletions framework/include/transfers/MultiAppFieldTransfer.h
Expand Up @@ -52,10 +52,4 @@ class MultiAppFieldTransfer : public MultiAppTransfer
virtual std::vector<VariableName> getFromVarNames() const = 0;
/// Virtual function defining variables to transfer to
virtual std::vector<AuxVariableName> getToVarNames() const = 0;

void computeTransformation(MooseMesh & mesh,
std::unordered_map<dof_id_type, Point> & transformation);

Real _shrink_gap_width;
MooseEnum _shrink_mesh;
};
13 changes: 12 additions & 1 deletion framework/include/transfers/MultiAppInterpolationTransfer.h
Expand Up @@ -62,10 +62,21 @@ class MultiAppInterpolationTransfer : public MultiAppConservativeTransfer
Point & to_app_position,
std::unique_ptr<InverseDistanceInterpolation<LIBMESH_DIM>> & idi);

subdomain_id_type subdomainIDNode(MooseMesh & mesh, Node & node);
void subdomainIDsNode(MooseMesh & mesh, Node & node, std::set<subdomain_id_type> & subdomainids);

void computeTransformation(MooseMesh & mesh,
std::unordered_map<dof_id_type, Point> & transformation);

unsigned int _num_points;
Real _power;
MooseEnum _interp_type;
Real _radius;
// How much we want to shrink gap
Real _shrink_gap_width;
// Which mesh we want to shrink
MooseEnum _shrink_mesh;
// Which gap blocks want to exclude during solution transfers
std::vector<SubdomainName> _exclude_gap_blocks;
// How small we can consider two points are identical
Real _distance_tol;
};
73 changes: 1 addition & 72 deletions framework/src/transfers/MultiAppFieldTransfer.C
Expand Up @@ -24,20 +24,11 @@ InputParameters
MultiAppFieldTransfer::validParams()
{
InputParameters params = MultiAppTransfer::validParams();
params.addParam<Real>(
"shrink_gap_width",
0,
"gap width with which we want to temporarily shrink mesh in transfering solution");

MooseEnum shrink_type("SOURCE TARGET", "SOURCE");
params.addParam<MooseEnum>("shrink_mesh", shrink_type, "Which mesh we want to shrink");
return params;
}

MultiAppFieldTransfer::MultiAppFieldTransfer(const InputParameters & parameters)
: MultiAppTransfer(parameters),
_shrink_gap_width(getParam<Real>("shrink_gap_width")),
_shrink_mesh(getParam<MooseEnum>("shrink_mesh"))
: MultiAppTransfer(parameters)
{
}

Expand All @@ -52,68 +43,6 @@ MultiAppFieldTransfer::initialSetup()
variableIntegrityCheck(from_var);
}

void
MultiAppFieldTransfer::computeTransformation(
MooseMesh & mesh, std::unordered_map<dof_id_type, Point> & transformation)
{
auto & libmesh_mesh = mesh.getMesh();

auto & subdomainids = mesh.meshSubdomains();

int max_subdomain_id = 0;

for (auto subdomain_id : subdomainids)
{
max_subdomain_id = max_subdomain_id > subdomain_id ? max_subdomain_id : subdomain_id;
}

max_subdomain_id += 1;

std::unordered_map<dof_id_type, Point> subdomain_centers;
std::unordered_map<dof_id_type, dof_id_type> nelems;

for (auto & elem :
as_range(libmesh_mesh.local_elements_begin(), libmesh_mesh.local_elements_end()))
{
subdomain_centers[max_subdomain_id] += elem->centroid();
nelems[max_subdomain_id] += 1;

auto subdomain = elem->subdomain_id();

if (subdomain == Moose::INVALID_BLOCK_ID)
mooseError("block is invalid");

subdomain_centers[subdomain] += elem->centroid();

nelems[subdomain] += 1;
}

comm().sum(subdomain_centers);

comm().sum(nelems);

subdomain_centers[max_subdomain_id] /= nelems[max_subdomain_id];

for (auto subdomain_id : subdomainids)
{
subdomain_centers[subdomain_id] /= nelems[subdomain_id];
}

transformation.clear();
for (auto subdomain_id : subdomainids)
{
transformation[subdomain_id] =
subdomain_centers[max_subdomain_id] - subdomain_centers[subdomain_id];

auto norm = transformation[subdomain_id].norm();

if (norm > 1e-10)
transformation[subdomain_id] /= norm;

transformation[subdomain_id] *= _shrink_gap_width;
}
}

void
MultiAppFieldTransfer::transferDofObject(libMesh::DofObject * to_object,
libMesh::DofObject * from_object,
Expand Down
168 changes: 151 additions & 17 deletions framework/src/transfers/MultiAppInterpolationTransfer.C
Expand Up @@ -40,7 +40,21 @@ MultiAppInterpolationTransfer::validParams()
"Radius to use for radial_basis interpolation. If negative "
"then the radius is taken as the max distance between "
"points.");
params.addParam<Real>(
"shrink_gap_width",
0,
"gap width with which we want to temporarily shrink mesh in transfering solution");

MooseEnum shrink_type("SOURCE TARGET", "SOURCE");
params.addParam<MooseEnum>("shrink_mesh", shrink_type, "Which mesh we want to shrink");

params.addParam<std::vector<SubdomainName>>(
"exclude_gap_blocks", "Gap subdomains we want to exclude when constructing/using virtually translated points");

params.addParam<Real>(
"distance_tol",
1e-10,
"If the distance between two points is smaller than distance_tol, two points will be considered as identical");
return params;
}

Expand All @@ -49,7 +63,11 @@ MultiAppInterpolationTransfer::MultiAppInterpolationTransfer(const InputParamete
_num_points(getParam<unsigned int>("num_points")),
_power(getParam<Real>("power")),
_interp_type(getParam<MooseEnum>("interp_type")),
_radius(getParam<Real>("radius"))
_radius(getParam<Real>("radius")),
_shrink_gap_width(getParam<Real>("shrink_gap_width")),
_shrink_mesh(getParam<MooseEnum>("shrink_mesh")),
_exclude_gap_blocks(getParam<std::vector<SubdomainName>>("exclude_gap_blocks")),
_distance_tol(getParam<Real>("distance_tol"))
{
// This transfer does not work with DistributedMesh
_fe_problem.mesh().errorIfDistributedMesh("MultiAppInterpolationTransfer");
Expand All @@ -61,8 +79,10 @@ MultiAppInterpolationTransfer::MultiAppInterpolationTransfer(const InputParamete
paramError("source_variable", " Support single from-variable only ");
}

subdomain_id_type
MultiAppInterpolationTransfer::subdomainIDNode(MooseMesh & mesh, Node & node)
void
MultiAppInterpolationTransfer::subdomainIDsNode(MooseMesh & mesh,
Node & node,
std::set<subdomain_id_type> & subdomainids)
{
// We need this map to figure out to which subdomains a given mesh point is attached
auto & node_to_elem = mesh.nodeToElemMap();
Expand All @@ -71,17 +91,15 @@ MultiAppInterpolationTransfer::subdomainIDNode(MooseMesh & mesh, Node & node)
if (node_to_elem_pair == node_to_elem.end())
mooseError("Can not find elements for node ", node.id());

auto subdomain = Moose::INVALID_BLOCK_ID;
subdomainids.clear();
// Add all subdomain IDs that are attached to node
for (auto element : node_to_elem_pair->second)
{
auto & elem = mesh.getMesh().elem_ref(element);
subdomain = elem.subdomain_id();
}
auto subdomain = elem.subdomain_id();

if (subdomain == Moose::INVALID_BLOCK_ID)
mooseError("subdomain id does not make sense", subdomain);

return subdomain;
subdomainids.insert(subdomain);
}
}

void
Expand Down Expand Up @@ -131,13 +149,19 @@ MultiAppInterpolationTransfer::fillSourceInterpolationPoints(

// How much we want to translate mesh if users ask
std::unordered_map<dof_id_type, Point> from_tranforms;

std::set<subdomain_id_type> exclude_block_ids;
if (_shrink_gap_width > 0 && _shrink_mesh == "source")
{
computeTransformation(*from_moose_mesh, from_tranforms);
auto exclude_subdomainids = from_moose_mesh->getSubdomainIDs(_exclude_gap_blocks);
exclude_block_ids.insert(exclude_subdomainids.begin(), exclude_subdomainids.end());
}

// The solution from the system with which the from_var is associated
NumericVector<Number> & from_solution = *from_sys.solution;

std::set<subdomain_id_type> subdomainids;
std::vector<subdomain_id_type> include_block_ids;
if (from_is_nodal)
{
for (const auto & from_node : from_mesh->local_node_ptr_range())
Expand All @@ -150,10 +174,24 @@ MultiAppInterpolationTransfer::fillSourceInterpolationPoints(

if (from_tranforms.size() > 0)
{
auto subdomain = subdomainIDNode(*from_moose_mesh, *from_node);
translate = from_tranforms[subdomain];
subdomainIDsNode(*from_moose_mesh, *from_node, subdomainids);
// Check if node is excluded
// Node will be excluded if it is in the interior of excluded subdomains
include_block_ids.clear();
include_block_ids.resize(std::max(subdomainids.size(), exclude_block_ids.size()));
auto it = std::set_difference(subdomainids.begin(),
subdomainids.end(),
exclude_block_ids.begin(),
exclude_block_ids.end(),
include_block_ids.begin());
include_block_ids.resize(it - include_block_ids.begin());
if (include_block_ids.size())
translate = from_tranforms[*include_block_ids.begin()];
else
continue;
}

// Push value and point to KDTree
dof_id_type from_dof = from_node->dof_number(from_sys_num, from_var_num, 0);
src_vals.push_back(from_solution(from_dof));
src_pts.push_back(*from_node + translate + from_app_position);
Expand Down Expand Up @@ -196,7 +234,10 @@ MultiAppInterpolationTransfer::fillSourceInterpolationPoints(
if (subdomain == Moose::INVALID_BLOCK_ID)
mooseError("subdomain id does not make sense", subdomain);

translate = from_tranforms[subdomain];
if (exclude_block_ids.find(subdomain) != exclude_block_ids.end())
translate = from_tranforms[subdomain];
else
continue;
}

for (auto & point : points)
Expand Down Expand Up @@ -241,8 +282,13 @@ MultiAppInterpolationTransfer::interpolateTargetPoints(

// Compute transform info
std::unordered_map<dof_id_type, Point> to_tranforms;
std::set<subdomain_id_type> exclude_block_ids;
if (_shrink_gap_width > 0 && _shrink_mesh == "target")
{
computeTransformation(*to_moose_mesh, to_tranforms);
auto exclude_subdomainids = to_moose_mesh->getSubdomainIDs(_exclude_gap_blocks);
exclude_block_ids.insert(exclude_subdomainids.begin(), exclude_subdomainids.end());
}

auto & to_fe_type = to_sys.variable_type(to_var_num);
bool to_is_constant = to_fe_type.order == CONSTANT;
Expand All @@ -251,6 +297,8 @@ MultiAppInterpolationTransfer::interpolateTargetPoints(
if (to_fe_type.order > FIRST && !to_is_nodal)
mooseError("We don't currently support second order or higher elemental variable ");

std::set<subdomain_id_type> subdomainids;
std::vector<subdomain_id_type> include_block_ids;
if (to_is_nodal)
{
for (const auto & node : mesh->local_node_ptr_range())
Expand All @@ -261,8 +309,21 @@ MultiAppInterpolationTransfer::interpolateTargetPoints(
Point translate(0);
if (to_tranforms.size() > 0)
{
auto subdomain = subdomainIDNode(*to_moose_mesh, *node);
translate = to_tranforms[subdomain];
subdomainIDsNode(*to_moose_mesh, *node, subdomainids);
// Check if node is excluded
// Node will be excluded if it is in the interior of excluded subdomains
include_block_ids.clear();
include_block_ids.resize(std::max(subdomainids.size(), exclude_block_ids.size()));
auto it = std::set_difference(subdomainids.begin(),
subdomainids.end(),
exclude_block_ids.begin(),
exclude_block_ids.end(),
include_block_ids.begin());
include_block_ids.resize(it - include_block_ids.begin());
if (include_block_ids.size())
translate = to_tranforms[*include_block_ids.begin()];
else
continue;
}

std::vector<Point> pts;
Expand Down Expand Up @@ -314,7 +375,10 @@ MultiAppInterpolationTransfer::interpolateTargetPoints(
if (subdomain == Moose::INVALID_BLOCK_ID)
mooseError("subdomain id does not make sense", subdomain);

translate = to_tranforms[subdomain];
if (exclude_block_ids.find(subdomain) != exclude_block_ids.end())
translate = to_tranforms[subdomain];
else
continue;
}

unsigned int offset = 0;
Expand Down Expand Up @@ -439,3 +503,73 @@ MultiAppInterpolationTransfer::execute()

_console << "End InterpolationTransfer " << name() << std::endl;
}

void
MultiAppInterpolationTransfer::computeTransformation(
MooseMesh & mesh, std::unordered_map<dof_id_type, Point> & transformation)
{
auto & libmesh_mesh = mesh.getMesh();

auto & subdomainids = mesh.meshSubdomains();

subdomain_id_type max_subdomain_id = 0;

// max_subdomain_id will be used to represent the center of the entire domain
for (auto subdomain_id : subdomainids)
{
max_subdomain_id = max_subdomain_id > subdomain_id ? max_subdomain_id : subdomain_id;
}

max_subdomain_id += 1;

std::unordered_map<dof_id_type, Point> subdomain_centers;
std::unordered_map<dof_id_type, dof_id_type> nelems;

for (auto & elem :
as_range(libmesh_mesh.local_elements_begin(), libmesh_mesh.local_elements_end()))
{
// Compute center of the entire domain
subdomain_centers[max_subdomain_id] += elem->centroid();
nelems[max_subdomain_id] += 1;

auto subdomain = elem->subdomain_id();

if (subdomain == Moose::INVALID_BLOCK_ID)
mooseError("block is invalid");

// Centers for subdomains
subdomain_centers[subdomain] += elem->centroid();

nelems[subdomain] += 1;
}

comm().sum(subdomain_centers);

comm().sum(nelems);


subdomain_centers[max_subdomain_id] /= nelems[max_subdomain_id];

for (auto subdomain_id : subdomainids)
{
subdomain_centers[subdomain_id] /= nelems[subdomain_id];
}

// Compute unit vectors representing directions in which we want to shrink mesh
// The unit vectors is scaled by 'shrink_gap_width'
transformation.clear();
for (auto subdomain_id : subdomainids)
{
transformation[subdomain_id] =
subdomain_centers[max_subdomain_id] - subdomain_centers[subdomain_id];

auto norm = transformation[subdomain_id].norm();

// The current subdomain is the center of the entire domain,
// then we do not move this subdomain
if (norm > _distance_tol)
transformation[subdomain_id] /= norm;

transformation[subdomain_id] *= _shrink_gap_width;
}
}
Binary file not shown.
Binary file not shown.
2 changes: 2 additions & 0 deletions test/tests/transfers/multiapp_transfer_transformation/tests
Expand Up @@ -6,6 +6,8 @@
type = 'Exodiff'
input = 'transfer_transformation.i'
exodiff = 'transfer_transformation_out.e transfer_transformation_out_sub0.e'
# MultiAppInterpolationTransfer does not support distributed mesh at this moment
mesh_mode = 'replicated'
requirement = "The system shall be able to create virtually translated points during MultiApp transfers"
[]
[]

0 comments on commit fac1439

Please sign in to comment.