// Copyright (c) 2010-2023, 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. #include "gmsh.hpp" #include "vtk.hpp" namespace mfem { int BarycentricToGmshTet(int *b, int ref) { int i = b[0]; int j = b[1]; int k = b[2]; int l = b[3]; bool ibdr = (i == 0); bool jbdr = (j == 0); bool kbdr = (k == 0); bool lbdr = (l == 0); if (ibdr && jbdr && kbdr) { return 0; } else if (jbdr && kbdr && lbdr) { return 1; } else if (ibdr && kbdr && lbdr) { return 2; } else if (ibdr && jbdr && lbdr) { return 3; } int offset = 4; if (jbdr && kbdr) // Edge DOF on j == 0 and k == 0 { return offset + i - 1; } else if (kbdr && lbdr) // Edge DOF on k == 0 and l == 0 { return offset + ref - 1 + j - 1; } else if (ibdr && kbdr) // Edge DOF on i == 0 and k == 0 { return offset + 2 * (ref - 1) + ref - j - 1; } else if (ibdr && jbdr) // Edge DOF on i == 0 and j == 0 { return offset + 3 * (ref - 1) + ref - k - 1; } else if (ibdr && lbdr) // Edge DOF on i == 0 and l == 0 { return offset + 4 * (ref - 1) + ref - k - 1; } else if (jbdr && lbdr) // Edge DOF on j == 0 and l == 0 { return offset + 5 * (ref - 1) + ref - k - 1; } // Recursive numbering for the faces offset += 6 * (ref - 1); if (kbdr) { int b_out[3]; b_out[0] = j-1; b_out[1] = i-1; b_out[2] = ref - i - j - 1; return offset + BarycentricToVTKTriangle(b_out, ref-3); } else if (jbdr) { int b_out[3]; b_out[0] = i-1; b_out[1] = k-1; b_out[2] = ref - i - k - 1; offset += (ref - 1) * (ref - 2) / 2; return offset + BarycentricToVTKTriangle(b_out, ref-3); } else if (ibdr) { int b_out[3]; b_out[0] = k-1; b_out[1] = j-1; b_out[2] = ref - j - k - 1; offset += (ref - 1) * (ref - 2); return offset + BarycentricToVTKTriangle(b_out, ref-3); } else if (lbdr) { int b_out[3]; b_out[0] = ref-j-k-1; b_out[1] = j-1; b_out[2] = k-1; offset += 3 * (ref - 1) * (ref - 2) / 2; return offset + BarycentricToVTKTriangle(b_out, ref-3); } // Recursive numbering for interior { int b_out[4]; b_out[0] = i-1; b_out[1] = j-1; b_out[2] = k-1; b_out[3] = ref - i - j - k - 1; offset += 2 * (ref - 1) * (ref - 2); return offset + BarycentricToGmshTet(b_out, ref-4); } } int CartesianToGmshQuad(int idx_in[], int ref) { int i = idx_in[0]; int j = idx_in[1]; // Do we lie on any of the edges bool ibdr = (i == 0 || i == ref); bool jbdr = (j == 0 || j == ref); if (ibdr && jbdr) // Vertex DOF { return (i ? (j ? 2 : 1) : (j ? 3 : 0)); } int offset = 4; if (jbdr) // Edge DOF on j==0 or j==ref { return offset + (j ? 3*ref - 3 - i : i - 1); } else if (ibdr) // Edge DOF on i==0 or i==ref { return offset + (i ? ref - 1 + j - 1 : 4*ref - 4 - j); } else // Recursive numbering for interior { int idx_out[2]; idx_out[0] = i-1; idx_out[1] = j-1; offset += 4 * (ref - 1); return offset + CartesianToGmshQuad(idx_out, ref-2); } } int CartesianToGmshHex(int idx_in[], int ref) { int i = idx_in[0]; int j = idx_in[1]; int k = idx_in[2]; // Do we lie on any of the edges bool ibdr = (i == 0 || i == ref); bool jbdr = (j == 0 || j == ref); bool kbdr = (k == 0 || k == ref); if (ibdr && jbdr && kbdr) // Vertex DOF { return (i ? (j ? (k ? 6 : 2) : (k ? 5 : 1)) : (j ? (k ? 7 : 3) : (k ? 4 : 0))); } int offset = 8; if (jbdr && kbdr) // Edge DOF on x-directed edge { return offset + (j ? (k ? 12*ref-12-i: 6*ref-6-i) : (k ? 8*ref-9+i: i-1)); } else if (ibdr && kbdr) // Edge DOF on y-directed edge { return offset + (k ? (i ? 10*ref-11+j: 9*ref-10+j) : (i ? 3*ref-4+j: ref-2+j)); } else if (ibdr && jbdr) // Edge DOF on z-directed edge { return offset + (i ? (j ? 6*ref-7+k: 4*ref-5+k) : (j ? 7*ref-8+k: 2*ref-3+k)); } else if (ibdr) // Face DOF on x-directed face { int idx_out[2]; idx_out[0] = i ? j-1 : k-1; idx_out[1] = i ? k-1 : j-1; offset += (12 + (i ? 3 : 2) * (ref - 1)) * (ref - 1); return offset + CartesianToGmshQuad(idx_out, ref-2); } else if (jbdr) // Face DOF on y-directed face { int idx_out[2]; idx_out[0] = j ? ref-i-1 : i-1; idx_out[1] = j ? k-1 : k-1; offset += (12 + (j ? 4 : 1) * (ref - 1)) * (ref - 1); return offset + CartesianToGmshQuad(idx_out, ref-2); } else if (kbdr) // Face DOF on z-directed face { int idx_out[2]; idx_out[0] = k ? i-1 : j-1; idx_out[1] = k ? j-1 : i-1; offset += (12 + (k ? 5 : 0) * (ref - 1)) * (ref - 1); return offset + CartesianToGmshQuad(idx_out, ref-2); } else // Recursive numbering for interior { int idx_out[3]; idx_out[0] = i-1; idx_out[1] = j-1; idx_out[2] = k-1; offset += (12 + 6 * (ref - 1)) * (ref - 1); return offset + CartesianToGmshHex(idx_out, ref-2); } } int WedgeToGmshPri(int idx_in[], int ref) { int i = idx_in[0]; int j = idx_in[1]; int k = idx_in[2]; int l = ref - i -j; bool ibdr = (i == 0); bool jbdr = (j == 0); bool kbdr = (k == 0 || k == ref); bool lbdr = (l == 0); if (ibdr && jbdr && kbdr) { return k ? 3 : 0; } else if (jbdr && lbdr && kbdr) { return k ? 4 : 1; } else if (ibdr && lbdr && kbdr) { return k ? 5 : 2; } int offset = 6; if (jbdr && kbdr) { return offset + (k ? 6 * (ref - 1) + i - 1: i - 1); } else if (ibdr && kbdr) { return offset + (k ? 7 * (ref -1) + j-1 : ref - 1 + j - 1); } else if (ibdr && jbdr) { return offset + 2 * (ref - 1) + k - 1; } else if (lbdr && kbdr) { return offset + (k ? 8 * (ref -1) + j - 1 : 3 * (ref - 1) + j - 1); } else if (jbdr && lbdr) { return offset + 4 * (ref - 1) + k - 1; } else if (ibdr && lbdr) { return offset + 5 * (ref - 1) + k - 1; } offset += 9 * (ref-1); if (kbdr) // Triangular faces at k=0 and k=ref { int b_out[3]; b_out[0] = k ? i-1 : j-1; b_out[1] = k ? j-1 : i-1; b_out[2] = ref - i - j - 1; offset += k ? (ref-1)*(ref-2) / 2: 0; return offset + BarycentricToVTKTriangle(b_out, ref-3); } offset += (ref-1)*(ref-2); if (jbdr) // Quadrilateral face at j=0 { int idx_out[2]; idx_out[0] = i-1; idx_out[1] = k-1; return offset + CartesianToGmshQuad(idx_out, ref-2); } else if (ibdr) // Quadrilateral face at i=0 { int idx_out[2]; idx_out[0] = k-1; idx_out[1] = j-1; offset += (ref-1)*(ref-1); return offset + CartesianToGmshQuad(idx_out, ref-2); } else if (lbdr) // Quadrilateral face at l=ref-i-j=0 { int idx_out[2]; idx_out[0] = j-1; idx_out[1] = k-1; offset += 2*(ref-1)*(ref-1); return offset + CartesianToGmshQuad(idx_out, ref-2); } offset += 3*(ref-1)*(ref-1); // The Gmsh Prism interiors are a tensor product of segments of order ref-2 // and triangles of order ref-3 { int b_out[3]; b_out[0] = i-1; b_out[1] = j-1; b_out[2] = ref - i - j - 1; int ot = BarycentricToVTKTriangle(b_out, ref-3); int os = (k==1) ? 0 : (k == ref-1 ? 1 : k); return offset + (ref-1) * ot + os; } } int CartesianToGmshPyramid(int idx_in[], int ref) { int i = idx_in[0]; int j = idx_in[1]; int k = idx_in[2]; // Do we lie on any of the edges bool ibdr = (i == 0 || i == ref-k); bool jbdr = (j == 0 || j == ref-k); bool kbdr = (k == 0); if (ibdr && jbdr && kbdr) { return i ? (j ? 2 : 1): (j ? 3 : 0); } else if (k == ref) { return 4; } int offset = 5; if (jbdr && kbdr) { return offset + (j ? (6 * ref - 6 - i) : (i - 1)); } else if (ibdr && kbdr) { return offset + (i ? (3 * ref - 4 + j) : (ref - 2 + j)); } else if (ibdr && jbdr) { return offset + (i ? (j ? 6 : 4) : (j ? 7 : 2 )) * (ref-1) + k - 1; } offset += 8*(ref-1); if (jbdr) { int b_out[3]; b_out[0] = j ? ref - i - k - 1 : i - 1; b_out[1] = k - 1; b_out[2] = (j ? i - 1 : ref - i - k - 1); offset += (j ? 3 : 0) * (ref - 1) * (ref - 2) / 2; return offset + BarycentricToVTKTriangle(b_out, ref-3); } else if (ibdr) { int b_out[3]; b_out[0] = i ? j - 1: ref - j - k - 1; b_out[1] = k - 1; b_out[2] = (i ? ref - j - k - 1: j - 1); offset += (i ? 2 : 1) * (ref - 1) * (ref - 2) / 2; return offset + BarycentricToVTKTriangle(b_out, ref-3); } else if (kbdr) { int idx_out[2]; idx_out[0] = k ? i-1 : j-1; idx_out[1] = k ? j-1 : i-1; offset += 2 * (ref - 1) * (ref - 2); return offset + CartesianToGmshQuad(idx_out, ref-2); } offset += (2 * (ref - 2) + (ref - 1)) * (ref - 1) ; { int idx_out[3]; idx_out[0] = i-1; idx_out[1] = j-1; idx_out[2] = k-1; return offset + CartesianToGmshPyramid(idx_out, ref-3); } } void GmshHOSegmentMapping(int order, int *map) { map[0] = 0; map[order] = 1; for (int i=1; i