xref: /libCEED/examples/petsc/dmswarm.c (revision 49a40c8a2d720db341b0b117b89656b473cbebfb)
19dbcead6SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
29dbcead6SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
39dbcead6SJeremy L Thompson //
49dbcead6SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
59dbcead6SJeremy L Thompson //
69dbcead6SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
79dbcead6SJeremy L Thompson 
89dbcead6SJeremy L Thompson //                        libCEED + PETSc DMSwarm Example
99dbcead6SJeremy L Thompson //
109dbcead6SJeremy L Thompson // This example demonstrates a simple usage of libCEED with DMSwarm.
119dbcead6SJeremy L Thompson // This example combines elements of PETSc src/impls/dm/swam/tutorials/ex1.c and src/impls/dm/swarm/tests/ex6.c
129dbcead6SJeremy L Thompson //
139dbcead6SJeremy L Thompson // Build with:
149dbcead6SJeremy L Thompson //
159dbcead6SJeremy L Thompson //     make dmswarm [PETSC_DIR=</path/to/petsc>] [CEED_DIR=</path/to/libceed>]
169dbcead6SJeremy L Thompson //
179dbcead6SJeremy L Thompson // Sample runs:
189dbcead6SJeremy L Thompson //
199dbcead6SJeremy L Thompson //  ./dmswarm -dm_plex_dim 3 -dm_plex_box_faces 3,3,3 -dm_plex_box_lower -1.0,-1.0,-1.0 -dm_plex_simplex 0 -num_comp 2 -swarm gauss
209dbcead6SJeremy L Thompson //
219dbcead6SJeremy L Thompson //TESTARGS(name="Uniform swarm, CG projection") -ceed {ceed_resource} -test -dm_plex_dim 3 -dm_plex_box_faces 3,3,3 -dm_plex_box_lower -1.0,-1.0,-1.0 -dm_plex_simplex 0 -dm_plex_hash_location true -num_comp 2 -swarm uniform -solution_order 3 -points_per_cell 125
229dbcead6SJeremy L Thompson //TESTARGS(name="Gauss swarm, lumped projection") -ceed {ceed_resource} -test -dm_plex_dim 3 -dm_plex_box_faces 3,3,3 -dm_plex_box_lower -1.0,-1.0,-1.0 -dm_plex_simplex 0 -dm_plex_hash_location true -num_comp 2 -swarm gauss -ksp_type preonly -pc_type jacobi -pc_jacobi_type rowsum -tolerance 9e-2
239dbcead6SJeremy L Thompson 
249dbcead6SJeremy L Thompson /// @file
259dbcead6SJeremy L Thompson /// libCEED example using PETSc with DMSwarm
269dbcead6SJeremy L Thompson const char help[] = "libCEED example using PETSc with DMSwarm\n";
279dbcead6SJeremy L Thompson 
289dbcead6SJeremy L Thompson #include <ceed.h>
299dbcead6SJeremy L Thompson #include <math.h>
309dbcead6SJeremy L Thompson #include <petscdmplex.h>
319dbcead6SJeremy L Thompson #include <petscdmswarm.h>
329dbcead6SJeremy L Thompson #include <petscds.h>
339dbcead6SJeremy L Thompson #include <petscfe.h>
349dbcead6SJeremy L Thompson #include <petscksp.h>
359dbcead6SJeremy L Thompson #include <petsc/private/petscfeimpl.h> /* For interpolation */
369dbcead6SJeremy L Thompson 
379dbcead6SJeremy L Thompson #include "include/petscutils.h"
38d31f425aSJeremy L Thompson #include "include/petscversion.h"
399dbcead6SJeremy L Thompson 
409dbcead6SJeremy L Thompson const char DMSwarmPICField_u[] = "u";
419dbcead6SJeremy L Thompson 
429dbcead6SJeremy L Thompson // libCEED context data
439dbcead6SJeremy L Thompson typedef struct DMSwarmCeedContext_ *DMSwarmCeedContext;
449dbcead6SJeremy L Thompson struct DMSwarmCeedContext_ {
459dbcead6SJeremy L Thompson   Ceed                ceed;
469dbcead6SJeremy L Thompson   CeedVector          u_mesh_loc, v_mesh_loc, u_mesh_elem, u_points_loc, u_points_elem, x_ref_points_loc, x_ref_points_elem;
479dbcead6SJeremy L Thompson   CeedElemRestriction restriction_u_mesh, restriction_x_points, restriction_u_points;
489dbcead6SJeremy L Thompson   CeedBasis           basis_u;
499dbcead6SJeremy L Thompson };
509dbcead6SJeremy L Thompson 
519dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCeedContextCreate(DM dm_swarm, const char *ceed_resource, DMSwarmCeedContext *ctx);
529dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCeedContextDestroy(DMSwarmCeedContext *ctx);
539dbcead6SJeremy L Thompson 
549dbcead6SJeremy L Thompson // Target functions
559dbcead6SJeremy L Thompson typedef enum { TARGET_TANH = 0, TARGET_POLYNOMIAL = 1, TARGET_SPHERE = 2 } TargetType;
569dbcead6SJeremy L Thompson static const char *const target_types[] = {"tanh", "polynomial", "sphere", "TargetType", "TARGET", 0};
579dbcead6SJeremy L Thompson 
589dbcead6SJeremy L Thompson typedef PetscErrorCode (*TargetFunc)(PetscInt dim, const PetscScalar x[]);
599dbcead6SJeremy L Thompson typedef PetscErrorCode (*TargetFuncProj)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx);
609dbcead6SJeremy L Thompson 
619dbcead6SJeremy L Thompson PetscScalar    EvalU_Tanh(PetscInt dim, const PetscScalar x[]);
629dbcead6SJeremy L Thompson PetscScalar    EvalU_Poly(PetscInt dim, const PetscScalar x[]);
639dbcead6SJeremy L Thompson PetscScalar    EvalU_Sphere(PetscInt dim, const PetscScalar x[]);
649dbcead6SJeremy L Thompson PetscErrorCode EvalU_Tanh_proj(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt num_comp, PetscScalar *u, void *ctx);
659dbcead6SJeremy L Thompson PetscErrorCode EvalU_Poly_proj(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt num_comp, PetscScalar *u, void *ctx);
669dbcead6SJeremy L Thompson PetscErrorCode EvalU_Sphere_proj(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt num_comp, PetscScalar *u, void *ctx);
679dbcead6SJeremy L Thompson 
689dbcead6SJeremy L Thompson // Swarm point distribution
699dbcead6SJeremy L Thompson typedef enum { SWARM_GAUSS = 0, SWARM_UNIFORM = 1, SWARM_CELL_RANDOM = 2, SWARM_SINUSOIDAL = 3 } PointSwarmType;
709dbcead6SJeremy L Thompson static const char *const point_swarm_types[] = {"gauss", "uniform", "cell_random", "sinusoidal", "PointSwarmType", "SWARM", 0};
719dbcead6SJeremy L Thompson 
729dbcead6SJeremy L Thompson // Swarm helper function
739dbcead6SJeremy L Thompson PetscErrorCode DMSwarmInitalizePointLocations(DM dm_swarm, PointSwarmType point_swarm_type, PetscInt num_points, PetscInt num_points_per_cell);
749dbcead6SJeremy L Thompson 
759dbcead6SJeremy L Thompson // Memory utilities
769dbcead6SJeremy L Thompson PetscErrorCode VecP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed);
779dbcead6SJeremy L Thompson PetscErrorCode VecC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc);
789dbcead6SJeremy L Thompson PetscErrorCode VecReadP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed);
799dbcead6SJeremy L Thompson PetscErrorCode VecReadC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc);
809dbcead6SJeremy L Thompson PetscErrorCode DMSwarmPICFieldP2C(DM dm_swarm, const char *field, CeedVector x_ceed);
819dbcead6SJeremy L Thompson PetscErrorCode DMSwarmPICFieldC2P(DM dm_swarm, const char *field, CeedVector x_ceed);
829dbcead6SJeremy L Thompson 
839dbcead6SJeremy L Thompson // Swarm to mesh and mesh to swarm
849dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCreateReferenceCoordinates(DM dm_swarm, IS *is_points, Vec *ref_coords);
859dbcead6SJeremy L Thompson PetscErrorCode DMSwarmInterpolateFromCellToSwarm_Petsc(DM dm_swarm, const char *field, Vec U_mesh);
869dbcead6SJeremy L Thompson PetscErrorCode DMSwarmInterpolateFromCellToSwarm_Ceed(DM dm_swarm, const char *field, Vec U_mesh);
879dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCheckSwarmValues(DM dm_swarm, const char *field, PetscScalar tolerance, TargetFuncProj TrueSolution);
889dbcead6SJeremy L Thompson 
899dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCreateProjectionRHS(DM dm_swarm, const char *field, Vec B_mesh);
909dbcead6SJeremy L Thompson PetscErrorCode MatMult_SwarmMass(Mat A, Vec U_mesh, Vec V_mesh);
919dbcead6SJeremy L Thompson 
929dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
939dbcead6SJeremy L Thompson // main driver
949dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
959dbcead6SJeremy L Thompson int main(int argc, char **argv) {
969dbcead6SJeremy L Thompson   MPI_Comm           comm;
979dbcead6SJeremy L Thompson   char               ceed_resource[PETSC_MAX_PATH_LEN] = "/cpu/self";
989dbcead6SJeremy L Thompson   PetscBool          test_mode = PETSC_FALSE, view_petsc_swarm = PETSC_FALSE, view_ceed_swarm = PETSC_FALSE;
999dbcead6SJeremy L Thompson   PetscInt           dim = 3, num_comp = 1, num_points = 1728, num_points_per_cell = 64, mesh_order = 1, solution_order = 2, q_extra = 3;
1009dbcead6SJeremy L Thompson   PetscScalar        tolerance = 1E-3;
1019dbcead6SJeremy L Thompson   DM                 dm_mesh, dm_swarm;
1029dbcead6SJeremy L Thompson   Vec                U_mesh;
1039dbcead6SJeremy L Thompson   DMSwarmCeedContext swarm_ceed_context;
1049dbcead6SJeremy L Thompson   PointSwarmType     point_swarm_type     = SWARM_UNIFORM;
1059dbcead6SJeremy L Thompson   TargetType         target_type          = TARGET_TANH;
1069dbcead6SJeremy L Thompson   TargetFuncProj     target_function_proj = EvalU_Tanh_proj;
1079dbcead6SJeremy L Thompson 
1089dbcead6SJeremy L Thompson   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
1099dbcead6SJeremy L Thompson   comm = PETSC_COMM_WORLD;
1109dbcead6SJeremy L Thompson 
1119dbcead6SJeremy L Thompson   // Read command line options
1129dbcead6SJeremy L Thompson   PetscOptionsBegin(comm, NULL, "libCEED example using PETSc with DMSwarm", NULL);
1139dbcead6SJeremy L Thompson 
1149dbcead6SJeremy L Thompson   PetscCall(PetscOptionsBool("-test", "Testing mode (do not print unless error is large)", NULL, test_mode, &test_mode, NULL));
1159dbcead6SJeremy L Thompson   PetscCall(
1169dbcead6SJeremy L Thompson       PetscOptionsBool("-u_petsc_swarm_view", "View XDMF of swarm values interpolated by PETSc", NULL, view_petsc_swarm, &view_petsc_swarm, NULL));
1179dbcead6SJeremy L Thompson   PetscCall(
1189dbcead6SJeremy L Thompson       PetscOptionsBool("-u_ceed_swarm_view", "View XDMF of swarm values interpolated by libCEED", NULL, view_ceed_swarm, &view_ceed_swarm, NULL));
1199dbcead6SJeremy L Thompson   PetscCall(PetscOptionsEnum("-target", "Target field function", NULL, target_types, (PetscEnum)target_type, (PetscEnum *)&target_type, NULL));
1209dbcead6SJeremy L Thompson   PetscCall(PetscOptionsInt("-solution_order", "Order of mesh solution space", NULL, solution_order, &solution_order, NULL));
1219dbcead6SJeremy L Thompson   PetscCall(PetscOptionsInt("-mesh_order", "Order of mesh coordinate space", NULL, mesh_order, &mesh_order, NULL));
1229dbcead6SJeremy L Thompson   PetscCall(PetscOptionsInt("-q_extra", "Number of extra quadrature points", NULL, q_extra, &q_extra, NULL));
1239dbcead6SJeremy L Thompson   PetscCall(PetscOptionsInt("-num_comp", "Number of components in solution", NULL, num_comp, &num_comp, NULL));
1249dbcead6SJeremy L Thompson   PetscCall(PetscOptionsEnum("-swarm", "Swarm points distribution", NULL, point_swarm_types, (PetscEnum)point_swarm_type,
1259dbcead6SJeremy L Thompson                              (PetscEnum *)&point_swarm_type, NULL));
1269dbcead6SJeremy L Thompson   {
1279dbcead6SJeremy L Thompson     PetscBool user_set_num_points_per_cell = PETSC_FALSE;
1289dbcead6SJeremy L Thompson     PetscInt  dim = 3, num_cells_total = 1;
1299dbcead6SJeremy L Thompson     PetscInt  num_cells[] = {1, 1, 1};
1309dbcead6SJeremy L Thompson 
1319dbcead6SJeremy L Thompson     PetscCall(PetscOptionsInt("-points_per_cell", "Total number of swarm points in each cell", NULL, num_points_per_cell, &num_points_per_cell,
1329dbcead6SJeremy L Thompson                               &user_set_num_points_per_cell));
1339dbcead6SJeremy L Thompson     PetscCall(PetscOptionsInt("-dm_plex_dim", "Background mesh dimension", NULL, dim, &dim, NULL));
1349dbcead6SJeremy L Thompson     PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of cells", NULL, num_cells, &dim, NULL));
1359dbcead6SJeremy L Thompson 
1369dbcead6SJeremy L Thompson     num_cells_total = num_cells[0] * num_cells[1] * num_cells[2];
1379dbcead6SJeremy L Thompson     PetscCheck(!user_set_num_points_per_cell || point_swarm_type != SWARM_SINUSOIDAL, comm, PETSC_ERR_USER,
1389dbcead6SJeremy L Thompson                "Cannot specify points per cell with sinusoidal points locations");
1399dbcead6SJeremy L Thompson     if (!user_set_num_points_per_cell) {
1409dbcead6SJeremy L Thompson       PetscCall(PetscOptionsInt("-points", "Total number of swarm points", NULL, num_points, &num_points, NULL));
1419dbcead6SJeremy L Thompson       num_points_per_cell = PetscCeilInt(num_points, num_cells_total);
1429dbcead6SJeremy L Thompson     }
1439dbcead6SJeremy L Thompson     if (point_swarm_type != SWARM_SINUSOIDAL) {
1449dbcead6SJeremy L Thompson       PetscInt num_points_per_cell_1d = round(cbrt(num_points_per_cell * 1.0));
1459dbcead6SJeremy L Thompson 
1469dbcead6SJeremy L Thompson       num_points_per_cell = 1;
1479dbcead6SJeremy L Thompson       for (PetscInt i = 0; i < dim; i++) num_points_per_cell *= num_points_per_cell_1d;
1489dbcead6SJeremy L Thompson     }
1499dbcead6SJeremy L Thompson     num_points = num_points_per_cell * num_cells_total;
1509dbcead6SJeremy L Thompson   }
1519dbcead6SJeremy L Thompson   PetscCall(PetscOptionsScalar("-tolerance", "Tolerance for swarm point values and projection relative L2 error", NULL, tolerance, &tolerance, NULL));
1529dbcead6SJeremy L Thompson   PetscCall(PetscOptionsString("-ceed", "CEED resource specifier", NULL, ceed_resource, ceed_resource, sizeof(ceed_resource), NULL));
1539dbcead6SJeremy L Thompson 
1549dbcead6SJeremy L Thompson   PetscOptionsEnd();
1559dbcead6SJeremy L Thompson 
1569dbcead6SJeremy L Thompson   // Create background mesh
1579dbcead6SJeremy L Thompson   {
1589dbcead6SJeremy L Thompson     PetscCall(DMCreate(comm, &dm_mesh));
1599dbcead6SJeremy L Thompson     PetscCall(DMSetType(dm_mesh, DMPLEX));
1609dbcead6SJeremy L Thompson     PetscCall(DMSetFromOptions(dm_mesh));
1619dbcead6SJeremy L Thompson 
1629dbcead6SJeremy L Thompson     // -- Check for tensor product mesh
1639dbcead6SJeremy L Thompson     {
1649dbcead6SJeremy L Thompson       PetscBool is_simplex;
1659dbcead6SJeremy L Thompson 
1669dbcead6SJeremy L Thompson       PetscCall(DMPlexIsSimplex(dm_mesh, &is_simplex));
1679dbcead6SJeremy L Thompson       PetscCheck(!is_simplex, comm, PETSC_ERR_USER, "Only tensor-product background meshes supported");
1689dbcead6SJeremy L Thompson     }
1699dbcead6SJeremy L Thompson 
1709dbcead6SJeremy L Thompson     // -- Mesh FE space
1719dbcead6SJeremy L Thompson     PetscCall(DMGetDimension(dm_mesh, &dim));
1729dbcead6SJeremy L Thompson     {
1739dbcead6SJeremy L Thompson       PetscFE fe;
1749dbcead6SJeremy L Thompson 
1759dbcead6SJeremy L Thompson       PetscCall(DMGetDimension(dm_mesh, &dim));
1769dbcead6SJeremy L Thompson       PetscCall(PetscFECreateLagrange(comm, dim, num_comp, PETSC_FALSE, solution_order, solution_order + q_extra, &fe));
1779dbcead6SJeremy L Thompson       PetscCall(DMAddField(dm_mesh, NULL, (PetscObject)fe));
1789dbcead6SJeremy L Thompson       PetscCall(PetscFEDestroy(&fe));
1799dbcead6SJeremy L Thompson     }
1809dbcead6SJeremy L Thompson     PetscCall(DMCreateDS(dm_mesh));
1819dbcead6SJeremy L Thompson 
1829dbcead6SJeremy L Thompson     // -- Coordinate FE space
1839dbcead6SJeremy L Thompson     {
1849dbcead6SJeremy L Thompson       PetscFE fe_coord;
1859dbcead6SJeremy L Thompson 
1869dbcead6SJeremy L Thompson       PetscCall(PetscFECreateLagrange(comm, dim, dim, PETSC_FALSE, mesh_order, solution_order + q_extra, &fe_coord));
187*49a40c8aSKenneth E. Jansen       PetscCall(DMSetCoordinateDisc(dm_mesh, fe_coord, PETSC_TRUE));
1889dbcead6SJeremy L Thompson       PetscCall(PetscFEDestroy(&fe_coord));
1899dbcead6SJeremy L Thompson     }
1909dbcead6SJeremy L Thompson 
1919dbcead6SJeremy L Thompson     // -- Set tensor permutation
1929dbcead6SJeremy L Thompson     {
1939dbcead6SJeremy L Thompson       DM dm_coord;
1949dbcead6SJeremy L Thompson 
1959dbcead6SJeremy L Thompson       PetscCall(DMGetCoordinateDM(dm_mesh, &dm_coord));
1969dbcead6SJeremy L Thompson       PetscCall(DMPlexSetClosurePermutationTensor(dm_mesh, PETSC_DETERMINE, NULL));
1979dbcead6SJeremy L Thompson       PetscCall(DMPlexSetClosurePermutationTensor(dm_coord, PETSC_DETERMINE, NULL));
1989dbcead6SJeremy L Thompson     }
1999dbcead6SJeremy L Thompson 
2009dbcead6SJeremy L Thompson     // -- Final background mesh
2019dbcead6SJeremy L Thompson     PetscCall(PetscObjectSetName((PetscObject)dm_mesh, "Background Mesh"));
2029dbcead6SJeremy L Thompson     PetscCall(DMViewFromOptions(dm_mesh, NULL, "-dm_mesh_view"));
2039dbcead6SJeremy L Thompson   }
2049dbcead6SJeremy L Thompson 
2059dbcead6SJeremy L Thompson   // Create particle swarm
2069dbcead6SJeremy L Thompson   {
2079dbcead6SJeremy L Thompson     PetscCall(DMCreate(comm, &dm_swarm));
2089dbcead6SJeremy L Thompson     PetscCall(DMSetType(dm_swarm, DMSWARM));
2099dbcead6SJeremy L Thompson     PetscCall(DMSetDimension(dm_swarm, dim));
2109dbcead6SJeremy L Thompson     PetscCall(DMSwarmSetType(dm_swarm, DMSWARM_PIC));
2119dbcead6SJeremy L Thompson     PetscCall(DMSwarmSetCellDM(dm_swarm, dm_mesh));
2129dbcead6SJeremy L Thompson 
2139dbcead6SJeremy L Thompson     // -- Swarm field
2149dbcead6SJeremy L Thompson     PetscCall(DMSwarmRegisterPetscDatatypeField(dm_swarm, DMSwarmPICField_u, num_comp, PETSC_SCALAR));
2159dbcead6SJeremy L Thompson     PetscCall(DMSwarmFinalizeFieldRegister(dm_swarm));
2169dbcead6SJeremy L Thompson     PetscCall(DMSwarmSetLocalSizes(dm_swarm, num_points, 0));
2179dbcead6SJeremy L Thompson     PetscCall(DMSetFromOptions(dm_swarm));
2189dbcead6SJeremy L Thompson 
2199dbcead6SJeremy L Thompson     // -- Set swarm point locations
2209dbcead6SJeremy L Thompson     PetscCall(DMSwarmInitalizePointLocations(dm_swarm, point_swarm_type, num_points, num_points_per_cell));
2219dbcead6SJeremy L Thompson 
2229dbcead6SJeremy L Thompson     // -- Final particle swarm
2239dbcead6SJeremy L Thompson     PetscCall(PetscObjectSetName((PetscObject)dm_swarm, "Particle Swarm"));
2249dbcead6SJeremy L Thompson     PetscCall(DMViewFromOptions(dm_swarm, NULL, "-dm_swarm_view"));
2259dbcead6SJeremy L Thompson   }
2269dbcead6SJeremy L Thompson 
2279dbcead6SJeremy L Thompson   // Set field values on background mesh
2289dbcead6SJeremy L Thompson   PetscCall(DMCreateGlobalVector(dm_mesh, &U_mesh));
2299dbcead6SJeremy L Thompson   switch (target_type) {
2309dbcead6SJeremy L Thompson     case TARGET_TANH:
2319dbcead6SJeremy L Thompson       target_function_proj = EvalU_Tanh_proj;
2329dbcead6SJeremy L Thompson       break;
2339dbcead6SJeremy L Thompson     case TARGET_POLYNOMIAL:
2349dbcead6SJeremy L Thompson       target_function_proj = EvalU_Poly_proj;
2359dbcead6SJeremy L Thompson       break;
2369dbcead6SJeremy L Thompson     case TARGET_SPHERE:
2379dbcead6SJeremy L Thompson       target_function_proj = EvalU_Sphere_proj;
2389dbcead6SJeremy L Thompson       break;
2399dbcead6SJeremy L Thompson   }
2409dbcead6SJeremy L Thompson   {
2419dbcead6SJeremy L Thompson     TargetFuncProj mesh_solution[1] = {target_function_proj};
2429dbcead6SJeremy L Thompson 
2439dbcead6SJeremy L Thompson     PetscCall(DMProjectFunction(dm_mesh, 0.0, mesh_solution, NULL, INSERT_VALUES, U_mesh));
2449dbcead6SJeremy L Thompson   }
2459dbcead6SJeremy L Thompson 
2469dbcead6SJeremy L Thompson   // Visualize background mesh
2479dbcead6SJeremy L Thompson   PetscCall(PetscObjectSetName((PetscObject)U_mesh, "U on Background Mesh"));
2489dbcead6SJeremy L Thompson   PetscCall(VecViewFromOptions(U_mesh, NULL, "-u_mesh_view"));
2499dbcead6SJeremy L Thompson 
2509dbcead6SJeremy L Thompson   // libCEED objects for swarm and background mesh
2519dbcead6SJeremy L Thompson   PetscCall(DMSwarmCeedContextCreate(dm_swarm, ceed_resource, &swarm_ceed_context));
2529dbcead6SJeremy L Thompson 
2539dbcead6SJeremy L Thompson   // Interpolate from mesh to points via PETSc
2549dbcead6SJeremy L Thompson   {
2559dbcead6SJeremy L Thompson     PetscCall(DMSwarmInterpolateFromCellToSwarm_Petsc(dm_swarm, DMSwarmPICField_u, U_mesh));
2569dbcead6SJeremy L Thompson     if (view_petsc_swarm) PetscCall(DMSwarmViewXDMF(dm_swarm, "swarm_petsc.xmf"));
2579dbcead6SJeremy L Thompson     PetscCall(DMSwarmCheckSwarmValues(dm_swarm, DMSwarmPICField_u, tolerance, target_function_proj));
2589dbcead6SJeremy L Thompson   }
2599dbcead6SJeremy L Thompson 
2609dbcead6SJeremy L Thompson   // Interpolate from mesh to points via libCEED
2619dbcead6SJeremy L Thompson   {
2629dbcead6SJeremy L Thompson     PetscCall(DMSwarmInterpolateFromCellToSwarm_Ceed(dm_swarm, DMSwarmPICField_u, U_mesh));
2639dbcead6SJeremy L Thompson     if (view_ceed_swarm) PetscCall(DMSwarmViewXDMF(dm_swarm, "swarm_ceed.xmf"));
2649dbcead6SJeremy L Thompson     PetscCall(DMSwarmCheckSwarmValues(dm_swarm, DMSwarmPICField_u, tolerance, target_function_proj));
2659dbcead6SJeremy L Thompson   }
2669dbcead6SJeremy L Thompson 
2679dbcead6SJeremy L Thompson   // Project from points to mesh via libCEED
2689dbcead6SJeremy L Thompson   {
2699dbcead6SJeremy L Thompson     Vec B_mesh, U_projected;
2709dbcead6SJeremy L Thompson     Mat M;
2719dbcead6SJeremy L Thompson     KSP ksp;
2729dbcead6SJeremy L Thompson 
2739dbcead6SJeremy L Thompson     PetscCall(VecDuplicate(U_mesh, &B_mesh));
2749dbcead6SJeremy L Thompson     PetscCall(VecDuplicate(U_mesh, &U_projected));
2759dbcead6SJeremy L Thompson 
2769dbcead6SJeremy L Thompson     // -- Setup "mass matrix"
2779dbcead6SJeremy L Thompson     {
2789dbcead6SJeremy L Thompson       PetscInt l_size, g_size;
2799dbcead6SJeremy L Thompson 
2809dbcead6SJeremy L Thompson       PetscCall(VecGetLocalSize(U_mesh, &l_size));
2819dbcead6SJeremy L Thompson       PetscCall(VecGetSize(U_mesh, &g_size));
2829dbcead6SJeremy L Thompson       PetscCall(MatCreateShell(comm, l_size, l_size, g_size, g_size, swarm_ceed_context, &M));
2839dbcead6SJeremy L Thompson       PetscCall(MatSetDM(M, dm_mesh));
2849dbcead6SJeremy L Thompson       PetscCall(MatShellSetOperation(M, MATOP_MULT, (void (*)(void))MatMult_SwarmMass));
2859dbcead6SJeremy L Thompson     }
2869dbcead6SJeremy L Thompson 
2879dbcead6SJeremy L Thompson     // -- Setup KSP
2889dbcead6SJeremy L Thompson     {
2899dbcead6SJeremy L Thompson       PC pc;
2909dbcead6SJeremy L Thompson 
2919dbcead6SJeremy L Thompson       PetscCall(KSPCreate(comm, &ksp));
2929dbcead6SJeremy L Thompson       PetscCall(KSPGetPC(ksp, &pc));
2939dbcead6SJeremy L Thompson       PetscCall(PCSetType(pc, PCJACOBI));
2949dbcead6SJeremy L Thompson       PetscCall(PCJacobiSetType(pc, PC_JACOBI_ROWSUM));
2959dbcead6SJeremy L Thompson       PetscCall(KSPSetType(ksp, KSPCG));
2969dbcead6SJeremy L Thompson       PetscCall(KSPSetNormType(ksp, KSP_NORM_NATURAL));
2979dbcead6SJeremy L Thompson       PetscCall(KSPSetTolerances(ksp, 1e-10, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT));
2989dbcead6SJeremy L Thompson       PetscCall(KSPSetOperators(ksp, M, M));
2999dbcead6SJeremy L Thompson       PetscCall(KSPSetFromOptions(ksp));
3009dbcead6SJeremy L Thompson       PetscCall(PetscObjectSetName((PetscObject)ksp, "Swarm-to-Mesh Projection"));
3019dbcead6SJeremy L Thompson       PetscCall(KSPViewFromOptions(ksp, NULL, "-ksp_projection_view"));
3029dbcead6SJeremy L Thompson     }
3039dbcead6SJeremy L Thompson 
3049dbcead6SJeremy L Thompson     // -- Setup RHS
3059dbcead6SJeremy L Thompson     PetscCall(DMSwarmCreateProjectionRHS(dm_swarm, DMSwarmPICField_u, B_mesh));
3069dbcead6SJeremy L Thompson 
3079dbcead6SJeremy L Thompson     // -- Solve
3089dbcead6SJeremy L Thompson     PetscCall(VecZeroEntries(U_projected));
3099dbcead6SJeremy L Thompson     PetscCall(KSPSolve(ksp, B_mesh, U_projected));
3109dbcead6SJeremy L Thompson 
3119dbcead6SJeremy L Thompson     // -- KSP summary
3129dbcead6SJeremy L Thompson     {
3139dbcead6SJeremy L Thompson       KSPType            ksp_type;
3149dbcead6SJeremy L Thompson       KSPConvergedReason reason;
3159dbcead6SJeremy L Thompson       PetscReal          rnorm;
3169dbcead6SJeremy L Thompson       PetscInt           its;
3179dbcead6SJeremy L Thompson       PetscCall(KSPGetType(ksp, &ksp_type));
3189dbcead6SJeremy L Thompson       PetscCall(KSPGetConvergedReason(ksp, &reason));
3199dbcead6SJeremy L Thompson       PetscCall(KSPGetIterationNumber(ksp, &its));
3209dbcead6SJeremy L Thompson       PetscCall(KSPGetResidualNorm(ksp, &rnorm));
3219dbcead6SJeremy L Thompson 
3229dbcead6SJeremy L Thompson       if (!test_mode || reason < 0 || rnorm > 1e-8) {
3239dbcead6SJeremy L Thompson         PetscCall(PetscPrintf(comm,
3249dbcead6SJeremy L Thompson                               "Swarm-to-Mesh Projection KSP Solve:\n"
3259dbcead6SJeremy L Thompson                               "  KSP type: %s\n"
3269dbcead6SJeremy L Thompson                               "  KSP convergence: %s\n"
3279dbcead6SJeremy L Thompson                               "  Total KSP iterations: %" PetscInt_FMT "\n"
3289dbcead6SJeremy L Thompson                               "  Final rnorm: %e\n",
3299dbcead6SJeremy L Thompson                               ksp_type, KSPConvergedReasons[reason], its, (double)rnorm));
3309dbcead6SJeremy L Thompson       }
3319dbcead6SJeremy L Thompson     }
3329dbcead6SJeremy L Thompson 
3339dbcead6SJeremy L Thompson     // -- Check error
3349dbcead6SJeremy L Thompson     PetscCall(KSPViewFromOptions(ksp, NULL, "-ksp_view"));
3359dbcead6SJeremy L Thompson     PetscCall(PetscObjectSetName((PetscObject)U_mesh, "U projected to Background Mesh"));
3369dbcead6SJeremy L Thompson     PetscCall(VecViewFromOptions(U_projected, NULL, "-u_projected_view"));
3379dbcead6SJeremy L Thompson     PetscCall(VecAXPY(U_projected, -1.0, U_mesh));
3389dbcead6SJeremy L Thompson     PetscCall(PetscObjectSetName((PetscObject)U_projected, "U Projection Error"));
3399dbcead6SJeremy L Thompson     PetscCall(VecViewFromOptions(U_projected, NULL, "-u_error_view"));
3409dbcead6SJeremy L Thompson     {
3419dbcead6SJeremy L Thompson       PetscScalar error, norm_u_mesh;
3429dbcead6SJeremy L Thompson 
3439dbcead6SJeremy L Thompson       PetscCall(VecNorm(U_projected, NORM_2, &error));
3449dbcead6SJeremy L Thompson       PetscCall(VecNorm(U_mesh, NORM_2, &norm_u_mesh));
3459dbcead6SJeremy L Thompson       PetscCheck(error / norm_u_mesh < tolerance, comm, PETSC_ERR_USER, "Projection error too high: %e\n", error / norm_u_mesh);
3469dbcead6SJeremy L Thompson       if (!test_mode) PetscCall(PetscPrintf(comm, "  Projection error: %e\n", error / norm_u_mesh));
3479dbcead6SJeremy L Thompson     }
3489dbcead6SJeremy L Thompson 
3499dbcead6SJeremy L Thompson     // -- Cleanup
3509dbcead6SJeremy L Thompson     PetscCall(VecDestroy(&B_mesh));
3519dbcead6SJeremy L Thompson     PetscCall(VecDestroy(&U_projected));
3529dbcead6SJeremy L Thompson     PetscCall(MatDestroy(&M));
3539dbcead6SJeremy L Thompson     PetscCall(KSPDestroy(&ksp));
3549dbcead6SJeremy L Thompson   }
3559dbcead6SJeremy L Thompson 
3569dbcead6SJeremy L Thompson   // Cleanup
3579dbcead6SJeremy L Thompson   PetscCall(DMSwarmCeedContextDestroy(&swarm_ceed_context));
3589dbcead6SJeremy L Thompson   PetscCall(DMDestroy(&dm_swarm));
3599dbcead6SJeremy L Thompson   PetscCall(DMDestroy(&dm_mesh));
3609dbcead6SJeremy L Thompson   PetscCall(VecDestroy(&U_mesh));
3619dbcead6SJeremy L Thompson   return PetscFinalize();
3629dbcead6SJeremy L Thompson }
3639dbcead6SJeremy L Thompson 
3649dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
3659dbcead6SJeremy L Thompson // Context utilities
3669dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
3679dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCeedContextCreate(DM dm_swarm, const char *ceed_resource, DMSwarmCeedContext *ctx) {
3689dbcead6SJeremy L Thompson   DM dm_mesh;
3699dbcead6SJeremy L Thompson 
3709dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
3719dbcead6SJeremy L Thompson   PetscCall(PetscNew(ctx));
3729dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
3739dbcead6SJeremy L Thompson 
3749dbcead6SJeremy L Thompson   CeedInit(ceed_resource, &(*ctx)->ceed);
3759dbcead6SJeremy L Thompson   // Background mesh objects
3769dbcead6SJeremy L Thompson   {
3779dbcead6SJeremy L Thompson     CeedInt elem_size, num_comp;
3789dbcead6SJeremy L Thompson     BPData  bp_data = {.q_mode = CEED_GAUSS};
3799dbcead6SJeremy L Thompson 
3809dbcead6SJeremy L Thompson     PetscCall(CreateBasisFromPlex((*ctx)->ceed, dm_mesh, NULL, 0, 0, 0, bp_data, &(*ctx)->basis_u));
3819dbcead6SJeremy L Thompson     PetscCall(CreateRestrictionFromPlex((*ctx)->ceed, dm_mesh, 0, NULL, 0, &(*ctx)->restriction_u_mesh));
3829dbcead6SJeremy L Thompson 
3839dbcead6SJeremy L Thompson     // -- U vector
3849dbcead6SJeremy L Thompson     CeedElemRestrictionCreateVector((*ctx)->restriction_u_mesh, &(*ctx)->u_mesh_loc, NULL);
3859dbcead6SJeremy L Thompson     CeedElemRestrictionCreateVector((*ctx)->restriction_u_mesh, &(*ctx)->v_mesh_loc, NULL);
3869dbcead6SJeremy L Thompson     CeedElemRestrictionGetElementSize((*ctx)->restriction_u_mesh, &elem_size);
3879dbcead6SJeremy L Thompson     CeedElemRestrictionGetNumComponents((*ctx)->restriction_u_mesh, &num_comp);
3889dbcead6SJeremy L Thompson     CeedVectorCreate((*ctx)->ceed, elem_size * num_comp, &(*ctx)->u_mesh_elem);
3899dbcead6SJeremy L Thompson   }
3909dbcead6SJeremy L Thompson   // Swarm objects
3919dbcead6SJeremy L Thompson   {
3929dbcead6SJeremy L Thompson     PetscInt        dim;
3939dbcead6SJeremy L Thompson     const PetscInt *cell_points;
3949dbcead6SJeremy L Thompson     IS              is_points;
3959dbcead6SJeremy L Thompson     Vec             X_ref;
3969dbcead6SJeremy L Thompson     CeedInt         num_elem, num_comp, max_points_in_cell;
3979dbcead6SJeremy L Thompson 
3989dbcead6SJeremy L Thompson     PetscCall(DMSwarmCreateReferenceCoordinates(dm_swarm, &is_points, &X_ref));
3999dbcead6SJeremy L Thompson     PetscCall(DMGetDimension(dm_mesh, &dim));
4009dbcead6SJeremy L Thompson     CeedElemRestrictionGetNumElements((*ctx)->restriction_u_mesh, &num_elem);
4019dbcead6SJeremy L Thompson     CeedElemRestrictionGetNumComponents((*ctx)->restriction_u_mesh, &num_comp);
4029dbcead6SJeremy L Thompson 
4039dbcead6SJeremy L Thompson     PetscCall(ISGetIndices(is_points, &cell_points));
4049dbcead6SJeremy L Thompson     PetscInt num_points = cell_points[num_elem + 1] - num_elem - 2;
4059dbcead6SJeremy L Thompson     CeedInt  offsets[num_elem + 1 + num_points];
4069dbcead6SJeremy L Thompson 
4079dbcead6SJeremy L Thompson     for (PetscInt i = 0; i < num_elem + 1; i++) offsets[i] = cell_points[i + 1] - 1;
4089dbcead6SJeremy L Thompson     for (PetscInt i = num_elem + 1; i < num_points + num_elem + 1; i++) offsets[i] = cell_points[i + 1];
4099dbcead6SJeremy L Thompson     PetscCall(ISRestoreIndices(is_points, &cell_points));
4109dbcead6SJeremy L Thompson 
4119dbcead6SJeremy L Thompson     // -- Points restrictions
4129dbcead6SJeremy L Thompson     CeedElemRestrictionCreateAtPoints((*ctx)->ceed, num_elem, num_points, num_comp, num_points * num_comp, CEED_MEM_HOST, CEED_COPY_VALUES, offsets,
4139dbcead6SJeremy L Thompson                                       &(*ctx)->restriction_u_points);
4149dbcead6SJeremy L Thompson     CeedElemRestrictionCreateAtPoints((*ctx)->ceed, num_elem, num_points, dim, num_points * dim, CEED_MEM_HOST, CEED_COPY_VALUES, offsets,
4159dbcead6SJeremy L Thompson                                       &(*ctx)->restriction_x_points);
4169dbcead6SJeremy L Thompson 
4179dbcead6SJeremy L Thompson     // -- U vector
4189dbcead6SJeremy L Thompson     CeedElemRestrictionGetMaxPointsInElement((*ctx)->restriction_u_points, &max_points_in_cell);
4199dbcead6SJeremy L Thompson     CeedElemRestrictionCreateVector((*ctx)->restriction_u_points, &(*ctx)->u_points_loc, NULL);
4209dbcead6SJeremy L Thompson     CeedVectorCreate((*ctx)->ceed, max_points_in_cell * num_comp, &(*ctx)->u_points_elem);
4219dbcead6SJeremy L Thompson 
4229dbcead6SJeremy L Thompson     // -- Ref coordinates
4239dbcead6SJeremy L Thompson     {
4249dbcead6SJeremy L Thompson       PetscMemType       X_mem_type;
4259dbcead6SJeremy L Thompson       const PetscScalar *x;
4269dbcead6SJeremy L Thompson 
4279dbcead6SJeremy L Thompson       CeedVectorCreate((*ctx)->ceed, num_points * dim, &(*ctx)->x_ref_points_loc);
4289dbcead6SJeremy L Thompson       CeedVectorCreate((*ctx)->ceed, max_points_in_cell * dim, &(*ctx)->x_ref_points_elem);
4299dbcead6SJeremy L Thompson 
4309dbcead6SJeremy L Thompson       PetscCall(VecGetArrayReadAndMemType(X_ref, (const PetscScalar **)&x, &X_mem_type));
4319dbcead6SJeremy L Thompson       CeedVectorSetArray((*ctx)->x_ref_points_loc, MemTypeP2C(X_mem_type), CEED_COPY_VALUES, (CeedScalar *)x);
4329dbcead6SJeremy L Thompson       PetscCall(VecRestoreArrayReadAndMemType(X_ref, (const PetscScalar **)&x));
4339dbcead6SJeremy L Thompson     }
4349dbcead6SJeremy L Thompson 
4359dbcead6SJeremy L Thompson     // -- Cleanup
4369dbcead6SJeremy L Thompson     PetscCall(ISDestroy(&is_points));
4379dbcead6SJeremy L Thompson     PetscCall(VecDestroy(&X_ref));
4389dbcead6SJeremy L Thompson   }
4399dbcead6SJeremy L Thompson 
4409dbcead6SJeremy L Thompson   PetscCall(DMSetApplicationContext(dm_mesh, (void *)(*ctx)));
4419dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
4429dbcead6SJeremy L Thompson }
4439dbcead6SJeremy L Thompson 
4449dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCeedContextDestroy(DMSwarmCeedContext *ctx) {
4459dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
4469dbcead6SJeremy L Thompson   CeedDestroy(&(*ctx)->ceed);
4479dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->u_mesh_loc);
4489dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->v_mesh_loc);
4499dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->u_mesh_elem);
4509dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->u_points_loc);
4519dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->u_points_elem);
4529dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->x_ref_points_loc);
4539dbcead6SJeremy L Thompson   CeedVectorDestroy(&(*ctx)->x_ref_points_elem);
4549dbcead6SJeremy L Thompson   CeedElemRestrictionDestroy(&(*ctx)->restriction_u_mesh);
4559dbcead6SJeremy L Thompson   CeedElemRestrictionDestroy(&(*ctx)->restriction_x_points);
4569dbcead6SJeremy L Thompson   CeedElemRestrictionDestroy(&(*ctx)->restriction_u_points);
4579dbcead6SJeremy L Thompson   CeedBasisDestroy(&(*ctx)->basis_u);
4589dbcead6SJeremy L Thompson   PetscCall(PetscFree(*ctx));
4599dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
4609dbcead6SJeremy L Thompson }
4619dbcead6SJeremy L Thompson 
4629dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
4639dbcead6SJeremy L Thompson // PETSc-libCEED memory space utilities
4649dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
4659dbcead6SJeremy L Thompson PetscErrorCode VecP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed) {
4669dbcead6SJeremy L Thompson   PetscScalar *x;
4679dbcead6SJeremy L Thompson 
4689dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
4699dbcead6SJeremy L Thompson   PetscCall(VecGetArrayAndMemType(X_petsc, &x, mem_type));
4709dbcead6SJeremy L Thompson   CeedVectorSetArray(x_ceed, MemTypeP2C(*mem_type), CEED_USE_POINTER, x);
4719dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
4729dbcead6SJeremy L Thompson }
4739dbcead6SJeremy L Thompson 
4749dbcead6SJeremy L Thompson PetscErrorCode VecC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc) {
4759dbcead6SJeremy L Thompson   PetscScalar *x;
4769dbcead6SJeremy L Thompson 
4779dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
4789dbcead6SJeremy L Thompson   CeedVectorTakeArray(x_ceed, MemTypeP2C(mem_type), &x);
4799dbcead6SJeremy L Thompson   PetscCall(VecRestoreArrayAndMemType(X_petsc, &x));
4809dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
4819dbcead6SJeremy L Thompson }
4829dbcead6SJeremy L Thompson 
4839dbcead6SJeremy L Thompson PetscErrorCode VecReadP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed) {
4849dbcead6SJeremy L Thompson   PetscScalar *x;
4859dbcead6SJeremy L Thompson 
4869dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
4879dbcead6SJeremy L Thompson   PetscCall(VecGetArrayReadAndMemType(X_petsc, (const PetscScalar **)&x, mem_type));
4889dbcead6SJeremy L Thompson   CeedVectorSetArray(x_ceed, MemTypeP2C(*mem_type), CEED_USE_POINTER, x);
4899dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
4909dbcead6SJeremy L Thompson }
4919dbcead6SJeremy L Thompson 
4929dbcead6SJeremy L Thompson PetscErrorCode VecReadC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc) {
4939dbcead6SJeremy L Thompson   PetscScalar *x;
4949dbcead6SJeremy L Thompson 
4959dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
4969dbcead6SJeremy L Thompson   CeedVectorTakeArray(x_ceed, MemTypeP2C(mem_type), &x);
4979dbcead6SJeremy L Thompson   PetscCall(VecRestoreArrayReadAndMemType(X_petsc, (const PetscScalar **)&x));
4989dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
4999dbcead6SJeremy L Thompson }
5009dbcead6SJeremy L Thompson 
5019dbcead6SJeremy L Thompson PetscErrorCode DMSwarmPICFieldP2C(DM dm_swarm, const char *field, CeedVector x_ceed) {
5029dbcead6SJeremy L Thompson   PetscScalar *x;
5039dbcead6SJeremy L Thompson 
5049dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
5059dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetField(dm_swarm, field, NULL, NULL, (void **)&x));
5069dbcead6SJeremy L Thompson   CeedVectorSetArray(x_ceed, CEED_MEM_HOST, CEED_USE_POINTER, (CeedScalar *)x);
5079dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
5089dbcead6SJeremy L Thompson }
5099dbcead6SJeremy L Thompson 
5109dbcead6SJeremy L Thompson PetscErrorCode DMSwarmPICFieldC2P(DM dm_swarm, const char *field, CeedVector x_ceed) {
5119dbcead6SJeremy L Thompson   PetscScalar *x;
5129dbcead6SJeremy L Thompson 
5139dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
5149dbcead6SJeremy L Thompson   CeedVectorTakeArray(x_ceed, CEED_MEM_HOST, (CeedScalar **)&x);
5159dbcead6SJeremy L Thompson   PetscCall(DMSwarmRestoreField(dm_swarm, field, NULL, NULL, (void **)&x));
5169dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
5179dbcead6SJeremy L Thompson }
5189dbcead6SJeremy L Thompson 
5199dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
5209dbcead6SJeremy L Thompson // Solution functions
5219dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
5229dbcead6SJeremy L Thompson PetscScalar EvalU_Poly(PetscInt dim, const PetscScalar x[]) {
5239dbcead6SJeremy L Thompson   PetscScalar       result = 0.0;
5249dbcead6SJeremy L Thompson   const PetscScalar p[5]   = {3, 1, 4, 1, 5};
5259dbcead6SJeremy L Thompson 
5269dbcead6SJeremy L Thompson   for (PetscInt d = 0; d < dim; d++) {
5279dbcead6SJeremy L Thompson     PetscScalar result_1d = 1.0;
5289dbcead6SJeremy L Thompson 
5299dbcead6SJeremy L Thompson     for (PetscInt i = 4; i >= 0; i--) result_1d = result_1d * x[d] + p[i];
5309dbcead6SJeremy L Thompson     result += result_1d;
5319dbcead6SJeremy L Thompson   }
5329dbcead6SJeremy L Thompson   return result * 1E-3;
5339dbcead6SJeremy L Thompson }
5349dbcead6SJeremy L Thompson 
5359dbcead6SJeremy L Thompson PetscScalar EvalU_Tanh(PetscInt dim, const PetscScalar x[]) {
5369dbcead6SJeremy L Thompson   PetscScalar result = 1.0, center = 0.1;
5379dbcead6SJeremy L Thompson 
5389dbcead6SJeremy L Thompson   for (PetscInt d = 0; d < dim; d++) {
5399dbcead6SJeremy L Thompson     result *= tanh(x[d] - center);
5409dbcead6SJeremy L Thompson     center += 0.1;
5419dbcead6SJeremy L Thompson   }
5429dbcead6SJeremy L Thompson   return result;
5439dbcead6SJeremy L Thompson }
5449dbcead6SJeremy L Thompson 
5459dbcead6SJeremy L Thompson PetscScalar EvalU_Sphere(PetscInt dim, const PetscScalar x[]) {
5469dbcead6SJeremy L Thompson   PetscScalar distance = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
5479dbcead6SJeremy L Thompson 
5489dbcead6SJeremy L Thompson   return distance < 1.0 ? 1.0 : 0.1;
5499dbcead6SJeremy L Thompson }
5509dbcead6SJeremy L Thompson 
5519dbcead6SJeremy L Thompson PetscErrorCode EvalU_Poly_proj(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt num_comp, PetscScalar *u, void *ctx) {
5529dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
5539dbcead6SJeremy L Thompson 
5549dbcead6SJeremy L Thompson   const PetscScalar f_x = EvalU_Poly(dim, x);
5559dbcead6SJeremy L Thompson 
5569dbcead6SJeremy L Thompson   for (PetscInt c = 0; c < num_comp; c++) u[c] = (c + 1.0) * f_x;
5579dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
5589dbcead6SJeremy L Thompson }
5599dbcead6SJeremy L Thompson 
5609dbcead6SJeremy L Thompson PetscErrorCode EvalU_Tanh_proj(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt num_comp, PetscScalar *u, void *ctx) {
5619dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
5629dbcead6SJeremy L Thompson 
5639dbcead6SJeremy L Thompson   const PetscScalar f_x = EvalU_Tanh(dim, x);
5649dbcead6SJeremy L Thompson 
5659dbcead6SJeremy L Thompson   for (PetscInt c = 0; c < num_comp; c++) u[c] = (c + 1.0) * f_x;
5669dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
5679dbcead6SJeremy L Thompson }
5689dbcead6SJeremy L Thompson 
5699dbcead6SJeremy L Thompson PetscErrorCode EvalU_Sphere_proj(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt num_comp, PetscScalar *u, void *ctx) {
5709dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
5719dbcead6SJeremy L Thompson 
5729dbcead6SJeremy L Thompson   const PetscScalar f_x = EvalU_Sphere(dim, x);
5739dbcead6SJeremy L Thompson 
5749dbcead6SJeremy L Thompson   for (PetscInt c = 0; c < num_comp; c++) u[c] = (c + 1.0) * f_x;
5759dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
5769dbcead6SJeremy L Thompson }
5779dbcead6SJeremy L Thompson 
5789dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
5799dbcead6SJeremy L Thompson // Swarm point location utility
5809dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
5819dbcead6SJeremy L Thompson PetscErrorCode DMSwarmInitalizePointLocations(DM dm_swarm, PointSwarmType point_swarm_type, PetscInt num_points, PetscInt num_points_per_cell) {
5829dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
5839dbcead6SJeremy L Thompson 
5849dbcead6SJeremy L Thompson   switch (point_swarm_type) {
5859dbcead6SJeremy L Thompson     case SWARM_GAUSS:
5869dbcead6SJeremy L Thompson     case SWARM_UNIFORM: {
5879dbcead6SJeremy L Thompson       // -- Set gauss or uniform point locations in each cell
5889dbcead6SJeremy L Thompson       PetscInt    num_points_per_cell_1d = round(cbrt(num_points_per_cell * 1.0)), dim = 3;
5899dbcead6SJeremy L Thompson       PetscScalar point_coords[num_points_per_cell * 3];
5909dbcead6SJeremy L Thompson       CeedScalar  points_1d[num_points_per_cell_1d], weights_1d[num_points_per_cell_1d];
5919dbcead6SJeremy L Thompson 
5929dbcead6SJeremy L Thompson       if (point_swarm_type == SWARM_GAUSS) {
5939dbcead6SJeremy L Thompson         PetscCall(CeedGaussQuadrature(num_points_per_cell_1d, points_1d, weights_1d));
5949dbcead6SJeremy L Thompson       } else {
5959dbcead6SJeremy L Thompson         for (PetscInt i = 0; i < num_points_per_cell_1d; i++) points_1d[i] = 2.0 * (PetscReal)(i + 1) / (PetscReal)(num_points_per_cell_1d + 1) - 1;
5969dbcead6SJeremy L Thompson       }
5979dbcead6SJeremy L Thompson       for (PetscInt i = 0; i < num_points_per_cell_1d; i++) {
5989dbcead6SJeremy L Thompson         for (PetscInt j = 0; j < num_points_per_cell_1d; j++) {
5999dbcead6SJeremy L Thompson           for (PetscInt k = 0; k < num_points_per_cell_1d; k++) {
6009dbcead6SJeremy L Thompson             PetscInt p = (i * num_points_per_cell_1d + j) * num_points_per_cell_1d + k;
6019dbcead6SJeremy L Thompson 
6029dbcead6SJeremy L Thompson             point_coords[p * dim + 0] = points_1d[i];
6039dbcead6SJeremy L Thompson             point_coords[p * dim + 1] = points_1d[j];
6049dbcead6SJeremy L Thompson             point_coords[p * dim + 2] = points_1d[k];
6059dbcead6SJeremy L Thompson           }
6069dbcead6SJeremy L Thompson         }
6079dbcead6SJeremy L Thompson       }
6089dbcead6SJeremy L Thompson       PetscCall(DMSwarmSetPointCoordinatesCellwise(dm_swarm, num_points_per_cell_1d * num_points_per_cell_1d * num_points_per_cell_1d, point_coords));
6099dbcead6SJeremy L Thompson     } break;
6109dbcead6SJeremy L Thompson     case SWARM_CELL_RANDOM: {
6119dbcead6SJeremy L Thompson       // -- Set points randomly in each cell
6129dbcead6SJeremy L Thompson       PetscInt     dim = 3, num_cells_total = 1, num_cells[] = {1, 1, 1};
6139dbcead6SJeremy L Thompson       PetscScalar *point_coords;
6149dbcead6SJeremy L Thompson       PetscRandom  rng;
6159dbcead6SJeremy L Thompson 
6169dbcead6SJeremy L Thompson       PetscOptionsBegin(PetscObjectComm((PetscObject)dm_swarm), NULL, "libCEED example using PETSc with DMSwarm", NULL);
6179dbcead6SJeremy L Thompson 
6189dbcead6SJeremy L Thompson       PetscCall(PetscOptionsInt("-dm_plex_dim", "Background mesh dimension", NULL, dim, &dim, NULL));
6199dbcead6SJeremy L Thompson       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of cells", NULL, num_cells, &dim, NULL));
6209dbcead6SJeremy L Thompson 
6219dbcead6SJeremy L Thompson       PetscOptionsEnd();
6229dbcead6SJeremy L Thompson 
6239dbcead6SJeremy L Thompson       PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)dm_swarm), &rng));
6249dbcead6SJeremy L Thompson 
6259dbcead6SJeremy L Thompson       num_cells_total = num_cells[0] * num_cells[1] * num_cells[2];
6269dbcead6SJeremy L Thompson       PetscCall(DMSwarmGetField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&point_coords));
6279dbcead6SJeremy L Thompson       for (PetscInt c = 0; c < num_cells_total; c++) {
6289dbcead6SJeremy L Thompson         PetscInt cell_index[3] = {c % num_cells[0], (c / num_cells[0]) % num_cells[1], (c / num_cells[0] / num_cells[1]) % num_cells[2]};
6299dbcead6SJeremy L Thompson 
6309dbcead6SJeremy L Thompson         for (PetscInt p = 0; p < num_points_per_cell; p++) {
6319dbcead6SJeremy L Thompson           PetscInt    point_index = c * num_points_per_cell + p;
6329dbcead6SJeremy L Thompson           PetscScalar random_value;
6339dbcead6SJeremy L Thompson 
6349dbcead6SJeremy L Thompson           for (PetscInt i = 0; i < dim; i++) {
6359dbcead6SJeremy L Thompson             PetscCall(PetscRandomGetValue(rng, &random_value));
6369dbcead6SJeremy L Thompson             point_coords[point_index * dim + i] = -1.0 + cell_index[i] * 2.0 / (num_cells[i] + 1.0) + random_value;
6379dbcead6SJeremy L Thompson           }
6389dbcead6SJeremy L Thompson         }
6399dbcead6SJeremy L Thompson       }
6409dbcead6SJeremy L Thompson       PetscCall(DMSwarmRestoreField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&point_coords));
6419dbcead6SJeremy L Thompson       PetscCall(PetscRandomDestroy(&rng));
6429dbcead6SJeremy L Thompson     } break;
6439dbcead6SJeremy L Thompson     case SWARM_SINUSOIDAL: {
6449dbcead6SJeremy L Thompson       // -- Set points distributed per sinusoidal functions
6459dbcead6SJeremy L Thompson       PetscInt     dim = 3;
6469dbcead6SJeremy L Thompson       PetscScalar *point_coords;
6479dbcead6SJeremy L Thompson       DM           dm_mesh;
6489dbcead6SJeremy L Thompson 
6499dbcead6SJeremy L Thompson       PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
6509dbcead6SJeremy L Thompson       PetscCall(DMGetDimension(dm_mesh, &dim));
6519dbcead6SJeremy L Thompson 
6529dbcead6SJeremy L Thompson       PetscCall(DMSwarmGetField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&point_coords));
6539dbcead6SJeremy L Thompson       for (PetscInt p = 0; p < num_points; p++) {
6549dbcead6SJeremy L Thompson         point_coords[p * dim + 0] = -PetscCosReal((PetscReal)(p + 1) / (PetscReal)(num_points + 1) * PETSC_PI);
6559dbcead6SJeremy L Thompson         if (dim > 1) point_coords[p * dim + 1] = -PetscSinReal((PetscReal)(p + 1) / (PetscReal)(num_points + 1) * PETSC_PI);
6569dbcead6SJeremy L Thompson         if (dim > 2) point_coords[p * dim + 2] = PetscSinReal((PetscReal)(p + 1) / (PetscReal)(num_points + 1) * PETSC_PI);
6579dbcead6SJeremy L Thompson       }
6589dbcead6SJeremy L Thompson       PetscCall(DMSwarmRestoreField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&point_coords));
6599dbcead6SJeremy L Thompson     } break;
6609dbcead6SJeremy L Thompson   }
6619dbcead6SJeremy L Thompson   PetscCall(DMSwarmMigrate(dm_swarm, PETSC_TRUE));
6629dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
6639dbcead6SJeremy L Thompson }
6649dbcead6SJeremy L Thompson 
6659dbcead6SJeremy L Thompson /*@C
6669dbcead6SJeremy L Thompson   DMSwarmCreateReferenceCoordinates - Compute the cell reference coordinates for local DMSwarm points.
6679dbcead6SJeremy L Thompson 
6689dbcead6SJeremy L Thompson   Collective
6699dbcead6SJeremy L Thompson 
6709dbcead6SJeremy L Thompson   Input Parameter:
6719dbcead6SJeremy L Thompson . dm_swarm  - the `DMSwarm`
6729dbcead6SJeremy L Thompson 
6739dbcead6SJeremy L Thompson   Output Parameters:
6749dbcead6SJeremy L Thompson + is_points    - The IS object for indexing into points per cell
6759dbcead6SJeremy L Thompson - X_points_ref - Vec holding the cell reference coordinates for local DMSwarm points
6769dbcead6SJeremy L Thompson 
6779dbcead6SJeremy L Thompson The index set contains ranges of indices for each local cell. This range contains the indices of every point in the cell.
6789dbcead6SJeremy L Thompson 
6799dbcead6SJeremy L Thompson ```
6809dbcead6SJeremy L Thompson total_num_cells
6819dbcead6SJeremy L Thompson cell_0_start_index
6829dbcead6SJeremy L Thompson cell_1_start_index
6839dbcead6SJeremy L Thompson cell_2_start_index
6849dbcead6SJeremy L Thompson ...
6859dbcead6SJeremy L Thompson cell_n_start_index
6869dbcead6SJeremy L Thompson cell_n_stop_index
6879dbcead6SJeremy L Thompson cell_0_point_0
6889dbcead6SJeremy L Thompson cell_0_point_0
6899dbcead6SJeremy L Thompson ...
6909dbcead6SJeremy L Thompson cell_n_point_m
6919dbcead6SJeremy L Thompson ```
6929dbcead6SJeremy L Thompson 
6939dbcead6SJeremy L Thompson   Level: beginner
6949dbcead6SJeremy L Thompson 
6959dbcead6SJeremy L Thompson .seealso: `DMSwarm`
6969dbcead6SJeremy L Thompson @*/
6979dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCreateReferenceCoordinates(DM dm_swarm, IS *is_points, Vec *X_points_ref) {
6989dbcead6SJeremy L Thompson   PetscInt           cell_start, cell_end, num_cells_local, dim, num_points_local, *cell_points, points_offset;
6999dbcead6SJeremy L Thompson   PetscScalar       *coords_points_ref;
7009dbcead6SJeremy L Thompson   const PetscScalar *coords_points_true;
7019dbcead6SJeremy L Thompson   DM                 dm_mesh;
7029dbcead6SJeremy L Thompson 
7039dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
7049dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
7059dbcead6SJeremy L Thompson 
7069dbcead6SJeremy L Thompson   // Create vector to hold reference coordinates
7079dbcead6SJeremy L Thompson   {
7089dbcead6SJeremy L Thompson     Vec X_points_true;
7099dbcead6SJeremy L Thompson 
7109dbcead6SJeremy L Thompson     PetscCall(DMSwarmCreateLocalVectorFromField(dm_swarm, DMSwarmPICField_coor, &X_points_true));
7119dbcead6SJeremy L Thompson     PetscCall(VecDuplicate(X_points_true, X_points_ref));
7129dbcead6SJeremy L Thompson     PetscCall(DMSwarmDestroyLocalVectorFromField(dm_swarm, DMSwarmPICField_coor, &X_points_true));
7139dbcead6SJeremy L Thompson   }
7149dbcead6SJeremy L Thompson 
7159dbcead6SJeremy L Thompson   // Allocate index set array
7169dbcead6SJeremy L Thompson   PetscCall(DMPlexGetHeightStratum(dm_mesh, 0, &cell_start, &cell_end));
7179dbcead6SJeremy L Thompson   num_cells_local = cell_end - cell_start;
7189dbcead6SJeremy L Thompson   points_offset   = num_cells_local + 2;
7199dbcead6SJeremy L Thompson   PetscCall(VecGetLocalSize(*X_points_ref, &num_points_local));
7209dbcead6SJeremy L Thompson   PetscCall(DMGetDimension(dm_mesh, &dim));
7219dbcead6SJeremy L Thompson   num_points_local /= dim;
7229dbcead6SJeremy L Thompson   PetscCall(PetscMalloc1(num_points_local + num_cells_local + 2, &cell_points));
7239dbcead6SJeremy L Thompson   cell_points[0] = num_cells_local;
7249dbcead6SJeremy L Thompson 
7259dbcead6SJeremy L Thompson   // Get reference coordinates for each swarm point wrt the elements in the background mesh
7269dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortGetAccess(dm_swarm));
7279dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords_points_true));
7289dbcead6SJeremy L Thompson   PetscCall(VecGetArray(*X_points_ref, &coords_points_ref));
7299dbcead6SJeremy L Thompson   for (PetscInt cell = cell_start, num_points_processed = 0; cell < cell_end; cell++) {
7309dbcead6SJeremy L Thompson     PetscInt *points_in_cell, num_points_in_cell, local_cell = cell - cell_start;
7319dbcead6SJeremy L Thompson     PetscReal v[3], J[9], invJ[9], detJ, v0_ref[3] = {-1.0, -1.0, -1.0};
7329dbcead6SJeremy L Thompson 
7339dbcead6SJeremy L Thompson     PetscCall(DMSwarmSortGetPointsPerCell(dm_swarm, cell, &num_points_in_cell, &points_in_cell));
7349dbcead6SJeremy L Thompson     // -- Reference coordinates for swarm points in background mesh element
7359dbcead6SJeremy L Thompson     PetscCall(DMPlexComputeCellGeometryFEM(dm_mesh, cell, NULL, v, J, invJ, &detJ));
7369dbcead6SJeremy L Thompson     cell_points[local_cell + 1] = num_points_processed + points_offset;
7379dbcead6SJeremy L Thompson     for (PetscInt p = 0; p < num_points_in_cell; p++) {
7389dbcead6SJeremy L Thompson       const CeedInt point = points_in_cell[p];
7399dbcead6SJeremy L Thompson 
7409dbcead6SJeremy L Thompson       cell_points[points_offset + (num_points_processed++)] = point;
7419dbcead6SJeremy L Thompson       CoordinatesRealToRef(dim, dim, v0_ref, v, invJ, &coords_points_true[point * dim], &coords_points_ref[point * dim]);
7429dbcead6SJeremy L Thompson     }
7439dbcead6SJeremy L Thompson 
7449dbcead6SJeremy L Thompson     // -- Cleanup
7459dbcead6SJeremy L Thompson     PetscCall(PetscFree(points_in_cell));
7469dbcead6SJeremy L Thompson   }
7479dbcead6SJeremy L Thompson   cell_points[points_offset - 1] = num_points_local + points_offset;
7489dbcead6SJeremy L Thompson 
7499dbcead6SJeremy L Thompson   // Cleanup
7509dbcead6SJeremy L Thompson   PetscCall(DMSwarmRestoreField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords_points_true));
7519dbcead6SJeremy L Thompson   PetscCall(VecRestoreArray(*X_points_ref, &coords_points_ref));
7529dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortRestoreAccess(dm_swarm));
7539dbcead6SJeremy L Thompson 
7549dbcead6SJeremy L Thompson   // Create index set
7559dbcead6SJeremy L Thompson   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, num_points_local + points_offset, cell_points, PETSC_OWN_POINTER, is_points));
7569dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
7579dbcead6SJeremy L Thompson }
7589dbcead6SJeremy L Thompson 
7599dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
7609dbcead6SJeremy L Thompson // Projection via PETSc
7619dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
7629dbcead6SJeremy L Thompson PetscErrorCode DMSwarmInterpolateFromCellToSwarm_Petsc(DM dm_swarm, const char *field, Vec U_mesh) {
7639dbcead6SJeremy L Thompson   PetscInt           dim, num_comp, cell_start, cell_end;
7649dbcead6SJeremy L Thompson   PetscScalar       *u_points;
7659dbcead6SJeremy L Thompson   const PetscScalar *coords_points;
7669dbcead6SJeremy L Thompson   const PetscReal    v0_ref[3] = {-1.0, -1.0, -1.0};
7679dbcead6SJeremy L Thompson   DM                 dm_mesh;
7689dbcead6SJeremy L Thompson   PetscSection       section_u_mesh_loc;
7699dbcead6SJeremy L Thompson   PetscDS            ds;
7709dbcead6SJeremy L Thompson   PetscFE            fe;
7719dbcead6SJeremy L Thompson   PetscFEGeom        fe_geometry;
7729dbcead6SJeremy L Thompson   PetscQuadrature    quadrature;
7739dbcead6SJeremy L Thompson   Vec                U_loc;
7749dbcead6SJeremy L Thompson 
7759dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
7769dbcead6SJeremy L Thompson   // Get mesh DM
7779dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
7789dbcead6SJeremy L Thompson   PetscCall(DMGetDimension(dm_mesh, &dim));
7799dbcead6SJeremy L Thompson   {
7809dbcead6SJeremy L Thompson     PetscSection section_u_mesh_loc_closure_permutation;
7819dbcead6SJeremy L Thompson 
7829dbcead6SJeremy L Thompson     PetscCall(DMGetLocalSection(dm_mesh, &section_u_mesh_loc_closure_permutation));
7839dbcead6SJeremy L Thompson     PetscCall(PetscSectionClone(section_u_mesh_loc_closure_permutation, &section_u_mesh_loc));
7849dbcead6SJeremy L Thompson     PetscCall(PetscSectionResetClosurePermutation(section_u_mesh_loc));
7859dbcead6SJeremy L Thompson   }
7869dbcead6SJeremy L Thompson 
7879dbcead6SJeremy L Thompson   // Get local mesh values
7889dbcead6SJeremy L Thompson   PetscCall(DMGetLocalVector(dm_mesh, &U_loc));
7899dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(U_loc));
7909dbcead6SJeremy L Thompson   PetscCall(DMGlobalToLocal(dm_mesh, U_mesh, INSERT_VALUES, U_loc));
7919dbcead6SJeremy L Thompson 
7929dbcead6SJeremy L Thompson   // Get local swarm data
7939dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortGetAccess(dm_swarm));
7949dbcead6SJeremy L Thompson   PetscCall(DMPlexGetHeightStratum(dm_mesh, 0, &cell_start, &cell_end));
7959dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords_points));
7969dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetField(dm_swarm, field, &num_comp, NULL, (void **)&u_points));
7979dbcead6SJeremy L Thompson 
7989dbcead6SJeremy L Thompson   // Interpolate values to each swarm point, one element in the background mesh at a time
7999dbcead6SJeremy L Thompson   PetscCall(DMGetDS(dm_mesh, &ds));
8009dbcead6SJeremy L Thompson   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
8019dbcead6SJeremy L Thompson   for (PetscInt cell = cell_start; cell < cell_end; cell++) {
8029dbcead6SJeremy L Thompson     PetscTabulation tabulation;
8039dbcead6SJeremy L Thompson     PetscScalar    *u_cell = NULL, *coords_points_cell_true, *coords_points_cell_ref;
8049dbcead6SJeremy L Thompson     PetscReal       v[dim], J[dim * dim], invJ[dim * dim], detJ;
8059dbcead6SJeremy L Thompson     PetscInt       *points_cell;
8069dbcead6SJeremy L Thompson     PetscInt        num_points_in_cell;
8079dbcead6SJeremy L Thompson 
8089dbcead6SJeremy L Thompson     PetscCall(DMSwarmSortGetPointsPerCell(dm_swarm, cell, &num_points_in_cell, &points_cell));
8099dbcead6SJeremy L Thompson     PetscCall(DMGetWorkArray(dm_mesh, num_points_in_cell * dim, MPIU_REAL, &coords_points_cell_true));
8109dbcead6SJeremy L Thompson     PetscCall(DMGetWorkArray(dm_mesh, num_points_in_cell * dim, MPIU_REAL, &coords_points_cell_ref));
8119dbcead6SJeremy L Thompson     // -- Reference coordinates for swarm points in background mesh element
8129dbcead6SJeremy L Thompson     for (PetscInt p = 0; p < num_points_in_cell; p++) {
8139dbcead6SJeremy L Thompson       for (PetscInt d = 0; d < dim; d++) coords_points_cell_true[p * dim + d] = coords_points[points_cell[p] * dim + d];
8149dbcead6SJeremy L Thompson     }
8159dbcead6SJeremy L Thompson     PetscCall(DMPlexComputeCellGeometryFEM(dm_mesh, cell, NULL, v, J, invJ, &detJ));
8169dbcead6SJeremy L Thompson     for (PetscInt p = 0; p < num_points_in_cell; p++) {
8179dbcead6SJeremy L Thompson       CoordinatesRealToRef(dim, dim, v0_ref, v, invJ, &coords_points_cell_true[p * dim], &coords_points_cell_ref[p * dim]);
8189dbcead6SJeremy L Thompson     }
8199dbcead6SJeremy L Thompson     // -- Interpolate values from current element in background mesh to swarm points
8209dbcead6SJeremy L Thompson     PetscCall(PetscFECreateTabulation(fe, 1, num_points_in_cell, coords_points_cell_ref, 1, &tabulation));
8219dbcead6SJeremy L Thompson     PetscCall(DMPlexVecGetClosure(dm_mesh, section_u_mesh_loc, U_loc, cell, NULL, &u_cell));
8229dbcead6SJeremy L Thompson     PetscCall(PetscFEGetQuadrature(fe, &quadrature));
8239dbcead6SJeremy L Thompson     PetscCall(PetscFECreateCellGeometry(fe, quadrature, &fe_geometry));
8249dbcead6SJeremy L Thompson     for (PetscInt p = 0; p < num_points_in_cell; p++) {
8259dbcead6SJeremy L Thompson       PetscCall(PetscFEInterpolateAtPoints_Static(fe, tabulation, u_cell, &fe_geometry, p, &u_points[points_cell[p] * num_comp]));
8269dbcead6SJeremy L Thompson     }
8279dbcead6SJeremy L Thompson 
8289dbcead6SJeremy L Thompson     // -- Cleanup
8299dbcead6SJeremy L Thompson     PetscCall(PetscFEDestroyCellGeometry(fe, &fe_geometry));
8309dbcead6SJeremy L Thompson     PetscCall(DMPlexVecRestoreClosure(dm_mesh, section_u_mesh_loc, U_loc, cell, NULL, &u_cell));
8319dbcead6SJeremy L Thompson     PetscCall(DMRestoreWorkArray(dm_mesh, num_points_in_cell * dim, MPIU_REAL, &coords_points_cell_true));
8329dbcead6SJeremy L Thompson     PetscCall(DMRestoreWorkArray(dm_mesh, num_points_in_cell * dim, MPIU_REAL, &coords_points_cell_ref));
8339dbcead6SJeremy L Thompson     PetscCall(PetscTabulationDestroy(&tabulation));
8349dbcead6SJeremy L Thompson     PetscCall(PetscFree(points_cell));
8359dbcead6SJeremy L Thompson   }
8369dbcead6SJeremy L Thompson 
8379dbcead6SJeremy L Thompson   // Cleanup
8389dbcead6SJeremy L Thompson   PetscCall(DMSwarmRestoreField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords_points));
8399dbcead6SJeremy L Thompson   PetscCall(DMSwarmRestoreField(dm_swarm, field, NULL, NULL, (void **)&u_points));
8409dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortRestoreAccess(dm_swarm));
8419dbcead6SJeremy L Thompson   PetscCall(DMRestoreLocalVector(dm_mesh, &U_loc));
8429dbcead6SJeremy L Thompson   PetscCall(PetscSectionDestroy(&section_u_mesh_loc));
8439dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
8449dbcead6SJeremy L Thompson }
8459dbcead6SJeremy L Thompson 
8469dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
8479dbcead6SJeremy L Thompson // Projection via libCEED
8489dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
8499dbcead6SJeremy L Thompson PetscErrorCode DMSwarmInterpolateFromCellToSwarm_Ceed(DM dm_swarm, const char *field, Vec U_mesh) {
8509dbcead6SJeremy L Thompson   PetscInt           num_elem;
8519dbcead6SJeremy L Thompson   PetscMemType       U_mem_type;
8529dbcead6SJeremy L Thompson   DM                 dm_mesh;
8539dbcead6SJeremy L Thompson   Vec                U_mesh_loc;
8549dbcead6SJeremy L Thompson   DMSwarmCeedContext swarm_ceed_context;
8559dbcead6SJeremy L Thompson 
8569dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
8579dbcead6SJeremy L Thompson   // Get mesh DM
8589dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
8599dbcead6SJeremy L Thompson   PetscCall(DMGetApplicationContext(dm_mesh, (void *)&swarm_ceed_context));
8609dbcead6SJeremy L Thompson 
8619dbcead6SJeremy L Thompson   // Get mesh values
8629dbcead6SJeremy L Thompson   PetscCall(DMGetLocalVector(dm_mesh, &U_mesh_loc));
8639dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(U_mesh_loc));
8649dbcead6SJeremy L Thompson   PetscCall(DMGlobalToLocal(dm_mesh, U_mesh, INSERT_VALUES, U_mesh_loc));
8659dbcead6SJeremy L Thompson   PetscCall(VecReadP2C(U_mesh_loc, &U_mem_type, swarm_ceed_context->u_mesh_loc));
8669dbcead6SJeremy L Thompson 
8679dbcead6SJeremy L Thompson   // Get swarm access
8689dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortGetAccess(dm_swarm));
8699dbcead6SJeremy L Thompson   PetscCall(DMSwarmPICFieldP2C(dm_swarm, field, swarm_ceed_context->u_points_loc));
8709dbcead6SJeremy L Thompson 
8719dbcead6SJeremy L Thompson   // Interpolate values to each swarm point, one element in the background mesh at a time
8729dbcead6SJeremy L Thompson   CeedElemRestrictionGetNumElements(swarm_ceed_context->restriction_u_mesh, &num_elem);
8739dbcead6SJeremy L Thompson   for (PetscInt e = 0; e < num_elem; e++) {
8749dbcead6SJeremy L Thompson     PetscInt num_points_in_elem;
8759dbcead6SJeremy L Thompson 
8769dbcead6SJeremy L Thompson     CeedElemRestrictionGetNumPointsInElement(swarm_ceed_context->restriction_u_points, e, &num_points_in_elem);
8779dbcead6SJeremy L Thompson 
8789dbcead6SJeremy L Thompson     // -- Reference coordinates for swarm points in background mesh element
8799dbcead6SJeremy L Thompson     CeedElemRestrictionApplyAtPointsInElement(swarm_ceed_context->restriction_x_points, e, CEED_NOTRANSPOSE, swarm_ceed_context->x_ref_points_loc,
8809dbcead6SJeremy L Thompson                                               swarm_ceed_context->x_ref_points_elem, CEED_REQUEST_IMMEDIATE);
8819dbcead6SJeremy L Thompson 
8829dbcead6SJeremy L Thompson     // -- Interpolate values from current element in background mesh to swarm points
8839dbcead6SJeremy L Thompson     // Note: This will only work for CPU backends at this time, as only CPU backends support ApplyBlock and ApplyAtPoints
8849dbcead6SJeremy L Thompson     CeedElemRestrictionApplyBlock(swarm_ceed_context->restriction_u_mesh, e, CEED_NOTRANSPOSE, swarm_ceed_context->u_mesh_loc,
8859dbcead6SJeremy L Thompson                                   swarm_ceed_context->u_mesh_elem, CEED_REQUEST_IMMEDIATE);
8869dbcead6SJeremy L Thompson     CeedBasisApplyAtPoints(swarm_ceed_context->basis_u, num_points_in_elem, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, swarm_ceed_context->x_ref_points_elem,
8879dbcead6SJeremy L Thompson                            swarm_ceed_context->u_mesh_elem, swarm_ceed_context->u_points_elem);
8889dbcead6SJeremy L Thompson 
8899dbcead6SJeremy L Thompson     // -- Insert result back into local vector
8909dbcead6SJeremy L Thompson     CeedElemRestrictionApplyAtPointsInElement(swarm_ceed_context->restriction_u_points, e, CEED_TRANSPOSE, swarm_ceed_context->u_points_elem,
8919dbcead6SJeremy L Thompson                                               swarm_ceed_context->u_points_loc, CEED_REQUEST_IMMEDIATE);
8929dbcead6SJeremy L Thompson   }
8939dbcead6SJeremy L Thompson 
8949dbcead6SJeremy L Thompson   // Cleanup
8959dbcead6SJeremy L Thompson   PetscCall(DMSwarmPICFieldC2P(dm_swarm, field, swarm_ceed_context->u_points_loc));
8969dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortRestoreAccess(dm_swarm));
8979dbcead6SJeremy L Thompson   PetscCall(VecReadC2P(swarm_ceed_context->u_mesh_loc, U_mem_type, U_mesh_loc));
8989dbcead6SJeremy L Thompson   PetscCall(DMRestoreLocalVector(dm_mesh, &U_mesh_loc));
8999dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
9009dbcead6SJeremy L Thompson }
9019dbcead6SJeremy L Thompson 
9029dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
9039dbcead6SJeremy L Thompson // Error checking utility
9049dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
9059dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCheckSwarmValues(DM dm_swarm, const char *field, PetscScalar tolerance, TargetFuncProj TrueSolution) {
9069dbcead6SJeremy L Thompson   PetscBool          within_tolerance = PETSC_TRUE;
9079dbcead6SJeremy L Thompson   PetscInt           dim, num_comp, cell_start, cell_end;
9089dbcead6SJeremy L Thompson   const PetscScalar *u_points, *coords_points;
9099dbcead6SJeremy L Thompson   DM                 dm_mesh;
9109dbcead6SJeremy L Thompson 
9119dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
9129dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortGetAccess(dm_swarm));
9139dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
9149dbcead6SJeremy L Thompson   PetscCall(DMGetDimension(dm_mesh, &dim));
9159dbcead6SJeremy L Thompson   PetscCall(DMPlexGetHeightStratum(dm_mesh, 0, &cell_start, &cell_end));
9169dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords_points));
9179dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetField(dm_swarm, field, &num_comp, NULL, (void **)&u_points));
9189dbcead6SJeremy L Thompson 
9199dbcead6SJeremy L Thompson   // Interpolate values to each swarm point, one element in the background mesh at a time
9209dbcead6SJeremy L Thompson   for (PetscInt cell = cell_start; cell < cell_end; cell++) {
9219dbcead6SJeremy L Thompson     PetscInt *points;
9229dbcead6SJeremy L Thompson     PetscInt  num_points_in_cell;
9239dbcead6SJeremy L Thompson 
9249dbcead6SJeremy L Thompson     PetscCall(DMSwarmSortGetPointsPerCell(dm_swarm, cell, &num_points_in_cell, &points));
9259dbcead6SJeremy L Thompson     // -- Reference coordinates for swarm points in background mesh element
9269dbcead6SJeremy L Thompson     for (PetscInt p = 0; p < num_points_in_cell; p++) {
9279dbcead6SJeremy L Thompson       PetscScalar x[dim], u_true[num_comp];
9289dbcead6SJeremy L Thompson 
9299dbcead6SJeremy L Thompson       for (PetscInt d = 0; d < dim; d++) x[d] = coords_points[points[p] * dim + d];
9309dbcead6SJeremy L Thompson       PetscCall(TrueSolution(dim, 0.0, x, num_comp, u_true, NULL));
9319dbcead6SJeremy L Thompson       for (PetscInt i = 0; i < num_comp; i++) {
9329dbcead6SJeremy L Thompson         if (PetscAbs(u_points[points[p] * num_comp + i] - u_true[i]) > tolerance) {
9339dbcead6SJeremy L Thompson           within_tolerance = PETSC_FALSE;
9349dbcead6SJeremy L Thompson           PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm_swarm),
9359dbcead6SJeremy L Thompson                                 "Incorrect interpolated value, cell %" PetscInt_FMT " point %" PetscInt_FMT " component %" PetscInt_FMT
9369dbcead6SJeremy L Thompson                                 ", found %f expected %f\n",
9379dbcead6SJeremy L Thompson                                 cell, p, i, u_points[points[p] * num_comp + i], u_true[i]));
9389dbcead6SJeremy L Thompson         }
9399dbcead6SJeremy L Thompson       }
9409dbcead6SJeremy L Thompson     }
9419dbcead6SJeremy L Thompson 
9429dbcead6SJeremy L Thompson     // -- Cleanup
9439dbcead6SJeremy L Thompson     PetscCall(PetscFree(points));
9449dbcead6SJeremy L Thompson   }
9459dbcead6SJeremy L Thompson 
9469dbcead6SJeremy L Thompson   // Cleanup
9479dbcead6SJeremy L Thompson   PetscCall(DMSwarmRestoreField(dm_swarm, DMSwarmPICField_coor, NULL, NULL, (void **)&coords_points));
9489dbcead6SJeremy L Thompson   PetscCall(DMSwarmRestoreField(dm_swarm, field, NULL, NULL, (void **)&u_points));
9499dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortRestoreAccess(dm_swarm));
9509dbcead6SJeremy L Thompson   PetscCheck(within_tolerance, PetscObjectComm((PetscObject)dm_swarm), PETSC_ERR_USER, "Interpolation to swarm points not within tolerance");
9519dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
9529dbcead6SJeremy L Thompson }
9539dbcead6SJeremy L Thompson 
9549dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
9559dbcead6SJeremy L Thompson // RHS for Swarm to Mesh projection
9569dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
9579dbcead6SJeremy L Thompson PetscErrorCode DMSwarmCreateProjectionRHS(DM dm_swarm, const char *field, Vec B_mesh) {
9589dbcead6SJeremy L Thompson   PetscInt           num_elem;
9599dbcead6SJeremy L Thompson   PetscMemType       B_mem_type;
9609dbcead6SJeremy L Thompson   DM                 dm_mesh;
9619dbcead6SJeremy L Thompson   Vec                B_mesh_loc;
9629dbcead6SJeremy L Thompson   DMSwarmCeedContext swarm_ceed_context;
9639dbcead6SJeremy L Thompson 
9649dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
9659dbcead6SJeremy L Thompson   // Get mesh DM
9669dbcead6SJeremy L Thompson   PetscCall(DMSwarmGetCellDM(dm_swarm, &dm_mesh));
9679dbcead6SJeremy L Thompson   PetscCall(DMGetApplicationContext(dm_mesh, (void *)&swarm_ceed_context));
9689dbcead6SJeremy L Thompson 
9699dbcead6SJeremy L Thompson   // Get mesh values
9709dbcead6SJeremy L Thompson   PetscCall(DMGetLocalVector(dm_mesh, &B_mesh_loc));
9719dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(B_mesh_loc));
9729dbcead6SJeremy L Thompson   PetscCall(VecP2C(B_mesh_loc, &B_mem_type, swarm_ceed_context->v_mesh_loc));
9739dbcead6SJeremy L Thompson 
9749dbcead6SJeremy L Thompson   // Get swarm access
9759dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortGetAccess(dm_swarm));
9769dbcead6SJeremy L Thompson   PetscCall(DMSwarmPICFieldP2C(dm_swarm, field, swarm_ceed_context->u_points_loc));
9779dbcead6SJeremy L Thompson 
9789dbcead6SJeremy L Thompson   // Interpolate values to each swarm point, one element in the background mesh at a time
9799dbcead6SJeremy L Thompson   CeedElemRestrictionGetNumElements(swarm_ceed_context->restriction_u_mesh, &num_elem);
9809dbcead6SJeremy L Thompson   for (PetscInt e = 0; e < num_elem; e++) {
9819dbcead6SJeremy L Thompson     PetscInt num_points_in_elem;
9829dbcead6SJeremy L Thompson 
9839dbcead6SJeremy L Thompson     CeedElemRestrictionGetNumPointsInElement(swarm_ceed_context->restriction_u_points, e, &num_points_in_elem);
9849dbcead6SJeremy L Thompson 
9859dbcead6SJeremy L Thompson     // -- Reference coordinates for swarm points in background mesh element
9869dbcead6SJeremy L Thompson     CeedElemRestrictionApplyAtPointsInElement(swarm_ceed_context->restriction_x_points, e, CEED_NOTRANSPOSE, swarm_ceed_context->x_ref_points_loc,
9879dbcead6SJeremy L Thompson                                               swarm_ceed_context->x_ref_points_elem, CEED_REQUEST_IMMEDIATE);
9889dbcead6SJeremy L Thompson 
9899dbcead6SJeremy L Thompson     // -- Interpolate values from current element in background mesh to swarm points
9909dbcead6SJeremy L Thompson     // Note: This will only work for CPU backends at this time, as only CPU backends support ApplyBlock and ApplyAtPoints
9919dbcead6SJeremy L Thompson     CeedElemRestrictionApplyAtPointsInElement(swarm_ceed_context->restriction_u_points, e, CEED_NOTRANSPOSE, swarm_ceed_context->u_points_loc,
9929dbcead6SJeremy L Thompson                                               swarm_ceed_context->u_points_elem, CEED_REQUEST_IMMEDIATE);
9939dbcead6SJeremy L Thompson     CeedBasisApplyAtPoints(swarm_ceed_context->basis_u, num_points_in_elem, CEED_TRANSPOSE, CEED_EVAL_INTERP, swarm_ceed_context->x_ref_points_elem,
9949dbcead6SJeremy L Thompson                            swarm_ceed_context->u_points_elem, swarm_ceed_context->u_mesh_elem);
9959dbcead6SJeremy L Thompson 
9969dbcead6SJeremy L Thompson     // -- Insert result back into local vector
9979dbcead6SJeremy L Thompson     CeedElemRestrictionApplyBlock(swarm_ceed_context->restriction_u_mesh, e, CEED_TRANSPOSE, swarm_ceed_context->u_mesh_elem,
9989dbcead6SJeremy L Thompson                                   swarm_ceed_context->v_mesh_loc, CEED_REQUEST_IMMEDIATE);
9999dbcead6SJeremy L Thompson   }
10009dbcead6SJeremy L Thompson 
10019dbcead6SJeremy L Thompson   // Restore PETSc Vecs and Local to Global
10029dbcead6SJeremy L Thompson   PetscCall(VecC2P(swarm_ceed_context->v_mesh_loc, B_mem_type, B_mesh_loc));
10039dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(B_mesh));
10049dbcead6SJeremy L Thompson   PetscCall(DMLocalToGlobal(dm_mesh, B_mesh_loc, ADD_VALUES, B_mesh));
10059dbcead6SJeremy L Thompson 
10069dbcead6SJeremy L Thompson   // Cleanup
10079dbcead6SJeremy L Thompson   PetscCall(DMSwarmPICFieldC2P(dm_swarm, field, swarm_ceed_context->u_points_loc));
10089dbcead6SJeremy L Thompson   PetscCall(DMSwarmSortRestoreAccess(dm_swarm));
10099dbcead6SJeremy L Thompson   PetscCall(DMRestoreLocalVector(dm_mesh, &B_mesh_loc));
10109dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
10119dbcead6SJeremy L Thompson }
10129dbcead6SJeremy L Thompson 
10139dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
10149dbcead6SJeremy L Thompson // Swarm "mass matrix"
10159dbcead6SJeremy L Thompson // ------------------------------------------------------------------------------------------------
10169dbcead6SJeremy L Thompson PetscErrorCode MatMult_SwarmMass(Mat A, Vec U_mesh, Vec V_mesh) {
10179dbcead6SJeremy L Thompson   PetscInt           num_elem;
10189dbcead6SJeremy L Thompson   PetscMemType       U_mem_type, V_mem_type;
10199dbcead6SJeremy L Thompson   DM                 dm_mesh;
10209dbcead6SJeremy L Thompson   Vec                U_mesh_loc, V_mesh_loc;
10219dbcead6SJeremy L Thompson   DMSwarmCeedContext swarm_ceed_context;
10229dbcead6SJeremy L Thompson 
10239dbcead6SJeremy L Thompson   PetscFunctionBeginUser;
10249dbcead6SJeremy L Thompson   // Get mesh DM
10259dbcead6SJeremy L Thompson   PetscCall(MatGetDM(A, &dm_mesh));
10269dbcead6SJeremy L Thompson   PetscCall(DMGetApplicationContext(dm_mesh, (void *)&swarm_ceed_context));
10279dbcead6SJeremy L Thompson 
10289dbcead6SJeremy L Thompson   // Global to Local and get PETSc Vec access
10299dbcead6SJeremy L Thompson   PetscCall(DMGetLocalVector(dm_mesh, &U_mesh_loc));
10309dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(U_mesh_loc));
10319dbcead6SJeremy L Thompson   PetscCall(DMGlobalToLocal(dm_mesh, U_mesh, INSERT_VALUES, U_mesh_loc));
10329dbcead6SJeremy L Thompson   PetscCall(VecReadP2C(U_mesh_loc, &U_mem_type, swarm_ceed_context->u_mesh_loc));
10339dbcead6SJeremy L Thompson   PetscCall(DMGetLocalVector(dm_mesh, &V_mesh_loc));
10349dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(V_mesh_loc));
10359dbcead6SJeremy L Thompson   PetscCall(VecP2C(V_mesh_loc, &V_mem_type, swarm_ceed_context->v_mesh_loc));
10369dbcead6SJeremy L Thompson 
10379dbcead6SJeremy L Thompson   // Interpolate values to each swarm point, one element in the background mesh at a time
10389dbcead6SJeremy L Thompson   CeedElemRestrictionGetNumElements(swarm_ceed_context->restriction_u_mesh, &num_elem);
10399dbcead6SJeremy L Thompson   for (PetscInt e = 0; e < num_elem; e++) {
10409dbcead6SJeremy L Thompson     PetscInt num_points_in_elem;
10419dbcead6SJeremy L Thompson 
10429dbcead6SJeremy L Thompson     CeedElemRestrictionGetNumPointsInElement(swarm_ceed_context->restriction_u_points, e, &num_points_in_elem);
10439dbcead6SJeremy L Thompson 
10449dbcead6SJeremy L Thompson     // -- Reference coordinates for swarm points in background mesh element
10459dbcead6SJeremy L Thompson     CeedElemRestrictionApplyAtPointsInElement(swarm_ceed_context->restriction_x_points, e, CEED_NOTRANSPOSE, swarm_ceed_context->x_ref_points_loc,
10469dbcead6SJeremy L Thompson                                               swarm_ceed_context->x_ref_points_elem, CEED_REQUEST_IMMEDIATE);
10479dbcead6SJeremy L Thompson 
10489dbcead6SJeremy L Thompson     // -- Interpolate values from current element in background mesh to swarm points
10499dbcead6SJeremy L Thompson     // Note: This will only work for CPU backends at this time, as only CPU backends support ApplyBlock and ApplyAtPoints
10509dbcead6SJeremy L Thompson     CeedElemRestrictionApplyBlock(swarm_ceed_context->restriction_u_mesh, e, CEED_NOTRANSPOSE, swarm_ceed_context->u_mesh_loc,
10519dbcead6SJeremy L Thompson                                   swarm_ceed_context->u_mesh_elem, CEED_REQUEST_IMMEDIATE);
10529dbcead6SJeremy L Thompson     CeedBasisApplyAtPoints(swarm_ceed_context->basis_u, num_points_in_elem, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, swarm_ceed_context->x_ref_points_elem,
10539dbcead6SJeremy L Thompson                            swarm_ceed_context->u_mesh_elem, swarm_ceed_context->u_points_elem);
10549dbcead6SJeremy L Thompson 
10559dbcead6SJeremy L Thompson     // -- Interpolate transpose back from swarm points to mesh
10569dbcead6SJeremy L Thompson     CeedBasisApplyAtPoints(swarm_ceed_context->basis_u, num_points_in_elem, CEED_TRANSPOSE, CEED_EVAL_INTERP, swarm_ceed_context->x_ref_points_elem,
10579dbcead6SJeremy L Thompson                            swarm_ceed_context->u_points_elem, swarm_ceed_context->u_mesh_elem);
10589dbcead6SJeremy L Thompson     CeedElemRestrictionApplyBlock(swarm_ceed_context->restriction_u_mesh, e, CEED_TRANSPOSE, swarm_ceed_context->u_mesh_elem,
10599dbcead6SJeremy L Thompson                                   swarm_ceed_context->v_mesh_loc, CEED_REQUEST_IMMEDIATE);
10609dbcead6SJeremy L Thompson   }
10619dbcead6SJeremy L Thompson 
10629dbcead6SJeremy L Thompson   // Restore PETSc Vecs and Local to Global
10639dbcead6SJeremy L Thompson   PetscCall(VecReadC2P(swarm_ceed_context->u_mesh_loc, U_mem_type, U_mesh_loc));
10649dbcead6SJeremy L Thompson   PetscCall(VecC2P(swarm_ceed_context->v_mesh_loc, V_mem_type, V_mesh_loc));
10659dbcead6SJeremy L Thompson   PetscCall(VecZeroEntries(V_mesh));
10669dbcead6SJeremy L Thompson   PetscCall(DMLocalToGlobal(dm_mesh, V_mesh_loc, ADD_VALUES, V_mesh));
10679dbcead6SJeremy L Thompson 
10689dbcead6SJeremy L Thompson   // Cleanup
10699dbcead6SJeremy L Thompson   PetscCall(DMRestoreLocalVector(dm_mesh, &U_mesh_loc));
10709dbcead6SJeremy L Thompson   PetscCall(DMRestoreLocalVector(dm_mesh, &V_mesh_loc));
10719dbcead6SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
10729dbcead6SJeremy L Thompson }
1073