17b8c5038SJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
27b8c5038SJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
37b8c5038SJames Wright
47b8c5038SJames Wright /// @file
57b8c5038SJames Wright /// Utilities for setting up DM and PetscFE
67b8c5038SJames Wright
77b8c5038SJames Wright #include <ceed.h>
87b8c5038SJames Wright #include <dm-utils.h>
97b8c5038SJames Wright #include <petsc-ceed-utils.h>
107b8c5038SJames Wright #include <petscdmplex.h>
117b8c5038SJames Wright #include <petscds.h>
127b8c5038SJames Wright
137b8c5038SJames Wright /**
147b8c5038SJames Wright @brief Convert `DM` field to `DS` field.
157b8c5038SJames Wright
167b8c5038SJames Wright @param[in] dm `DM` holding mesh
177b8c5038SJames Wright @param[in] domain_label Label for `DM` domain
187b8c5038SJames Wright @param[in] dm_field Index of `DM` field
197b8c5038SJames Wright @param[out] ds_field Index of `DS` field
207b8c5038SJames Wright
217b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
227b8c5038SJames Wright **/
DMFieldToDSField(DM dm,DMLabel domain_label,PetscInt dm_field,PetscInt * ds_field)237b8c5038SJames Wright PetscErrorCode DMFieldToDSField(DM dm, DMLabel domain_label, PetscInt dm_field, PetscInt *ds_field) {
247b8c5038SJames Wright PetscDS ds;
257b8c5038SJames Wright IS field_is;
267b8c5038SJames Wright const PetscInt *fields;
277b8c5038SJames Wright PetscInt num_fields;
287b8c5038SJames Wright
297b8c5038SJames Wright PetscFunctionBeginUser;
307b8c5038SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, &field_is, &ds, NULL));
317b8c5038SJames Wright PetscCall(ISGetIndices(field_is, &fields));
327b8c5038SJames Wright PetscCall(ISGetSize(field_is, &num_fields));
337b8c5038SJames Wright for (PetscInt i = 0; i < num_fields; i++) {
347b8c5038SJames Wright if (dm_field == fields[i]) {
357b8c5038SJames Wright *ds_field = i;
367b8c5038SJames Wright break;
377b8c5038SJames Wright }
387b8c5038SJames Wright }
397b8c5038SJames Wright PetscCall(ISRestoreIndices(field_is, &fields));
407b8c5038SJames Wright
417b8c5038SJames Wright PetscCheck(*ds_field != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Could not find dm_field %" PetscInt_FMT " in DS", dm_field);
427b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
437b8c5038SJames Wright }
447b8c5038SJames Wright
457b8c5038SJames Wright /**
467b8c5038SJames Wright @brief Destroy `ElemRestriction` in a `PetscContainer`.
477b8c5038SJames Wright
487b8c5038SJames Wright Not collective across MPI processes.
497b8c5038SJames Wright
507b8c5038SJames Wright @param[in,out] ctx `CeedElemRestriction`
517b8c5038SJames Wright
527b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
537b8c5038SJames Wright **/
DMPlexCeedElemRestrictionDestroy(void ** ctx)547b8c5038SJames Wright static PetscErrorCode DMPlexCeedElemRestrictionDestroy(void **ctx) {
557b8c5038SJames Wright CeedElemRestriction rstr = *(CeedElemRestriction *)ctx;
567b8c5038SJames Wright
577b8c5038SJames Wright PetscFunctionBegin;
587b8c5038SJames Wright PetscCallCeed(CeedElemRestrictionReturnCeed(rstr), CeedElemRestrictionDestroy(&rstr));
597b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
607b8c5038SJames Wright }
617b8c5038SJames Wright
627b8c5038SJames Wright /**
637b8c5038SJames Wright @brief Create `CeedElemRestriction` from `DMPlex`.
647b8c5038SJames Wright
657b8c5038SJames Wright The `CeedElemRestriction` is stored in the `DMPlex` object for reuse;
667b8c5038SJames Wright if the routine is called again with the same arguments, the same `CeedElemRestriction` is returned.
677b8c5038SJames Wright
687b8c5038SJames Wright Not collective across MPI processes.
697b8c5038SJames Wright
707b8c5038SJames Wright @param[in] ceed `Ceed` context
717b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
727b8c5038SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
737b8c5038SJames Wright @param[in] label_value Stratum value
747b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
757b8c5038SJames Wright @param[in] dm_field Index of `DMPlex` field
767b8c5038SJames Wright @param[out] restriction `CeedElemRestriction` for `DMPlex`
777b8c5038SJames Wright
787b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
797b8c5038SJames Wright **/
DMPlexCeedElemRestrictionCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,PetscInt dm_field,CeedElemRestriction * restriction)807b8c5038SJames Wright PetscErrorCode DMPlexCeedElemRestrictionCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height, PetscInt dm_field,
817b8c5038SJames Wright CeedElemRestriction *restriction) {
827b8c5038SJames Wright char container_name[1024];
837b8c5038SJames Wright CeedElemRestriction container_restriction;
847b8c5038SJames Wright
857b8c5038SJames Wright PetscFunctionBeginUser;
867b8c5038SJames Wright {
877b8c5038SJames Wright const char *label_name = NULL;
887b8c5038SJames Wright
897b8c5038SJames Wright if (domain_label) PetscCall(PetscObjectGetName((PetscObject)domain_label, &label_name));
907b8c5038SJames Wright PetscCall(PetscSNPrintf(container_name, sizeof(container_name),
917b8c5038SJames Wright "DM CeedElemRestriction - label: %s label value: %" PetscInt_FMT " height: %" PetscInt_FMT " DM field: %" PetscInt_FMT,
927b8c5038SJames Wright label_name ? label_name : "NONE", label_value, height, dm_field));
937b8c5038SJames Wright }
947b8c5038SJames Wright PetscCall(PetscObjectContainerQuery((PetscObject)dm, container_name, (void **)&container_restriction));
957b8c5038SJames Wright
967b8c5038SJames Wright if (container_restriction) {
977b8c5038SJames Wright // Copy existing restriction
987b8c5038SJames Wright *restriction = NULL;
997b8c5038SJames Wright PetscCallCeed(ceed, CeedElemRestrictionReferenceCopy(container_restriction, restriction));
1007b8c5038SJames Wright } else {
1017b8c5038SJames Wright PetscInt num_elem, elem_size, num_dof, num_comp, *restriction_offsets_petsc;
1027b8c5038SJames Wright CeedInt *restriction_offsets_ceed = NULL;
1037b8c5038SJames Wright
1047b8c5038SJames Wright // Build restriction
1057b8c5038SJames Wright PetscCall(DMPlexGetLocalOffsets(dm, domain_label, label_value, height, dm_field, &num_elem, &elem_size, &num_comp, &num_dof,
1067b8c5038SJames Wright &restriction_offsets_petsc));
1077b8c5038SJames Wright PetscCall(IntArrayPetscToCeed(num_elem * elem_size, &restriction_offsets_petsc, &restriction_offsets_ceed));
1087b8c5038SJames Wright PetscCallCeed(ceed, CeedElemRestrictionCreate(ceed, num_elem, elem_size, num_comp, 1, num_dof, CEED_MEM_HOST, CEED_COPY_VALUES,
1097b8c5038SJames Wright restriction_offsets_ceed, restriction));
1107b8c5038SJames Wright PetscCall(PetscFree(restriction_offsets_ceed));
1117b8c5038SJames Wright
1127b8c5038SJames Wright // Set in container
1137b8c5038SJames Wright PetscCallCeed(ceed, CeedElemRestrictionReferenceCopy(*restriction, &container_restriction));
114*26d401f3SJames Wright PetscCall(PetscObjectContainerCompose((PetscObject)dm, container_name, container_restriction,
115*26d401f3SJames Wright (PetscCtxDestroyFn *)DMPlexCeedElemRestrictionDestroy));
1167b8c5038SJames Wright }
1177b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
1187b8c5038SJames Wright }
1197b8c5038SJames Wright
1207b8c5038SJames Wright /**
1217b8c5038SJames Wright @brief Create `CeedElemRestriction` from `DMPlex` domain for mesh coordinates.
1227b8c5038SJames Wright
1237b8c5038SJames Wright The `CeedElemRestriction` is stored in the coordinate `DMPlex` object for reuse;
1247b8c5038SJames Wright if the routine is called again with the same arguments, the same `CeedElemRestriction` is returned.
1257b8c5038SJames Wright
1267b8c5038SJames Wright Not collective across MPI processes.
1277b8c5038SJames Wright
1287b8c5038SJames Wright @param[in] ceed `Ceed` context
1297b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
1307b8c5038SJames Wright @param[in] domain_label Label for `DMPlex` domain
1317b8c5038SJames Wright @param[in] label_value Stratum value
1327b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
1337b8c5038SJames Wright @param[out] restriction `CeedElemRestriction` for mesh
1347b8c5038SJames Wright
1357b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
1367b8c5038SJames Wright **/
DMPlexCeedElemRestrictionCoordinateCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,CeedElemRestriction * restriction)1377b8c5038SJames Wright PetscErrorCode DMPlexCeedElemRestrictionCoordinateCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height,
1387b8c5038SJames Wright CeedElemRestriction *restriction) {
1397b8c5038SJames Wright DM dm_coord;
1407b8c5038SJames Wright
1417b8c5038SJames Wright PetscFunctionBeginUser;
1427b8c5038SJames Wright PetscCall(DMGetCellCoordinateDM(dm, &dm_coord));
1437b8c5038SJames Wright if (!dm_coord) {
1447b8c5038SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord));
1457b8c5038SJames Wright }
1467b8c5038SJames Wright PetscCall(DMPlexCeedElemRestrictionCreate(ceed, dm_coord, domain_label, label_value, height, 0, restriction));
1477b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
1487b8c5038SJames Wright }
1497b8c5038SJames Wright
1507b8c5038SJames Wright /**
1517b8c5038SJames Wright @brief Create `CeedElemRestriction` from `DMPlex` domain for auxilury `QFunction` data.
1527b8c5038SJames Wright
1537b8c5038SJames Wright Not collective across MPI processes.
1547b8c5038SJames Wright
1557b8c5038SJames Wright @param[in] ceed `Ceed` context
1567b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
1577b8c5038SJames Wright @param[in] domain_label Label for `DMPlex` domain
1587b8c5038SJames Wright @param[in] label_value Stratum value
1597b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
1607b8c5038SJames Wright @param[in] q_data_size Number of components for `QFunction` data
1617b8c5038SJames Wright @param[in] is_collocated Boolean flag indicating if the data is collocated on the nodes (`PETSC_TRUE`) or on quadrature points (`PETSC_FALSE`)
1627b8c5038SJames Wright @param[out] restriction Strided `CeedElemRestriction` for `QFunction` data
1637b8c5038SJames Wright
1647b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
1657b8c5038SJames Wright **/
DMPlexCeedElemRestrictionStridedCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,PetscInt q_data_size,PetscBool is_collocated,CeedElemRestriction * restriction)1667b8c5038SJames Wright static PetscErrorCode DMPlexCeedElemRestrictionStridedCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height,
1677b8c5038SJames Wright PetscInt q_data_size, PetscBool is_collocated, CeedElemRestriction *restriction) {
1687b8c5038SJames Wright PetscInt num_elem, num_qpts, dm_field = 0;
1697b8c5038SJames Wright
1707b8c5038SJames Wright PetscFunctionBeginUser;
1717b8c5038SJames Wright { // Get number of elements
1727b8c5038SJames Wright PetscInt depth;
1737b8c5038SJames Wright DMLabel depth_label;
1747b8c5038SJames Wright IS point_is, depth_is;
1757b8c5038SJames Wright
1767b8c5038SJames Wright PetscCall(DMPlexGetDepth(dm, &depth));
1777b8c5038SJames Wright PetscCall(DMPlexGetDepthLabel(dm, &depth_label));
1787b8c5038SJames Wright PetscCall(DMLabelGetStratumIS(depth_label, depth - height, &depth_is));
1797b8c5038SJames Wright if (domain_label) {
1807b8c5038SJames Wright IS domain_is;
1817b8c5038SJames Wright
1827b8c5038SJames Wright PetscCall(DMLabelGetStratumIS(domain_label, label_value, &domain_is));
1837b8c5038SJames Wright if (domain_is) {
1847b8c5038SJames Wright PetscCall(ISIntersect(depth_is, domain_is, &point_is));
1857b8c5038SJames Wright PetscCall(ISDestroy(&domain_is));
1867b8c5038SJames Wright } else {
1877b8c5038SJames Wright point_is = NULL;
1887b8c5038SJames Wright }
1897b8c5038SJames Wright PetscCall(ISDestroy(&depth_is));
1907b8c5038SJames Wright } else {
1917b8c5038SJames Wright point_is = depth_is;
1927b8c5038SJames Wright }
1937b8c5038SJames Wright if (point_is) {
1947b8c5038SJames Wright PetscCall(ISGetLocalSize(point_is, &num_elem));
1957b8c5038SJames Wright } else {
1967b8c5038SJames Wright num_elem = 0;
1977b8c5038SJames Wright }
1987b8c5038SJames Wright PetscCall(ISDestroy(&point_is));
1997b8c5038SJames Wright }
2007b8c5038SJames Wright
2017b8c5038SJames Wright { // Get number of quadrature points
2027b8c5038SJames Wright PetscDS ds;
2037b8c5038SJames Wright PetscFE fe;
2047b8c5038SJames Wright PetscInt ds_field = -1;
2057b8c5038SJames Wright
2067b8c5038SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds, NULL));
2077b8c5038SJames Wright PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field));
2087b8c5038SJames Wright PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe));
2097b8c5038SJames Wright PetscCall(PetscFEGetHeightSubspace(fe, height, &fe));
2107b8c5038SJames Wright if (is_collocated) {
2117b8c5038SJames Wright PetscDualSpace dual_space;
2127b8c5038SJames Wright PetscInt num_dual_basis_vectors, dim, num_comp;
2137b8c5038SJames Wright
2147b8c5038SJames Wright PetscCall(PetscFEGetSpatialDimension(fe, &dim));
2157b8c5038SJames Wright PetscCall(PetscFEGetNumComponents(fe, &num_comp));
2167b8c5038SJames Wright PetscCall(PetscFEGetDualSpace(fe, &dual_space));
2177b8c5038SJames Wright PetscCall(PetscDualSpaceGetDimension(dual_space, &num_dual_basis_vectors));
2187b8c5038SJames Wright num_qpts = num_dual_basis_vectors / num_comp;
2197b8c5038SJames Wright } else {
2207b8c5038SJames Wright PetscQuadrature quadrature;
2217b8c5038SJames Wright
2227b8c5038SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds, NULL));
2237b8c5038SJames Wright PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field));
2247b8c5038SJames Wright PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe));
2257b8c5038SJames Wright PetscCall(PetscFEGetHeightSubspace(fe, height, &fe));
2267b8c5038SJames Wright PetscCall(PetscFEGetQuadrature(fe, &quadrature));
2277b8c5038SJames Wright PetscCall(PetscQuadratureGetData(quadrature, NULL, NULL, &num_qpts, NULL, NULL));
2287b8c5038SJames Wright }
2297b8c5038SJames Wright }
2307b8c5038SJames Wright
2317b8c5038SJames Wright // Create the restriction
2327b8c5038SJames Wright PetscCallCeed(ceed, CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, q_data_size, num_elem * num_qpts * q_data_size, CEED_STRIDES_BACKEND,
2337b8c5038SJames Wright restriction));
2347b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
2357b8c5038SJames Wright }
2367b8c5038SJames Wright
2377b8c5038SJames Wright /**
2387b8c5038SJames Wright @brief Create `CeedElemRestriction` from `DMPlex` domain for auxilury `QFunction` data.
2397b8c5038SJames Wright
2407b8c5038SJames Wright Not collective across MPI processes.
2417b8c5038SJames Wright
2427b8c5038SJames Wright @param[in] ceed `Ceed` context
2437b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
2447b8c5038SJames Wright @param[in] domain_label Label for `DMPlex` domain
2457b8c5038SJames Wright @param[in] label_value Stratum value
2467b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
2477b8c5038SJames Wright @param[in] q_data_size Number of components for `QFunction` data
2487b8c5038SJames Wright @param[out] restriction Strided `CeedElemRestriction` for `QFunction` data
2497b8c5038SJames Wright
2507b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
2517b8c5038SJames Wright **/
DMPlexCeedElemRestrictionQDataCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,PetscInt q_data_size,CeedElemRestriction * restriction)2527b8c5038SJames Wright PetscErrorCode DMPlexCeedElemRestrictionQDataCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height,
2537b8c5038SJames Wright PetscInt q_data_size, CeedElemRestriction *restriction) {
2547b8c5038SJames Wright PetscFunctionBeginUser;
2557b8c5038SJames Wright PetscCall(DMPlexCeedElemRestrictionStridedCreate(ceed, dm, domain_label, label_value, height, q_data_size, PETSC_FALSE, restriction));
2567b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
2577b8c5038SJames Wright }
2587b8c5038SJames Wright
2597b8c5038SJames Wright /**
2607b8c5038SJames Wright @brief Create `CeedElemRestriction` from `DMPlex` domain for nodally collocated auxilury `QFunction` data.
2617b8c5038SJames Wright
2627b8c5038SJames Wright Not collective across MPI processes.
2637b8c5038SJames Wright
2647b8c5038SJames Wright @param[in] ceed `Ceed` context
2657b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
2667b8c5038SJames Wright @param[in] domain_label Label for `DMPlex` domain
2677b8c5038SJames Wright @param[in] label_value Stratum value
2687b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
2697b8c5038SJames Wright @param[in] q_data_size Number of components for `QFunction` data
2707b8c5038SJames Wright @param[out] restriction Strided `CeedElemRestriction` for `QFunction` data
2717b8c5038SJames Wright
2727b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
2737b8c5038SJames Wright **/
DMPlexCeedElemRestrictionCollocatedCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,PetscInt q_data_size,CeedElemRestriction * restriction)2747b8c5038SJames Wright PetscErrorCode DMPlexCeedElemRestrictionCollocatedCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height,
2757b8c5038SJames Wright PetscInt q_data_size, CeedElemRestriction *restriction) {
2767b8c5038SJames Wright PetscFunctionBeginUser;
2777b8c5038SJames Wright PetscCall(DMPlexCeedElemRestrictionStridedCreate(ceed, dm, domain_label, label_value, height, q_data_size, PETSC_TRUE, restriction));
2787b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
2797b8c5038SJames Wright }
2807b8c5038SJames Wright
2817b8c5038SJames Wright /**
2827b8c5038SJames Wright @brief Creates a tensor-product uniform quadrature.
2837b8c5038SJames Wright This is only for comparison studies and generally should not be used.
2847b8c5038SJames Wright
2857b8c5038SJames Wright @param[in] dim Spatial dimension
2867b8c5038SJames Wright @param[in] num_comp Number of components
2877b8c5038SJames Wright @param[in] num_points Number of points in one dimension
2887b8c5038SJames Wright @param[in] a Left end of interval (often -1)
2897b8c5038SJames Wright @param[in] b Right end of interval (often +1)
2907b8c5038SJames Wright @param[out] q `PetscQuadrature` object
2917b8c5038SJames Wright
2927b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
2937b8c5038SJames Wright **/
PetscDTUniformTensorQuadrature(PetscInt dim,PetscInt num_comp,PetscInt num_points,PetscReal a,PetscReal b,PetscQuadrature * q)2947b8c5038SJames Wright static PetscErrorCode PetscDTUniformTensorQuadrature(PetscInt dim, PetscInt num_comp, PetscInt num_points, PetscReal a, PetscReal b,
2957b8c5038SJames Wright PetscQuadrature *q) {
2967b8c5038SJames Wright DMPolytopeType ct;
2977b8c5038SJames Wright PetscInt num_total_points = dim > 1 ? (dim > 2 ? (num_points * num_points * num_points) : (num_points * num_points)) : num_points;
2987b8c5038SJames Wright PetscReal *coords, *weights, *coords_1d;
2997b8c5038SJames Wright
3007b8c5038SJames Wright PetscFunctionBeginUser;
3017b8c5038SJames Wright PetscCall(PetscMalloc1(num_total_points * dim, &coords));
3027b8c5038SJames Wright PetscCall(PetscMalloc1(num_total_points * num_comp, &weights));
3037b8c5038SJames Wright // Compute weights, points
3047b8c5038SJames Wright switch (dim) {
3057b8c5038SJames Wright case 0:
3067b8c5038SJames Wright ct = DM_POLYTOPE_POINT;
3077b8c5038SJames Wright PetscCall(PetscFree(coords));
3087b8c5038SJames Wright PetscCall(PetscFree(weights));
3097b8c5038SJames Wright PetscCall(PetscMalloc1(1, &coords));
3107b8c5038SJames Wright PetscCall(PetscMalloc1(num_comp, &weights));
3117b8c5038SJames Wright num_total_points = 1;
3127b8c5038SJames Wright coords[0] = 0.0;
3137b8c5038SJames Wright for (PetscInt c = 0; c < num_comp; c++) weights[c] = 1.0;
3147b8c5038SJames Wright break;
3157b8c5038SJames Wright case 1: {
3167b8c5038SJames Wright ct = DM_POLYTOPE_SEGMENT;
3177b8c5038SJames Wright PetscReal step = (b - a) / num_points;
3187b8c5038SJames Wright
3197b8c5038SJames Wright for (PetscInt i = 0; i < num_points; i++) {
3207b8c5038SJames Wright coords[i] = step * (i + 0.5) + a;
3217b8c5038SJames Wright for (PetscInt c = 0; c < num_comp; c++) weights[i * num_comp + c] = 1.0;
3227b8c5038SJames Wright }
3237b8c5038SJames Wright } break;
3247b8c5038SJames Wright case 2: {
3257b8c5038SJames Wright ct = DM_POLYTOPE_QUADRILATERAL;
3267b8c5038SJames Wright PetscCall(PetscMalloc1(num_points, &coords_1d));
3277b8c5038SJames Wright PetscReal step = (b - a) / num_points;
3287b8c5038SJames Wright
3297b8c5038SJames Wright for (PetscInt i = 0; i < num_points; i++) coords_1d[i] = step * (i + 0.5) + a;
3307b8c5038SJames Wright for (PetscInt i = 0; i < num_points; i++) {
3317b8c5038SJames Wright for (PetscInt j = 0; j < num_points; j++) {
3327b8c5038SJames Wright coords[(i * num_points + j) * dim + 0] = coords_1d[i];
3337b8c5038SJames Wright coords[(i * num_points + j) * dim + 1] = coords_1d[j];
3347b8c5038SJames Wright for (PetscInt c = 0; c < num_comp; c++) weights[(i * num_points + j) * num_comp + c] = 1.0;
3357b8c5038SJames Wright }
3367b8c5038SJames Wright }
3377b8c5038SJames Wright PetscCall(PetscFree(coords_1d));
3387b8c5038SJames Wright } break;
3397b8c5038SJames Wright case 3: {
3407b8c5038SJames Wright ct = DM_POLYTOPE_HEXAHEDRON;
3417b8c5038SJames Wright PetscCall(PetscMalloc1(num_points, &coords_1d));
3427b8c5038SJames Wright PetscReal step = (b - a) / num_points;
3437b8c5038SJames Wright
3447b8c5038SJames Wright for (PetscInt i = 0; i < num_points; i++) coords_1d[i] = step * (i + 0.5) + a;
3457b8c5038SJames Wright for (PetscInt i = 0; i < num_points; i++) {
3467b8c5038SJames Wright for (PetscInt j = 0; j < num_points; j++) {
3477b8c5038SJames Wright for (PetscInt k = 0; k < num_points; k++) {
3487b8c5038SJames Wright coords[((i * num_points + j) * num_points + k) * dim + 0] = coords_1d[i];
3497b8c5038SJames Wright coords[((i * num_points + j) * num_points + k) * dim + 1] = coords_1d[j];
3507b8c5038SJames Wright coords[((i * num_points + j) * num_points + k) * dim + 2] = coords_1d[k];
3517b8c5038SJames Wright for (PetscInt c = 0; c < num_comp; c++) weights[((i * num_points + j) * num_points + k) * num_comp + c] = 1.0;
3527b8c5038SJames Wright }
3537b8c5038SJames Wright }
3547b8c5038SJames Wright }
3557b8c5038SJames Wright PetscCall(PetscFree(coords_1d));
3567b8c5038SJames Wright } break;
3577b8c5038SJames Wright // LCOV_EXCL_START
3587b8c5038SJames Wright default:
3597b8c5038SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %" PetscInt_FMT, dim);
3607b8c5038SJames Wright // LCOV_EXCL_STOP
3617b8c5038SJames Wright }
3627b8c5038SJames Wright PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q));
3637b8c5038SJames Wright PetscCall(PetscQuadratureSetCellType(*q, ct));
3647b8c5038SJames Wright PetscCall(PetscQuadratureSetOrder(*q, num_points));
3657b8c5038SJames Wright PetscCall(PetscQuadratureSetData(*q, dim, num_comp, num_total_points, coords, weights));
3667b8c5038SJames Wright PetscCall(PetscObjectChangeTypeName((PetscObject)*q, "UniformTensor"));
3677b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
3687b8c5038SJames Wright }
3697b8c5038SJames Wright
3707b8c5038SJames Wright /**
3717b8c5038SJames Wright @brief Setup `DM` with FE space of appropriate degree
3727b8c5038SJames Wright
3737b8c5038SJames Wright @param[in] comm MPI communicator
3747b8c5038SJames Wright @param[in] dim Spatial dimension
3757b8c5038SJames Wright @param[in] num_comp Number of components
3767b8c5038SJames Wright @param[in] is_simplex Flag for simplex or tensor product element
3777b8c5038SJames Wright @param[in] order Polynomial order of space
3787b8c5038SJames Wright @param[in] q_order Quadrature order
3797b8c5038SJames Wright @param[in] prefix The options prefix, or `NULL`
3807b8c5038SJames Wright @param[out] fem `PetscFE` object
3817b8c5038SJames Wright
3827b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
3837b8c5038SJames Wright **/
PetscFECreateLagrangeFromOptions(MPI_Comm comm,PetscInt dim,PetscInt num_comp,PetscBool is_simplex,PetscInt order,PetscInt q_order,const char prefix[],PetscFE * fem)3847b8c5038SJames Wright PetscErrorCode PetscFECreateLagrangeFromOptions(MPI_Comm comm, PetscInt dim, PetscInt num_comp, PetscBool is_simplex, PetscInt order,
3857b8c5038SJames Wright PetscInt q_order, const char prefix[], PetscFE *fem) {
3867b8c5038SJames Wright PetscBool is_tensor = !is_simplex;
3877b8c5038SJames Wright DMPolytopeType polytope_type = DMPolytopeTypeSimpleShape(dim, is_simplex);
3887b8c5038SJames Wright PetscSpace fe_space;
3897b8c5038SJames Wright PetscDualSpace fe_dual_space;
3907b8c5038SJames Wright PetscQuadrature quadrature, face_quadrature;
3917b8c5038SJames Wright
3927b8c5038SJames Wright PetscFunctionBeginUser;
3937b8c5038SJames Wright // Create space
3947b8c5038SJames Wright PetscCall(PetscSpaceCreate(comm, &fe_space));
3957b8c5038SJames Wright PetscCall(PetscSpaceSetType(fe_space, PETSCSPACEPOLYNOMIAL));
3967b8c5038SJames Wright PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fe_space, prefix));
3977b8c5038SJames Wright PetscCall(PetscSpacePolynomialSetTensor(fe_space, is_tensor));
3987b8c5038SJames Wright PetscCall(PetscSpaceSetNumComponents(fe_space, num_comp));
3997b8c5038SJames Wright PetscCall(PetscSpaceSetNumVariables(fe_space, dim));
4007b8c5038SJames Wright if (order >= 0) {
4017b8c5038SJames Wright PetscCall(PetscSpaceSetDegree(fe_space, order, PETSC_DETERMINE));
4027b8c5038SJames Wright if (polytope_type == DM_POLYTOPE_TRI_PRISM || polytope_type == DM_POLYTOPE_TRI_PRISM_TENSOR) {
4037b8c5038SJames Wright PetscSpace fe_space_end, fe_space_side;
4047b8c5038SJames Wright
4057b8c5038SJames Wright PetscCall(PetscSpaceSetNumComponents(fe_space, 1));
4067b8c5038SJames Wright PetscCall(PetscSpaceCreate(comm, &fe_space_end));
4077b8c5038SJames Wright PetscCall(PetscSpaceSetType(fe_space_end, PETSCSPACEPOLYNOMIAL));
4087b8c5038SJames Wright PetscCall(PetscSpacePolynomialSetTensor(fe_space_end, PETSC_FALSE));
4097b8c5038SJames Wright PetscCall(PetscSpaceSetNumComponents(fe_space_end, 1));
4107b8c5038SJames Wright PetscCall(PetscSpaceSetNumVariables(fe_space_end, dim - 1));
4117b8c5038SJames Wright PetscCall(PetscSpaceSetDegree(fe_space_end, order, PETSC_DETERMINE));
4127b8c5038SJames Wright PetscCall(PetscSpaceCreate(comm, &fe_space_side));
4137b8c5038SJames Wright PetscCall(PetscSpaceSetType(fe_space_side, PETSCSPACEPOLYNOMIAL));
4147b8c5038SJames Wright PetscCall(PetscSpacePolynomialSetTensor(fe_space_side, PETSC_FALSE));
4157b8c5038SJames Wright PetscCall(PetscSpaceSetNumComponents(fe_space_side, 1));
4167b8c5038SJames Wright PetscCall(PetscSpaceSetNumVariables(fe_space_side, 1));
4177b8c5038SJames Wright PetscCall(PetscSpaceSetDegree(fe_space_side, order, PETSC_DETERMINE));
4187b8c5038SJames Wright PetscCall(PetscSpaceSetType(fe_space, PETSCSPACETENSOR));
4197b8c5038SJames Wright PetscCall(PetscSpaceTensorSetNumSubspaces(fe_space, 2));
4207b8c5038SJames Wright PetscCall(PetscSpaceTensorSetSubspace(fe_space, 0, fe_space_end));
4217b8c5038SJames Wright PetscCall(PetscSpaceTensorSetSubspace(fe_space, 1, fe_space_side));
4227b8c5038SJames Wright PetscCall(PetscSpaceDestroy(&fe_space_end));
4237b8c5038SJames Wright PetscCall(PetscSpaceDestroy(&fe_space_side));
4247b8c5038SJames Wright
4257b8c5038SJames Wright if (num_comp > 1) {
4267b8c5038SJames Wright PetscSpace scalar_fe_space = fe_space;
4277b8c5038SJames Wright
4287b8c5038SJames Wright PetscCall(PetscSpaceCreate(comm, &fe_space));
4297b8c5038SJames Wright PetscCall(PetscSpaceSetNumVariables(fe_space, dim));
4307b8c5038SJames Wright PetscCall(PetscSpaceSetNumComponents(fe_space, num_comp));
4317b8c5038SJames Wright PetscCall(PetscSpaceSetType(fe_space, PETSCSPACESUM));
4327b8c5038SJames Wright PetscCall(PetscSpaceSumSetNumSubspaces(fe_space, num_comp));
4337b8c5038SJames Wright PetscCall(PetscSpaceSumSetConcatenate(fe_space, PETSC_TRUE));
4347b8c5038SJames Wright PetscCall(PetscSpaceSumSetInterleave(fe_space, PETSC_TRUE, PETSC_FALSE));
4357b8c5038SJames Wright for (PetscInt i = 0; i < num_comp; i++) PetscCall(PetscSpaceSumSetSubspace(fe_space, i, scalar_fe_space));
4367b8c5038SJames Wright PetscCall(PetscSpaceDestroy(&scalar_fe_space));
4377b8c5038SJames Wright }
4387b8c5038SJames Wright }
4397b8c5038SJames Wright }
4407b8c5038SJames Wright PetscCall(PetscSpaceSetFromOptions(fe_space));
4417b8c5038SJames Wright PetscCall(PetscSpaceSetUp(fe_space));
4427b8c5038SJames Wright PetscCall(PetscSpaceGetDegree(fe_space, &order, NULL));
4437b8c5038SJames Wright PetscCall(PetscSpacePolynomialGetTensor(fe_space, &is_tensor));
4447b8c5038SJames Wright PetscCall(PetscSpaceGetNumComponents(fe_space, &num_comp));
4457b8c5038SJames Wright
4467b8c5038SJames Wright // Create dual space
4477b8c5038SJames Wright PetscCall(PetscDualSpaceCreate(comm, &fe_dual_space));
4487b8c5038SJames Wright PetscCall(PetscDualSpaceSetType(fe_dual_space, PETSCDUALSPACELAGRANGE));
4497b8c5038SJames Wright PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fe_dual_space, prefix));
4507b8c5038SJames Wright {
4517b8c5038SJames Wright DM dual_space_dm;
4527b8c5038SJames Wright
4537b8c5038SJames Wright PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, polytope_type, &dual_space_dm));
4547b8c5038SJames Wright PetscCall(PetscDualSpaceSetDM(fe_dual_space, dual_space_dm));
4557b8c5038SJames Wright PetscCall(DMDestroy(&dual_space_dm));
4567b8c5038SJames Wright }
4577b8c5038SJames Wright PetscCall(PetscDualSpaceSetNumComponents(fe_dual_space, num_comp));
4587b8c5038SJames Wright PetscCall(PetscDualSpaceSetOrder(fe_dual_space, order));
4597b8c5038SJames Wright PetscCall(PetscDualSpaceLagrangeSetTensor(fe_dual_space, (is_tensor || (polytope_type == DM_POLYTOPE_TRI_PRISM)) ? PETSC_TRUE : PETSC_FALSE));
4607b8c5038SJames Wright PetscCall(PetscDualSpaceSetFromOptions(fe_dual_space));
4617b8c5038SJames Wright PetscCall(PetscDualSpaceSetUp(fe_dual_space));
4627b8c5038SJames Wright
4637b8c5038SJames Wright // Create quadrature
4647b8c5038SJames Wright q_order = q_order >= 0 ? q_order : order;
4657b8c5038SJames Wright PetscBool use_uniform = PETSC_FALSE;
4667b8c5038SJames Wright
4677b8c5038SJames Wright PetscOptionsBegin(comm, NULL, "Uniform quadrature check", NULL);
4687b8c5038SJames Wright PetscCall(PetscOptionsBool("-petscdt_uniform_tensor_quadrature", "", NULL, use_uniform, &use_uniform, NULL));
4697b8c5038SJames Wright PetscOptionsEnd();
4707b8c5038SJames Wright PetscCheck(!use_uniform || (is_tensor || dim == 1), comm, PETSC_ERR_SUP, "Can only use uniform quadrature on tensor product elements");
4717b8c5038SJames Wright if (use_uniform) {
4727b8c5038SJames Wright PetscCall(PetscDTUniformTensorQuadrature(dim, 1, q_order + 1, -1.0, 1.0, &quadrature));
4737b8c5038SJames Wright PetscCall(PetscDTUniformTensorQuadrature(dim - 1, 1, q_order + 1, -1.0, 1.0, &face_quadrature));
4747b8c5038SJames Wright } else {
4757b8c5038SJames Wright PetscCall(PetscDTCreateDefaultQuadrature(polytope_type, q_order, &quadrature, &face_quadrature));
4767b8c5038SJames Wright }
4777b8c5038SJames Wright
4787b8c5038SJames Wright // Create finite element
4797b8c5038SJames Wright PetscCall(PetscFECreateFromSpaces(fe_space, fe_dual_space, quadrature, face_quadrature, fem));
4807b8c5038SJames Wright PetscCall(PetscFESetFromOptions(*fem));
4817b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
4827b8c5038SJames Wright }
4837b8c5038SJames Wright
4847b8c5038SJames Wright /**
4857b8c5038SJames Wright @brief Get global `DMPlex` topology type.
4867b8c5038SJames Wright
4877b8c5038SJames Wright Collective across MPI processes.
4887b8c5038SJames Wright
4897b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
4907b8c5038SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
4917b8c5038SJames Wright @param[in] label_value Stratum value
4927b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
4937b8c5038SJames Wright @param[out] cell_type `DMPlex` topology type
4947b8c5038SJames Wright **/
GetGlobalDMPlexPolytopeType(DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,DMPolytopeType * cell_type)4957b8c5038SJames Wright static inline PetscErrorCode GetGlobalDMPlexPolytopeType(DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height,
4967b8c5038SJames Wright DMPolytopeType *cell_type) {
4977b8c5038SJames Wright PetscInt first_point;
4987b8c5038SJames Wright PetscInt ids[1] = {label_value};
4997b8c5038SJames Wright DMLabel depth_label;
5007b8c5038SJames Wright
5017b8c5038SJames Wright PetscFunctionBeginUser;
5027b8c5038SJames Wright // Use depth label if no domain label present
5037b8c5038SJames Wright if (!domain_label) {
5047b8c5038SJames Wright PetscInt depth;
5057b8c5038SJames Wright
5067b8c5038SJames Wright PetscCall(DMPlexGetDepth(dm, &depth));
5077b8c5038SJames Wright PetscCall(DMPlexGetDepthLabel(dm, &depth_label));
5087b8c5038SJames Wright ids[0] = depth - height;
5097b8c5038SJames Wright }
5107b8c5038SJames Wright
5117b8c5038SJames Wright // Get cell interp, grad, and quadrature data
5127b8c5038SJames Wright PetscCall(DMGetFirstLabeledPoint(dm, dm, domain_label ? domain_label : depth_label, 1, ids, height, &first_point, NULL));
5137b8c5038SJames Wright if (first_point != -1) PetscCall(DMPlexGetCellType(dm, first_point, cell_type));
5147b8c5038SJames Wright
5157b8c5038SJames Wright { // Form agreement about CellType
5167b8c5038SJames Wright PetscInt cell_type_local = -1, cell_type_global = -1;
5177b8c5038SJames Wright
5187b8c5038SJames Wright if (first_point != -1) cell_type_local = (PetscInt)*cell_type;
5197b8c5038SJames Wright PetscCallMPI(MPIU_Allreduce(&cell_type_local, &cell_type_global, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
5207b8c5038SJames Wright *cell_type = (DMPolytopeType)cell_type_global;
5217b8c5038SJames Wright }
5227b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
5237b8c5038SJames Wright }
5247b8c5038SJames Wright
5257b8c5038SJames Wright /**
5267b8c5038SJames Wright @brief Get the permutation and field offset for a given depth.
5277b8c5038SJames Wright
5287b8c5038SJames Wright Not collective across MPI processes.
5297b8c5038SJames Wright
5307b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
5317b8c5038SJames Wright @param[in] depth Depth of `DMPlex` topology
5327b8c5038SJames Wright @param[in] field Index of `DMPlex` field
5337b8c5038SJames Wright @param[out] permutation Permutation for `DMPlex` field
5347b8c5038SJames Wright @param[out] field_offset Offset to `DMPlex` field
5357b8c5038SJames Wright **/
GetClosurePermutationAndFieldOffsetAtDepth(DM dm,PetscInt depth,PetscInt field,IS * permutation,PetscInt * field_offset)5367b8c5038SJames Wright static inline PetscErrorCode GetClosurePermutationAndFieldOffsetAtDepth(DM dm, PetscInt depth, PetscInt field, IS *permutation,
5377b8c5038SJames Wright PetscInt *field_offset) {
5387b8c5038SJames Wright PetscBool is_field_continuous = PETSC_TRUE;
5397b8c5038SJames Wright PetscInt dim, num_fields, offset = 0, size = 0;
5407b8c5038SJames Wright PetscSection section;
5417b8c5038SJames Wright
5427b8c5038SJames Wright PetscFunctionBeginUser;
5437b8c5038SJames Wright *field_offset = 0;
5447b8c5038SJames Wright
5457b8c5038SJames Wright PetscCall(DMGetDimension(dm, &dim));
5467b8c5038SJames Wright PetscCall(DMGetLocalSection(dm, §ion));
5477b8c5038SJames Wright PetscCall(PetscSectionGetNumFields(section, &num_fields));
5487b8c5038SJames Wright // ---- Permutation size and offset to current field
5497b8c5038SJames Wright for (PetscInt f = 0; f < num_fields; f++) {
5507b8c5038SJames Wright PetscBool is_continuous;
5517b8c5038SJames Wright PetscInt num_components, num_dof_1d, dual_space_size, field_size;
5527b8c5038SJames Wright PetscObject obj;
5537b8c5038SJames Wright PetscFE fe = NULL;
5547b8c5038SJames Wright PetscDualSpace dual_space;
5557b8c5038SJames Wright
5567b8c5038SJames Wright PetscCall(PetscSectionGetFieldComponents(section, f, &num_components));
5577b8c5038SJames Wright PetscCall(DMGetField(dm, f, NULL, &obj));
5587b8c5038SJames Wright fe = (PetscFE)obj;
5597b8c5038SJames Wright PetscCall(PetscFEGetDualSpace(fe, &dual_space));
5607b8c5038SJames Wright PetscCall(PetscDualSpaceLagrangeGetContinuity(dual_space, &is_continuous));
5617b8c5038SJames Wright if (f == field) is_field_continuous = is_continuous;
5627b8c5038SJames Wright if (!is_continuous) continue;
5637b8c5038SJames Wright PetscCall(PetscDualSpaceGetDimension(dual_space, &dual_space_size));
5647b8c5038SJames Wright num_dof_1d = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / num_components, 1.0 / dim));
5657b8c5038SJames Wright field_size = PetscPowInt(num_dof_1d, depth) * num_components;
5667b8c5038SJames Wright if (f < field) offset += field_size;
5677b8c5038SJames Wright size += field_size;
5687b8c5038SJames Wright }
5697b8c5038SJames Wright
5707b8c5038SJames Wright if (is_field_continuous) {
5717b8c5038SJames Wright *field_offset = offset;
5727b8c5038SJames Wright PetscCall(PetscSectionGetClosurePermutation(section, (PetscObject)dm, depth, size, permutation));
5737b8c5038SJames Wright }
5747b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
5757b8c5038SJames Wright }
5767b8c5038SJames Wright
5777b8c5038SJames Wright /**
5787b8c5038SJames Wright @brief Compute field tabulation from `PetscTabulation`.
5797b8c5038SJames Wright
5807b8c5038SJames Wright Not collective across MPI processes.
5817b8c5038SJames Wright
5827b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
5837b8c5038SJames Wright @param[in] field Index of `DMPlex` field
5847b8c5038SJames Wright @param[in] face Index of basis face, or 0
5857b8c5038SJames Wright @param[in] tabulation PETSc basis tabulation
5867b8c5038SJames Wright @param[out] interp Interpolation matrix in libCEED orientation
5877b8c5038SJames Wright @param[out] grad Gradient matrix in libCEED orientation
5887b8c5038SJames Wright
5897b8c5038SJames Wright @note `interp` and `grad` are allocated using `PetscCalloc1` and must be freed by the user.
5907b8c5038SJames Wright **/
ComputeFieldTabulationP2C(DM dm,PetscInt field,PetscInt face,PetscTabulation tabulation,CeedScalar ** interp,CeedScalar ** grad)5917b8c5038SJames Wright static inline PetscErrorCode ComputeFieldTabulationP2C(DM dm, PetscInt field, PetscInt face, PetscTabulation tabulation, CeedScalar **interp,
5927b8c5038SJames Wright CeedScalar **grad) {
5937b8c5038SJames Wright PetscBool is_simplex, has_permutation = PETSC_FALSE;
5947b8c5038SJames Wright PetscInt field_offset = 0, num_comp, P, Q, dim;
5957b8c5038SJames Wright const PetscInt *permutation_indices;
5967b8c5038SJames Wright IS permutation = NULL;
5977b8c5038SJames Wright
5987b8c5038SJames Wright PetscFunctionBeginUser;
5997b8c5038SJames Wright num_comp = tabulation->Nc;
6007b8c5038SJames Wright P = tabulation->Nb / num_comp;
6017b8c5038SJames Wright Q = tabulation->Np;
6027b8c5038SJames Wright dim = tabulation->cdim;
6037b8c5038SJames Wright
6047b8c5038SJames Wright PetscCall(PetscCalloc1(P * Q, interp));
6057b8c5038SJames Wright PetscCall(PetscCalloc1(P * Q * dim, grad));
6067b8c5038SJames Wright
6077b8c5038SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex));
6087b8c5038SJames Wright if (!is_simplex) {
6097b8c5038SJames Wright PetscCall(GetClosurePermutationAndFieldOffsetAtDepth(dm, dim, field, &permutation, &field_offset));
6107b8c5038SJames Wright has_permutation = !!permutation;
6117b8c5038SJames Wright if (has_permutation) PetscCall(ISGetIndices(permutation, &permutation_indices));
6127b8c5038SJames Wright }
6137b8c5038SJames Wright
6147b8c5038SJames Wright const CeedInt c = 0;
6157b8c5038SJames Wright for (CeedInt q = 0; q < Q; q++) {
6167b8c5038SJames Wright for (CeedInt p_ceed = 0; p_ceed < P; p_ceed++) {
6177b8c5038SJames Wright CeedInt p_petsc = has_permutation ? (permutation_indices[field_offset + p_ceed * num_comp] - field_offset) : (p_ceed * num_comp);
6187b8c5038SJames Wright (*interp)[q * P + p_ceed] = tabulation->T[0][((face * Q + q) * P * num_comp + p_petsc) * num_comp + c];
6197b8c5038SJames Wright for (CeedInt d = 0; d < dim; d++) {
6207b8c5038SJames Wright (*grad)[(d * Q + q) * P + p_ceed] = tabulation->T[1][(((face * Q + q) * P * num_comp + p_petsc) * num_comp + c) * dim + d];
6217b8c5038SJames Wright }
6227b8c5038SJames Wright }
6237b8c5038SJames Wright }
6247b8c5038SJames Wright
6257b8c5038SJames Wright if (has_permutation) PetscCall(ISRestoreIndices(permutation, &permutation_indices));
6267b8c5038SJames Wright PetscCall(ISDestroy(&permutation));
6277b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
6287b8c5038SJames Wright }
6297b8c5038SJames Wright
6307b8c5038SJames Wright /**
6317b8c5038SJames Wright @brief Get quadrature data from `PetscQuadrature` for use with libCEED.
6327b8c5038SJames Wright
6337b8c5038SJames Wright Not collective across MPI processes.
6347b8c5038SJames Wright
6357b8c5038SJames Wright @param[in] fe `PetscFE` object
6367b8c5038SJames Wright @param[in] quadrature PETSc basis quadrature
6377b8c5038SJames Wright @param[out] q_dim Quadrature dimension, or NULL if not needed
6387b8c5038SJames Wright @param[out] num_comp Number of components, or NULL if not needed
6397b8c5038SJames Wright @param[out] Q Number of quadrature points, or NULL if not needed
6407b8c5038SJames Wright @param[out] q_points Quadrature points in libCEED orientation, or NULL if not needed
6417b8c5038SJames Wright @param[out] q_weights Quadrature weights in libCEED orientation, or NULL if not needed
6427b8c5038SJames Wright
6437b8c5038SJames Wright @note `q_weights` and `q_points` are allocated using `PetscCalloc1` and must be freed by the user.
6447b8c5038SJames Wright **/
GetQuadratureDataP2C(PetscFE fe,PetscQuadrature quadrature,PetscInt * q_dim,PetscInt * num_comp,PetscInt * Q,CeedScalar ** q_points,CeedScalar ** q_weights)6457b8c5038SJames Wright static inline PetscErrorCode GetQuadratureDataP2C(PetscFE fe, PetscQuadrature quadrature, PetscInt *q_dim, PetscInt *num_comp, PetscInt *Q,
6467b8c5038SJames Wright CeedScalar **q_points, CeedScalar **q_weights) {
6477b8c5038SJames Wright PetscInt spatial_dim, dim, num_comp_quadrature, num_q_points;
6487b8c5038SJames Wright const PetscReal *q_points_petsc, *q_weights_petsc;
6497b8c5038SJames Wright
6507b8c5038SJames Wright PetscFunctionBeginUser;
6517b8c5038SJames Wright PetscCall(PetscFEGetSpatialDimension(fe, &spatial_dim));
6527b8c5038SJames Wright PetscCall(PetscQuadratureGetData(quadrature, &dim, &num_comp_quadrature, &num_q_points, &q_points_petsc, &q_weights_petsc));
6537b8c5038SJames Wright if (q_dim) *q_dim = dim;
6547b8c5038SJames Wright if (num_comp) *num_comp = num_comp_quadrature;
6557b8c5038SJames Wright if (Q) *Q = num_q_points;
6567b8c5038SJames Wright if (q_weights) {
6577b8c5038SJames Wright PetscSizeT q_weights_size = num_q_points;
6587b8c5038SJames Wright
6597b8c5038SJames Wright PetscCall(PetscCalloc1(q_weights_size, q_weights));
6607b8c5038SJames Wright for (CeedInt i = 0; i < num_q_points; i++) (*q_weights)[i] = q_weights_petsc[i];
6617b8c5038SJames Wright }
6627b8c5038SJames Wright if (q_points) {
6637b8c5038SJames Wright PetscSizeT q_points_size = num_q_points * spatial_dim;
6647b8c5038SJames Wright
6657b8c5038SJames Wright PetscCall(PetscCalloc1(q_points_size, q_points));
6667b8c5038SJames Wright for (CeedInt i = 0; i < num_q_points; i++) {
6677b8c5038SJames Wright for (CeedInt d = 0; d < dim; d++) (*q_points)[i * spatial_dim + d] = q_points_petsc[i * dim + d];
6687b8c5038SJames Wright }
6697b8c5038SJames Wright }
6707b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
6717b8c5038SJames Wright }
6727b8c5038SJames Wright
6737b8c5038SJames Wright /**
6747b8c5038SJames Wright @brief Create 1D tabulation from `PetscFE`.
6757b8c5038SJames Wright
6767b8c5038SJames Wright Collective across MPI processes.
6777b8c5038SJames Wright
6787b8c5038SJames Wright @note `q_weights` and `q_points` are allocated using `PetscCalloc1` and must be freed by the user.
6797b8c5038SJames Wright
6807b8c5038SJames Wright @param[in] comm `MPI_Comm` for creating `FE` object from options
6817b8c5038SJames Wright @param[in] fe PETSc basis `FE` object
6827b8c5038SJames Wright @param[out] tabulation PETSc basis tabulation
6837b8c5038SJames Wright @param[out] q_points_1d Quadrature points in libCEED orientation
6847b8c5038SJames Wright @param[out] q_weights_1d Quadrature weights in libCEED orientation
6857b8c5038SJames Wright
6867b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
6877b8c5038SJames Wright **/
Create1DTabulation_Tensor(MPI_Comm comm,PetscFE fe,PetscTabulation * tabulation,PetscReal ** q_points_1d,CeedScalar ** q_weights_1d)6887b8c5038SJames Wright static inline PetscErrorCode Create1DTabulation_Tensor(MPI_Comm comm, PetscFE fe, PetscTabulation *tabulation, PetscReal **q_points_1d,
6897b8c5038SJames Wright CeedScalar **q_weights_1d) {
6907b8c5038SJames Wright PetscFE fe_1d;
6917b8c5038SJames Wright PetscInt dim, num_comp, Q = -1, q_dim = -1, num_derivatives = 1;
6927b8c5038SJames Wright PetscQuadrature quadrature;
6937b8c5038SJames Wright
6947b8c5038SJames Wright PetscFunctionBeginUser;
6957b8c5038SJames Wright // Create 1D FE
6967b8c5038SJames Wright PetscCall(PetscFEGetNumComponents(fe, &num_comp));
6977b8c5038SJames Wright PetscCall(PetscFEGetSpatialDimension(fe, &dim));
6987b8c5038SJames Wright {
6997b8c5038SJames Wright const char *prefix;
7007b8c5038SJames Wright PetscBool is_tensor;
7017b8c5038SJames Wright PetscInt num_comp, order, q_order;
7027b8c5038SJames Wright PetscDualSpace dual_space;
7037b8c5038SJames Wright PetscQuadrature quadrature;
7047b8c5038SJames Wright
7057b8c5038SJames Wright PetscCall(PetscObjectGetOptionsPrefix((PetscObject)fe, &prefix));
7067b8c5038SJames Wright PetscCall(PetscFEGetDualSpace(fe, &dual_space));
7077b8c5038SJames Wright PetscCall(PetscFEGetNumComponents(fe, &num_comp));
7087b8c5038SJames Wright PetscCall(PetscDualSpaceLagrangeGetTensor(dual_space, &is_tensor));
7097b8c5038SJames Wright PetscCall(PetscDualSpaceGetOrder(dual_space, &order));
7107b8c5038SJames Wright PetscCall(PetscFEGetQuadrature(fe, &quadrature));
7117b8c5038SJames Wright PetscCall(PetscQuadratureGetData(quadrature, NULL, NULL, &q_order, NULL, NULL));
7127b8c5038SJames Wright PetscCall(PetscFECreateLagrangeFromOptions(comm, 1, num_comp, !is_tensor, order,
7137b8c5038SJames Wright (PetscInt)PetscCeilReal(PetscPowReal(1.0 * q_order, 1.0 / dim)) - 1, prefix, &fe_1d));
7147b8c5038SJames Wright }
7157b8c5038SJames Wright
7167b8c5038SJames Wright // Get quadrature data
7177b8c5038SJames Wright PetscCall(PetscFEGetQuadrature(fe_1d, &quadrature));
7187b8c5038SJames Wright PetscCall(GetQuadratureDataP2C(fe_1d, quadrature, &q_dim, NULL, &Q, q_points_1d, q_weights_1d));
7197b8c5038SJames Wright
7207b8c5038SJames Wright // Compute 1D tabulation
7217b8c5038SJames Wright PetscCall(PetscFECreateTabulation(fe_1d, 1, Q, *q_points_1d, num_derivatives, tabulation));
7227b8c5038SJames Wright
7237b8c5038SJames Wright // Cleanup
7247b8c5038SJames Wright PetscCall(PetscFEDestroy(&fe_1d));
7257b8c5038SJames Wright
7267b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
7277b8c5038SJames Wright }
7287b8c5038SJames Wright
7297b8c5038SJames Wright /**
7307b8c5038SJames Wright @brief Destroy `CeedBasis` in a `PetscContainer`.
7317b8c5038SJames Wright
7327b8c5038SJames Wright Not collective across MPI processes.
7337b8c5038SJames Wright
7347b8c5038SJames Wright @param[in,out] ctx `CeedBasis`
7357b8c5038SJames Wright
7367b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
7377b8c5038SJames Wright **/
DMPlexCeedBasisDestroy(void ** ctx)7387b8c5038SJames Wright static PetscErrorCode DMPlexCeedBasisDestroy(void **ctx) {
7397b8c5038SJames Wright CeedBasis basis = *(CeedBasis *)ctx;
7407b8c5038SJames Wright
7417b8c5038SJames Wright PetscFunctionBegin;
7427b8c5038SJames Wright PetscCallCeed(CeedBasisReturnCeed(basis), CeedBasisDestroy(&basis));
7437b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
7447b8c5038SJames Wright }
7457b8c5038SJames Wright
7467b8c5038SJames Wright /**
7477b8c5038SJames Wright @brief Create `CeedBasis` from `DMPlex`.
7487b8c5038SJames Wright
7497b8c5038SJames Wright The `CeedBasis` is stored in the `DMPlex` object for reuse;
7507b8c5038SJames Wright if the routine is called again with the same arguments, the same `CeedBasis` is returned.
7517b8c5038SJames Wright
7527b8c5038SJames Wright Collective across MPI processes.
7537b8c5038SJames Wright
7547b8c5038SJames Wright @param[in] ceed `Ceed` context
7557b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
7567b8c5038SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
7577b8c5038SJames Wright @param[in] label_value Stratum value
7587b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
7597b8c5038SJames Wright @param[in] dm_field Index of `DMPlex` field
7607b8c5038SJames Wright @param[out] basis `CeedBasis` for `DMPlex`
7617b8c5038SJames Wright
7627b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
7637b8c5038SJames Wright **/
DMPlexCeedBasisCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,PetscInt dm_field,CeedBasis * basis)7647b8c5038SJames Wright PetscErrorCode DMPlexCeedBasisCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height, PetscInt dm_field,
7657b8c5038SJames Wright CeedBasis *basis) {
7667b8c5038SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
7677b8c5038SJames Wright char container_name[1024];
7687b8c5038SJames Wright CeedBasis container_basis;
7697b8c5038SJames Wright
7707b8c5038SJames Wright PetscFunctionBeginUser;
7717b8c5038SJames Wright {
7727b8c5038SJames Wright const char *label_name = NULL;
7737b8c5038SJames Wright
7747b8c5038SJames Wright if (domain_label) PetscCall(PetscObjectGetName((PetscObject)domain_label, &label_name));
7757b8c5038SJames Wright PetscCall(PetscSNPrintf(container_name, sizeof(container_name),
7767b8c5038SJames Wright "DM CeedBasis - label: %s label value: %" PetscInt_FMT " height: %" PetscInt_FMT " DM field: %" PetscInt_FMT,
7777b8c5038SJames Wright label_name ? label_name : "NONE", label_value, height, dm_field));
7787b8c5038SJames Wright }
7797b8c5038SJames Wright PetscCall(PetscObjectContainerQuery((PetscObject)dm, container_name, (void **)&container_basis));
7807b8c5038SJames Wright
7817b8c5038SJames Wright if (container_basis) {
7827b8c5038SJames Wright // Copy existing basis
7837b8c5038SJames Wright *basis = NULL;
7847b8c5038SJames Wright PetscCallCeed(ceed, CeedBasisReferenceCopy(container_basis, basis));
7857b8c5038SJames Wright } else {
7867b8c5038SJames Wright PetscDS ds;
7877b8c5038SJames Wright PetscFE fe;
7887b8c5038SJames Wright PetscDualSpace dual_space;
7897b8c5038SJames Wright PetscQuadrature quadrature;
7907b8c5038SJames Wright PetscBool is_tensor = PETSC_TRUE;
7917b8c5038SJames Wright PetscInt ds_field = -1;
7927b8c5038SJames Wright
7937b8c5038SJames Wright // Get element information
7947b8c5038SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds, NULL));
7957b8c5038SJames Wright PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field));
7967b8c5038SJames Wright PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe));
7977b8c5038SJames Wright PetscCall(PetscFEGetHeightSubspace(fe, height, &fe));
7987b8c5038SJames Wright PetscCall(PetscFEGetQuadrature(fe, &quadrature));
7997b8c5038SJames Wright PetscCall(PetscFEGetDualSpace(fe, &dual_space));
8007b8c5038SJames Wright PetscCall(PetscDualSpaceLagrangeGetTensor(dual_space, &is_tensor));
8017b8c5038SJames Wright
8027b8c5038SJames Wright // Build libCEED basis
8037b8c5038SJames Wright PetscBool use_nontensor = PETSC_FALSE;
8047b8c5038SJames Wright
8057b8c5038SJames Wright PetscOptionsBegin(comm, NULL, "Tensor Basis as Nontensor Check", NULL);
8067b8c5038SJames Wright PetscCall(PetscOptionsBool("-ceed_basis_as_nontensor", "", NULL, use_nontensor, &use_nontensor, NULL));
8077b8c5038SJames Wright PetscOptionsEnd();
8087b8c5038SJames Wright
8097b8c5038SJames Wright if (!is_tensor || use_nontensor) {
8107b8c5038SJames Wright PetscTabulation basis_tabulation;
8117b8c5038SJames Wright PetscInt num_derivatives = 1, face = 0;
8127b8c5038SJames Wright CeedScalar *q_points, *q_weights, *interp, *grad;
8137b8c5038SJames Wright CeedElemTopology elem_topo;
8147b8c5038SJames Wright
8157b8c5038SJames Wright {
8167b8c5038SJames Wright DMPolytopeType cell_type;
8177b8c5038SJames Wright
8187b8c5038SJames Wright PetscCall(GetGlobalDMPlexPolytopeType(dm, domain_label, label_value, height, &cell_type));
8197b8c5038SJames Wright elem_topo = PolytopeTypePetscToCeed(cell_type);
8207b8c5038SJames Wright PetscCheck(elem_topo, comm, PETSC_ERR_SUP, "DMPlex topology not supported: %s", DMPolytopeTypes[cell_type]);
8217b8c5038SJames Wright }
8227b8c5038SJames Wright
8237b8c5038SJames Wright // Compute basis tabulation
8247b8c5038SJames Wright PetscCall(GetQuadratureDataP2C(fe, quadrature, NULL, NULL, NULL, &q_points, &q_weights));
8257b8c5038SJames Wright PetscCall(PetscFEGetCellTabulation(fe, num_derivatives, &basis_tabulation));
8267b8c5038SJames Wright PetscCall(ComputeFieldTabulationP2C(dm, dm_field, face, basis_tabulation, &interp, &grad));
8277b8c5038SJames Wright {
8287b8c5038SJames Wright PetscInt num_comp = basis_tabulation->Nc, P = basis_tabulation->Nb / num_comp, Q = basis_tabulation->Np;
8297b8c5038SJames Wright
8307b8c5038SJames Wright PetscCallCeed(ceed, CeedBasisCreateH1(ceed, elem_topo, num_comp, P, Q, interp, grad, q_points, q_weights, basis));
8317b8c5038SJames Wright }
8327b8c5038SJames Wright
8337b8c5038SJames Wright PetscCall(PetscFree(q_points));
8347b8c5038SJames Wright PetscCall(PetscFree(q_weights));
8357b8c5038SJames Wright PetscCall(PetscFree(interp));
8367b8c5038SJames Wright PetscCall(PetscFree(grad));
8377b8c5038SJames Wright } else {
8387b8c5038SJames Wright PetscInt P_1d, Q_1d, num_comp, dim;
8397b8c5038SJames Wright PetscTabulation basis_tabulation;
8407b8c5038SJames Wright CeedScalar *q_points_1d, *q_weights_1d, *interp_1d, *grad_1d;
8417b8c5038SJames Wright
8427b8c5038SJames Wright PetscCall(PetscFEGetSpatialDimension(fe, &dim));
8437b8c5038SJames Wright PetscCall(Create1DTabulation_Tensor(comm, fe, &basis_tabulation, &q_points_1d, &q_weights_1d));
8447b8c5038SJames Wright num_comp = basis_tabulation->Nc;
8457b8c5038SJames Wright P_1d = basis_tabulation->Nb / num_comp;
8467b8c5038SJames Wright Q_1d = basis_tabulation->Np;
8477b8c5038SJames Wright PetscCall(ComputeFieldTabulationP2C(dm, dm_field, 0, basis_tabulation, &interp_1d, &grad_1d));
8487b8c5038SJames Wright PetscCallCeed(ceed, CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d, Q_1d, interp_1d, grad_1d, q_points_1d, q_weights_1d, basis));
8497b8c5038SJames Wright
8507b8c5038SJames Wright // Cleanup
8517b8c5038SJames Wright PetscCall(PetscFree(q_points_1d));
8527b8c5038SJames Wright PetscCall(PetscFree(q_weights_1d));
8537b8c5038SJames Wright PetscCall(PetscFree(interp_1d));
8547b8c5038SJames Wright PetscCall(PetscFree(grad_1d));
8557b8c5038SJames Wright PetscCall(PetscTabulationDestroy(&basis_tabulation));
8567b8c5038SJames Wright }
8577b8c5038SJames Wright // Set in container
8587b8c5038SJames Wright PetscCallCeed(ceed, CeedBasisReferenceCopy(*basis, &container_basis));
859*26d401f3SJames Wright PetscCall(PetscObjectContainerCompose((PetscObject)dm, container_name, container_basis, (PetscCtxDestroyFn *)DMPlexCeedBasisDestroy));
8607b8c5038SJames Wright }
8617b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
8627b8c5038SJames Wright }
8637b8c5038SJames Wright
8647b8c5038SJames Wright /**
8657b8c5038SJames Wright @brief Create `CeedBasis` for coordinate space of `DMPlex`.
8667b8c5038SJames Wright
8677b8c5038SJames Wright The `CeedBasis` is stored in the coordinate `DMPlex` object for reuse;
8687b8c5038SJames Wright if the routine is called again with the same arguments, the same `CeedBasis` is returned.
8697b8c5038SJames Wright
8707b8c5038SJames Wright Collective across MPI processes.
8717b8c5038SJames Wright
8727b8c5038SJames Wright @param[in] ceed `Ceed` context
8737b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
8747b8c5038SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
8757b8c5038SJames Wright @param[in] label_value Stratum value
8767b8c5038SJames Wright @param[in] height Height of `DMPlex` topology
8777b8c5038SJames Wright @param[out] basis `CeedBasis` for coordinate space of `DMPlex`
8787b8c5038SJames Wright **/
DMPlexCeedBasisCoordinateCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,CeedBasis * basis)8797b8c5038SJames Wright PetscErrorCode DMPlexCeedBasisCoordinateCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height, CeedBasis *basis) {
8807b8c5038SJames Wright DM dm_coord = NULL;
8817b8c5038SJames Wright
8827b8c5038SJames Wright PetscFunctionBeginUser;
88377efe802SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord));
8847b8c5038SJames Wright PetscCall(DMPlexCeedBasisCreate(ceed, dm_coord, domain_label, label_value, height, 0, basis));
8857b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
8867b8c5038SJames Wright }
8877b8c5038SJames Wright
88877efe802SJames Wright typedef struct CeedVectorAndState_ *CeedVectorAndState;
88977efe802SJames Wright struct CeedVectorAndState_ {
89077efe802SJames Wright CeedVector vector; // !< `CeedVector` containing copy of data from a `Vec`
89177efe802SJames Wright PetscObjectState state; // !< Object state of the `Vec` when the data was copied
89277efe802SJames Wright };
89377efe802SJames Wright
89477efe802SJames Wright /**
89577efe802SJames Wright @brief Destroy `CeedVectorAndState` in a `PetscContainer`.
89677efe802SJames Wright
89777efe802SJames Wright Not collective across MPI processes.
89877efe802SJames Wright
89977efe802SJames Wright @param[in,out] ctx `CeedVectorAndState`
90077efe802SJames Wright
90177efe802SJames Wright @return An error code: 0 - success, otherwise - failure
90277efe802SJames Wright **/
CeedVectorAndStateDestroy(void ** ctx)90377efe802SJames Wright static PetscErrorCode CeedVectorAndStateDestroy(void **ctx) {
90477efe802SJames Wright CeedVectorAndState vec_and_state = *(CeedVectorAndState *)ctx;
90577efe802SJames Wright
90677efe802SJames Wright PetscFunctionBegin;
90777efe802SJames Wright PetscCallCeed(CeedVectorReturnCeed(vec_and_state->vector), CeedVectorDestroy(&vec_and_state->vector));
90877efe802SJames Wright PetscCall(PetscFree(vec_and_state));
90977efe802SJames Wright *ctx = NULL;
91077efe802SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
91177efe802SJames Wright }
91277efe802SJames Wright
91377efe802SJames Wright /**
91477efe802SJames Wright @brief Get Ceed objects for coordinate field of DM
91577efe802SJames Wright
91677efe802SJames Wright @param[in] ceed `Ceed` context
91777efe802SJames Wright @param[in] dm `DMPlex` holding mesh
91877efe802SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
91977efe802SJames Wright @param[in] label_value Stratum value
92077efe802SJames Wright @param[in] height Height of `DMPlex` topology
92177efe802SJames Wright @param[out] elem_restr `CeedElemRestriction` for coodinates of `DMPlex`, or `NULL`
92277efe802SJames Wright @param[out] basis `CeedBasis` for coordinate space of `DMPlex`, or `NULL`
92377efe802SJames Wright @param[out] vector `CeedVector` for coordinates of `DMPlex`, or `NULL`
92477efe802SJames Wright **/
DMPlexCeedCoordinateCreateField(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt height,CeedElemRestriction * elem_restr,CeedBasis * basis,CeedVector * vector)92577efe802SJames Wright PetscErrorCode DMPlexCeedCoordinateCreateField(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt height,
92677efe802SJames Wright CeedElemRestriction *elem_restr, CeedBasis *basis, CeedVector *vector) {
92777efe802SJames Wright CeedElemRestriction elem_restr_ = NULL;
92877efe802SJames Wright
92977efe802SJames Wright PetscFunctionBeginUser;
93077efe802SJames Wright PetscCall(DMPlexCeedElemRestrictionCoordinateCreate(ceed, dm, domain_label, label_value, height, &elem_restr_));
93177efe802SJames Wright if (elem_restr) {
93277efe802SJames Wright *elem_restr = NULL;
93377efe802SJames Wright PetscCallCeed(ceed, CeedElemRestrictionReferenceCopy(elem_restr_, elem_restr));
93477efe802SJames Wright }
93577efe802SJames Wright if (basis) PetscCall(DMPlexCeedBasisCoordinateCreate(ceed, dm, domain_label, label_value, height, basis));
93677efe802SJames Wright if (vector) {
93777efe802SJames Wright DM cdm;
93877efe802SJames Wright char container_name[] = "DM Coordinate CeedVectorAndState";
93977efe802SJames Wright CeedVectorAndState vec_and_state;
94077efe802SJames Wright Vec X_loc;
94177efe802SJames Wright PetscObjectState X_loc_state;
94277efe802SJames Wright
94377efe802SJames Wright PetscCall(DMGetCellCoordinateDM(dm, &cdm));
94477efe802SJames Wright if (cdm) {
94577efe802SJames Wright PetscCall(DMGetCellCoordinatesLocal(dm, &X_loc));
94677efe802SJames Wright } else {
94777efe802SJames Wright PetscCall(DMGetCoordinatesLocal(dm, &X_loc));
94877efe802SJames Wright }
94977efe802SJames Wright PetscCall(VecGetState(X_loc, &X_loc_state));
95077efe802SJames Wright PetscCall(PetscObjectContainerQuery((PetscObject)X_loc, container_name, (void **)&vec_and_state));
95177efe802SJames Wright
95277efe802SJames Wright if (vec_and_state && vec_and_state->state == X_loc_state) {
95377efe802SJames Wright // Copy existing vector
95477efe802SJames Wright *vector = NULL;
95577efe802SJames Wright PetscCallCeed(ceed, CeedVectorReferenceCopy(vec_and_state->vector, vector));
95677efe802SJames Wright } else {
95777efe802SJames Wright PetscCall(CeedElemRestrictionCreateVector(elem_restr_, vector, NULL));
95877efe802SJames Wright PetscCall(VecCopyPetscToCeed(X_loc, *vector));
95977efe802SJames Wright
96077efe802SJames Wright // Set in container
96177efe802SJames Wright PetscCall(PetscNew(&vec_and_state));
96277efe802SJames Wright PetscCallCeed(ceed, CeedVectorReferenceCopy(*vector, &vec_and_state->vector));
96377efe802SJames Wright vec_and_state->state = X_loc_state;
964*26d401f3SJames Wright PetscCall(PetscObjectContainerCompose((PetscObject)X_loc, container_name, vec_and_state, (PetscCtxDestroyFn *)CeedVectorAndStateDestroy));
96577efe802SJames Wright }
96677efe802SJames Wright }
96777efe802SJames Wright PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_));
96877efe802SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
96977efe802SJames Wright }
97077efe802SJames Wright
9717b8c5038SJames Wright /**
9727b8c5038SJames Wright @brief Create `CeedBasis` for cell to face quadrature space evaluation from `DMPlex`.
9737b8c5038SJames Wright
9747b8c5038SJames Wright Collective across MPI processes.
9757b8c5038SJames Wright
9767b8c5038SJames Wright @param[in] ceed `Ceed` context
9777b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
9787b8c5038SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
9797b8c5038SJames Wright @param[in] label_value Stratum value
9807b8c5038SJames Wright @param[in] face Index of face
9817b8c5038SJames Wright @param[in] dm_field Index of `DMPlex` field
9827b8c5038SJames Wright @param[out] basis `CeedBasis` for cell to face evaluation
9837b8c5038SJames Wright **/
DMPlexCeedBasisCellToFaceCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt face,PetscInt dm_field,CeedBasis * basis)9847b8c5038SJames Wright PetscErrorCode DMPlexCeedBasisCellToFaceCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt face, PetscInt dm_field,
9857b8c5038SJames Wright CeedBasis *basis) {
9867b8c5038SJames Wright PetscInt ds_field = -1, height = 0;
9877b8c5038SJames Wright PetscDS ds;
9887b8c5038SJames Wright PetscFE fe;
9897b8c5038SJames Wright PetscQuadrature face_quadrature;
9907b8c5038SJames Wright
9917b8c5038SJames Wright PetscFunctionBeginUser;
9927b8c5038SJames Wright // Get element information
9937b8c5038SJames Wright PetscCall(DMGetRegionDS(dm, domain_label, NULL, &ds, NULL));
9947b8c5038SJames Wright PetscCall(DMFieldToDSField(dm, domain_label, dm_field, &ds_field));
9957b8c5038SJames Wright PetscCall(PetscDSGetDiscretization(ds, ds_field, (PetscObject *)&fe));
9967b8c5038SJames Wright PetscCall(PetscFEGetFaceQuadrature(fe, &face_quadrature));
9977b8c5038SJames Wright
9987b8c5038SJames Wright { // Build libCEED basis
9997b8c5038SJames Wright PetscInt num_derivatives = 1, num_comp, P, Q = -1;
10007b8c5038SJames Wright PetscTabulation basis_tabulation;
10017b8c5038SJames Wright CeedScalar *q_points, *q_weights, *interp, *grad;
10027b8c5038SJames Wright CeedElemTopology elem_topo;
10037b8c5038SJames Wright
10047b8c5038SJames Wright { // Verify compatible element topology
10057b8c5038SJames Wright DMPolytopeType cell_type;
10067b8c5038SJames Wright
10077b8c5038SJames Wright PetscCall(GetGlobalDMPlexPolytopeType(dm, domain_label, label_value, height, &cell_type));
10087b8c5038SJames Wright elem_topo = PolytopeTypePetscToCeed(cell_type);
10097b8c5038SJames Wright PetscCheck(elem_topo, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMPlex topology not supported: %s", DMPolytopeTypes[cell_type]);
10107b8c5038SJames Wright }
10117b8c5038SJames Wright
10127b8c5038SJames Wright // Compute basis tabulation
10137b8c5038SJames Wright PetscCall(GetQuadratureDataP2C(fe, face_quadrature, NULL, NULL, &Q, &q_points, &q_weights));
10147b8c5038SJames Wright PetscCall(PetscFEGetFaceTabulation(fe, num_derivatives, &basis_tabulation));
10157b8c5038SJames Wright num_comp = basis_tabulation->Nc;
10167b8c5038SJames Wright P = basis_tabulation->Nb / num_comp;
10177b8c5038SJames Wright PetscCall(ComputeFieldTabulationP2C(dm, dm_field, face, basis_tabulation, &interp, &grad));
10187b8c5038SJames Wright PetscCallCeed(ceed, CeedBasisCreateH1(ceed, elem_topo, num_comp, P, Q, interp, grad, q_points, q_weights, basis));
10197b8c5038SJames Wright
10207b8c5038SJames Wright PetscCall(PetscFree(q_points));
10217b8c5038SJames Wright PetscCall(PetscFree(q_weights));
10227b8c5038SJames Wright PetscCall(PetscFree(interp));
10237b8c5038SJames Wright PetscCall(PetscFree(grad));
10247b8c5038SJames Wright }
10257b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
10267b8c5038SJames Wright }
10277b8c5038SJames Wright
10287b8c5038SJames Wright /**
10297b8c5038SJames Wright @brief Create `CeedBasis` for cell to face quadrature space evaluation on coordinate space of `DMPlex`.
10307b8c5038SJames Wright
10317b8c5038SJames Wright Collective across MPI processes.
10327b8c5038SJames Wright
10337b8c5038SJames Wright @param[in] ceed `Ceed` context
10347b8c5038SJames Wright @param[in] dm `DMPlex` holding mesh
10357b8c5038SJames Wright @param[in] domain_label `DMLabel` for `DMPlex` domain
10367b8c5038SJames Wright @param[in] label_value Stratum value
10377b8c5038SJames Wright @param[in] face Index of face
10387b8c5038SJames Wright @param[out] basis `CeedBasis` for cell to face evaluation on coordinate space of `DMPlex`
10397b8c5038SJames Wright **/
DMPlexCeedBasisCellToFaceCoordinateCreate(Ceed ceed,DM dm,DMLabel domain_label,PetscInt label_value,PetscInt face,CeedBasis * basis)10407b8c5038SJames Wright PetscErrorCode DMPlexCeedBasisCellToFaceCoordinateCreate(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, PetscInt face,
10417b8c5038SJames Wright CeedBasis *basis) {
10427b8c5038SJames Wright DM dm_coord;
10437b8c5038SJames Wright
10447b8c5038SJames Wright PetscFunctionBeginUser;
10457b8c5038SJames Wright PetscCall(DMGetCellCoordinateDM(dm, &dm_coord));
10467b8c5038SJames Wright if (!dm_coord) {
10477b8c5038SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord));
10487b8c5038SJames Wright }
10497b8c5038SJames Wright PetscCall(DMPlexCeedBasisCellToFaceCreate(ceed, dm_coord, domain_label, label_value, face, 0, basis));
10507b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
10517b8c5038SJames Wright }
10527b8c5038SJames Wright
10537b8c5038SJames Wright /**
10547b8c5038SJames Wright @brief Setup `DM` with FE space of appropriate degree
10557b8c5038SJames Wright
10567b8c5038SJames Wright Must be followed by `DMSetupByOrderEnd_FEM`
10577b8c5038SJames Wright
10587b8c5038SJames Wright @param[in] setup_faces Flag to setup face geometry
10597b8c5038SJames Wright @param[in] setup_coords Flag to setup coordinate spaces
10607b8c5038SJames Wright @param[in] degree Polynomial orders of field
10617b8c5038SJames Wright @param[in] coord_order Polynomial order of coordinate basis, or `PETSC_DECIDE` for default
10627b8c5038SJames Wright @param[in] q_extra Additional quadrature order
10637b8c5038SJames Wright @param[in] num_fields Number of fields in solution vector
10647b8c5038SJames Wright @param[in] field_sizes Array of number of components for each field
10657b8c5038SJames Wright @param[out] dm `DM` to setup
10667b8c5038SJames Wright
10677b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
10687b8c5038SJames Wright **/
DMSetupByOrderBegin_FEM(PetscBool setup_faces,PetscBool setup_coords,PetscInt degree,PetscInt coord_order,PetscInt q_extra,PetscInt num_fields,const PetscInt * field_sizes,DM dm)10697b8c5038SJames Wright PetscErrorCode DMSetupByOrderBegin_FEM(PetscBool setup_faces, PetscBool setup_coords, PetscInt degree, PetscInt coord_order, PetscInt q_extra,
10707b8c5038SJames Wright PetscInt num_fields, const PetscInt *field_sizes, DM dm) {
10717b8c5038SJames Wright PetscInt dim, q_order = degree + q_extra;
10727b8c5038SJames Wright PetscBool is_simplex = PETSC_TRUE;
10737b8c5038SJames Wright PetscFE fe;
10747b8c5038SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
10757b8c5038SJames Wright
10767b8c5038SJames Wright PetscFunctionBeginUser;
10777b8c5038SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex));
10787b8c5038SJames Wright
10797b8c5038SJames Wright // Setup DM
10807b8c5038SJames Wright PetscCall(DMGetDimension(dm, &dim));
10817b8c5038SJames Wright for (PetscInt i = 0; i < num_fields; i++) {
10827b8c5038SJames Wright PetscFE fe_face;
10837b8c5038SJames Wright PetscInt q_order = degree + q_extra;
10847b8c5038SJames Wright
10857b8c5038SJames Wright PetscCall(PetscFECreateLagrange(comm, dim, field_sizes[i], is_simplex, degree, q_order, &fe));
10867b8c5038SJames Wright if (setup_faces) PetscCall(PetscFEGetHeightSubspace(fe, 1, &fe_face));
10877b8c5038SJames Wright PetscCall(DMAddField(dm, NULL, (PetscObject)fe));
10887b8c5038SJames Wright PetscCall(PetscFEDestroy(&fe));
10897b8c5038SJames Wright }
10907b8c5038SJames Wright PetscCall(DMCreateDS(dm));
10917b8c5038SJames Wright
10927b8c5038SJames Wright // Project coordinates to enrich quadrature space
10937b8c5038SJames Wright if (setup_coords) {
10947b8c5038SJames Wright DM dm_coord;
10957b8c5038SJames Wright PetscDS ds_coord;
10967b8c5038SJames Wright PetscFE fe_coord_current, fe_coord_new, fe_coord_face_new;
10977b8c5038SJames Wright PetscDualSpace fe_coord_dual_space;
10987b8c5038SJames Wright PetscInt fe_coord_order, num_comp_coord;
10997b8c5038SJames Wright
11007b8c5038SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord));
11017b8c5038SJames Wright PetscCall(DMGetCoordinateDim(dm, &num_comp_coord));
11027b8c5038SJames Wright PetscCall(DMGetRegionDS(dm_coord, NULL, NULL, &ds_coord, NULL));
11037b8c5038SJames Wright PetscCall(PetscDSGetDiscretization(ds_coord, 0, (PetscObject *)&fe_coord_current));
11047b8c5038SJames Wright PetscCall(PetscFEGetDualSpace(fe_coord_current, &fe_coord_dual_space));
11057b8c5038SJames Wright PetscCall(PetscDualSpaceGetOrder(fe_coord_dual_space, &fe_coord_order));
11067b8c5038SJames Wright
11077b8c5038SJames Wright // Create FE for coordinates
11087b8c5038SJames Wright if (coord_order != PETSC_DECIDE) fe_coord_order = coord_order;
11097b8c5038SJames Wright PetscCall(PetscFECreateLagrange(comm, dim, num_comp_coord, is_simplex, fe_coord_order, q_order, &fe_coord_new));
11107b8c5038SJames Wright if (setup_faces) PetscCall(PetscFEGetHeightSubspace(fe_coord_new, 1, &fe_coord_face_new));
11117b8c5038SJames Wright PetscCall(DMSetCoordinateDisc(dm, fe_coord_new, PETSC_FALSE, PETSC_TRUE));
11127b8c5038SJames Wright PetscCall(PetscFEDestroy(&fe_coord_new));
11137b8c5038SJames Wright }
11147b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
11157b8c5038SJames Wright }
11167b8c5038SJames Wright
11177b8c5038SJames Wright /**
11187b8c5038SJames Wright @brief Finish setting up `DM`
11197b8c5038SJames Wright
11207b8c5038SJames Wright Must be called after `DMSetupByOrderBegin_FEM` and all strong BCs have be declared via `DMAddBoundaries`.
11217b8c5038SJames Wright
11227b8c5038SJames Wright @param[in] setup_coords Flag to setup coordinate spaces
11237b8c5038SJames Wright @param[out] dm `DM` to setup
11247b8c5038SJames Wright
11257b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
11267b8c5038SJames Wright **/
DMSetupByOrderEnd_FEM(PetscBool setup_coords,DM dm)11277b8c5038SJames Wright PetscErrorCode DMSetupByOrderEnd_FEM(PetscBool setup_coords, DM dm) {
11287b8c5038SJames Wright PetscBool is_simplex;
11297b8c5038SJames Wright
11307b8c5038SJames Wright PetscFunctionBeginUser;
11317b8c5038SJames Wright PetscCall(DMPlexIsSimplex(dm, &is_simplex));
11327b8c5038SJames Wright // Set tensor permutation if needed
11337b8c5038SJames Wright if (!is_simplex) {
11347b8c5038SJames Wright PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
11357b8c5038SJames Wright if (setup_coords) {
11367b8c5038SJames Wright DM dm_coord;
11377b8c5038SJames Wright
11387b8c5038SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord));
11397b8c5038SJames Wright PetscCall(DMPlexSetClosurePermutationTensor(dm_coord, PETSC_DETERMINE, NULL));
11407b8c5038SJames Wright }
11417b8c5038SJames Wright }
11427b8c5038SJames Wright PetscCall(DMLocalizeCoordinates(dm)); // Must localize after tensor closure setting
11437b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
11447b8c5038SJames Wright }
11457b8c5038SJames Wright
11467b8c5038SJames Wright /**
11477b8c5038SJames Wright @brief Setup `DM` with FE space of appropriate degree with no boundary conditions
11487b8c5038SJames Wright
11497b8c5038SJames Wright Calls `DMSetupByOrderBegin_FEM` and `DMSetupByOrderEnd_FEM` successively
11507b8c5038SJames Wright
11517b8c5038SJames Wright @param[in] setup_faces Flag to setup face geometry
11527b8c5038SJames Wright @param[in] setup_coords Flag to setup coordinate spaces
11537b8c5038SJames Wright @param[in] degree Polynomial orders of field
11547b8c5038SJames Wright @param[in] coord_order Polynomial order of coordinate basis, or `PETSC_DECIDE` for default
11557b8c5038SJames Wright @param[in] q_extra Additional quadrature order
11567b8c5038SJames Wright @param[in] num_fields Number of fields in solution vector
11577b8c5038SJames Wright @param[in] field_sizes Array of number of components for each field
11587b8c5038SJames Wright @param[out] dm `DM` to setup
11597b8c5038SJames Wright
11607b8c5038SJames Wright @return An error code: 0 - success, otherwise - failure
11617b8c5038SJames Wright **/
DMSetupByOrder_FEM(PetscBool setup_faces,PetscBool setup_coords,PetscInt degree,PetscInt coord_order,PetscInt q_extra,PetscInt num_fields,const PetscInt * field_sizes,DM dm)11627b8c5038SJames Wright PetscErrorCode DMSetupByOrder_FEM(PetscBool setup_faces, PetscBool setup_coords, PetscInt degree, PetscInt coord_order, PetscInt q_extra,
11637b8c5038SJames Wright PetscInt num_fields, const PetscInt *field_sizes, DM dm) {
11647b8c5038SJames Wright PetscFunctionBeginUser;
11657b8c5038SJames Wright PetscCall(DMSetupByOrderBegin_FEM(setup_faces, setup_coords, degree, coord_order, q_extra, num_fields, field_sizes, dm));
11667b8c5038SJames Wright PetscCall(DMSetupByOrderEnd_FEM(setup_coords, dm));
11677b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
11687b8c5038SJames Wright }
11697b8c5038SJames Wright
11707b8c5038SJames Wright /**
11717b8c5038SJames Wright @brief Get the points in a label stratum which have requested height
11727b8c5038SJames Wright
11737b8c5038SJames Wright Example, from the "Face Sets" label (which contains face, edge, and vertex points), return points that correspond to face points (height = 1) and have a label value of 3:
11747b8c5038SJames Wright ```
11757b8c5038SJames Wright PetscCall(DMGetStratumISAtHeight(dm, "Face Sets", 3, 1, &is_face_points));
11767b8c5038SJames Wright ```
11777b8c5038SJames Wright
11787b8c5038SJames Wright @param[in] dm DM which has the label
11797b8c5038SJames Wright @param[in] name Name fo the label
11807b8c5038SJames Wright @param[in] value Label value of points to return
11817b8c5038SJames Wright @param[in] height Height of points to return
11827b8c5038SJames Wright @param[out] points `IS` of points, or `NULL` is there are no points in that stratum at height
11837b8c5038SJames Wright **/
DMGetStratumISAtHeight(DM dm,const char name[],PetscInt value,PetscInt height,IS * points)11847b8c5038SJames Wright static PetscErrorCode DMGetStratumISAtHeight(DM dm, const char name[], PetscInt value, PetscInt height, IS *points) {
11857b8c5038SJames Wright PetscInt depth;
11867b8c5038SJames Wright DMLabel depth_label;
11877b8c5038SJames Wright IS label_is, depth_is;
11887b8c5038SJames Wright
11897b8c5038SJames Wright PetscFunctionBeginUser;
11907b8c5038SJames Wright PetscCall(DMPlexGetDepth(dm, &depth));
11917b8c5038SJames Wright PetscCall(DMPlexGetDepthLabel(dm, &depth_label));
11927b8c5038SJames Wright PetscCall(DMLabelGetStratumIS(depth_label, depth - height, &depth_is));
11937b8c5038SJames Wright PetscCall(DMGetStratumIS(dm, name, value, &label_is));
11947b8c5038SJames Wright if (label_is == NULL || depth_is == NULL) *points = NULL;
11957b8c5038SJames Wright else PetscCall(ISIntersect(depth_is, label_is, points));
11967b8c5038SJames Wright PetscCall(ISDestroy(&depth_is));
11977b8c5038SJames Wright PetscCall(ISDestroy(&label_is));
11987b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
11997b8c5038SJames Wright }
12007b8c5038SJames Wright
12017b8c5038SJames Wright /**
12027b8c5038SJames Wright @brief Create a label with separate values for the `FE` orientations for all cells with this material for the `DMPlex` face.
12037b8c5038SJames Wright
12047b8c5038SJames Wright Collective across MPI processes.
12057b8c5038SJames Wright
12067b8c5038SJames Wright @param[in,out] dm `DMPlex` holding mesh
12077b8c5038SJames Wright @param[in] dm_face Face number on `DMPlex`
12087b8c5038SJames Wright @param[out] face_label_name Label name for newly created label, or `NULL` if no elements match the `material` and `dm_face`
12097b8c5038SJames Wright **/
DMPlexCreateFaceLabel(DM dm,PetscInt dm_face,char ** face_label_name)12107b8c5038SJames Wright PetscErrorCode DMPlexCreateFaceLabel(DM dm, PetscInt dm_face, char **face_label_name) {
12117b8c5038SJames Wright PetscInt num_face_points = 0, face_height = 1;
12127b8c5038SJames Wright const PetscInt *face_points;
12137b8c5038SJames Wright IS is_face_points;
12147b8c5038SJames Wright DMLabel face_label = NULL;
12157b8c5038SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
12167b8c5038SJames Wright
12177b8c5038SJames Wright PetscFunctionBeginUser;
12187b8c5038SJames Wright { // Create label name and label
12197b8c5038SJames Wright PetscSizeT label_name_len = 64;
12207b8c5038SJames Wright PetscBool has_label_already;
12217b8c5038SJames Wright
12227b8c5038SJames Wright // Face label
12237b8c5038SJames Wright PetscCall(PetscCalloc1(label_name_len, face_label_name));
12247b8c5038SJames Wright PetscCall(PetscSNPrintf(*face_label_name, label_name_len, "Orientation for DM face %" PetscInt_FMT, dm_face));
12257b8c5038SJames Wright PetscCall(DMHasLabel(dm, *face_label_name, &has_label_already));
12267b8c5038SJames Wright if (has_label_already) PetscFunctionReturn(PETSC_SUCCESS);
12277b8c5038SJames Wright
12287b8c5038SJames Wright PetscCall(DMCreateLabel(dm, *face_label_name));
12297b8c5038SJames Wright PetscCall(DMGetLabel(dm, *face_label_name, &face_label));
12307b8c5038SJames Wright }
12317b8c5038SJames Wright
12327b8c5038SJames Wright PetscCall(DMGetStratumISAtHeight(dm, "Face Sets", dm_face, face_height, &is_face_points));
12337b8c5038SJames Wright if (is_face_points) {
12347b8c5038SJames Wright PetscCall(ISGetLocalSize(is_face_points, &num_face_points));
12357b8c5038SJames Wright PetscCall(ISGetIndices(is_face_points, &face_points));
12367b8c5038SJames Wright }
12377b8c5038SJames Wright
12387b8c5038SJames Wright for (PetscInt face_index = 0; face_index < num_face_points; face_index++) {
12397b8c5038SJames Wright const PetscInt *face_support, *cell_cone;
12407b8c5038SJames Wright PetscInt face_support_size = 0, cell_cone_size = 0, fe_face_on_cell = -1;
12417b8c5038SJames Wright PetscInt face_point = face_points[face_index];
12427b8c5038SJames Wright
12437b8c5038SJames Wright // Get cell supporting face
12447b8c5038SJames Wright PetscCall(DMPlexGetSupport(dm, face_point, &face_support));
12457b8c5038SJames Wright PetscCall(DMPlexGetSupportSize(dm, face_point, &face_support_size));
12467b8c5038SJames Wright PetscCheck(face_support_size == 1, comm, PETSC_ERR_SUP, "Expected one cell in support of exterior face, but got %" PetscInt_FMT " cells",
12477b8c5038SJames Wright face_support_size);
12487b8c5038SJames Wright PetscInt cell_point = face_support[0];
12497b8c5038SJames Wright
12507b8c5038SJames Wright // Find face number
12517b8c5038SJames Wright PetscCall(DMPlexGetCone(dm, cell_point, &cell_cone));
12527b8c5038SJames Wright PetscCall(DMPlexGetConeSize(dm, cell_point, &cell_cone_size));
12537b8c5038SJames Wright for (PetscInt i = 0; i < cell_cone_size; i++) {
12547b8c5038SJames Wright if (cell_cone[i] == face_point) fe_face_on_cell = i;
12557b8c5038SJames Wright }
12567b8c5038SJames Wright PetscCheck(fe_face_on_cell != -1, comm, PETSC_ERR_SUP, "Could not find face %" PetscInt_FMT " in cone of its support", face_point);
12577b8c5038SJames Wright
12587b8c5038SJames Wright // Add to label
12597b8c5038SJames Wright PetscCall(DMLabelSetValue(face_label, face_point, fe_face_on_cell));
12607b8c5038SJames Wright }
12617b8c5038SJames Wright PetscCall(DMPlexLabelAddFaceCells(dm, face_label));
12627b8c5038SJames Wright PetscCall(ISDestroy(&is_face_points));
12637b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
12647b8c5038SJames Wright }
12657b8c5038SJames Wright
12667b8c5038SJames Wright /**
12677b8c5038SJames Wright @brief Creates an array of all the values set for a `DMLabel`
12687b8c5038SJames Wright
12697b8c5038SJames Wright Because `DMLabelGetValueIS` returns label values locally, not globally.
12707b8c5038SJames Wright
12717b8c5038SJames Wright Collective across MPI processes.
12727b8c5038SJames Wright
12737b8c5038SJames Wright @param[in] dm `DM` with the label
12747b8c5038SJames Wright @param[in] label `DMLabel` to get values of
12757b8c5038SJames Wright @param[out] num_values Total number of values
12767b8c5038SJames Wright @param[out] value_array Array of label values, must be freed by user
12777b8c5038SJames Wright **/
DMLabelCreateGlobalValueArray(DM dm,DMLabel label,PetscInt * num_values,PetscInt ** value_array)12787b8c5038SJames Wright PetscErrorCode DMLabelCreateGlobalValueArray(DM dm, DMLabel label, PetscInt *num_values, PetscInt **value_array) {
12797b8c5038SJames Wright PetscInt num_values_local, minmax_values[2], minmax_values_loc[2];
12807b8c5038SJames Wright PetscInt *values_local = NULL;
12817b8c5038SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
12827b8c5038SJames Wright PetscSegBuffer seg;
12837b8c5038SJames Wright PetscCount seg_size;
12847b8c5038SJames Wright
12857b8c5038SJames Wright PetscFunctionBeginUser;
12867b8c5038SJames Wright { // Extract array of local DMLabel values so it can be sorted
12877b8c5038SJames Wright IS is_values;
12887b8c5038SJames Wright const PetscInt *is_values_local = NULL;
12897b8c5038SJames Wright
12907b8c5038SJames Wright PetscCall(DMLabelGetValueIS(label, &is_values));
12917b8c5038SJames Wright PetscCall(ISGetLocalSize(is_values, &num_values_local));
12927b8c5038SJames Wright
12937b8c5038SJames Wright PetscCall(ISGetIndices(is_values, &is_values_local));
12947b8c5038SJames Wright PetscCall(PetscMalloc1(num_values_local, &values_local));
12957b8c5038SJames Wright PetscCall(PetscArraycpy(values_local, is_values_local, num_values_local));
12967b8c5038SJames Wright PetscCall(ISRestoreIndices(is_values, &is_values_local));
12977b8c5038SJames Wright PetscCall(ISDestroy(&is_values));
12987b8c5038SJames Wright }
12997b8c5038SJames Wright
13007b8c5038SJames Wright if (num_values_local) {
13017b8c5038SJames Wright PetscCall(PetscSortInt(num_values_local, values_local));
13027b8c5038SJames Wright minmax_values_loc[0] = values_local[0];
13037b8c5038SJames Wright minmax_values_loc[1] = values_local[num_values_local - 1];
13047b8c5038SJames Wright } else {
13057b8c5038SJames Wright // Rank has no set label values, therefore set local min/max to have no effect on global min/max
13067b8c5038SJames Wright minmax_values_loc[0] = PETSC_INT_MAX;
13077b8c5038SJames Wright minmax_values_loc[1] = PETSC_INT_MIN;
13087b8c5038SJames Wright }
13097b8c5038SJames Wright PetscCall(PetscGlobalMinMaxInt(comm, minmax_values_loc, minmax_values));
13107b8c5038SJames Wright
13117b8c5038SJames Wright PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 16, &seg));
13127b8c5038SJames Wright for (PetscInt value = minmax_values[0]; value <= minmax_values[1]; value++) {
13137b8c5038SJames Wright PetscInt location_local = -1, location_global = -1;
13147b8c5038SJames Wright
13157b8c5038SJames Wright PetscCall(PetscFindInt(value, num_values_local, values_local, &location_local));
13167b8c5038SJames Wright PetscCallMPI(MPIU_Allreduce(&location_local, &location_global, 1, MPIU_INT, MPI_MAX, comm));
13177b8c5038SJames Wright if (location_global < 0) continue;
13187b8c5038SJames Wright else {
13197b8c5038SJames Wright PetscInt *seg_slot;
13207b8c5038SJames Wright
13217b8c5038SJames Wright PetscCall(PetscSegBufferGetInts(seg, 1, &seg_slot));
13227b8c5038SJames Wright *seg_slot = value;
13237b8c5038SJames Wright }
13247b8c5038SJames Wright }
13257b8c5038SJames Wright PetscCall(PetscSegBufferGetSize(seg, &seg_size));
13267b8c5038SJames Wright *num_values = (PetscInt)seg_size;
13277b8c5038SJames Wright PetscCall(PetscSegBufferExtractAlloc(seg, value_array));
13287b8c5038SJames Wright PetscCall(PetscSegBufferDestroy(&seg));
13297b8c5038SJames Wright if (values_local) PetscCall(PetscFree(values_local));
13307b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
13317b8c5038SJames Wright }
13327b8c5038SJames Wright
13337b8c5038SJames Wright /**
13347b8c5038SJames Wright @brief Get the number of components for `dm`'s coordinate field
13357b8c5038SJames Wright
13367b8c5038SJames Wright @param[in] dm DM
13377b8c5038SJames Wright @param[out] num_comp Number of components for the coordinate field
13387b8c5038SJames Wright **/
DMGetCoordinateNumComps(DM dm,PetscInt * num_comp)13397b8c5038SJames Wright PetscErrorCode DMGetCoordinateNumComps(DM dm, PetscInt *num_comp) {
13407b8c5038SJames Wright DM dm_coord;
13417b8c5038SJames Wright PetscSection section_coord;
13427b8c5038SJames Wright PetscInt field = 0; // Default field has the coordinates
13437b8c5038SJames Wright
13447b8c5038SJames Wright PetscFunctionBeginUser;
13457b8c5038SJames Wright PetscCall(DMGetCoordinateDM(dm, &dm_coord));
13467b8c5038SJames Wright PetscCall(DMGetLocalSection(dm_coord, §ion_coord));
13477b8c5038SJames Wright PetscCall(PetscSectionGetFieldComponents(section_coord, field, num_comp));
13487b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
13497b8c5038SJames Wright }
13507b8c5038SJames Wright
13517b8c5038SJames Wright /**
13527b8c5038SJames Wright @brief Get the number of components for `dm`'s field
13537b8c5038SJames Wright
13547b8c5038SJames Wright @param[in] dm DM
13557b8c5038SJames Wright @param[in] field The field ID to get the number of components for
13567b8c5038SJames Wright @param[out] num_comp Number of components for the coordinate field
13577b8c5038SJames Wright **/
DMGetFieldNumComps(DM dm,PetscInt field,PetscInt * num_comp)13587b8c5038SJames Wright PetscErrorCode DMGetFieldNumComps(DM dm, PetscInt field, PetscInt *num_comp) {
13597b8c5038SJames Wright PetscSection section;
13607b8c5038SJames Wright
13617b8c5038SJames Wright PetscFunctionBeginUser;
13627b8c5038SJames Wright PetscCall(DMGetLocalSection(dm, §ion));
13637b8c5038SJames Wright PetscCall(PetscSectionGetFieldComponents(section, field, num_comp));
13647b8c5038SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
13657b8c5038SJames Wright }
1366