10#include <kernel/geometry/factory.hpp>
11#include <kernel/geometry/mesh_permutation.hpp>
12#include <kernel/geometry/mesh_node.hpp>
13#include <kernel/geometry/intern/facet_neighbors.hpp>
14#include <kernel/geometry/intern/standard_index_refiner.hpp>
15#include <kernel/geometry/intern/standard_vertex_refiner.hpp>
16#include <kernel/geometry/index_calculator.hpp>
17#include <kernel/util/dist.hpp>
19#include <kernel/util/random.hpp>
21#include <kernel/util/tiny_algebra.hpp>
45 template<
typename MeshType_>
49 typedef typename MeshType_::CoordType CoordType;
50 typedef typename MeshType_::VertexSetType VertexSetType;
51 static constexpr int shape_dim = MeshType_::shape_dim;
52 static constexpr int world_dim = MeshType_::world_dim;
62 std::vector<CoordType> _edge_weights;
79 _vtx(
_mesh.get_vertex_set())
120 const auto& verts_at_edge =
_mesh.template get_index_set<1, 0>();
121 const Index num_edges =
_mesh.get_num_entities(1);
122 const Index num_vtx =
_mesh.get_num_vertices();
125 const CoordType eps =
Math::sqrt(Math::eps<CoordType>());
128 std::vector<Tiny::Vector<CoordType, world_dim>> sum_neigh(num_vtx);
131 std::vector<CoordType> deg(num_vtx, CoordType(0));
133 for (
Index iter = 0; iter < max_iter; ++iter)
136 for (
Index i(0); i < num_vtx; ++i)
138 sum_neigh[i].format();
139 deg[i] = CoordType(0);
143 for (
Index e(0); e < num_edges; ++e)
146 const Index i = verts_at_edge(e,0);
147 const Index j = verts_at_edge(e,1);
149 CoordType weight = CoordType(1);
154 weight = CoordType(1) / std::max((_vtx[i] - _vtx[j]).norm_euclid(), eps);
158 if (!_edge_weights.empty())
160 weight *= _edge_weights[e];
166 sum_neigh[i].axpy(weight, _vtx[j]);
171 sum_neigh[j].axpy(weight, _vtx[i]);
179 CoordType max_change = 0;
182 for (
Index i(0); i < num_vtx; ++i)
187 auto x_old = _vtx[i];
188 _vtx[i] = (CoordType(1) / deg[i]) * sum_neigh[i];
191 Math::maxi(max_change, (_vtx[i] - x_old).norm_euclid_sqr());
199 if (max_change < tol*tol)
212 const auto& vtx_neighbors =
_mesh.get_neighbors();
214 const auto& faces_at_elem =
_mesh.template get_index_set<shape_dim, shape_dim - 1>();
216 int num_faces = faces_at_elem.num_indices;
221 for (
Index i = 0; i < num_elements; ++i)
224 for (
int j = 0; j < num_faces; ++j)
227 if (vtx_neighbors[i][j] > num_elements)
243 const auto& verts_at_face =
_mesh.template get_index_set<shape_dim - 1, 0>();
245 int vert_per_face = verts_at_face.num_indices;
248 for (
Index i = 0; i <
_mesh.get_num_entities(shape_dim - 1); ++i)
254 for (
int j = 0; j < vert_per_face; ++j)
291 template<
typename MeshType_>
297 typedef MeshType_ MeshType;
301 static constexpr int world_dim = MeshType::world_dim;
302 static constexpr int facet_dim = MeshType::shape_dim - 1;
304 typedef typename BaseClass::CoordType CoordType;
348 for(
const auto& v : halo_map)
351 const TargetSet& halo_facets = v.second->template get_target_set<facet_dim>();
353 this->_boundary_facets.at(halo_facets[i]) = 0;
367 const Index num_edges = this->_mesh.get_num_entities(1);
370 this->_edge_weights.assign(num_edges, CoordType(1.0));
371 std::vector<int> multiplicity(num_edges, 1);
377 for (
const auto& hm : halo_map)
379 const int neighbor_rank = hm.first;
380 const std::unique_ptr<MeshPartType>& part_ptr = hm.second;
393 const auto& target_edges = part_ptr->template get_target_set<1>();
395 for (
Index k(0); k < target_edges.get_num_entities(); ++k)
398 const Index e = target_edges[k];
400 multiplicity[e] += 1;
403 for (
Index e(0); e < num_edges; ++e)
406 const int m = std::max(1, multiplicity[e]);
407 this->_edge_weights[e] = CoordType(1.0) / CoordType(m);
418 if (halo_map.empty() ||
_comm.
size() == 1)
return;
421 const std::size_t stride = std::size_t(world_dim + 1);
424 std::vector<int> ranks;
425 std::vector<std::vector<CoordType>> send_bufs, recv_bufs;
427 ranks.
reserve(halo_map.size());
428 send_bufs.resize(halo_map.size());
429 recv_bufs.resize(halo_map.size());
430 send_reqs.
reserve(halo_map.size());
431 recv_reqs.
reserve(halo_map.size());
434 for (
auto it = halo_map.begin(); it != halo_map.end(); ++it)
437 const int halo_rank = it->first;
438 const auto& part = it->second;
445 const auto& halo_vtx = part->template get_target_set<0>();
446 const Index halo_size = halo_vtx.get_num_entities();
449 const std::size_t len = std::size_t(halo_size) * stride;
452 const std::size_t idx = ranks.size();
453 ranks.push_back(halo_rank);
454 auto& rbuf = recv_bufs[idx];
462 for (std::size_t idx = 0; idx < ranks.size(); ++idx)
465 const int halo_rank = ranks[idx];
466 auto it = halo_map.find(halo_rank);
470 const auto& halo_vtx = it->second->template get_target_set<0>();
471 const Index halo_size = halo_vtx.get_num_entities();
474 const std::size_t len = std::size_t(halo_size) * stride;
477 auto& sbuf = send_bufs[idx];
481 for (
Index k(0); k < halo_size; ++k)
483 const Index v = halo_vtx[k];
484 const std::size_t base = std::size_t(k) * stride;
486 for (
int d(0); d < world_dim; ++d)
488 sbuf[base + std::size_t(d)] = sum_neigh[v][d];
490 sbuf[base + std::size_t(world_dim)] = deg[v];
498 for (std::size_t idx(0); recv_reqs.
wait_any(idx); )
501 const int halo_rank = ranks.at(idx);
502 auto it = halo_map.find(halo_rank);
506 const auto& halo_vtx = it->second->template get_target_set<0>();
507 const Index halo_size = halo_vtx.get_num_entities();
508 const auto& rbuf = recv_bufs.at(idx);
511 XASSERT(rbuf.size() == std::size_t(halo_size) * stride);
514 for (
Index k(0); k < halo_size; ++k)
516 const Index v = halo_vtx[k];
517 const std::size_t base = std::size_t(k) * stride;
520 for (
int d(0); d < world_dim; ++d)
522 sum_neigh[v][d] += rbuf[base + std::size_t(d)];
524 deg[v] += rbuf[base + std::size_t(world_dim)];
#define XASSERT(expr)
Assertion macro definition.
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
int size() const
Returns the size of this communicator.
Request irecv(void *buffer, std::size_t count, const Datatype &datatype, int source, int tag=0) const
Nonblocking Receive.
Request isend(const void *buffer, std::size_t count, const Datatype &datatype, int dest, int tag=0) const
Nonblocking Send.
int rank() const
Returns the rank of this process in this communicator.
Communication Request vector class.
void push_back(Request &&request)
Inserts a new request at the end of the request vector.
void reserve(std::size_t size_)
Reserves sufficient space for a specified number of requests.
bool wait_any(std::size_t &idx, Status &status)
Blocks until one of the active requests has been fulfilled.
void wait_all()
Blocks until all active requests are fulfilled.
Umbrella smoother class template.
DistributedUmbrellaSmoother(const Dist::Comm &comm, RootMeshNodeType &root_mesh_node)
Constructor.
virtual void _calc_boundary_facets() override
determines for each facet whether it is a boundary facet or an inner facet
void _calc_max(CoordType &global_max) override
calculates global maximum over all processes; is overridden in DistributedUmbrellaSmoother
RootMeshNodeType & _root_mesh_node
a reference to our root mesh node
void _init_edge_multiplicity()
Computes per-edge weights for distributed smoothing.
const Dist::Comm & _comm
a reference to our communicator
void _synchronize(std::vector< Tiny::Vector< CoordType, world_dim > > &sum_neigh, std::vector< CoordType > °) override
synchronizes the smoother over all processes; is overridden in DistributedUmbrellaSmoother
Class template for partial meshes.
Root mesh node class template.
const std::map< int, std::unique_ptr< MeshPartType > > & get_halo_map() const
Index get_num_entities() const
Returns the number of entities.
Umbrella mesh smoother with both uniform and scale-dependent neighbor averaging For more information ...
UmbrellaSmoother(MeshType_ &mesh)
Constructor.
std::vector< int > _boundary_facets
vector to store which facet is at the boundary
MeshType_ & _mesh
the mesh we want to smooth
void smooth(Index max_iter, CoordType tol, bool uniform=true)
Smooths the mesh with an umbrella operator.
virtual void _calc_boundary_vertices()
determines for each vertex whether it is a boundary vertex or an inner vertex
virtual void _calc_boundary_facets()
determines for each facet whether it is a boundary facet or an inner facet
std::vector< int > _boundary_vertices
vector to store which vertex is at the boundary
virtual void _synchronize(std::vector< Tiny::Vector< CoordType, world_dim > > &, std::vector< CoordType > &)
synchronizes the smoother over all processes; is overridden in DistributedUmbrellaSmoother
virtual void _calc_max(CoordType &)
calculates global maximum over all processes; is overridden in DistributedUmbrellaSmoother
Tiny Vector class template.
const Operation op_max(MPI_MAX)
Operation wrapper for MPI_MAX.
T_ sqrt(T_ x)
Returns the square-root of a value.
void maxi(T_ &xmax, T_ x)
Updates the maximum of a set of values.
std::uint64_t Index
Index data type.