1*d68a66c4SJames Wright // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2*d68a66c4SJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3*d68a66c4SJames Wright // 4*d68a66c4SJames Wright // SPDX-License-Identifier: BSD-2-Clause 5*d68a66c4SJames Wright // 6*d68a66c4SJames Wright // This file is part of CEED: http://github.com/ceed 7*d68a66c4SJames Wright 8*d68a66c4SJames Wright /// @file 9*d68a66c4SJames Wright /// Utilities for setting up DM and PetscFE 10*d68a66c4SJames Wright 11*d68a66c4SJames Wright #include <ceed.h> 12*d68a66c4SJames Wright #include <petscdmplex.h> 13*d68a66c4SJames Wright #include <petscds.h> 14*d68a66c4SJames Wright 15*d68a66c4SJames Wright #include "../navierstokes.h" 16*d68a66c4SJames Wright 17*d68a66c4SJames Wright // Utility function to create local CEED restriction 18*d68a66c4SJames Wright PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt height, DMLabel domain_label, CeedInt label_value, PetscInt dm_field, 19*d68a66c4SJames Wright CeedElemRestriction *elem_restr) { 20*d68a66c4SJames Wright PetscInt num_elem, elem_size, num_dof, num_comp, *elem_restr_offsets_petsc; 21*d68a66c4SJames Wright CeedInt *elem_restr_offsets_ceed; 22*d68a66c4SJames Wright 23*d68a66c4SJames Wright PetscFunctionBeginUser; 24*d68a66c4SJames Wright PetscCall( 25*d68a66c4SJames Wright DMPlexGetLocalOffsets(dm, domain_label, label_value, height, dm_field, &num_elem, &elem_size, &num_comp, &num_dof, &elem_restr_offsets_petsc)); 26*d68a66c4SJames Wright 27*d68a66c4SJames Wright PetscCall(IntArrayP2C(num_elem * elem_size, &elem_restr_offsets_petsc, &elem_restr_offsets_ceed)); 28*d68a66c4SJames Wright PetscCallCeed(ceed, CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp, 1, num_dof, CEED_MEM_HOST, CEED_COPY_VALUES, 29*d68a66c4SJames Wright elem_restr_offsets_ceed, elem_restr)); 30*d68a66c4SJames Wright PetscCall(PetscFree(elem_restr_offsets_ceed)); 31*d68a66c4SJames Wright 32*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 33*d68a66c4SJames Wright } 34*d68a66c4SJames Wright 35*d68a66c4SJames Wright // Utility function to get Ceed Restriction for each domain 36*d68a66c4SJames Wright PetscErrorCode GetRestrictionForDomain(Ceed ceed, DM dm, CeedInt height, DMLabel domain_label, PetscInt label_value, PetscInt dm_field, CeedInt Q, 37*d68a66c4SJames Wright CeedInt q_data_size, CeedElemRestriction *elem_restr_q, CeedElemRestriction *elem_restr_x, 38*d68a66c4SJames Wright CeedElemRestriction *elem_restr_qd_i) { 39*d68a66c4SJames Wright DM dm_coord; 40*d68a66c4SJames Wright CeedInt loc_num_elem; 41*d68a66c4SJames Wright PetscInt dim; 42*d68a66c4SJames Wright CeedElemRestriction elem_restr_tmp; 43*d68a66c4SJames Wright PetscFunctionBeginUser; 44*d68a66c4SJames Wright 45*d68a66c4SJames Wright PetscCall(DMGetDimension(dm, &dim)); 46*d68a66c4SJames Wright dim -= height; 47*d68a66c4SJames Wright PetscCall(CreateRestrictionFromPlex(ceed, dm, height, domain_label, label_value, dm_field, &elem_restr_tmp)); 48*d68a66c4SJames Wright if (elem_restr_q) *elem_restr_q = elem_restr_tmp; 49*d68a66c4SJames Wright if (elem_restr_x) { 50*d68a66c4SJames Wright PetscCall(DMGetCellCoordinateDM(dm, &dm_coord)); 51*d68a66c4SJames Wright if (!dm_coord) { 52*d68a66c4SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 53*d68a66c4SJames Wright } 54*d68a66c4SJames Wright PetscCall(DMPlexSetClosurePermutationTensor(dm_coord, PETSC_DETERMINE, NULL)); 55*d68a66c4SJames Wright PetscCall(CreateRestrictionFromPlex(ceed, dm_coord, height, domain_label, label_value, dm_field, elem_restr_x)); 56*d68a66c4SJames Wright } 57*d68a66c4SJames Wright if (elem_restr_qd_i) { 58*d68a66c4SJames Wright PetscCallCeed(ceed, CeedElemRestrictionGetNumElements(elem_restr_tmp, &loc_num_elem)); 59*d68a66c4SJames Wright PetscCallCeed(ceed, CeedElemRestrictionCreateStrided(ceed, loc_num_elem, Q, q_data_size, q_data_size * loc_num_elem * Q, CEED_STRIDES_BACKEND, 60*d68a66c4SJames Wright elem_restr_qd_i)); 61*d68a66c4SJames Wright } 62*d68a66c4SJames Wright if (!elem_restr_q) PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_tmp)); 63*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 64*d68a66c4SJames Wright } 65*d68a66c4SJames Wright 66*d68a66c4SJames Wright /** 67*d68a66c4SJames Wright @brief Convert `DM` field to `DS` field. 68*d68a66c4SJames Wright 69*d68a66c4SJames Wright @param[in] dm `DM` holding mesh 70*d68a66c4SJames Wright @param[in] domain_label Label for `DM` domain 71*d68a66c4SJames Wright @param[in] dm_field Index of `DM` field 72*d68a66c4SJames Wright @param[out] ds_field Index of `DS` field 73*d68a66c4SJames Wright 74*d68a66c4SJames Wright @return An error code: 0 - success, otherwise - failure 75*d68a66c4SJames Wright **/ 76*d68a66c4SJames Wright PetscErrorCode DMFieldToDSField(DM dm, DMLabel domain_label, PetscInt dm_field, PetscInt *ds_field) { 77*d68a66c4SJames Wright PetscDS ds; 78*d68a66c4SJames Wright IS field_is; 79*d68a66c4SJames Wright const PetscInt *fields; 80*d68a66c4SJames Wright PetscInt num_fields; 81*d68a66c4SJames Wright 82*d68a66c4SJames Wright PetscFunctionBeginUser; 83*d68a66c4SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, &field_is, &ds, NULL)); 84*d68a66c4SJames Wright PetscCall(ISGetIndices(field_is, &fields)); 85*d68a66c4SJames Wright PetscCall(ISGetSize(field_is, &num_fields)); 86*d68a66c4SJames Wright for (PetscInt i = 0; i < num_fields; i++) { 87*d68a66c4SJames Wright if (dm_field == fields[i]) { 88*d68a66c4SJames Wright *ds_field = i; 89*d68a66c4SJames Wright break; 90*d68a66c4SJames Wright } 91*d68a66c4SJames Wright } 92*d68a66c4SJames Wright PetscCall(ISRestoreIndices(field_is, &fields)); 93*d68a66c4SJames Wright 94*d68a66c4SJames Wright if (*ds_field == -1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Could not find dm_field %" PetscInt_FMT " in DS", dm_field); 95*d68a66c4SJames Wright 96*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 97*d68a66c4SJames Wright } 98*d68a66c4SJames Wright 99*d68a66c4SJames Wright // ----------------------------------------------------------------------------- 100*d68a66c4SJames Wright // Utility function - convert from DMPolytopeType to CeedElemTopology 101*d68a66c4SJames Wright // ----------------------------------------------------------------------------- 102*d68a66c4SJames Wright static CeedElemTopology ElemTopologyP2C(DMPolytopeType cell_type) { 103*d68a66c4SJames Wright switch (cell_type) { 104*d68a66c4SJames Wright case DM_POLYTOPE_TRIANGLE: 105*d68a66c4SJames Wright return CEED_TOPOLOGY_TRIANGLE; 106*d68a66c4SJames Wright case DM_POLYTOPE_QUADRILATERAL: 107*d68a66c4SJames Wright return CEED_TOPOLOGY_QUAD; 108*d68a66c4SJames Wright case DM_POLYTOPE_TETRAHEDRON: 109*d68a66c4SJames Wright return CEED_TOPOLOGY_TET; 110*d68a66c4SJames Wright case DM_POLYTOPE_HEXAHEDRON: 111*d68a66c4SJames Wright return CEED_TOPOLOGY_HEX; 112*d68a66c4SJames Wright default: 113*d68a66c4SJames Wright return 0; 114*d68a66c4SJames Wright } 115*d68a66c4SJames Wright } 116*d68a66c4SJames Wright 117*d68a66c4SJames Wright // ----------------------------------------------------------------------------- 118*d68a66c4SJames Wright // Create libCEED Basis from PetscTabulation 119*d68a66c4SJames Wright // ----------------------------------------------------------------------------- 120*d68a66c4SJames Wright PetscErrorCode BasisCreateFromTabulation(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height, PetscInt face, PetscFE fe, 121*d68a66c4SJames Wright PetscTabulation basis_tabulation, PetscQuadrature quadrature, CeedBasis *basis) { 122*d68a66c4SJames Wright PetscInt first_point; 123*d68a66c4SJames Wright PetscInt ids[1] = {label_value}; 124*d68a66c4SJames Wright DMLabel depth_label; 125*d68a66c4SJames Wright DMPolytopeType cell_type; 126*d68a66c4SJames Wright CeedElemTopology elem_topo; 127*d68a66c4SJames Wright PetscScalar *q_points, *interp, *grad; 128*d68a66c4SJames Wright const PetscScalar *q_weights; 129*d68a66c4SJames Wright PetscDualSpace dual_space; 130*d68a66c4SJames Wright PetscInt num_dual_basis_vectors; 131*d68a66c4SJames Wright PetscInt dim, num_comp, P, Q; 132*d68a66c4SJames Wright 133*d68a66c4SJames Wright PetscFunctionBeginUser; 134*d68a66c4SJames Wright PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 135*d68a66c4SJames Wright PetscCall(PetscFEGetNumComponents(fe, &num_comp)); 136*d68a66c4SJames Wright PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 137*d68a66c4SJames Wright PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors)); 138*d68a66c4SJames Wright P = num_dual_basis_vectors / num_comp; 139*d68a66c4SJames Wright 140*d68a66c4SJames Wright // Use depth label if no domain label present 141*d68a66c4SJames Wright if (!domain_label) { 142*d68a66c4SJames Wright PetscInt depth; 143*d68a66c4SJames Wright 144*d68a66c4SJames Wright PetscCall(DMPlexGetDepth(dm, &depth)); 145*d68a66c4SJames Wright PetscCall(DMPlexGetDepthLabel(dm, &depth_label)); 146*d68a66c4SJames Wright ids[0] = depth - height; 147*d68a66c4SJames Wright } 148*d68a66c4SJames Wright 149*d68a66c4SJames Wright // Get cell interp, grad, and quadrature data 150*d68a66c4SJames Wright PetscCall(DMGetFirstLabeledPoint(dm, dm, domain_label ? domain_label : depth_label, 1, ids, height, &first_point, NULL)); 151*d68a66c4SJames Wright PetscCall(DMPlexGetCellType(dm, first_point, &cell_type)); 152*d68a66c4SJames Wright elem_topo = ElemTopologyP2C(cell_type); 153*d68a66c4SJames Wright if (!elem_topo) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMPlex topology not supported"); 154*d68a66c4SJames Wright { 155*d68a66c4SJames Wright size_t q_points_size; 156*d68a66c4SJames Wright const PetscScalar *q_points_petsc; 157*d68a66c4SJames Wright PetscInt q_dim; 158*d68a66c4SJames Wright 159*d68a66c4SJames Wright PetscCall(PetscQuadratureGetData(quadrature, &q_dim, NULL, &Q, &q_points_petsc, &q_weights)); 160*d68a66c4SJames Wright q_points_size = Q * dim * sizeof(CeedScalar); 161*d68a66c4SJames Wright PetscCall(PetscCalloc(q_points_size, &q_points)); 162*d68a66c4SJames Wright for (PetscInt q = 0; q < Q; q++) { 163*d68a66c4SJames Wright for (PetscInt d = 0; d < q_dim; d++) q_points[q * dim + d] = q_points_petsc[q * q_dim + d]; 164*d68a66c4SJames Wright } 165*d68a66c4SJames Wright } 166*d68a66c4SJames Wright 167*d68a66c4SJames Wright { // Convert to libCEED orientation 168*d68a66c4SJames Wright PetscBool is_simplex = PETSC_FALSE; 169*d68a66c4SJames Wright IS permutation = NULL; 170*d68a66c4SJames Wright const PetscInt *permutation_indices; 171*d68a66c4SJames Wright 172*d68a66c4SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 173*d68a66c4SJames Wright if (!is_simplex) { 174*d68a66c4SJames Wright PetscSection section; 175*d68a66c4SJames Wright 176*d68a66c4SJames Wright // -- Get permutation 177*d68a66c4SJames Wright PetscCall(DMGetLocalSection(dm, §ion)); 178*d68a66c4SJames Wright PetscCall(PetscSectionGetClosurePermutation(section, (PetscObject)dm, dim, num_comp * P, &permutation)); 179*d68a66c4SJames Wright PetscCall(ISGetIndices(permutation, &permutation_indices)); 180*d68a66c4SJames Wright } 181*d68a66c4SJames Wright 182*d68a66c4SJames Wright // -- Copy interp, grad matrices 183*d68a66c4SJames Wright PetscCall(PetscCalloc(P * Q * sizeof(CeedScalar), &interp)); 184*d68a66c4SJames Wright PetscCall(PetscCalloc(P * Q * dim * sizeof(CeedScalar), &grad)); 185*d68a66c4SJames Wright const CeedInt c = 0; 186*d68a66c4SJames Wright for (CeedInt q = 0; q < Q; q++) { 187*d68a66c4SJames Wright for (CeedInt p_ceed = 0; p_ceed < P; p_ceed++) { 188*d68a66c4SJames Wright CeedInt p_petsc = is_simplex ? (p_ceed * num_comp) : permutation_indices[p_ceed * num_comp]; 189*d68a66c4SJames Wright 190*d68a66c4SJames Wright interp[q * P + p_ceed] = basis_tabulation->T[0][((face * Q + q) * P * num_comp + p_petsc) * num_comp + c]; 191*d68a66c4SJames Wright for (CeedInt d = 0; d < dim; d++) { 192*d68a66c4SJames Wright grad[(d * Q + q) * P + p_ceed] = basis_tabulation->T[1][(((face * Q + q) * P * num_comp + p_petsc) * num_comp + c) * dim + d]; 193*d68a66c4SJames Wright } 194*d68a66c4SJames Wright } 195*d68a66c4SJames Wright } 196*d68a66c4SJames Wright 197*d68a66c4SJames Wright // -- Cleanup 198*d68a66c4SJames Wright if (permutation) PetscCall(ISRestoreIndices(permutation, &permutation_indices)); 199*d68a66c4SJames Wright PetscCall(ISDestroy(&permutation)); 200*d68a66c4SJames Wright } 201*d68a66c4SJames Wright 202*d68a66c4SJames Wright // Finally, create libCEED basis 203*d68a66c4SJames Wright PetscCallCeed(ceed, CeedBasisCreateH1(ceed, elem_topo, num_comp, P, Q, interp, grad, q_points, q_weights, basis)); 204*d68a66c4SJames Wright PetscCall(PetscFree(q_points)); 205*d68a66c4SJames Wright PetscCall(PetscFree(interp)); 206*d68a66c4SJames Wright PetscCall(PetscFree(grad)); 207*d68a66c4SJames Wright 208*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 209*d68a66c4SJames Wright } 210*d68a66c4SJames Wright 211*d68a66c4SJames Wright // ----------------------------------------------------------------------------- 212*d68a66c4SJames Wright // Get CEED Basis from DMPlex 213*d68a66c4SJames Wright // ----------------------------------------------------------------------------- 214*d68a66c4SJames Wright PetscErrorCode CreateBasisFromPlex(Ceed ceed, DM dm, DMLabel domain_label, CeedInt label_value, CeedInt height, CeedInt dm_field, CeedBasis *basis) { 215*d68a66c4SJames Wright PetscDS ds; 216*d68a66c4SJames Wright PetscFE fe; 217*d68a66c4SJames Wright PetscQuadrature quadrature; 218*d68a66c4SJames Wright PetscBool is_simplex = PETSC_TRUE; 219*d68a66c4SJames Wright PetscInt ds_field = -1; 220*d68a66c4SJames Wright 221*d68a66c4SJames Wright PetscFunctionBeginUser; 222*d68a66c4SJames Wright 223*d68a66c4SJames Wright // Get element information 224*d68a66c4SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds, NULL)); 225*d68a66c4SJames Wright PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field)); 226*d68a66c4SJames Wright PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe)); 227*d68a66c4SJames Wright PetscCall(PetscFEGetHeightSubspace(fe, height, &fe)); 228*d68a66c4SJames Wright PetscCall(PetscFEGetQuadrature(fe, &quadrature)); 229*d68a66c4SJames Wright 230*d68a66c4SJames Wright // Check if simplex or tensor-product mesh 231*d68a66c4SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 232*d68a66c4SJames Wright 233*d68a66c4SJames Wright // Build libCEED basis 234*d68a66c4SJames Wright if (is_simplex) { 235*d68a66c4SJames Wright PetscTabulation basis_tabulation; 236*d68a66c4SJames Wright PetscInt num_derivatives = 1, face = 0; 237*d68a66c4SJames Wright 238*d68a66c4SJames Wright PetscCall(PetscFEGetCellTabulation(fe, num_derivatives, &basis_tabulation)); 239*d68a66c4SJames Wright PetscCall(BasisCreateFromTabulation(ceed, dm, domain_label, label_value, height, face, fe, basis_tabulation, quadrature, basis)); 240*d68a66c4SJames Wright } else { 241*d68a66c4SJames Wright PetscDualSpace dual_space; 242*d68a66c4SJames Wright PetscInt num_dual_basis_vectors; 243*d68a66c4SJames Wright PetscInt dim, num_comp, P, Q; 244*d68a66c4SJames Wright 245*d68a66c4SJames Wright PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 246*d68a66c4SJames Wright PetscCall(PetscFEGetNumComponents(fe, &num_comp)); 247*d68a66c4SJames Wright PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 248*d68a66c4SJames Wright PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors)); 249*d68a66c4SJames Wright P = num_dual_basis_vectors / num_comp; 250*d68a66c4SJames Wright PetscCall(PetscQuadratureGetData(quadrature, NULL, NULL, &Q, NULL, NULL)); 251*d68a66c4SJames Wright 252*d68a66c4SJames Wright CeedInt P_1d = (CeedInt)round(pow(P, 1.0 / dim)); 253*d68a66c4SJames Wright CeedInt Q_1d = (CeedInt)round(pow(Q, 1.0 / dim)); 254*d68a66c4SJames Wright 255*d68a66c4SJames Wright PetscCallCeed(ceed, CeedBasisCreateTensorH1Lagrange(ceed, dim, num_comp, P_1d, Q_1d, CEED_GAUSS, basis)); 256*d68a66c4SJames Wright } 257*d68a66c4SJames Wright 258*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 259*d68a66c4SJames Wright } 260*d68a66c4SJames Wright 261*d68a66c4SJames Wright /** 262*d68a66c4SJames Wright @brief Setup `DM` with FE space of appropriate degree 263*d68a66c4SJames Wright 264*d68a66c4SJames Wright Must be followed by `DMSetupByOrderEnd_FEM` 265*d68a66c4SJames Wright 266*d68a66c4SJames Wright @param[in] setup_faces Flag to setup face geometry 267*d68a66c4SJames Wright @param[in] setup_coords Flag to setup coordinate spaces 268*d68a66c4SJames Wright @param[in] degree Polynomial orders of field 269*d68a66c4SJames Wright @param[in] coord_order Polynomial order of coordinate basis, or `RATEL_DECIDE` for default 270*d68a66c4SJames Wright @param[in] q_extra Additional quadrature order, or `RATEL_DECIDE` for default 271*d68a66c4SJames Wright @param[in] num_fields Number of fields in solution vector 272*d68a66c4SJames Wright @param[in] field_sizes Array of number of components for each field 273*d68a66c4SJames Wright @param[out] dm `DM` to setup 274*d68a66c4SJames Wright 275*d68a66c4SJames Wright @return An error code: 0 - success, otherwise - failure 276*d68a66c4SJames Wright **/ 277*d68a66c4SJames Wright PetscErrorCode DMSetupByOrderBegin_FEM(PetscBool setup_faces, PetscBool setup_coords, PetscInt degree, PetscInt coord_order, PetscInt q_extra, 278*d68a66c4SJames Wright CeedInt num_fields, const CeedInt *field_sizes, DM dm) { 279*d68a66c4SJames Wright PetscInt dim, q_order = degree + q_extra; 280*d68a66c4SJames Wright PetscBool is_simplex = PETSC_TRUE; 281*d68a66c4SJames Wright PetscFE fe; 282*d68a66c4SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm); 283*d68a66c4SJames Wright 284*d68a66c4SJames Wright PetscFunctionBeginUser; 285*d68a66c4SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 286*d68a66c4SJames Wright 287*d68a66c4SJames Wright // Setup DM 288*d68a66c4SJames Wright PetscCall(DMGetDimension(dm, &dim)); 289*d68a66c4SJames Wright for (PetscInt i = 0; i < num_fields; i++) { 290*d68a66c4SJames Wright PetscFE fe_face; 291*d68a66c4SJames Wright PetscInt q_order = degree + q_extra; 292*d68a66c4SJames Wright 293*d68a66c4SJames Wright PetscCall(PetscFECreateLagrange(comm, dim, field_sizes[i], is_simplex, degree, q_order, &fe)); 294*d68a66c4SJames Wright if (setup_faces) PetscCall(PetscFEGetHeightSubspace(fe, 1, &fe_face)); 295*d68a66c4SJames Wright PetscCall(DMAddField(dm, NULL, (PetscObject)fe)); 296*d68a66c4SJames Wright PetscCall(PetscFEDestroy(&fe)); 297*d68a66c4SJames Wright } 298*d68a66c4SJames Wright PetscCall(DMCreateDS(dm)); 299*d68a66c4SJames Wright 300*d68a66c4SJames Wright // Project coordinates to enrich quadrature space 301*d68a66c4SJames Wright if (setup_coords) { 302*d68a66c4SJames Wright DM dm_coord; 303*d68a66c4SJames Wright PetscDS ds_coord; 304*d68a66c4SJames Wright PetscFE fe_coord_current, fe_coord_new, fe_coord_face_new; 305*d68a66c4SJames Wright PetscDualSpace fe_coord_dual_space; 306*d68a66c4SJames Wright PetscInt fe_coord_order, num_comp_coord; 307*d68a66c4SJames Wright 308*d68a66c4SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 309*d68a66c4SJames Wright PetscCall(DMGetCoordinateDim(dm, &num_comp_coord)); 310*d68a66c4SJames Wright PetscCall(DMGetRegionDS(dm_coord, NULL, NULL, &ds_coord, NULL)); 311*d68a66c4SJames Wright PetscCall(PetscDSGetDiscretization(ds_coord, 0, (PetscObject *)&fe_coord_current)); 312*d68a66c4SJames Wright PetscCall(PetscFEGetDualSpace(fe_coord_current, &fe_coord_dual_space)); 313*d68a66c4SJames Wright PetscCall(PetscDualSpaceGetOrder(fe_coord_dual_space, &fe_coord_order)); 314*d68a66c4SJames Wright 315*d68a66c4SJames Wright // Create FE for coordinates 316*d68a66c4SJames Wright PetscCheck(fe_coord_order == 1 || coord_order == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER_INPUT, 317*d68a66c4SJames Wright "Only linear mesh geometry supported. Recieved %d order", fe_coord_order); 318*d68a66c4SJames Wright PetscCall(PetscFECreateLagrange(comm, dim, num_comp_coord, is_simplex, fe_coord_order, q_order, &fe_coord_new)); 319*d68a66c4SJames Wright if (setup_faces) PetscCall(PetscFEGetHeightSubspace(fe_coord_new, 1, &fe_coord_face_new)); 320*d68a66c4SJames Wright PetscCall(DMProjectCoordinates(dm, fe_coord_new)); 321*d68a66c4SJames Wright PetscCall(PetscFEDestroy(&fe_coord_new)); 322*d68a66c4SJames Wright } 323*d68a66c4SJames Wright 324*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 325*d68a66c4SJames Wright } 326*d68a66c4SJames Wright 327*d68a66c4SJames Wright /** 328*d68a66c4SJames Wright @brief Finish setting up `DM` 329*d68a66c4SJames Wright 330*d68a66c4SJames Wright Must be called after `DMSetupByOrderBegin_FEM` and all strong BCs have be declared via `DMAddBoundaries`. 331*d68a66c4SJames Wright 332*d68a66c4SJames Wright @param[in] setup_coords Flag to setup coordinate spaces 333*d68a66c4SJames Wright @param[out] dm `DM` to setup 334*d68a66c4SJames Wright 335*d68a66c4SJames Wright @return An error code: 0 - success, otherwise - failure 336*d68a66c4SJames Wright **/ 337*d68a66c4SJames Wright PetscErrorCode DMSetupByOrderEnd_FEM(PetscBool setup_coords, DM dm) { 338*d68a66c4SJames Wright PetscBool is_simplex; 339*d68a66c4SJames Wright PetscFunctionBeginUser; 340*d68a66c4SJames Wright 341*d68a66c4SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 342*d68a66c4SJames Wright // Set tensor permutation if needed 343*d68a66c4SJames Wright if (!is_simplex) { 344*d68a66c4SJames Wright PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 345*d68a66c4SJames Wright if (setup_coords) { 346*d68a66c4SJames Wright DM dm_coord; 347*d68a66c4SJames Wright 348*d68a66c4SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 349*d68a66c4SJames Wright PetscCall(DMPlexSetClosurePermutationTensor(dm_coord, PETSC_DETERMINE, NULL)); 350*d68a66c4SJames Wright } 351*d68a66c4SJames Wright } 352*d68a66c4SJames Wright 353*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 354*d68a66c4SJames Wright } 355*d68a66c4SJames Wright 356*d68a66c4SJames Wright /** 357*d68a66c4SJames Wright @brief Setup `DM` with FE space of appropriate degree with no boundary conditions 358*d68a66c4SJames Wright 359*d68a66c4SJames Wright Calls `DMSetupByOrderBegin_FEM` and `DMSetupByOrderEnd_FEM` successively 360*d68a66c4SJames Wright 361*d68a66c4SJames Wright @param[in] setup_faces Flag to setup face geometry 362*d68a66c4SJames Wright @param[in] setup_coords Flag to setup coordinate spaces 363*d68a66c4SJames Wright @param[in] degree Polynomial orders of field 364*d68a66c4SJames Wright @param[in] coord_order Polynomial order of coordinate basis, or `RATEL_DECIDE` for default 365*d68a66c4SJames Wright @param[in] q_extra Additional quadrature order, or `RATEL_DECIDE` for default 366*d68a66c4SJames Wright @param[in] num_fields Number of fields in solution vector 367*d68a66c4SJames Wright @param[in] field_sizes Array of number of components for each field 368*d68a66c4SJames Wright @param[out] dm `DM` to setup 369*d68a66c4SJames Wright 370*d68a66c4SJames Wright @return An error code: 0 - success, otherwise - failure 371*d68a66c4SJames Wright **/ 372*d68a66c4SJames Wright PetscErrorCode DMSetupByOrder_FEM(PetscBool setup_faces, PetscBool setup_coords, PetscInt degree, PetscInt coord_order, PetscInt q_extra, 373*d68a66c4SJames Wright CeedInt num_fields, const CeedInt *field_sizes, DM dm) { 374*d68a66c4SJames Wright PetscFunctionBeginUser; 375*d68a66c4SJames Wright PetscCall(DMSetupByOrderBegin_FEM(setup_faces, setup_coords, degree, coord_order, q_extra, num_fields, field_sizes, dm)); 376*d68a66c4SJames Wright PetscCall(DMSetupByOrderEnd_FEM(setup_coords, dm)); 377*d68a66c4SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 378*d68a66c4SJames Wright } 379