Files
mfem/mesh/pmesh.hpp
T
2026-01-14 10:14:10 -08:00

836 lines
34 KiB
C++

// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_PMESH
#define MFEM_PMESH
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "../general/communication.hpp"
#include "../general/globals.hpp"
#include "mesh.hpp"
#include "pncmesh.hpp"
#include <iostream>
namespace mfem
{
#ifdef MFEM_USE_PUMI
class ParPumiMesh;
#endif
/// Class for parallel meshes
class ParMesh : public Mesh
{
friend class ParNCMesh;
friend class ParSubMesh;
#ifdef MFEM_USE_PUMI
friend class ParPumiMesh;
#endif
#ifdef MFEM_USE_ADIOS2
friend class adios2stream;
#endif
protected:
MPI_Comm MyComm;
int NRanks, MyRank;
struct Vert3
{
int v[3];
Vert3() = default;
Vert3(int v0, int v1, int v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
void Set(int v0, int v1, int v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
void Set(const int *w) { v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; }
};
struct Vert4
{
int v[4];
Vert4() = default;
Vert4(int v0, int v1, int v2, int v3)
{ v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
void Set(int v0, int v1, int v2, int v3)
{ v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
void Set(const int *w)
{ v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; v[3] = w[3]; }
};
Array<Element *> shared_edges;
// shared face id 'i' is:
// * triangle id 'i', if i < shared_trias.Size()
// * quad id 'i-shared_trias.Size()', otherwise
Array<Vert3> shared_trias;
Array<Vert4> shared_quads;
/// Shared objects in each group.
Table group_svert;
Table group_sedge;
Table group_stria; // contains shared triangle indices
Table group_squad; // contains shared quadrilateral indices
/// Shared to local index mapping.
Array<int> svert_lvert;
Array<int> sedge_ledge;
// sface ids: all triangles first, then all quads
Array<int> sface_lface;
/// Table that maps from face neighbor element number, to the face numbers of
/// that element.
std::unique_ptr<Table> face_nbr_el_to_face;
/// orientations for each face (from nbr processor)
std::unique_ptr<Table> face_nbr_el_ori;
// glob_elem_offset + local element number defines a global element numbering
mutable long long glob_elem_offset;
mutable long glob_offset_sequence;
void ComputeGlobalElementOffset() const;
// Enable Print() to add the parallel interface as boundary (typically used
// for visualization purposes)
bool print_shared = true;
/// Create from a nonconforming mesh.
ParMesh(const ParNCMesh &pncmesh);
// Convert the local 'meshgen' to a global one.
void ReduceMeshGen();
// Determine sedge_ledge and sface_lface.
void FinalizeParTopo();
// Mark all tets to ensure consistency across MPI tasks; also mark the shared
// and boundary triangle faces using the consistently marked tets.
void MarkTetMeshForRefinement(const DSTable &v_to_v) override;
/// Return a number(0-1) identifying how the given edge has been split
int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle);
/// Append codes identifying how the given face has been split to @a codes
void GetFaceSplittings(const int *fv, const HashTable<Hashed2> &v_to_v,
Array<unsigned> &codes);
bool DecodeFaceSplittings(HashTable<Hashed2> &v_to_v, const int *v,
const Array<unsigned> &codes, int &pos);
// Given a completed FacesTable and SharedFacesTable, construct a table that
// maps from face neighbor element number, to the set of faces of that
// element. Store the resulting data in the member variable
// face_nbr_el_to_face. If the mesh is nonconforming, this also builds the
// the face_nbr_el_ori variable from the faces_info.
void BuildFaceNbrElementToFaceTable();
/**
* @brief Helper function for adding triangle face neighbor element to face
* table entries. Have to use a template here rather than lambda capture
* because the FaceVert entries in Geometry have inner size of 3 for tets and
* 4 for everything else.
*
* @tparam N Inner dimension on the fvert variable, 3 for tet, 4 otherwise
* @param[in] v Set of vertices for this element
* @param[in] faces Table of faces interior to this rank
* @param[in] shared_faces Table of faces shared by this rank and another
* @param[in] elem The face neighbor element
* @param[in] start Starting index into fverts
* @param[in] end End index into fverts
* @param[in] fverts Array of face vertices for this particular geometry.
*/
template <int N>
void AddTriFaces(const Array<int> &v, const std::unique_ptr<STable3D> &faces,
const std::unique_ptr<STable3D> &shared_faces,
int elem, int start, int end, const int fverts[][N]);
void GetGhostFaceTransformation(
int FaceNo, FaceElementTransformations &FElTr) const;
/// Update the groups after triangle refinement
void RefineGroups(const DSTable &v_to_v, int *middle);
/// Update the groups after tetrahedron refinement
void RefineGroups(int old_nv, const HashTable<Hashed2> &v_to_v);
void UniformRefineGroups2D(int old_nv);
// f2qf can be NULL if all faces are quads or there are no quad faces
void UniformRefineGroups3D(int old_nv, int old_nedges,
const DSTable &old_v_to_v,
const STable3D &old_faces,
Array<int> *f2qf);
void ExchangeFaceNbrData(Table *gr_sface, int *s2l_face);
/// Refine a mixed 2D mesh uniformly.
void UniformRefinement2D() override;
/// Refine a mixed 3D mesh uniformly.
void UniformRefinement3D() override;
/** @brief Refine NURBS mesh, with an optional refinement factor.
@param[in] rf Optional refinement factor. If scalar, the factor is used
for all dimensions. If an array, factors can be specified
for each dimension.
@param[in] tol NURBS geometry deviation tolerance. */
void NURBSUniformRefinement(int rf = 2, real_t tol=1.0e-12) override;
void NURBSUniformRefinement(const Array<int> &rf, real_t tol=1.e-12) override;
void RefineNURBSWithKVFactors(int rf, const std::string &kvf) override;
/// This function is not public anymore. Use GeneralRefinement instead.
void LocalRefinement(const Array<int> &marked_el, int type = 3) override;
/// This function is not public anymore. Use GeneralRefinement instead.
void NonconformingRefinement(const Array<Refinement> &refinements,
int nc_limit = 0) override;
bool NonconformingDerefinement(Array<real_t> &elem_error,
real_t threshold, int nc_limit = 0,
int op = 1) override;
void RebalanceImpl(const Array<int> *partition);
void DeleteFaceNbrData();
bool WantSkipSharedMaster(const NCMesh::Master &master) const;
/// Fills out partitioned Mesh::vertices
int BuildLocalVertices(const Mesh& global_mesh, const int *partitioning,
Array<int> &vert_global_local);
/// Fills out partitioned Mesh::elements
int BuildLocalElements(const Mesh& global_mesh, const int *partitioning,
const Array<int> &vert_global_local);
/// Fills out partitioned Mesh::boundary
int BuildLocalBoundary(const Mesh& global_mesh, const int *partitioning,
const Array<int> &vert_global_local,
Array<bool>& activeBdrElem,
Table* &edge_element);
void FindSharedFaces(const Mesh &mesh, const int* partition,
Array<int>& face_group,
ListOfIntegerSets& groups);
int FindSharedEdges(const Mesh &mesh, const int* partition,
Table* &edge_element, ListOfIntegerSets& groups);
int FindSharedVertices(const int *partition, Table* vertex_element,
ListOfIntegerSets& groups);
void BuildFaceGroup(int ngroups, const Mesh &mesh,
const Array<int>& face_group,
int &nstria, int &nsquad);
void BuildEdgeGroup(int ngroups, const Table& edge_element);
void BuildVertexGroup(int ngroups, const Table& vert_element);
void BuildSharedFaceElems(int ntri_faces, int nquad_faces,
const Mesh &mesh, const int *partitioning,
const STable3D *faces_tbl,
const Array<int> &face_group,
const Array<int> &vert_global_local);
void BuildSharedEdgeElems(int nedges, Mesh &mesh,
const Array<int> &vert_global_local,
const Table *edge_element);
void BuildSharedVertMapping(int nvert, const Table* vert_element,
const Array<int> &vert_global_local);
/**
* @brief Get the shared edges GroupCommunicator.
*
* The output of the shared edges is chosen by the @a ordering parameter with
* the following options
* 0: Internal ordering. Not exposed to public interfaces.
* 1: Contiguous ordering.
*
* @param[in] ordering Ordering for the shared edges.
* @param[out] sedge_comm
*/
void GetSharedEdgeCommunicator(int ordering,
GroupCommunicator& sedge_comm) const;
/**
* @brief Get the shared vertices GroupCommunicator.
*
* The output of the shared vertices is chosen by the @a ordering parameter
* with the following options
* 0: Internal ordering. Not exposed to public interfaces.
* 1: Contiguous ordering.
*
* @param[in] ordering
* @param[out] svert_comm
*/
void GetSharedVertexCommunicator(int ordering,
GroupCommunicator& svert_comm) const;
/**
* @brief Get the shared face quadrilaterals GroupCommunicator.
*
* The output of the shared face quadrilaterals is chosen by the @a ordering
* parameter with the following options
* 0: Internal ordering. Not exposed to public interfaces.
* 1: Contiguous ordering.
*
* @param[in] ordering
* @param[out] squad_comm
*/
void GetSharedQuadCommunicator(int ordering,
GroupCommunicator& squad_comm) const;
/**
* @brief Get the shared face triangles GroupCommunicator.
*
* The output of the shared face triangles is chosen by the @a ordering
* parameter with the following options
* 0: Internal ordering. Not exposed to public interfaces.
* 1: Contiguous ordering.
*
* @param[in] ordering
* @param[out] stria_comm
*/
void GetSharedTriCommunicator(int ordering,
GroupCommunicator& stria_comm) const;
// Similar to Mesh::GetFacesTable()
STable3D *GetSharedFacesTable();
/// Ensure that bdr_attributes and attributes agree across processors
void DistributeAttributes(Array<int> &attr);
void LoadSharedEntities(std::istream &input);
/// If the mesh is curved, make sure 'Nodes' is ParGridFunction.
/** Note that this method is not related to the public 'Mesh::EnsureNodes`.*/
void EnsureParNodes();
/// Internal function used in ParMesh::MakeRefined (and related constructor)
void MakeRefined_(ParMesh &orig_mesh, int ref_factor, int ref_type);
// Mark Mesh::Swap as protected, should use ParMesh::Swap to swap @a ParMesh
// objects.
using Mesh::Swap;
void Destroy();
public:
/// Default constructor. Create an empty @a ParMesh.
ParMesh() : MyComm(0), NRanks(0), MyRank(-1),
glob_elem_offset(-1), glob_offset_sequence(-1),
have_face_nbr_data(false), pncmesh(NULL) { }
/// Create a parallel mesh by partitioning a serial Mesh.
/** The mesh is partitioned automatically or using external partitioning data
(the optional parameter 'partitioning_[i]' contains the desired MPI rank
for element 'i'). Automatic partitioning uses METIS for conforming meshes
and quick space-filling curve equipartitioning for nonconforming meshes
(elements of nonconforming meshes should ideally be ordered as a sequence
of face-neighbors). */
ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_ = nullptr,
int part_method = 1);
/** Copy constructor. Performs a deep copy of (almost) all data, so that the
source mesh can be modified (e.g. deleted, refined) without affecting the
new mesh. If 'copy_nodes' is false, use a shallow (pointer) copy for the
nodes, if present. */
explicit ParMesh(const ParMesh &pmesh, bool copy_nodes = true);
/// Read a parallel mesh, each MPI rank from its own file/stream.
/** The @a generate_edges parameter is passed to Mesh::Loader. The @a refine
and @a fix_orientation parameters are passed to the method
Mesh::Finalize().
@note The order of arguments and their default values are different than
for the Mesh class. */
ParMesh(MPI_Comm comm, std::istream &input, bool refine = true,
int generate_edges = 1, bool fix_orientation = true);
/// Deprecated: see @a ParMesh::MakeRefined
MFEM_DEPRECATED
ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type);
/// Move constructor. Used for named constructors.
ParMesh(ParMesh &&mesh);
/// Move assignment operator.
ParMesh& operator=(ParMesh &&mesh);
/// Explicitly delete the copy assignment operator.
ParMesh& operator=(const ParMesh &mesh) = delete;
/// Create a uniformly refined (by any factor) version of @a orig_mesh.
/** @param[in] orig_mesh The starting coarse mesh.
@param[in] ref_factor The refinement factor, an integer > 1.
@param[in] ref_type Specify the positions of the new vertices. The
options are BasisType::ClosedUniform or
BasisType::GaussLobatto.
The refinement data which can be accessed with GetRefinementTransforms()
is set to reflect the performed refinements.
@note The constructed ParMesh is linear, i.e. it does not have nodes. */
static ParMesh MakeRefined(ParMesh &orig_mesh, int ref_factor, int ref_type);
/** Create a mesh by splitting each element of @a orig_mesh into simplices.
See @a Mesh::MakeSimplicial for more details. */
static ParMesh MakeSimplicial(ParMesh &orig_mesh);
void Finalize(bool refine = false, bool fix_orientation = false) override;
void SetAttributes(bool elem_attrs_changed = true,
bool bdr_attrs_changed = true) override;
/// Checks if any rank in the mesh has boundary elements
bool HasBoundaryElements() const override;
MPI_Comm GetComm() const { return MyComm; }
int GetNRanks() const { return NRanks; }
int GetMyRank() const { return MyRank; }
/** Map a global element number to a local element number. If the global
element is not on this processor, return -1. */
int GetLocalElementNum(long long global_element_num) const;
/// Map a local element number to a global element number.
long long GetGlobalElementNum(int local_element_num) const;
/** The following functions define global indices for all local vertices,
edges, faces, or elements. The global indices have no meaning or
significance for ParMesh, but can be used for purposes beyond this class.
*/
/// AMR meshes are not supported.
void GetGlobalVertexIndices(Array<HYPRE_BigInt> &gi) const;
/// AMR meshes are not supported.
void GetGlobalEdgeIndices(Array<HYPRE_BigInt> &gi) const;
/// AMR meshes are not supported.
void GetGlobalFaceIndices(Array<HYPRE_BigInt> &gi) const;
/// AMR meshes are supported.
void GetGlobalElementIndices(Array<HYPRE_BigInt> &gi) const;
/// @brief Populate a marker array identifying exterior faces
///
/// @param[in,out] face_marker Resized if necessary to the number of
/// local faces. The array entries will be
/// zero for interior faces and 1 for exterior
/// faces.
void GetExteriorFaceMarker(Array<int> & face_marker) const override;
/// @brief Unmark boundary attributes of internal boundaries
///
/// @param[in,out] bdr_marker Array of length bdr_attributes.Max().
/// Entries associated with internal boundaries
/// will be set to zero. Other entries will remain
/// unchanged.
/// @param[in] excl Only unmark entries which exclusively contain
/// internal faces [default: true].
void UnmarkInternalBoundaries(Array<int> &bdr_marker,
bool excl = true) const override;
/// @brief Mark boundary attributes of external boundaries
///
/// @param[in,out] bdr_marker Array of length bdr_attributes.Max().
/// Entries associated with external boundaries
/// will be set to one. Other entries will remain
/// unchanged.
/// @param[in] excl Only mark entries which exclusively contain
/// external faces [default: true].
void MarkExternalBoundaries(Array<int> &bdr_marker,
bool excl = true) const override;
GroupTopology gtopo;
// Face-neighbor elements and vertices
bool have_face_nbr_data;
Array<int> face_nbr_group;
Array<int> face_nbr_elements_offset;
Array<int> face_nbr_vertices_offset;
Array<Element *> face_nbr_elements;
Array<Vertex> face_nbr_vertices;
// Local face-neighbor elements and vertices ordered by face-neighbor
Table send_face_nbr_elements;
Table send_face_nbr_vertices;
ParNCMesh* pncmesh;
int GetNGroups() const { return gtopo.NGroups(); }
///@{ @name These methods require group > 0
int GroupNVertices(int group) const { return group_svert.RowSize(group-1); }
int GroupNEdges(int group) const { return group_sedge.RowSize(group-1); }
int GroupNTriangles(int group) const { return group_stria.RowSize(group-1); }
int GroupNQuadrilaterals(int group) const { return group_squad.RowSize(group-1); }
/**
* @brief Accessors for entities within a shared group structure.
* @details For all vertex/edge/face the two argument version returns the
* local index, for those entities with an orientation. The two out parameter
* version additionally returns an orientation to use in manipulating the
* entity.
*
* @param group The communicator group's indices
* @param i the index within the group
* @return int The local index of the entity
*/
int GroupVertex(int group, int i) const
{ return svert_lvert[group_svert.GetRow(group-1)[i]]; }
void GroupEdge(int group, int i, int &edge, int &o) const;
void GroupTriangle(int group, int i, int &face, int &o) const;
void GroupQuadrilateral(int group, int i, int &face, int &o) const;
int GroupEdge(int group, int i) const
{
int e, o;
GroupEdge(group, i, e, o);
return e;
}
int GroupTriangle(int group, int i) const
{
int f, o;
GroupTriangle(group, i, f, o);
return f;
}
int GroupQuadrilateral(int group, int i) const
{
int f, o;
GroupQuadrilateral(group, i, f, o);
return f;
}
///@}
/**
* @brief Get the shared edges GroupCommunicator.
*
* @param[out] sedge_comm
*/
void GetSharedEdgeCommunicator(GroupCommunicator& sedge_comm) const
{
GetSharedEdgeCommunicator(1, sedge_comm);
}
/**
* @brief Get the shared vertices GroupCommunicator.
*
* @param[out] svert_comm
*/
void GetSharedVertexCommunicator(GroupCommunicator& svert_comm) const
{
GetSharedVertexCommunicator(1, svert_comm);
}
/**
* @brief Get the shared face quadrilaterals GroupCommunicator.
*
* @param[out] squad_comm
*/
void GetSharedQuadCommunicator(GroupCommunicator& squad_comm) const
{
GetSharedQuadCommunicator(1, squad_comm);
}
/**
* @brief Get the shared face triangles GroupCommunicator.
*
* @param[out] stria_comm
*/
void GetSharedTriCommunicator(GroupCommunicator& stria_comm) const
{
GetSharedTriCommunicator(1, stria_comm);
}
void GenerateOffsets(int N, HYPRE_BigInt loc_sizes[],
Array<HYPRE_BigInt> *offsets[]) const;
using Mesh::FaceIsTrueInterior;
void ExchangeFaceNbrData();
void ExchangeFaceNbrNodes();
void SetCurvature(int order, bool discont = false, int space_dim = -1,
int ordering = 1) override;
/** Replace the internal node GridFunction with a new GridFunction defined on
the given FiniteElementSpace. The new node coordinates are projected
(derived) from the current nodes/vertices. */
void SetNodalFESpace(FiniteElementSpace *nfes) override;
void SetNodalFESpace(ParFiniteElementSpace *npfes);
int GetNFaceNeighbors() const { return face_nbr_group.Size(); }
int GetNFaceNeighborElements() const { return face_nbr_elements.Size(); }
int GetFaceNbrGroup(int fn) const { return face_nbr_group[fn]; }
int GetFaceNbrRank(int fn) const;
/** Similar to Mesh::GetElementFaces */
void GetFaceNbrElementFaces(int i, Array<int> &faces,
Array<int> &orientation) const;
/** Similar to Mesh::GetFaceToElementTable with added face-neighbor elements
with indices offset by the local number of elements. */
/// @note The returned Table should be deleted by the caller
Table *GetFaceToAllElementTable() const;
/// Returns (a pointer to an object containing) the following data:
///
/// 1) Elem1No - the index of the first element that contains this face this
/// is the element that has the same outward unit normal vector as the
/// face;
///
/// 2) Elem2No - the index of the second element that contains this face this
/// element has outward unit normal vector as the face multiplied with -1;
///
/// 3) Elem1, Elem2 - pointers to the ElementTransformation's of the first
/// and the second element respectively;
///
/// 4) Face - pointer to the ElementTransformation of the face;
///
/// 5) Loc1, Loc2 - IntegrationPointTransformation's mapping the face
/// coordinate system to the element coordinate system (both in their
/// reference elements). Used to transform IntegrationPoints from face to
/// element. More formally, let:
/// TL1, TL2 be the transformations represented by Loc1, Loc2,
/// TE1, TE2 - the transformations represented by Elem1, Elem2,
/// TF - the transformation represented by Face, then
/// TF(x) = TE1(TL1(x)) = TE2(TL2(x)) for all x in the reference face.
///
/// 6) FaceGeom - the base geometry for the face.
///
/// The mask specifies which fields in the structure to return:
/// mask & 1 - Elem1, mask & 2 - Elem2
/// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face.
/// These mask values are defined in the ConfigMasks enum type as part of the
/// FaceElementTransformations class in fem/eltrans.hpp.
///
/// @note The returned object is owned by the class and is shared, i.e.,
/// calling this function resets pointers obtained from previous calls.
/// Also, the returned object should NOT be deleted by the caller.
FaceElementTransformations *
GetFaceElementTransformations(int FaceNo, int mask = 31) override;
/// @brief Variant of GetFaceElementTransformations using a user allocated
/// FaceElementTransformations object.
void GetFaceElementTransformations(int FaceNo,
FaceElementTransformations &FElTr,
IsoparametricTransformation &ElTr1,
IsoparametricTransformation &ElTr2,
int mask = 31) const override;
/// @brief Get the FaceElementTransformations for the given shared face (edge
/// 2D) using the shared face index @a sf. @a fill2 specifies whether
/// information for elem2 of the face should be computed. In the returned
/// object, 1 and 2 refer to the local and the neighbor elements,
/// respectively.
///
/// @note The returned object is owned by the class and is shared, i.e.,
/// calling this function resets pointers obtained from previous calls. Also,
/// the returned object should NOT be deleted by the caller.
FaceElementTransformations *
GetSharedFaceTransformations(int sf, bool fill2 = true);
/// @brief Variant of GetSharedFaceTransformations using a user allocated
/// FaceElementTransformations object.
void GetSharedFaceTransformations(int sf,
FaceElementTransformations &FElTr,
IsoparametricTransformation &ElTr1,
IsoparametricTransformation &ElTr2,
bool fill2 = true) const;
/// @brief Get the FaceElementTransformations for the given shared face (edge
/// 2D) using the face index @a FaceNo. @a fill2 specifies whether
/// information for elem2 of the face should be computed. In the returned
/// object, 1 and 2 refer to the local and the neighbor elements,
/// respectively.
///
/// @note The returned object is owned by the class and is shared, i.e.,
/// calling this function resets pointers obtained from previous calls. Also,
/// the returned object should NOT be deleted by the caller.
FaceElementTransformations *
GetSharedFaceTransformationsByLocalIndex(int FaceNo, bool fill2 = true);
/// @brief Variant of GetSharedFaceTransformationsByLocalIndex using a user
/// allocated FaceElementTransformations object.
void GetSharedFaceTransformationsByLocalIndex(int FaceNo,
FaceElementTransformations &FElTr,
IsoparametricTransformation &ElTr1,
IsoparametricTransformation &ElTr2,
bool fill2 = true) const;
/// @brief Returns a pointer to the transformation defining the i-th face
/// neighbor.
///
/// @note The returned object is owned by the class and is shared, i.e.,
/// calling this function resets pointers obtained from previous calls. Also,
/// the returned object should NOT be deleted by the caller.
ElementTransformation *GetFaceNbrElementTransformation(int FaceNo);
/// @brief Variant of GetFaceNbrElementTransformation using a user allocated
/// IsoparametricTransformation object.
void GetFaceNbrElementTransformation(int FaceNo,
IsoparametricTransformation &ElTr) const;
/// Get the size of the i-th face neighbor element relative to the reference
/// element.
real_t GetFaceNbrElementSize(int i, int type = 0);
/// Return the number of shared faces (3D), edges (2D), vertices (1D)
int GetNSharedFaces() const;
/// Return the local face index for the given shared face.
int GetSharedFace(int sface) const;
/** @brief Returns the number of local faces according to the requested type,
does not count master non-conforming faces.
If type==Boundary returns only the number of true boundary faces contrary
to GetNBE() that returns all "boundary" elements which may include actual
interior faces. Similarly, if type==Interior, only the true interior
faces (including shared faces) are counted excluding all master
non-conforming faces. */
int GetNFbyType(FaceType type) const override;
void GenerateBoundaryElements() override
{ MFEM_ABORT("Generation of boundary elements works properly only on serial meshes."); }
/// See the remarks for the serial version in mesh.hpp
MFEM_DEPRECATED void ReorientTetMesh() override;
/// Utility function: sum integers from all processors (Allreduce).
long long ReduceInt(int value) const override;
/** Load balance the mesh by equipartitioning the global space-filling
sequence of elements. Works for nonconforming meshes only. */
void Rebalance();
/** Load balance a nonconforming mesh using a user-defined partition. Each
local element 'i' is migrated to processor rank 'partition[i]', for 0 <=
i < GetNE(). */
void Rebalance(const Array<int> &partition);
/** Save the mesh in a parallel mesh format. If @a comments is non-empty, it
will be printed after the first line of the file, and each line should
begin with '#'. */
void ParPrint(std::ostream &out, const std::string &comments = "") const;
// Enable Print() to add the parallel interface as boundary (typically used
// for visualization purposes)
void SetPrintShared(bool print) { print_shared = print; }
/** Print the part of the mesh in the calling processor using the mfem v1.0
format. Depending on SetPrintShared(), the parallel interface can be
added as boundary for visualization (true by default). If @a comments is
non-empty, it will be printed after the first line of the file, and each
line should begin with '#'. */
void Print(std::ostream &out = mfem::out,
const std::string &comments = "") const override;
/// Save the ParMesh to files (one for each MPI rank). The files will be
/// given suffixes according to the MPI rank. The mesh will be written to the
/// files using ParMesh::Print. The given @a precision will be used for ASCII
/// output.
void Save(const std::string &fname, int precision=16) const override;
#ifdef MFEM_USE_ADIOS2
/** Print the part of the mesh in the calling processor using adios2 bp
format. */
void Print(adios2stream &out) const override;
#endif
/** Print the part of the mesh in the calling processor adding the interface
as boundary (for visualization purposes) using Netgen/Truegrid format .*/
void PrintXG(std::ostream &out = mfem::out) const override;
/** Write the mesh to the stream 'out' on Process 0 in a form suitable for
visualization: the mesh is written as a disjoint mesh and the shared
boundary is added to the actual boundary; both the element and boundary
attributes are set to the processor number. If @a comments is non-empty,
it will be printed after the first line of the file, and each line should
begin with '#'. */
void PrintAsOne(std::ostream &out = mfem::out,
const std::string &comments = "") const;
/** Write the mesh to the stream 'out' on Process 0 as a serial mesh. The
output mesh does not have any duplication of vertices/nodes at processor
boundaries. If @a comments is non-empty, it will be printed after the
first line of the file, and each line should begin with '#'. */
void PrintAsSerial(std::ostream &out = mfem::out,
const std::string &comments = "") const;
/** Returns a Serial mesh on MPI rank @a save_rank that does not have any
duplication of vertices/nodes at processor boundaries. */
Mesh GetSerialMesh(int save_rank) const;
/// Save the mesh as a single file (using ParMesh::PrintAsOne). The given
/// @a precision is used for ASCII output.
void SaveAsOne(const std::string &fname, int precision=16) const;
/// Old mesh format (Netgen/Truegrid) version of 'PrintAsOne'
void PrintAsOneXG(std::ostream &out = mfem::out);
/** Print the mesh in parallel PVTU format. The PVTU and VTU files will be
stored in the directory specified by @a pathname. If the directory does
not exist, it will be created. */
void PrintVTU(std::string pathname,
VTKFormat format=VTKFormat::ASCII,
bool high_order_output=false,
int compression_level=0,
bool bdr_elements=false) override;
/// Parallel version of Mesh::Load().
void Load(std::istream &input, int generate_edges = 0,
int refine = 1, bool fix_orientation = true) override;
/// Returns the minimum and maximum corners of the mesh bounding box. For
/// high-order meshes, the geometry is refined first "ref" times.
void GetBoundingBox(Vector &p_min, Vector &p_max, int ref = 2);
void GetCharacteristics(real_t &h_min, real_t &h_max,
real_t &kappa_min, real_t &kappa_max);
/// Swaps internal data with another ParMesh, including non-geometry members.
/// See @a Mesh::Swap
void Swap(ParMesh &other);
/// Print various parallel mesh stats
void PrintInfo(std::ostream &out = mfem::out) override;
int FindPoints(DenseMatrix& point_mat, Array<int>& elem_ids,
Array<IntegrationPoint>& ips, bool warn = true,
InverseElementTransformation *inv_trans = NULL) override;
/// Debugging method
void PrintSharedEntities(const std::string &fname_prefix) const;
/** @brief Return true if the input array of refinements to be performed would
result in conflicting anisotropic directions on a face. Indices of
@a refinements entries are contained in @a conflicts, for marked elements
neighboring a face with a conflict.
The return value is globally MPI-reduced (true if any MPI process has a
conflict), whereas @a conflicts contains local indices of conflicting
entries of @a refinements. Conflicts are defined as anisotropic
refinements in different directions on a face shared by two elements.
Conflicts are checked for the mesh that would result from the input
refinements. If there are no conflicts, then the refinements can be
performed without forced refinements. This function is supported only for
3D meshes with all hexahedral elements. */
bool AnisotropicConflict(const Array<Refinement> &refinements,
std::set<int> &conflicts) const;
virtual ~ParMesh();
};
}
#endif // MFEM_USE_MPI
#endif