1 // Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #ifndef MFEM_PUMI
13 #define MFEM_PUMI
14 
15 #include "../config/config.hpp"
16 
17 #ifdef MFEM_USE_PUMI
18 #ifdef MFEM_USE_MPI
19 
20 #include "../fem/fespace.hpp"
21 #include "../fem/gridfunc.hpp"
22 #include "../fem/pgridfunc.hpp"
23 #include "../fem/coefficient.hpp"
24 #include "../fem/bilininteg.hpp"
25 
26 #include <iostream>
27 #include <limits>
28 #include <ostream>
29 #include <string>
30 #include "mesh.hpp"
31 #include "pmesh.hpp"
32 
33 #include <apf.h>
34 #include <apfMesh2.h>
35 #include <apfShape.h>
36 #include <apfField.h>
37 #include <apfNumbering.h>
38 #include <apfDynamicVector.h>
39 
40 namespace mfem
41 {
42 
43 /// Base class for PUMI meshes
44 class PumiMesh : public Mesh
45 {
46 protected:
47    void CountBoundaryEntity(apf::Mesh2* apf_mesh, const int BcDim, int &NumBC);
48 
49    // Readers for PUMI mesh formats, used in the Load() method.
50    void ReadSCORECMesh(apf::Mesh2* apf_mesh, apf::Numbering* v_num_loc,
51                        const int curved);
52 
53 public:
54    /// Generate an MFEM mesh from a PUMI mesh.
55    PumiMesh(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1,
56             bool fix_orientation = true);
57 
58    using Mesh::Load;
59    /// Load a PUMI mesh (following the steps in the MFEM Load function).
60    void Load(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1,
61              bool fix_orientation = true);
62 
63    /// Destroys Mesh.
~PumiMesh()64    virtual ~PumiMesh() { }
65 };
66 
67 
68 /// Class for PUMI parallel meshes
69 class ParPumiMesh : public ParMesh
70 {
71 private:
72    // This has to persist during an adaptive simulation, and therefore
73    // needs to be updated each time the mesh changes.
74    apf::Numbering* v_num_loc;
75 
76 public:
77    /// Build a parallel MFEM mesh from a parallel PUMI mesh.
78    ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh,
79                int refine = 1, bool fix_orientation = true);
80 
81 
82    /// Returns the PUMI-to-MFEM permutation (aka rotation, aka orientation)
83    /** This represents the change in tet-to-vertex connectivity between
84        the PUMI and MFEM meshes. E.g.,
85        PUMI_tet{v0,v1,v2,v3}  --->  MFEM_tet{v1,v0,v3,v2}
86        * Note that change in the orientation can be caused by
87          a) fixing wrong boundary element orientations
88          b) a call to ReorientTetMesh() which is required for Nedelec */
89    int RotationPUMItoMFEM(apf::Mesh2* apf_mesh,
90                           apf::MeshEntity* tet,
91                           int elemId);
92    /// Convert the parent coordinate from PUMI to MFEM
93    /** By default this functions assumes that there is always
94        change in the orientations of some of the elements. In case it
95        is known for sure that there is NO change in the orientation,
96        call the functions with last argument = false */
97    IntegrationRule ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh,
98                                        apf::MeshEntity* tet,
99                                        int elemId,
100                                        apf::NewArray<apf::Vector3>& pumi_xi,
101                                        bool checkOrientation = true);
102    /// Convert the parent coordinate from MFEM to PUMI
103    /** This is the inverse of ParentXisPUMItoMFEM.
104        By default this functions assumes that there is always
105        change in the orientations of some of the elements. In case it
106        is known for sure that there is NO change in the orientation,
107        call the functions with last argument = false */
108    void ParentXisMFEMtoPUMI(apf::Mesh2* apf_mesh,
109                             int elemId,
110                             apf::MeshEntity* tet,
111                             const IntegrationRule& mfem_xi,
112                             apf::NewArray<apf::Vector3>& pumi_xi,
113                             bool checkOrientation = true);
114    /// Transfer field from MFEM mesh to PUMI mesh [Mixed].
115    void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
116                         ParGridFunction* grid_vel,
117                         ParGridFunction* grid_pr,
118                         apf::Field* vel_field,
119                         apf::Field* pr_field,
120                         apf::Field* vel_mag_field);
121 
122    /// Transfer field from MFEM mesh to PUMI mesh [Scalar].
123    void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
124                         ParGridFunction* grid_pr,
125                         apf::Field* pr_field,
126                         apf::Field* pr_mag_field);
127 
128    /// Transfer field from MFEM mesh to PUMI mesh [Vector].
129    void VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
130                               ParGridFunction* grid_vel,
131                               apf::Field* vel_field,
132                               apf::Field* vel_mag_field);
133 
134    /// Transfer Nedelec field from MFEM mesh to PUMI mesh [Vector].
135    void NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh,
136                                ParGridFunction* gf,
137                                apf::Field* nedelec_field);
138 
139    /// Update the mesh after adaptation.
140    void UpdateMesh(const ParMesh* AdaptedpMesh);
141 
142    /// Transfer a field from PUMI to MFEM after mesh adapt [Scalar and Vector].
143    void FieldPUMItoMFEM(apf::Mesh2* apf_mesh,
144                         apf::Field* field,
145                         ParGridFunction* grid);
146 
~ParPumiMesh()147    virtual ~ParPumiMesh() {}
148 };
149 
150 
151 /// Class for PUMI grid functions
152 class GridFunctionPumi : public GridFunction
153 {
154 public:
155    /// Construct a GridFunction from a PUMI mesh.
156    GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM, apf::Numbering* v_num_loc,
157                     const int mesh_order);
158 
159    /// Destroy the grid function.
~GridFunctionPumi()160    virtual ~GridFunctionPumi() { }
161 };
162 
163 } // namespace mfem
164 
165 #endif // MFEM_USE_MPI
166 #endif // MFEM_USE_PUMI
167 
168 #endif
169