15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors. 298285ab4SZach Atkins // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 398285ab4SZach Atkins // 498285ab4SZach Atkins // SPDX-License-Identifier: BSD-2-Clause 598285ab4SZach Atkins // 698285ab4SZach Atkins // This file is part of CEED: http://github.com/ceed 798285ab4SZach Atkins 8e83e87a5Sjeremylt #include "../include/petscutils.h" 9e83e87a5Sjeremylt 10e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 11e83e87a5Sjeremylt // Convert PETSc MemType to libCEED MemType 12e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 132b730f8bSJeremy L Thompson CeedMemType MemTypeP2C(PetscMemType mem_type) { return PetscMemTypeDevice(mem_type) ? CEED_MEM_DEVICE : CEED_MEM_HOST; } 14e83e87a5Sjeremylt 15b6972d74SZach Atkins // ------------------------------------------------------------------------------------------------ 16b6972d74SZach Atkins // PETSc-libCEED memory space utilities 17b6972d74SZach Atkins // ------------------------------------------------------------------------------------------------ 18b6972d74SZach Atkins PetscErrorCode VecP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed) { 19b6972d74SZach Atkins PetscScalar *x; 20b6972d74SZach Atkins 21b6972d74SZach Atkins PetscFunctionBeginUser; 22b6972d74SZach Atkins PetscCall(VecGetArrayAndMemType(X_petsc, &x, mem_type)); 23b6972d74SZach Atkins CeedVectorSetArray(x_ceed, MemTypeP2C(*mem_type), CEED_USE_POINTER, x); 24b6972d74SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 25b6972d74SZach Atkins } 26b6972d74SZach Atkins 27b6972d74SZach Atkins PetscErrorCode VecC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc) { 28b6972d74SZach Atkins PetscScalar *x; 29b6972d74SZach Atkins 30b6972d74SZach Atkins PetscFunctionBeginUser; 31b6972d74SZach Atkins CeedVectorTakeArray(x_ceed, MemTypeP2C(mem_type), &x); 32b6972d74SZach Atkins PetscCall(VecRestoreArrayAndMemType(X_petsc, &x)); 33b6972d74SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 34b6972d74SZach Atkins } 35b6972d74SZach Atkins 36b6972d74SZach Atkins PetscErrorCode VecReadP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed) { 37b6972d74SZach Atkins PetscScalar *x; 38b6972d74SZach Atkins 39b6972d74SZach Atkins PetscFunctionBeginUser; 40b6972d74SZach Atkins PetscCall(VecGetArrayReadAndMemType(X_petsc, (const PetscScalar **)&x, mem_type)); 41b6972d74SZach Atkins CeedVectorSetArray(x_ceed, MemTypeP2C(*mem_type), CEED_USE_POINTER, x); 42b6972d74SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 43b6972d74SZach Atkins } 44b6972d74SZach Atkins 45b6972d74SZach Atkins PetscErrorCode VecReadC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc) { 46b6972d74SZach Atkins PetscScalar *x; 47b6972d74SZach Atkins 48b6972d74SZach Atkins PetscFunctionBeginUser; 49b6972d74SZach Atkins CeedVectorTakeArray(x_ceed, MemTypeP2C(mem_type), &x); 50b6972d74SZach Atkins PetscCall(VecRestoreArrayReadAndMemType(X_petsc, (const PetscScalar **)&x)); 51b6972d74SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 52b6972d74SZach Atkins } 53b6972d74SZach Atkins 54e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 552c58efb6Sjeremylt // Apply 3D Kershaw mesh transformation 562c58efb6Sjeremylt // ----------------------------------------------------------------------------- 572c58efb6Sjeremylt // Transition from a value of "a" for x=0, to a value of "b" for x=1. Optionally 582c58efb6Sjeremylt // smooth -- see the commented versions at the end. 592c58efb6Sjeremylt static double step(const double a, const double b, double x) { 602c58efb6Sjeremylt if (x <= 0) return a; 612c58efb6Sjeremylt if (x >= 1) return b; 622c58efb6Sjeremylt return a + (b - a) * (x); 632c58efb6Sjeremylt } 642c58efb6Sjeremylt 652c58efb6Sjeremylt // 1D transformation at the right boundary 662b730f8bSJeremy L Thompson static double right(const double eps, const double x) { return (x <= 0.5) ? (2 - eps) * x : 1 + eps * (x - 1); } 672c58efb6Sjeremylt 682c58efb6Sjeremylt // 1D transformation at the left boundary 692b730f8bSJeremy L Thompson static double left(const double eps, const double x) { return 1 - right(eps, 1 - x); } 702c58efb6Sjeremylt 712c58efb6Sjeremylt // Apply 3D Kershaw mesh transformation 722c58efb6Sjeremylt // The eps parameters are in (0, 1] 732c58efb6Sjeremylt // Uniform mesh is recovered for eps=1 749b072555Sjeremylt PetscErrorCode Kershaw(DM dm_orig, PetscScalar eps) { 752c58efb6Sjeremylt Vec coord; 762c58efb6Sjeremylt PetscInt ncoord; 772c58efb6Sjeremylt PetscScalar *c; 782c58efb6Sjeremylt 792c58efb6Sjeremylt PetscFunctionBeginUser; 802b730f8bSJeremy L Thompson PetscCall(DMGetCoordinatesLocal(dm_orig, &coord)); 812b730f8bSJeremy L Thompson PetscCall(VecGetLocalSize(coord, &ncoord)); 822b730f8bSJeremy L Thompson PetscCall(VecGetArray(coord, &c)); 832c58efb6Sjeremylt 842c58efb6Sjeremylt for (PetscInt i = 0; i < ncoord; i += 3) { 852c58efb6Sjeremylt PetscScalar x = c[i], y = c[i + 1], z = c[i + 2]; 862c58efb6Sjeremylt PetscInt layer = x * 6; 872c58efb6Sjeremylt PetscScalar lambda = (x - layer / 6.0) * 6; 882c58efb6Sjeremylt c[i] = x; 892c58efb6Sjeremylt 902c58efb6Sjeremylt switch (layer) { 912c58efb6Sjeremylt case 0: 922c58efb6Sjeremylt c[i + 1] = left(eps, y); 932c58efb6Sjeremylt c[i + 2] = left(eps, z); 942c58efb6Sjeremylt break; 952c58efb6Sjeremylt case 1: 962c58efb6Sjeremylt case 4: 972c58efb6Sjeremylt c[i + 1] = step(left(eps, y), right(eps, y), lambda); 982c58efb6Sjeremylt c[i + 2] = step(left(eps, z), right(eps, z), lambda); 992c58efb6Sjeremylt break; 1002c58efb6Sjeremylt case 2: 1012c58efb6Sjeremylt c[i + 1] = step(right(eps, y), left(eps, y), lambda / 2); 1022c58efb6Sjeremylt c[i + 2] = step(right(eps, z), left(eps, z), lambda / 2); 1032c58efb6Sjeremylt break; 1042c58efb6Sjeremylt case 3: 1052c58efb6Sjeremylt c[i + 1] = step(right(eps, y), left(eps, y), (1 + lambda) / 2); 1062c58efb6Sjeremylt c[i + 2] = step(right(eps, z), left(eps, z), (1 + lambda) / 2); 1072c58efb6Sjeremylt break; 1082c58efb6Sjeremylt default: 1092c58efb6Sjeremylt c[i + 1] = right(eps, y); 1102c58efb6Sjeremylt c[i + 2] = right(eps, z); 1112c58efb6Sjeremylt } 1122c58efb6Sjeremylt } 1132b730f8bSJeremy L Thompson PetscCall(VecRestoreArray(coord, &c)); 114ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 1152c58efb6Sjeremylt } 1162c58efb6Sjeremylt 1172c58efb6Sjeremylt // ----------------------------------------------------------------------------- 118e83e87a5Sjeremylt // Create BC label 119e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 120e83e87a5Sjeremylt static PetscErrorCode CreateBCLabel(DM dm, const char name[]) { 121e83e87a5Sjeremylt DMLabel label; 122e83e87a5Sjeremylt 123e83e87a5Sjeremylt PetscFunctionBeginUser; 124751eb813Srezgarshakeri PetscCall(DMCreateLabel(dm, name)); 125751eb813Srezgarshakeri PetscCall(DMGetLabel(dm, name, &label)); 126751eb813Srezgarshakeri PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, label)); 127751eb813Srezgarshakeri PetscCall(DMPlexLabelComplete(dm, label)); 128ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 129fd8f24faSSebastian Grimberg } 130e83e87a5Sjeremylt 131e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 132e83e87a5Sjeremylt // This function sets up a DM for a given degree 133e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 1342b730f8bSJeremy L Thompson PetscErrorCode SetupDMByDegree(DM dm, PetscInt p_degree, PetscInt q_extra, PetscInt num_comp_u, PetscInt dim, bool enforce_bc) { 1352b730f8bSJeremy L Thompson PetscInt marker_ids[1] = {1}; 136de1229c5Srezgarshakeri PetscInt q_degree = p_degree + q_extra; 137e83e87a5Sjeremylt PetscFE fe; 13865233696SJeremy L Thompson MPI_Comm comm; 139129d8736Srezgarshakeri PetscBool is_simplex = PETSC_TRUE; 140e83e87a5Sjeremylt 141e83e87a5Sjeremylt PetscFunctionBeginUser; 142129d8736Srezgarshakeri // Check if simplex or tensor-product mesh 1432b730f8bSJeremy L Thompson PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 144e83e87a5Sjeremylt // Setup FE 1452b730f8bSJeremy L Thompson PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1462b730f8bSJeremy L Thompson PetscCall(PetscFECreateLagrange(comm, dim, num_comp_u, is_simplex, p_degree, q_degree, &fe)); 1472b730f8bSJeremy L Thompson PetscCall(DMAddField(dm, NULL, (PetscObject)fe)); 1482b730f8bSJeremy L Thompson PetscCall(DMCreateDS(dm)); 149129d8736Srezgarshakeri 150129d8736Srezgarshakeri { 151129d8736Srezgarshakeri // create FE field for coordinates 1527ed3e4cdSJeremy L Thompson PetscFE fe_coords; 1537ed3e4cdSJeremy L Thompson PetscInt num_comp_coord; 1542b730f8bSJeremy L Thompson PetscCall(DMGetCoordinateDim(dm, &num_comp_coord)); 1552b730f8bSJeremy L Thompson PetscCall(PetscFECreateLagrange(comm, dim, num_comp_coord, is_simplex, 1, q_degree, &fe_coords)); 15649a40c8aSKenneth E. Jansen PetscCall(DMSetCoordinateDisc(dm, fe_coords, PETSC_TRUE)); 1572b730f8bSJeremy L Thompson PetscCall(PetscFEDestroy(&fe_coords)); 1587ed3e4cdSJeremy L Thompson } 159de1229c5Srezgarshakeri 160ab1ff315Srezgarshakeri // Setup Dirichlet BC 161ab1ff315Srezgarshakeri // Note bp1, bp2 are projection and we don't need to apply BC 162ab1ff315Srezgarshakeri // For bp3,bp4, the target function is zero on the boundaries 163ab1ff315Srezgarshakeri // So we pass bcFunc = NULL in DMAddBoundary function 1649b072555Sjeremylt if (enforce_bc) { 1659b072555Sjeremylt PetscBool has_label; 166b6972d74SZach Atkins PetscCall(DMHasLabel(dm, "marker", &has_label)); 1672b730f8bSJeremy L Thompson if (!has_label) { 168b6972d74SZach Atkins PetscCall(CreateBCLabel(dm, "marker")); 1692b730f8bSJeremy L Thompson } 17069f5adf1Sjeremylt DMLabel label; 1712b730f8bSJeremy L Thompson PetscCall(DMGetLabel(dm, "marker", &label)); 1722b730f8bSJeremy L Thompson PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, marker_ids, 0, 0, NULL, NULL, NULL, NULL, NULL)); 173751eb813Srezgarshakeri PetscCall(DMSetOptionsPrefix(dm, "final_")); 174751eb813Srezgarshakeri PetscCall(DMViewFromOptions(dm, NULL, "-dm_view")); 175e83e87a5Sjeremylt } 176129d8736Srezgarshakeri 177129d8736Srezgarshakeri if (!is_simplex) { 178129d8736Srezgarshakeri DM dm_coord; 1792b730f8bSJeremy L Thompson PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 1802b730f8bSJeremy L Thompson PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 1812b730f8bSJeremy L Thompson PetscCall(DMPlexSetClosurePermutationTensor(dm_coord, PETSC_DETERMINE, NULL)); 182129d8736Srezgarshakeri } 1832b730f8bSJeremy L Thompson PetscCall(PetscFEDestroy(&fe)); 184ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 185fd8f24faSSebastian Grimberg } 186e83e87a5Sjeremylt 187e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 188e83e87a5Sjeremylt // Get CEED restriction data from DMPlex 189e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 1902b730f8bSJeremy L Thompson PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt height, DMLabel domain_label, CeedInt value, CeedElemRestriction *elem_restr) { 191*4d00b080SJeremy L Thompson PetscInt num_elem, elem_size, num_dof, num_comp, *elem_restr_offsets_petsc; 192*4d00b080SJeremy L Thompson CeedInt *elem_restr_offsets_ceed; 193e83e87a5Sjeremylt 194e83e87a5Sjeremylt PetscFunctionBeginUser; 195*4d00b080SJeremy L Thompson PetscCall(DMPlexGetLocalOffsets(dm, domain_label, value, height, 0, &num_elem, &elem_size, &num_comp, &num_dof, &elem_restr_offsets_petsc)); 196e83e87a5Sjeremylt 197*4d00b080SJeremy L Thompson PetscCall(IntArrayPetscToCeed(num_elem * elem_size, &elem_restr_offsets_petsc, &elem_restr_offsets_ceed)); 198*4d00b080SJeremy L Thompson CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp, 1, num_dof, CEED_MEM_HOST, CEED_COPY_VALUES, elem_restr_offsets_ceed, elem_restr); 199*4d00b080SJeremy L Thompson PetscCall(PetscFree(elem_restr_offsets_ceed)); 200ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 201fd8f24faSSebastian Grimberg } 202e83e87a5Sjeremylt 203e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 204129d8736Srezgarshakeri // Utility function - convert from DMPolytopeType to CeedElemTopology 205129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 206de1229c5Srezgarshakeri CeedElemTopology ElemTopologyP2C(DMPolytopeType cell_type) { 207129d8736Srezgarshakeri switch (cell_type) { 2082b730f8bSJeremy L Thompson case DM_POLYTOPE_TRIANGLE: 2092b730f8bSJeremy L Thompson return CEED_TOPOLOGY_TRIANGLE; 2102b730f8bSJeremy L Thompson case DM_POLYTOPE_QUADRILATERAL: 2112b730f8bSJeremy L Thompson return CEED_TOPOLOGY_QUAD; 2122b730f8bSJeremy L Thompson case DM_POLYTOPE_TETRAHEDRON: 2132b730f8bSJeremy L Thompson return CEED_TOPOLOGY_TET; 2142b730f8bSJeremy L Thompson case DM_POLYTOPE_HEXAHEDRON: 2152b730f8bSJeremy L Thompson return CEED_TOPOLOGY_HEX; 2162b730f8bSJeremy L Thompson default: 2172b730f8bSJeremy L Thompson return 0; 218129d8736Srezgarshakeri } 219129d8736Srezgarshakeri } 220129d8736Srezgarshakeri 221129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 222f755c37aSrezgarshakeri // Convert DM field to DS field 223129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 2242b730f8bSJeremy L Thompson PetscErrorCode DMFieldToDSField(DM dm, DMLabel domain_label, PetscInt dm_field, PetscInt *ds_field) { 225129d8736Srezgarshakeri PetscDS ds; 226129d8736Srezgarshakeri IS field_is; 227129d8736Srezgarshakeri const PetscInt *fields; 228129d8736Srezgarshakeri PetscInt num_fields; 229129d8736Srezgarshakeri 230f755c37aSrezgarshakeri PetscFunctionBeginUser; 231129d8736Srezgarshakeri // Translate dm_field to ds_field 232baf96a30SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, &field_is, &ds, NULL)); 233f755c37aSrezgarshakeri PetscCall(ISGetIndices(field_is, &fields)); 234f755c37aSrezgarshakeri PetscCall(ISGetSize(field_is, &num_fields)); 235129d8736Srezgarshakeri for (PetscInt i = 0; i < num_fields; i++) { 236129d8736Srezgarshakeri if (dm_field == fields[i]) { 237f755c37aSrezgarshakeri *ds_field = i; 238129d8736Srezgarshakeri break; 239129d8736Srezgarshakeri } 240129d8736Srezgarshakeri } 241f755c37aSrezgarshakeri PetscCall(ISRestoreIndices(field_is, &fields)); 242f755c37aSrezgarshakeri 2432b730f8bSJeremy L Thompson if (*ds_field == -1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Could not find dm_field %" PetscInt_FMT " in DS", dm_field); 244ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 245129d8736Srezgarshakeri } 246129d8736Srezgarshakeri 247f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 248f755c37aSrezgarshakeri // Create libCEED Basis from PetscTabulation 249f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 2502b730f8bSJeremy L Thompson PetscErrorCode BasisCreateFromTabulation(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height, PetscInt face, PetscFE fe, 2512b730f8bSJeremy L Thompson PetscTabulation basis_tabulation, PetscQuadrature quadrature, CeedBasis *basis) { 252f755c37aSrezgarshakeri PetscInt first_point; 253129d8736Srezgarshakeri PetscInt ids[1] = {label_value}; 254129d8736Srezgarshakeri DMLabel depth_label; 255129d8736Srezgarshakeri DMPolytopeType cell_type; 256129d8736Srezgarshakeri CeedElemTopology elem_topo; 257f755c37aSrezgarshakeri PetscScalar *q_points, *interp, *grad; 258f755c37aSrezgarshakeri const PetscScalar *q_weights; 259f755c37aSrezgarshakeri PetscDualSpace dual_space; 260f755c37aSrezgarshakeri PetscInt num_dual_basis_vectors; 261f755c37aSrezgarshakeri PetscInt dim, num_comp, P, Q; 262f755c37aSrezgarshakeri 263f755c37aSrezgarshakeri PetscFunctionBeginUser; 264f755c37aSrezgarshakeri // General basis information 265f755c37aSrezgarshakeri PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 266f755c37aSrezgarshakeri PetscCall(PetscFEGetNumComponents(fe, &num_comp)); 267f755c37aSrezgarshakeri PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 268f755c37aSrezgarshakeri PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors)); 269f755c37aSrezgarshakeri P = num_dual_basis_vectors / num_comp; 270129d8736Srezgarshakeri 271129d8736Srezgarshakeri // Use depth label if no domain label present 272129d8736Srezgarshakeri if (!domain_label) { 273129d8736Srezgarshakeri PetscInt depth; 274129d8736Srezgarshakeri 275f755c37aSrezgarshakeri PetscCall(DMPlexGetDepth(dm, &depth)); 276f755c37aSrezgarshakeri PetscCall(DMPlexGetDepthLabel(dm, &depth_label)); 277129d8736Srezgarshakeri ids[0] = depth - height; 278129d8736Srezgarshakeri } 279f755c37aSrezgarshakeri 280129d8736Srezgarshakeri // Get cell interp, grad, and quadrature data 2812b730f8bSJeremy L Thompson PetscCall(DMGetFirstLabeledPoint(dm, dm, domain_label ? domain_label : depth_label, 1, ids, height, &first_point, NULL)); 282f755c37aSrezgarshakeri PetscCall(DMPlexGetCellType(dm, first_point, &cell_type)); 283129d8736Srezgarshakeri elem_topo = ElemTopologyP2C(cell_type); 2842b730f8bSJeremy L Thompson if (!elem_topo) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMPlex topology not supported"); 285f755c37aSrezgarshakeri { 286f755c37aSrezgarshakeri size_t q_points_size; 287f755c37aSrezgarshakeri const PetscScalar *q_points_petsc; 288f755c37aSrezgarshakeri PetscInt q_dim; 289f755c37aSrezgarshakeri 2902b730f8bSJeremy L Thompson PetscCall(PetscQuadratureGetData(quadrature, &q_dim, NULL, &Q, &q_points_petsc, &q_weights)); 291f755c37aSrezgarshakeri q_points_size = Q * dim * sizeof(CeedScalar); 292f755c37aSrezgarshakeri PetscCall(PetscCalloc(q_points_size, &q_points)); 293f755c37aSrezgarshakeri for (PetscInt q = 0; q < Q; q++) { 2942b730f8bSJeremy L Thompson for (PetscInt d = 0; d < q_dim; d++) q_points[q * dim + d] = q_points_petsc[q * q_dim + d]; 295f755c37aSrezgarshakeri } 296f755c37aSrezgarshakeri } 297f755c37aSrezgarshakeri 298129d8736Srezgarshakeri // Convert to libCEED orientation 299f755c37aSrezgarshakeri { 300f755c37aSrezgarshakeri PetscBool is_simplex = PETSC_FALSE; 301f755c37aSrezgarshakeri IS permutation = NULL; 302f755c37aSrezgarshakeri const PetscInt *permutation_indices; 303f755c37aSrezgarshakeri 304f755c37aSrezgarshakeri PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 305f755c37aSrezgarshakeri if (!is_simplex) { 306f755c37aSrezgarshakeri PetscSection section; 307f755c37aSrezgarshakeri 308f755c37aSrezgarshakeri // -- Get permutation 309f755c37aSrezgarshakeri PetscCall(DMGetLocalSection(dm, §ion)); 3102b730f8bSJeremy L Thompson PetscCall(PetscSectionGetClosurePermutation(section, (PetscObject)dm, dim, num_comp * P, &permutation)); 311f755c37aSrezgarshakeri PetscCall(ISGetIndices(permutation, &permutation_indices)); 312f755c37aSrezgarshakeri } 313f755c37aSrezgarshakeri 314f755c37aSrezgarshakeri // -- Copy interp, grad matrices 315f755c37aSrezgarshakeri PetscCall(PetscCalloc(P * Q * sizeof(CeedScalar), &interp)); 316f755c37aSrezgarshakeri PetscCall(PetscCalloc(P * Q * dim * sizeof(CeedScalar), &grad)); 317129d8736Srezgarshakeri const CeedInt c = 0; 318129d8736Srezgarshakeri for (CeedInt q = 0; q < Q; q++) { 319f755c37aSrezgarshakeri for (CeedInt p_ceed = 0; p_ceed < P; p_ceed++) { 3202b730f8bSJeremy L Thompson CeedInt p_petsc = is_simplex ? (p_ceed * num_comp) : permutation_indices[p_ceed * num_comp]; 321f755c37aSrezgarshakeri 3222b730f8bSJeremy L Thompson interp[q * P + p_ceed] = basis_tabulation->T[0][((face * Q + q) * P * num_comp + p_petsc) * num_comp + c]; 323129d8736Srezgarshakeri for (CeedInt d = 0; d < dim; d++) { 3242b730f8bSJeremy L Thompson grad[(d * Q + q) * P + p_ceed] = basis_tabulation->T[1][(((face * Q + q) * P * num_comp + p_petsc) * num_comp + c) * dim + d]; 325129d8736Srezgarshakeri } 326129d8736Srezgarshakeri } 327129d8736Srezgarshakeri } 328f755c37aSrezgarshakeri 329f755c37aSrezgarshakeri // -- Cleanup 330f755c37aSrezgarshakeri if (permutation) PetscCall(ISRestoreIndices(permutation, &permutation_indices)); 331f755c37aSrezgarshakeri PetscCall(ISDestroy(&permutation)); 332f755c37aSrezgarshakeri } 333f755c37aSrezgarshakeri 334f755c37aSrezgarshakeri // Finally, create libCEED basis 3352b730f8bSJeremy L Thompson CeedBasisCreateH1(ceed, elem_topo, num_comp, P, Q, interp, grad, q_points, q_weights, basis); 336f755c37aSrezgarshakeri PetscCall(PetscFree(q_points)); 337f755c37aSrezgarshakeri PetscCall(PetscFree(interp)); 338f755c37aSrezgarshakeri PetscCall(PetscFree(grad)); 339ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 340f755c37aSrezgarshakeri } 341f755c37aSrezgarshakeri 342f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 343f755c37aSrezgarshakeri // Get CEED Basis from DMPlex 344f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 3452b730f8bSJeremy L Thompson PetscErrorCode CreateBasisFromPlex(Ceed ceed, DM dm, DMLabel domain_label, CeedInt label_value, CeedInt height, CeedInt dm_field, BPData bp_data, 3462b730f8bSJeremy L Thompson CeedBasis *basis) { 347f755c37aSrezgarshakeri PetscDS ds; 348f755c37aSrezgarshakeri PetscFE fe; 349f755c37aSrezgarshakeri PetscQuadrature quadrature; 350f755c37aSrezgarshakeri PetscBool is_simplex = PETSC_TRUE; 351f755c37aSrezgarshakeri PetscInt ds_field = -1; 352f755c37aSrezgarshakeri 353f755c37aSrezgarshakeri PetscFunctionBeginUser; 354f755c37aSrezgarshakeri // Get element information 355baf96a30SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds, NULL)); 356f755c37aSrezgarshakeri PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field)); 357f755c37aSrezgarshakeri PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe)); 358f755c37aSrezgarshakeri PetscCall(PetscFEGetHeightSubspace(fe, height, &fe)); 359f755c37aSrezgarshakeri PetscCall(PetscFEGetQuadrature(fe, &quadrature)); 360f755c37aSrezgarshakeri 361f755c37aSrezgarshakeri // Check if simplex or tensor-product mesh 362f755c37aSrezgarshakeri PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 363f755c37aSrezgarshakeri 364f755c37aSrezgarshakeri // Build libCEED basis 365f755c37aSrezgarshakeri if (is_simplex) { 366f755c37aSrezgarshakeri PetscTabulation basis_tabulation; 367f755c37aSrezgarshakeri PetscInt num_derivatives = 1, face = 0; 368f755c37aSrezgarshakeri 369f755c37aSrezgarshakeri PetscCall(PetscFEGetCellTabulation(fe, num_derivatives, &basis_tabulation)); 3702b730f8bSJeremy L Thompson PetscCall(BasisCreateFromTabulation(ceed, dm, domain_label, label_value, height, face, fe, basis_tabulation, quadrature, basis)); 371129d8736Srezgarshakeri } else { 372f755c37aSrezgarshakeri PetscDualSpace dual_space; 373f755c37aSrezgarshakeri PetscInt num_dual_basis_vectors; 374f755c37aSrezgarshakeri PetscInt dim, num_comp, P, Q; 375f755c37aSrezgarshakeri 376f755c37aSrezgarshakeri PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 377f755c37aSrezgarshakeri PetscCall(PetscFEGetNumComponents(fe, &num_comp)); 378f755c37aSrezgarshakeri PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 379f755c37aSrezgarshakeri PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors)); 380f755c37aSrezgarshakeri P = num_dual_basis_vectors / num_comp; 381f755c37aSrezgarshakeri PetscCall(PetscQuadratureGetData(quadrature, NULL, NULL, &Q, NULL, NULL)); 382f755c37aSrezgarshakeri 383129d8736Srezgarshakeri CeedInt P_1d = (CeedInt)round(pow(P, 1.0 / dim)); 384129d8736Srezgarshakeri CeedInt Q_1d = (CeedInt)round(pow(Q, 1.0 / dim)); 385129d8736Srezgarshakeri 3862b730f8bSJeremy L Thompson CeedBasisCreateTensorH1Lagrange(ceed, dim, num_comp, P_1d, Q_1d, bp_data.q_mode, basis); 387129d8736Srezgarshakeri } 388ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 389f755c37aSrezgarshakeri } 390129d8736Srezgarshakeri 391129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 392de1229c5Srezgarshakeri // Utilities 393de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 394de1229c5Srezgarshakeri 395de1229c5Srezgarshakeri // Utility function, compute three factors of an integer 396de1229c5Srezgarshakeri static void Split3(PetscInt size, PetscInt m[3], bool reverse) { 397de1229c5Srezgarshakeri for (PetscInt d = 0, size_left = size; d < 3; d++) { 398de1229c5Srezgarshakeri PetscInt try = (PetscInt)PetscCeilReal(PetscPowReal(size_left, 1. / (3 - d))); 399de1229c5Srezgarshakeri while (try * (size_left / try) != size_left) try++; 400de1229c5Srezgarshakeri m[reverse ? 2 - d : d] = try; 401de1229c5Srezgarshakeri size_left /= try; 402de1229c5Srezgarshakeri } 403de1229c5Srezgarshakeri } 404de1229c5Srezgarshakeri 4052b730f8bSJeremy L Thompson static int Max3(const PetscInt a[3]) { return PetscMax(a[0], PetscMax(a[1], a[2])); } 406de1229c5Srezgarshakeri 4072b730f8bSJeremy L Thompson static int Min3(const PetscInt a[3]) { return PetscMin(a[0], PetscMin(a[1], a[2])); } 408de1229c5Srezgarshakeri 409de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 410de1229c5Srezgarshakeri // Create distribute dm 411de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 412de1229c5Srezgarshakeri PetscErrorCode CreateDistributedDM(RunParams rp, DM *dm) { 413de1229c5Srezgarshakeri PetscFunctionBeginUser; 414de1229c5Srezgarshakeri // Setup DM 415de1229c5Srezgarshakeri if (rp->read_mesh) { 4162b730f8bSJeremy L Thompson PetscCall(DMPlexCreateFromFile(PETSC_COMM_WORLD, rp->filename, NULL, PETSC_TRUE, dm)); 417de1229c5Srezgarshakeri } else { 418de1229c5Srezgarshakeri if (rp->user_l_nodes) { 419de1229c5Srezgarshakeri // Find a nicely composite number of elements no less than global nodes 420de1229c5Srezgarshakeri PetscMPIInt size; 4212b730f8bSJeremy L Thompson PetscCall(MPI_Comm_size(rp->comm, &size)); 4222b730f8bSJeremy L Thompson for (PetscInt g_elem = PetscMax(1, size * rp->local_nodes / PetscPowInt(rp->degree, rp->dim));; g_elem++) { 423de1229c5Srezgarshakeri Split3(g_elem, rp->mesh_elem, true); 424de1229c5Srezgarshakeri if (Max3(rp->mesh_elem) / Min3(rp->mesh_elem) <= 2) break; 425de1229c5Srezgarshakeri } 426de1229c5Srezgarshakeri } 427ab1ff315Srezgarshakeri 4282b730f8bSJeremy L Thompson PetscCall(DMPlexCreateBoxMesh(PETSC_COMM_WORLD, rp->dim, rp->simplex, rp->mesh_elem, NULL, NULL, NULL, PETSC_TRUE, dm)); 429de1229c5Srezgarshakeri } 430de1229c5Srezgarshakeri 4312b730f8bSJeremy L Thompson PetscCall(DMSetFromOptions(*dm)); 4322b730f8bSJeremy L Thompson PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 433ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 434de1229c5Srezgarshakeri } 435de1229c5Srezgarshakeri 436de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 437