Skip to content
Snippets Groups Projects
gmsh_io.h 5.7 KiB
Newer Older
#pragma once

#include <vector>
#include <array>
#include <gmsh.h>
#include <type_traits>

#ifdef USE_MPI
#include <mpi/mpi.h>
#endif /* USE_MPI */
#include "entity.h"
Matteo Cicuttin's avatar
Matteo Cicuttin committed
#include "physical_element.h"

namespace g     = gmsh;
namespace go    = gmsh::option;
namespace gm    = gmsh::model;
namespace gmm   = gmsh::model::mesh;
namespace gmo   = gmsh::model::occ;
namespace gmg   = gmsh::model::geo;
namespace gv    = gmsh::view;

using gvp_t = gmsh::vectorpair;

/* Macros used to annotate GMSH integer inputs */
#define DIMENSION(x) x

std::string quadrature_name(int);
std::string basis_func_name(int);
std::string basis_grad_name(int);

using face_key = std::array<size_t, 3>;

enum class face_type : int
    BOUNDARY,
    INTERPROCESS_BOUNDARY
};

struct boundary_descriptor
{
    face_type   type;
    int         gmsh_entity;

    //auto operator <=> (const boundary_descriptor&) const = default;

    bool operator<(const boundary_descriptor& other) const
    {
        return (type < other.type) or
               ( (type == other.type) and (gmsh_entity < other.gmsh_entity) );
    }

    bool operator==(const boundary_descriptor& other) const
    {
        return (type == other.type) and (gmsh_entity == other.gmsh_entity);
    }

    boundary_descriptor()
        : type(face_type::NONE), gmsh_entity(0)
    {}
};

#if ((!defined(NDEBUG)) && defined(USE_MPI))
    #define ASSERT_MPI_RANK_0 {                 \
        int __rank;                             \
        MPI_Comm_rank(MPI_COMM_WORLD, &__rank); \
        assert(__rank == 0);                    \
    }
#else
    #define ASSERT_MPI_RANK_0 (void) 0
#endif

#define IMPLIES(a, b) ((not(a)) or (b))
#define IFF(a,b) (IMPLIES(a,b) and IMPLIES(b,a))

template<typename T>
void
priv_MPI_Bcast(std::vector<T>& vec, int root, MPI_Comm comm)
{
    static_assert(std::is_trivially_copyable<T>::value, "Type must be trivially copyable");

    int rank;
    MPI_Comm_rank(comm, &rank);

    if (rank == root)
    {
        size_t vsize = vec.size();
        MPI_Bcast(&vsize, 1, MPI_UNSIGNED_LONG_LONG, root, comm);
        MPI_Bcast(vec.data(), vec.size()*sizeof(T), MPI_PACKED, root, comm);
    }
    else
    {
        size_t vsize;
        MPI_Bcast(&vsize, 1, MPI_UNSIGNED_LONG_LONG, root, comm);
        vec.resize(vsize);
        MPI_Bcast(vec.data(), vec.size()*sizeof(T), MPI_PACKED, root, comm);
    }
}

template<typename T1, typename T2>
void
priv_MPI_Bcast(std::map<T1, std::vector<T2>>& map, int root, MPI_Comm comm)
{
    static_assert(std::is_trivially_copyable<T1>::value, "Type must be trivially copyable");
    static_assert(std::is_trivially_copyable<T2>::value, "Type must be trivially copyable");

    int rank;
    MPI_Comm_rank(comm, &rank);

    if (rank == root)
    {
        size_t msize = map.size();
        MPI_Bcast(&msize, 1, MPI_UNSIGNED_LONG_LONG, root, comm);
        for (auto& [l, rv] : map)
        {
            auto ll = l;
            MPI_Bcast(&ll, sizeof(T1), MPI_PACKED, root, comm);
            size_t vsize = rv.size();
            MPI_Bcast(&vsize, 1, MPI_UNSIGNED_LONG_LONG, root, comm);
            MPI_Bcast(rv.data(), vsize*sizeof(T2), MPI_PACKED, root, comm);
        }
    }
    else
    {
        size_t msize;
        MPI_Bcast(&msize, 1, MPI_UNSIGNED_LONG_LONG, root, comm);
        for (size_t i = 0; i < msize; i++)
        {
            T1 l;
            MPI_Bcast(&l, sizeof(T1), MPI_PACKED, root, comm);
            size_t vsize;
            MPI_Bcast(&vsize, 1, MPI_UNSIGNED_LONG_LONG, root, comm);
            std::vector<T2> rv;
            rv.resize(vsize);
            MPI_Bcast(rv.data(), vsize*sizeof(T2), MPI_PACKED, root, comm);
            map[l] = std::move(rv);
        }
    }
}

    int                                         geometric_order;
    int                                         approximation_order;
    int                                         num_partitions;
    std::map<int, std::vector<element_key>>     boundary_map;
    std::map<int, std::vector<int>>             comm_map;
    std::map<int, std::vector<int>>             partition_map;

    std::vector<entity>                         entities;
    std::vector<boundary_descriptor>            bnd_descriptors;
Matteo Cicuttin's avatar
Matteo Cicuttin committed
    element_connectivity<element_key>           conn;
    using entofs_pair = std::pair<size_t, size_t>;
    std::map<size_t, entofs_pair>               etag_to_entity_offset;

    void    map_boundaries(void);
    void    import_gmsh_entities(void);
Matteo Cicuttin's avatar
Matteo Cicuttin committed
    void    update_connectivity(const entity&, size_t);

    void    populate_from_gmsh_rank0(void);

#ifdef USE_MPI
    void    populate_from_gmsh_rankN(void);
#endif

    void    make_boundary_to_faces_map(void);
public:
    model();
    model(int, int);
    model(const char *);
    model(const char *, int, int);
    void build(void);
    void build(double);
    void generate_mesh(void);
    void generate_mesh(double);
    void partition_mesh(int);
    void populate_from_gmsh(void);

    const element_connectivity<element_key>& connectivity() const
    {
        return conn;
    }

    const std::vector<boundary_descriptor>& boundary_descriptors() const
    {
        return bnd_descriptors;
    }

    std::vector<element_key> get_bnd(size_t which)
    {
        return boundary_map.at(which);
    }

    size_t  num_dofs() const;
    size_t  num_fluxes() const;
    size_t  num_cells() const;
    size_t  num_faces() const;
Matteo Cicuttin's avatar
Matteo Cicuttin committed
    size_t  num_entities() const;
    std::vector<entity>::const_iterator begin() const;
    std::vector<entity>::const_iterator end() const;
    std::vector<entity>::iterator begin();
    std::vector<entity>::iterator end();

Matteo Cicuttin's avatar
Matteo Cicuttin committed
    entity&         entity_at(size_t);
    const entity&   entity_at(size_t) const;
    entofs_pair     lookup_tag(size_t tag) const;