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