1e83e87a5Sjeremylt #include "../include/petscutils.h" 2e83e87a5Sjeremylt 3e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 4e83e87a5Sjeremylt // Convert PETSc MemType to libCEED MemType 5e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 69b072555Sjeremylt CeedMemType MemTypeP2C(PetscMemType mem_type) { 79b072555Sjeremylt return PetscMemTypeDevice(mem_type) ? CEED_MEM_DEVICE : CEED_MEM_HOST; 8e83e87a5Sjeremylt } 9e83e87a5Sjeremylt 10e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 112c58efb6Sjeremylt // Apply 3D Kershaw mesh transformation 122c58efb6Sjeremylt // ----------------------------------------------------------------------------- 132c58efb6Sjeremylt // Transition from a value of "a" for x=0, to a value of "b" for x=1. Optionally 142c58efb6Sjeremylt // smooth -- see the commented versions at the end. 152c58efb6Sjeremylt static double step(const double a, const double b, double x) { 162c58efb6Sjeremylt if (x <= 0) return a; 172c58efb6Sjeremylt if (x >= 1) return b; 182c58efb6Sjeremylt return a + (b-a) * (x); 192c58efb6Sjeremylt } 202c58efb6Sjeremylt 212c58efb6Sjeremylt // 1D transformation at the right boundary 222c58efb6Sjeremylt static double right(const double eps, const double x) { 232c58efb6Sjeremylt return (x <= 0.5) ? (2-eps) * x : 1 + eps*(x-1); 242c58efb6Sjeremylt } 252c58efb6Sjeremylt 262c58efb6Sjeremylt // 1D transformation at the left boundary 272c58efb6Sjeremylt static double left(const double eps, const double x) { 282c58efb6Sjeremylt return 1-right(eps,1-x); 292c58efb6Sjeremylt } 302c58efb6Sjeremylt 312c58efb6Sjeremylt // Apply 3D Kershaw mesh transformation 322c58efb6Sjeremylt // The eps parameters are in (0, 1] 332c58efb6Sjeremylt // Uniform mesh is recovered for eps=1 349b072555Sjeremylt PetscErrorCode Kershaw(DM dm_orig, PetscScalar eps) { 352c58efb6Sjeremylt PetscErrorCode ierr; 362c58efb6Sjeremylt Vec coord; 372c58efb6Sjeremylt PetscInt ncoord; 382c58efb6Sjeremylt PetscScalar *c; 392c58efb6Sjeremylt 402c58efb6Sjeremylt PetscFunctionBeginUser; 419b072555Sjeremylt ierr = DMGetCoordinatesLocal(dm_orig, &coord); CHKERRQ(ierr); 422c58efb6Sjeremylt ierr = VecGetLocalSize(coord, &ncoord); CHKERRQ(ierr); 432c58efb6Sjeremylt ierr = VecGetArray(coord, &c); CHKERRQ(ierr); 442c58efb6Sjeremylt 452c58efb6Sjeremylt for (PetscInt i = 0; i < ncoord; i += 3) { 462c58efb6Sjeremylt PetscScalar x = c[i], y = c[i+1], z = c[i+2]; 472c58efb6Sjeremylt PetscInt layer = x*6; 482c58efb6Sjeremylt PetscScalar lambda = (x-layer/6.0)*6; 492c58efb6Sjeremylt c[i] = x; 502c58efb6Sjeremylt 512c58efb6Sjeremylt switch (layer) { 522c58efb6Sjeremylt case 0: 532c58efb6Sjeremylt c[i+1] = left(eps, y); 542c58efb6Sjeremylt c[i+2] = left(eps, z); 552c58efb6Sjeremylt break; 562c58efb6Sjeremylt case 1: 572c58efb6Sjeremylt case 4: 582c58efb6Sjeremylt c[i+1] = step(left(eps, y), right(eps, y), lambda); 592c58efb6Sjeremylt c[i+2] = step(left(eps, z), right(eps, z), lambda); 602c58efb6Sjeremylt break; 612c58efb6Sjeremylt case 2: 622c58efb6Sjeremylt c[i+1] = step(right(eps, y), left(eps, y), lambda/2); 632c58efb6Sjeremylt c[i+2] = step(right(eps, z), left(eps, z), lambda/2); 642c58efb6Sjeremylt break; 652c58efb6Sjeremylt case 3: 662c58efb6Sjeremylt c[i+1] = step(right(eps, y), left(eps, y), (1+lambda)/2); 672c58efb6Sjeremylt c[i+2] = step(right(eps, z), left(eps, z), (1+lambda)/2); 682c58efb6Sjeremylt break; 692c58efb6Sjeremylt default: 702c58efb6Sjeremylt c[i+1] = right(eps, y); 712c58efb6Sjeremylt c[i+2] = right(eps, z); 722c58efb6Sjeremylt } 732c58efb6Sjeremylt } 742c58efb6Sjeremylt ierr = VecRestoreArray(coord, &c); CHKERRQ(ierr); 752c58efb6Sjeremylt PetscFunctionReturn(0); 762c58efb6Sjeremylt } 772c58efb6Sjeremylt 782c58efb6Sjeremylt // ----------------------------------------------------------------------------- 79e83e87a5Sjeremylt // Create BC label 80e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 81e83e87a5Sjeremylt static PetscErrorCode CreateBCLabel(DM dm, const char name[]) { 82751eb813Srezgarshakeri 83e83e87a5Sjeremylt DMLabel label; 84e83e87a5Sjeremylt 85e83e87a5Sjeremylt PetscFunctionBeginUser; 86e83e87a5Sjeremylt 87751eb813Srezgarshakeri PetscCall(DMCreateLabel(dm, name)); 88751eb813Srezgarshakeri PetscCall(DMGetLabel(dm, name, &label)); 89751eb813Srezgarshakeri PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, label)); 90751eb813Srezgarshakeri PetscCall(DMPlexLabelComplete(dm, label)); 91e83e87a5Sjeremylt 92e83e87a5Sjeremylt PetscFunctionReturn(0); 93e83e87a5Sjeremylt }; 94e83e87a5Sjeremylt 95e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 96e83e87a5Sjeremylt // This function sets up a DM for a given degree 97e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 98de1229c5Srezgarshakeri PetscErrorCode SetupDMByDegree(DM dm, PetscInt p_degree, PetscInt q_extra, 99de1229c5Srezgarshakeri PetscInt num_comp_u, 1009b072555Sjeremylt PetscInt dim, bool enforce_bc, BCFunction bc_func) { 101e83e87a5Sjeremylt PetscInt ierr, marker_ids[1] = {1}; 102de1229c5Srezgarshakeri PetscInt q_degree = p_degree + q_extra; 103e83e87a5Sjeremylt PetscFE fe; 10465233696SJeremy L Thompson MPI_Comm comm; 105129d8736Srezgarshakeri PetscBool is_simplex = PETSC_TRUE; 106e83e87a5Sjeremylt 107e83e87a5Sjeremylt PetscFunctionBeginUser; 108e83e87a5Sjeremylt 109129d8736Srezgarshakeri // Check if simplex or tensor-product mesh 110129d8736Srezgarshakeri ierr = DMPlexIsSimplex(dm, &is_simplex); CHKERRQ(ierr); 111e83e87a5Sjeremylt // Setup FE 11265233696SJeremy L Thompson ierr = PetscObjectGetComm((PetscObject)dm, &comm); CHKERRQ(ierr); 113de1229c5Srezgarshakeri ierr = PetscFECreateLagrange(comm, dim, num_comp_u, is_simplex, p_degree, 114de1229c5Srezgarshakeri q_degree, &fe); CHKERRQ(ierr); 115e83e87a5Sjeremylt ierr = DMAddField(dm, NULL, (PetscObject)fe); CHKERRQ(ierr); 116129d8736Srezgarshakeri ierr = DMCreateDS(dm); CHKERRQ(ierr); 117129d8736Srezgarshakeri 118129d8736Srezgarshakeri { 119129d8736Srezgarshakeri // create FE field for coordinates 1207ed3e4cdSJeremy L Thompson PetscFE fe_coords; 1217ed3e4cdSJeremy L Thompson PetscInt num_comp_coord; 1227ed3e4cdSJeremy L Thompson ierr = DMGetCoordinateDim(dm, &num_comp_coord); CHKERRQ(ierr); 123de1229c5Srezgarshakeri ierr = PetscFECreateLagrange(comm, dim, num_comp_coord, is_simplex, 1, q_degree, 1247ed3e4cdSJeremy L Thompson &fe_coords); CHKERRQ(ierr); 1257ed3e4cdSJeremy L Thompson ierr = DMProjectCoordinates(dm, fe_coords); CHKERRQ(ierr); 1267ed3e4cdSJeremy L Thompson ierr = PetscFEDestroy(&fe_coords); CHKERRQ(ierr); 1277ed3e4cdSJeremy L Thompson } 128de1229c5Srezgarshakeri 129e83e87a5Sjeremylt // Setup DM 1309b072555Sjeremylt if (enforce_bc) { 1319b072555Sjeremylt PetscBool has_label; 1329b072555Sjeremylt DMHasLabel(dm, "marker", &has_label); 1339b072555Sjeremylt if (!has_label) {CreateBCLabel(dm, "marker");} 13469f5adf1Sjeremylt DMLabel label; 13569f5adf1Sjeremylt ierr = DMGetLabel(dm, "marker", &label); CHKERRQ(ierr); 136b8962995SJeremy L Thompson ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, 137b8962995SJeremy L Thompson marker_ids, 0, 0, NULL, (void(*)(void))bc_func, 138b8962995SJeremy L Thompson NULL, NULL, NULL); CHKERRQ(ierr); 139751eb813Srezgarshakeri PetscCall(DMSetOptionsPrefix(dm, "final_")); 140751eb813Srezgarshakeri PetscCall(DMViewFromOptions(dm, NULL, "-dm_view")); 141e83e87a5Sjeremylt } 142129d8736Srezgarshakeri 143129d8736Srezgarshakeri if (!is_simplex) { 144129d8736Srezgarshakeri DM dm_coord; 145129d8736Srezgarshakeri ierr = DMGetCoordinateDM(dm, &dm_coord); CHKERRQ(ierr); 146de1229c5Srezgarshakeri ierr = DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL); 147de1229c5Srezgarshakeri CHKERRQ(ierr); 148de1229c5Srezgarshakeri ierr = DMPlexSetClosurePermutationTensor(dm_coord, PETSC_DETERMINE, NULL); 149de1229c5Srezgarshakeri CHKERRQ(ierr); 150129d8736Srezgarshakeri } 151e83e87a5Sjeremylt ierr = PetscFEDestroy(&fe); CHKERRQ(ierr); 152e83e87a5Sjeremylt 153e83e87a5Sjeremylt PetscFunctionReturn(0); 154e83e87a5Sjeremylt }; 155e83e87a5Sjeremylt 156e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 157e83e87a5Sjeremylt // Get CEED restriction data from DMPlex 158e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 1597ed3e4cdSJeremy L Thompson PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt height, 1607ed3e4cdSJeremy L Thompson DMLabel domain_label, CeedInt value, CeedElemRestriction *elem_restr) { 1617ed3e4cdSJeremy L Thompson PetscInt num_elem, elem_size, num_dof, num_comp, *elem_restr_offsets; 162e83e87a5Sjeremylt PetscErrorCode ierr; 163e83e87a5Sjeremylt 164e83e87a5Sjeremylt PetscFunctionBeginUser; 165e83e87a5Sjeremylt 1667ed3e4cdSJeremy L Thompson ierr = DMPlexGetLocalOffsets(dm, domain_label, value, height, 0, &num_elem, 1677ed3e4cdSJeremy L Thompson &elem_size, &num_comp, &num_dof, &elem_restr_offsets); 1687ed3e4cdSJeremy L Thompson CHKERRQ(ierr); 169e83e87a5Sjeremylt 1707ed3e4cdSJeremy L Thompson CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp, 1717ed3e4cdSJeremy L Thompson 1, num_dof, CEED_MEM_HOST, CEED_COPY_VALUES, 1729b072555Sjeremylt elem_restr_offsets, elem_restr); 1739b072555Sjeremylt ierr = PetscFree(elem_restr_offsets); CHKERRQ(ierr); 1747ed3e4cdSJeremy L Thompson 175e83e87a5Sjeremylt PetscFunctionReturn(0); 176e83e87a5Sjeremylt }; 177e83e87a5Sjeremylt 178e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 179129d8736Srezgarshakeri // Utility function - convert from DMPolytopeType to CeedElemTopology 180129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 181de1229c5Srezgarshakeri CeedElemTopology ElemTopologyP2C(DMPolytopeType cell_type) { 182129d8736Srezgarshakeri switch (cell_type) { 183129d8736Srezgarshakeri case DM_POLYTOPE_TRIANGLE: return CEED_TOPOLOGY_TRIANGLE; 184129d8736Srezgarshakeri case DM_POLYTOPE_QUADRILATERAL: return CEED_TOPOLOGY_QUAD; 185129d8736Srezgarshakeri case DM_POLYTOPE_TETRAHEDRON: return CEED_TOPOLOGY_TET; 186129d8736Srezgarshakeri case DM_POLYTOPE_HEXAHEDRON: return CEED_TOPOLOGY_HEX; 187129d8736Srezgarshakeri default: return 0; 188129d8736Srezgarshakeri } 189129d8736Srezgarshakeri } 190129d8736Srezgarshakeri 191129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 192*f755c37aSrezgarshakeri // Convert DM field to DS field 193129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 194*f755c37aSrezgarshakeri PetscErrorCode DMFieldToDSField(DM dm, DMLabel domain_label, PetscInt dm_field, 195*f755c37aSrezgarshakeri PetscInt *ds_field) { 196129d8736Srezgarshakeri PetscDS ds; 197129d8736Srezgarshakeri IS field_is; 198129d8736Srezgarshakeri const PetscInt *fields; 199129d8736Srezgarshakeri PetscInt num_fields; 200129d8736Srezgarshakeri 201*f755c37aSrezgarshakeri PetscFunctionBeginUser; 202*f755c37aSrezgarshakeri 203129d8736Srezgarshakeri // Translate dm_field to ds_field 204*f755c37aSrezgarshakeri PetscCall(DMGetRegionDS(dm, domain_label, &field_is, &ds)); 205*f755c37aSrezgarshakeri PetscCall(ISGetIndices(field_is, &fields)); 206*f755c37aSrezgarshakeri PetscCall(ISGetSize(field_is, &num_fields)); 207129d8736Srezgarshakeri for (PetscInt i = 0; i < num_fields; i++) { 208129d8736Srezgarshakeri if (dm_field == fields[i]) { 209*f755c37aSrezgarshakeri *ds_field = i; 210129d8736Srezgarshakeri break; 211129d8736Srezgarshakeri } 212129d8736Srezgarshakeri } 213*f755c37aSrezgarshakeri PetscCall(ISRestoreIndices(field_is, &fields)); 214*f755c37aSrezgarshakeri 215*f755c37aSrezgarshakeri if (*ds_field == -1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, 21651ad7d5bSrezgarshakeri "Could not find dm_field %" PetscInt_FMT " in DS", dm_field); 217*f755c37aSrezgarshakeri 218*f755c37aSrezgarshakeri PetscFunctionReturn(0); 219129d8736Srezgarshakeri } 220129d8736Srezgarshakeri 221*f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 222*f755c37aSrezgarshakeri // Create libCEED Basis from PetscTabulation 223*f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 224*f755c37aSrezgarshakeri PetscErrorCode BasisCreateFromTabulation(Ceed ceed, DM dm, DMLabel domain_label, 225*f755c37aSrezgarshakeri PetscInt label_value, PetscInt height, PetscInt face, 226*f755c37aSrezgarshakeri PetscFE fe, PetscTabulation basis_tabulation, PetscQuadrature quadrature, 227*f755c37aSrezgarshakeri CeedBasis *basis) { 228129d8736Srezgarshakeri 229*f755c37aSrezgarshakeri PetscInt first_point; 230129d8736Srezgarshakeri PetscInt ids[1] = {label_value}; 231129d8736Srezgarshakeri DMLabel depth_label; 232129d8736Srezgarshakeri DMPolytopeType cell_type; 233129d8736Srezgarshakeri CeedElemTopology elem_topo; 234*f755c37aSrezgarshakeri PetscScalar *q_points, *interp, *grad; 235*f755c37aSrezgarshakeri const PetscScalar *q_weights; 236*f755c37aSrezgarshakeri PetscDualSpace dual_space; 237*f755c37aSrezgarshakeri PetscInt num_dual_basis_vectors; 238*f755c37aSrezgarshakeri PetscInt dim, num_comp, P, Q; 239*f755c37aSrezgarshakeri 240*f755c37aSrezgarshakeri PetscFunctionBeginUser; 241*f755c37aSrezgarshakeri 242*f755c37aSrezgarshakeri // General basis information 243*f755c37aSrezgarshakeri PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 244*f755c37aSrezgarshakeri PetscCall(PetscFEGetNumComponents(fe, &num_comp)); 245*f755c37aSrezgarshakeri PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 246*f755c37aSrezgarshakeri PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors)); 247*f755c37aSrezgarshakeri P = num_dual_basis_vectors / num_comp; 248129d8736Srezgarshakeri 249129d8736Srezgarshakeri // Use depth label if no domain label present 250129d8736Srezgarshakeri if (!domain_label) { 251129d8736Srezgarshakeri PetscInt depth; 252129d8736Srezgarshakeri 253*f755c37aSrezgarshakeri PetscCall(DMPlexGetDepth(dm, &depth)); 254*f755c37aSrezgarshakeri PetscCall(DMPlexGetDepthLabel(dm, &depth_label)); 255129d8736Srezgarshakeri ids[0] = depth - height; 256129d8736Srezgarshakeri } 257*f755c37aSrezgarshakeri 258129d8736Srezgarshakeri // Get cell interp, grad, and quadrature data 259*f755c37aSrezgarshakeri PetscCall(DMGetFirstLabeledPoint(dm, dm, 260*f755c37aSrezgarshakeri domain_label ? domain_label : depth_label, 1, ids, height, &first_point, NULL)); 261*f755c37aSrezgarshakeri PetscCall(DMPlexGetCellType(dm, first_point, &cell_type)); 262129d8736Srezgarshakeri elem_topo = ElemTopologyP2C(cell_type); 263129d8736Srezgarshakeri if (!elem_topo) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, 264129d8736Srezgarshakeri "DMPlex topology not supported"); 265*f755c37aSrezgarshakeri { 266*f755c37aSrezgarshakeri size_t q_points_size; 267*f755c37aSrezgarshakeri const PetscScalar *q_points_petsc; 268*f755c37aSrezgarshakeri PetscInt q_dim; 269*f755c37aSrezgarshakeri 270*f755c37aSrezgarshakeri PetscCall(PetscQuadratureGetData(quadrature, &q_dim, NULL, &Q, &q_points_petsc, 271*f755c37aSrezgarshakeri &q_weights)); 272*f755c37aSrezgarshakeri q_points_size = Q * dim * sizeof(CeedScalar); 273*f755c37aSrezgarshakeri PetscCall(PetscCalloc(q_points_size, &q_points)); 274*f755c37aSrezgarshakeri for (PetscInt q = 0; q < Q; q++) { 275*f755c37aSrezgarshakeri for (PetscInt d = 0; d < q_dim; 276*f755c37aSrezgarshakeri d++) q_points[q * dim + d] = q_points_petsc[q * q_dim + d]; 277*f755c37aSrezgarshakeri } 278*f755c37aSrezgarshakeri } 279*f755c37aSrezgarshakeri 280129d8736Srezgarshakeri // Convert to libCEED orientation 281*f755c37aSrezgarshakeri { 282*f755c37aSrezgarshakeri PetscBool is_simplex = PETSC_FALSE; 283*f755c37aSrezgarshakeri IS permutation = NULL; 284*f755c37aSrezgarshakeri const PetscInt *permutation_indices; 285*f755c37aSrezgarshakeri 286*f755c37aSrezgarshakeri PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 287*f755c37aSrezgarshakeri if (!is_simplex) { 288*f755c37aSrezgarshakeri PetscSection section; 289*f755c37aSrezgarshakeri 290*f755c37aSrezgarshakeri // -- Get permutation 291*f755c37aSrezgarshakeri PetscCall(DMGetLocalSection(dm, §ion)); 292*f755c37aSrezgarshakeri PetscCall(PetscSectionGetClosurePermutation(section, (PetscObject)dm, dim, 293*f755c37aSrezgarshakeri num_comp * P, &permutation)); 294*f755c37aSrezgarshakeri PetscCall(ISGetIndices(permutation, &permutation_indices)); 295*f755c37aSrezgarshakeri } 296*f755c37aSrezgarshakeri 297*f755c37aSrezgarshakeri // -- Copy interp, grad matrices 298*f755c37aSrezgarshakeri PetscCall(PetscCalloc(P * Q * sizeof(CeedScalar), &interp)); 299*f755c37aSrezgarshakeri PetscCall(PetscCalloc(P * Q * dim * sizeof(CeedScalar), &grad)); 300129d8736Srezgarshakeri const CeedInt c = 0; 301129d8736Srezgarshakeri for (CeedInt q = 0; q < Q; q++) { 302*f755c37aSrezgarshakeri for (CeedInt p_ceed = 0; p_ceed < P; p_ceed++) { 303*f755c37aSrezgarshakeri CeedInt p_petsc = is_simplex ? (p_ceed * num_comp) : permutation_indices[p_ceed 304*f755c37aSrezgarshakeri * num_comp]; 305*f755c37aSrezgarshakeri 306*f755c37aSrezgarshakeri interp[q * P + p_ceed] = basis_tabulation->T[0][((face * Q + q) * P * num_comp + 307*f755c37aSrezgarshakeri p_petsc) * num_comp + c]; 308129d8736Srezgarshakeri for (CeedInt d = 0; d < dim; d++) { 309*f755c37aSrezgarshakeri grad[(d * Q + q) * P + p_ceed] = basis_tabulation->T[1][((( 310*f755c37aSrezgarshakeri face * Q + q) * P * num_comp + p_petsc) * num_comp + c) * dim + d]; 311129d8736Srezgarshakeri } 312129d8736Srezgarshakeri } 313129d8736Srezgarshakeri } 314*f755c37aSrezgarshakeri 315*f755c37aSrezgarshakeri // -- Cleanup 316*f755c37aSrezgarshakeri if (permutation) PetscCall(ISRestoreIndices(permutation, &permutation_indices)); 317*f755c37aSrezgarshakeri PetscCall(ISDestroy(&permutation)); 318*f755c37aSrezgarshakeri } 319*f755c37aSrezgarshakeri 320*f755c37aSrezgarshakeri // Finally, create libCEED basis 321*f755c37aSrezgarshakeri CeedBasisCreateH1(ceed, elem_topo, num_comp, P, Q, interp, grad, q_points, 322*f755c37aSrezgarshakeri q_weights, basis); 323*f755c37aSrezgarshakeri PetscCall(PetscFree(q_points)); 324*f755c37aSrezgarshakeri PetscCall(PetscFree(interp)); 325*f755c37aSrezgarshakeri PetscCall(PetscFree(grad)); 326*f755c37aSrezgarshakeri 327*f755c37aSrezgarshakeri PetscFunctionReturn(0); 328*f755c37aSrezgarshakeri } 329*f755c37aSrezgarshakeri 330*f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 331*f755c37aSrezgarshakeri // Get CEED Basis from DMPlex 332*f755c37aSrezgarshakeri // ----------------------------------------------------------------------------- 333*f755c37aSrezgarshakeri PetscErrorCode CreateBasisFromPlex(Ceed ceed, DM dm, DMLabel domain_label, 334*f755c37aSrezgarshakeri CeedInt label_value, CeedInt height, 335*f755c37aSrezgarshakeri CeedInt dm_field, CeedBasis *basis) { 336*f755c37aSrezgarshakeri PetscDS ds; 337*f755c37aSrezgarshakeri PetscFE fe; 338*f755c37aSrezgarshakeri PetscQuadrature quadrature; 339*f755c37aSrezgarshakeri PetscBool is_simplex = PETSC_TRUE; 340*f755c37aSrezgarshakeri PetscInt ds_field = -1; 341*f755c37aSrezgarshakeri 342*f755c37aSrezgarshakeri PetscFunctionBeginUser; 343*f755c37aSrezgarshakeri 344*f755c37aSrezgarshakeri // Get element information 345*f755c37aSrezgarshakeri PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds)); 346*f755c37aSrezgarshakeri PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field)); 347*f755c37aSrezgarshakeri PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe)); 348*f755c37aSrezgarshakeri PetscCall(PetscFEGetHeightSubspace(fe, height, &fe)); 349*f755c37aSrezgarshakeri PetscCall(PetscFEGetQuadrature(fe, &quadrature)); 350*f755c37aSrezgarshakeri 351*f755c37aSrezgarshakeri // Check if simplex or tensor-product mesh 352*f755c37aSrezgarshakeri PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 353*f755c37aSrezgarshakeri 354*f755c37aSrezgarshakeri // Build libCEED basis 355*f755c37aSrezgarshakeri if (is_simplex) { 356*f755c37aSrezgarshakeri PetscTabulation basis_tabulation; 357*f755c37aSrezgarshakeri PetscInt num_derivatives = 1, face = 0; 358*f755c37aSrezgarshakeri 359*f755c37aSrezgarshakeri PetscCall(PetscFEGetCellTabulation(fe, num_derivatives, &basis_tabulation)); 360*f755c37aSrezgarshakeri PetscCall(BasisCreateFromTabulation(ceed, dm, domain_label, label_value, height, 361*f755c37aSrezgarshakeri face, fe, basis_tabulation, quadrature, basis)); 362129d8736Srezgarshakeri } else { 363*f755c37aSrezgarshakeri PetscDualSpace dual_space; 364*f755c37aSrezgarshakeri PetscInt num_dual_basis_vectors; 365*f755c37aSrezgarshakeri PetscInt dim, num_comp, P, Q; 366*f755c37aSrezgarshakeri 367*f755c37aSrezgarshakeri PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 368*f755c37aSrezgarshakeri PetscCall(PetscFEGetNumComponents(fe, &num_comp)); 369*f755c37aSrezgarshakeri PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 370*f755c37aSrezgarshakeri PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors)); 371*f755c37aSrezgarshakeri P = num_dual_basis_vectors / num_comp; 372*f755c37aSrezgarshakeri PetscCall(PetscQuadratureGetData(quadrature, NULL, NULL, &Q, NULL, NULL)); 373*f755c37aSrezgarshakeri 374129d8736Srezgarshakeri CeedInt P_1d = (CeedInt)round(pow(P, 1.0 / dim)); 375129d8736Srezgarshakeri CeedInt Q_1d = (CeedInt)round(pow(Q, 1.0 / dim)); 376129d8736Srezgarshakeri 377*f755c37aSrezgarshakeri CeedBasisCreateTensorH1Lagrange(ceed, dim, num_comp, P_1d, Q_1d, CEED_GAUSS, 378*f755c37aSrezgarshakeri basis); 379129d8736Srezgarshakeri } 380129d8736Srezgarshakeri 381129d8736Srezgarshakeri PetscFunctionReturn(0); 382*f755c37aSrezgarshakeri } 383129d8736Srezgarshakeri 384129d8736Srezgarshakeri // ----------------------------------------------------------------------------- 385de1229c5Srezgarshakeri // Utilities 386de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 387de1229c5Srezgarshakeri 388de1229c5Srezgarshakeri // Utility function, compute three factors of an integer 389de1229c5Srezgarshakeri static void Split3(PetscInt size, PetscInt m[3], bool reverse) { 390de1229c5Srezgarshakeri for (PetscInt d=0, size_left=size; d<3; d++) { 391de1229c5Srezgarshakeri PetscInt try = (PetscInt)PetscCeilReal(PetscPowReal(size_left, 1./(3 - d))); 392de1229c5Srezgarshakeri while (try * (size_left / try) != size_left) try++; 393de1229c5Srezgarshakeri m[reverse ? 2-d : d] = try; 394de1229c5Srezgarshakeri size_left /= try; 395de1229c5Srezgarshakeri } 396de1229c5Srezgarshakeri } 397de1229c5Srezgarshakeri 398de1229c5Srezgarshakeri static int Max3(const PetscInt a[3]) { 399de1229c5Srezgarshakeri return PetscMax(a[0], PetscMax(a[1], a[2])); 400de1229c5Srezgarshakeri } 401de1229c5Srezgarshakeri 402de1229c5Srezgarshakeri static int Min3(const PetscInt a[3]) { 403de1229c5Srezgarshakeri return PetscMin(a[0], PetscMin(a[1], a[2])); 404de1229c5Srezgarshakeri } 405de1229c5Srezgarshakeri 406de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 407de1229c5Srezgarshakeri // Create distribute dm 408de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 409de1229c5Srezgarshakeri PetscErrorCode CreateDistributedDM(RunParams rp, DM *dm) { 410de1229c5Srezgarshakeri PetscErrorCode ierr; 411de1229c5Srezgarshakeri 412de1229c5Srezgarshakeri PetscFunctionBeginUser; 413de1229c5Srezgarshakeri // Setup DM 414de1229c5Srezgarshakeri if (rp->read_mesh) { 415de1229c5Srezgarshakeri ierr = DMPlexCreateFromFile(PETSC_COMM_WORLD, rp->filename, NULL, PETSC_TRUE, 416de1229c5Srezgarshakeri dm); 417de1229c5Srezgarshakeri CHKERRQ(ierr); 418de1229c5Srezgarshakeri } else { 419de1229c5Srezgarshakeri if (rp->user_l_nodes) { 420de1229c5Srezgarshakeri // Find a nicely composite number of elements no less than global nodes 421de1229c5Srezgarshakeri PetscMPIInt size; 422de1229c5Srezgarshakeri ierr = MPI_Comm_size(rp->comm, &size); CHKERRQ(ierr); 423de1229c5Srezgarshakeri for (PetscInt g_elem = 424de1229c5Srezgarshakeri PetscMax(1, size * rp->local_nodes / PetscPowInt(rp->degree, rp->dim)); 425de1229c5Srezgarshakeri ; 426de1229c5Srezgarshakeri g_elem++) { 427de1229c5Srezgarshakeri Split3(g_elem, rp->mesh_elem, true); 428de1229c5Srezgarshakeri if (Max3(rp->mesh_elem) / Min3(rp->mesh_elem) <= 2) break; 429de1229c5Srezgarshakeri } 430de1229c5Srezgarshakeri } 431de1229c5Srezgarshakeri ierr = DMPlexCreateBoxMesh(PETSC_COMM_WORLD, rp->dim, rp->simplex, 432de1229c5Srezgarshakeri rp->mesh_elem, 433de1229c5Srezgarshakeri NULL, NULL, NULL, PETSC_TRUE, dm); CHKERRQ(ierr); 434de1229c5Srezgarshakeri } 435de1229c5Srezgarshakeri 436de1229c5Srezgarshakeri ierr = DMSetFromOptions(*dm); CHKERRQ(ierr); 437de1229c5Srezgarshakeri ierr = DMViewFromOptions(*dm, NULL, "-dm_view"); CHKERRQ(ierr); 438de1229c5Srezgarshakeri 439de1229c5Srezgarshakeri PetscFunctionReturn(0); 440de1229c5Srezgarshakeri } 441de1229c5Srezgarshakeri 442de1229c5Srezgarshakeri // ----------------------------------------------------------------------------- 443