xref: /libCEED/examples/fluids/src/mat-ceed.c (revision f965f5c6f80d9786386ec853fb0e2bfd6c15b6b7)
1c8564c30SJames Wright /// @file
25037d55dSJames Wright /// MatCEED implementation
3c8564c30SJames Wright 
4c8564c30SJames Wright #include <ceed.h>
5c8564c30SJames Wright #include <ceed/backend.h>
6c8564c30SJames Wright #include <mat-ceed-impl.h>
7c8564c30SJames Wright #include <mat-ceed.h>
85037d55dSJames Wright #include <petsc-ceed-utils.h>
95037d55dSJames Wright #include <petsc-ceed.h>
10c8564c30SJames Wright #include <petscdmplex.h>
11c8564c30SJames Wright #include <stdlib.h>
12c8564c30SJames Wright #include <string.h>
13c8564c30SJames Wright 
14c8564c30SJames Wright PetscClassId  MATCEED_CLASSID;
15c8564c30SJames Wright PetscLogEvent MATCEED_MULT, MATCEED_MULT_TRANSPOSE;
16c8564c30SJames Wright 
17c8564c30SJames Wright /**
18c8564c30SJames Wright   @brief Register MATCEED log events.
19c8564c30SJames Wright 
20c8564c30SJames Wright   Not collective across MPI processes.
21c8564c30SJames Wright 
22c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
23c8564c30SJames Wright **/
24c8564c30SJames Wright static PetscErrorCode MatCeedRegisterLogEvents() {
255037d55dSJames Wright   static PetscBool registered = PETSC_FALSE;
26c8564c30SJames Wright 
27c8564c30SJames Wright   PetscFunctionBeginUser;
28c8564c30SJames Wright   if (registered) PetscFunctionReturn(PETSC_SUCCESS);
29c8564c30SJames Wright   PetscCall(PetscClassIdRegister("MATCEED", &MATCEED_CLASSID));
30c8564c30SJames Wright   PetscCall(PetscLogEventRegister("MATCEED Mult", MATCEED_CLASSID, &MATCEED_MULT));
31c8564c30SJames Wright   PetscCall(PetscLogEventRegister("MATCEED Mult Transpose", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE));
325037d55dSJames Wright   registered = PETSC_TRUE;
33c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
34c8564c30SJames Wright }
35c8564c30SJames Wright 
36c8564c30SJames Wright /**
37c8564c30SJames Wright   @brief Assemble the point block diagonal of a `MATCEED` into a `MATAIJ` or similar.
38c8564c30SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
39c8564c30SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
40c8564c30SJames Wright 
41c8564c30SJames Wright   Collective across MPI processes.
42c8564c30SJames Wright 
43c8564c30SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
44c8564c30SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
45c8564c30SJames Wright 
46c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
47c8564c30SJames Wright **/
48c8564c30SJames Wright static PetscErrorCode MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed, Mat mat_coo) {
49c8564c30SJames Wright   MatCeedContext ctx;
50c8564c30SJames Wright 
51c8564c30SJames Wright   PetscFunctionBeginUser;
52c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
53c8564c30SJames Wright 
54c8564c30SJames Wright   // Check if COO pattern set
55c8564c30SJames Wright   {
56c8564c30SJames Wright     PetscInt index = -1;
57c8564c30SJames Wright 
58c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
59c8564c30SJames Wright       if (ctx->mats_assembled_pbd[i] == mat_coo) index = i;
60c8564c30SJames Wright     }
61c8564c30SJames Wright     if (index == -1) {
62c8564c30SJames Wright       PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
63c8564c30SJames Wright       CeedInt      *rows_ceed, *cols_ceed;
64c8564c30SJames Wright       PetscCount    num_entries;
65c8564c30SJames Wright       PetscLogStage stage_amg_setup;
66c8564c30SJames Wright 
67c8564c30SJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
68c8564c30SJames Wright       PetscCall(PetscLogStageGetId("MATCEED Assembly Setup", &stage_amg_setup));
69c8564c30SJames Wright       if (stage_amg_setup == -1) {
70c8564c30SJames Wright         PetscCall(PetscLogStageRegister("MATCEED Assembly Setup", &stage_amg_setup));
71c8564c30SJames Wright       }
72c8564c30SJames Wright       PetscCall(PetscLogStagePush(stage_amg_setup));
7354831c5fSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
74d0593705SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
75d0593705SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
76c8564c30SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
77c8564c30SJames Wright       free(rows_petsc);
78c8564c30SJames Wright       free(cols_petsc);
7954831c5fSJames Wright       if (!ctx->coo_values_pbd) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_pbd));
80c8564c30SJames Wright       PetscCall(PetscRealloc(++ctx->num_mats_assembled_pbd * sizeof(Mat), &ctx->mats_assembled_pbd));
81c8564c30SJames Wright       ctx->mats_assembled_pbd[ctx->num_mats_assembled_pbd - 1] = mat_coo;
82c8564c30SJames Wright       PetscCall(PetscLogStagePop());
83c8564c30SJames Wright     }
84c8564c30SJames Wright   }
85c8564c30SJames Wright 
86c8564c30SJames Wright   // Assemble mat_ceed
87c8564c30SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
88c8564c30SJames Wright   {
89c8564c30SJames Wright     const CeedScalar *values;
90c8564c30SJames Wright     MatType           mat_type;
91c8564c30SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
92c8564c30SJames Wright     PetscBool         is_spd, is_spd_known;
93c8564c30SJames Wright 
94c8564c30SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
95c8564c30SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
96c8564c30SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
97c8564c30SJames Wright     else mem_type = CEED_MEM_HOST;
98c8564c30SJames Wright 
9954831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonal(ctx->op_mult, ctx->coo_values_pbd, CEED_REQUEST_IMMEDIATE));
10054831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_pbd, mem_type, &values));
101c8564c30SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
102c8564c30SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
103c8564c30SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
10454831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_pbd, &values));
105c8564c30SJames Wright   }
106c8564c30SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
107c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
108c8564c30SJames Wright }
109c8564c30SJames Wright 
110c8564c30SJames Wright /**
111c8564c30SJames Wright   @brief Assemble inner `Mat` for diagonal `PC` operations
112c8564c30SJames Wright 
113c8564c30SJames Wright   Collective across MPI processes.
114c8564c30SJames Wright 
115c8564c30SJames Wright   @param[in]   mat_ceed      `MATCEED` to invert
116c8564c30SJames Wright   @param[in]   use_ceed_pbd  Boolean flag to use libCEED PBD assembly
117c8564c30SJames Wright   @param[out]  mat_inner     Inner `Mat` for diagonal operations
118c8564c30SJames Wright 
119c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
120c8564c30SJames Wright **/
121c8564c30SJames Wright static PetscErrorCode MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed, PetscBool use_ceed_pbd, Mat *mat_inner) {
122c8564c30SJames Wright   MatCeedContext ctx;
123c8564c30SJames Wright 
124c8564c30SJames Wright   PetscFunctionBeginUser;
125c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
126c8564c30SJames Wright   if (use_ceed_pbd) {
127c8564c30SJames Wright     // Check if COO pattern set
1285037d55dSJames Wright     if (!ctx->mat_assembled_pbd_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_pbd_internal));
129c8564c30SJames Wright 
130c8564c30SJames Wright     // Assemble mat_assembled_full_internal
131c8564c30SJames Wright     PetscCall(MatCeedAssemblePointBlockDiagonalCOO(mat_ceed, ctx->mat_assembled_pbd_internal));
132c8564c30SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_pbd_internal;
133c8564c30SJames Wright   } else {
134c8564c30SJames Wright     // Check if COO pattern set
1355037d55dSJames Wright     if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
136c8564c30SJames Wright 
137c8564c30SJames Wright     // Assemble mat_assembled_full_internal
138c8564c30SJames Wright     PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
139c8564c30SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_full_internal;
140c8564c30SJames Wright   }
141c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
142c8564c30SJames Wright }
143c8564c30SJames Wright 
144c8564c30SJames Wright /**
145c8564c30SJames Wright   @brief Get `MATCEED` diagonal block for Jacobi.
146c8564c30SJames Wright 
147c8564c30SJames Wright   Collective across MPI processes.
148c8564c30SJames Wright 
149c8564c30SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
150c8564c30SJames Wright   @param[out]  mat_block  The diagonal block matrix
151c8564c30SJames Wright 
152c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
153c8564c30SJames Wright **/
154c8564c30SJames Wright static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) {
155c8564c30SJames Wright   Mat            mat_inner = NULL;
156c8564c30SJames Wright   MatCeedContext ctx;
157c8564c30SJames Wright 
158c8564c30SJames Wright   PetscFunctionBeginUser;
159c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
160c8564c30SJames Wright 
161c8564c30SJames Wright   // Assemble inner mat if needed
162c8564c30SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
163c8564c30SJames Wright 
164c8564c30SJames Wright   // Get block diagonal
165c8564c30SJames Wright   PetscCall(MatGetDiagonalBlock(mat_inner, mat_block));
166c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
167c8564c30SJames Wright }
168c8564c30SJames Wright 
169c8564c30SJames Wright /**
170c8564c30SJames Wright   @brief Invert `MATCEED` diagonal block for Jacobi.
171c8564c30SJames Wright 
172c8564c30SJames Wright   Collective across MPI processes.
173c8564c30SJames Wright 
174c8564c30SJames Wright   @param[in]   mat_ceed  `MATCEED` to invert
175c8564c30SJames Wright   @param[out]  values    The block inverses in column major order
176c8564c30SJames Wright 
177c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
178c8564c30SJames Wright **/
179c8564c30SJames Wright static PetscErrorCode MatInvertBlockDiagonal_Ceed(Mat mat_ceed, const PetscScalar **values) {
180c8564c30SJames Wright   Mat            mat_inner = NULL;
181c8564c30SJames Wright   MatCeedContext ctx;
182c8564c30SJames Wright 
183c8564c30SJames Wright   PetscFunctionBeginUser;
184c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
185c8564c30SJames Wright 
186c8564c30SJames Wright   // Assemble inner mat if needed
187c8564c30SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
188c8564c30SJames Wright 
189c8564c30SJames Wright   // Invert PB diagonal
190c8564c30SJames Wright   PetscCall(MatInvertBlockDiagonal(mat_inner, values));
191c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
192c8564c30SJames Wright }
193c8564c30SJames Wright 
194c8564c30SJames Wright /**
195c8564c30SJames Wright   @brief Invert `MATCEED` variable diagonal block for Jacobi.
196c8564c30SJames Wright 
197c8564c30SJames Wright   Collective across MPI processes.
198c8564c30SJames Wright 
199c8564c30SJames Wright   @param[in]   mat_ceed     `MATCEED` to invert
200c8564c30SJames Wright   @param[in]   num_blocks   The number of blocks on the process
201c8564c30SJames Wright   @param[in]   block_sizes  The size of each block on the process
202c8564c30SJames Wright   @param[out]  values       The block inverses in column major order
203c8564c30SJames Wright 
204c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
205c8564c30SJames Wright **/
206c8564c30SJames Wright static PetscErrorCode MatInvertVariableBlockDiagonal_Ceed(Mat mat_ceed, PetscInt num_blocks, const PetscInt *block_sizes, PetscScalar *values) {
207c8564c30SJames Wright   Mat            mat_inner = NULL;
208c8564c30SJames Wright   MatCeedContext ctx;
209c8564c30SJames Wright 
210c8564c30SJames Wright   PetscFunctionBeginUser;
211c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
212c8564c30SJames Wright 
213c8564c30SJames Wright   // Assemble inner mat if needed
214c8564c30SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, &mat_inner));
215c8564c30SJames Wright 
216c8564c30SJames Wright   // Invert PB diagonal
217c8564c30SJames Wright   PetscCall(MatInvertVariableBlockDiagonal(mat_inner, num_blocks, block_sizes, values));
218c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
219c8564c30SJames Wright }
220c8564c30SJames Wright 
2213933d9a0SJames Wright /**
2223933d9a0SJames Wright   @brief View `MATCEED`.
2233933d9a0SJames Wright 
2243933d9a0SJames Wright   Collective across MPI processes.
2253933d9a0SJames Wright 
2263933d9a0SJames Wright   @param[in]   mat_ceed  `MATCEED` to view
2273933d9a0SJames Wright   @param[in]   viewer    The visualization context
2283933d9a0SJames Wright 
2293933d9a0SJames Wright   @return An error code: 0 - success, otherwise - failure
2303933d9a0SJames Wright **/
2313933d9a0SJames Wright static PetscErrorCode MatView_Ceed(Mat mat_ceed, PetscViewer viewer) {
2323933d9a0SJames Wright   PetscBool         is_ascii;
2333933d9a0SJames Wright   PetscViewerFormat format;
2343933d9a0SJames Wright   PetscMPIInt       size;
2353933d9a0SJames Wright   MatCeedContext    ctx;
2363933d9a0SJames Wright 
2373933d9a0SJames Wright   PetscFunctionBeginUser;
2383933d9a0SJames Wright   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2393933d9a0SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
2403933d9a0SJames Wright   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat_ceed), &viewer));
2413933d9a0SJames Wright 
2423933d9a0SJames Wright   PetscCall(PetscViewerGetFormat(viewer, &format));
2433933d9a0SJames Wright   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat_ceed), &size));
2443933d9a0SJames Wright   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
2453933d9a0SJames Wright 
2463933d9a0SJames Wright   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii));
2473933d9a0SJames Wright   {
2483933d9a0SJames Wright     FILE *file;
2493933d9a0SJames Wright 
2505037d55dSJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n  Default COO MatType:%s\n", ctx->coo_mat_type));
2513933d9a0SJames Wright     PetscCall(PetscViewerASCIIGetPointer(viewer, &file));
2523933d9a0SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, " libCEED Operator:\n"));
2533933d9a0SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file));
2543933d9a0SJames Wright     if (ctx->op_mult_transpose) {
2553933d9a0SJames Wright       PetscCall(PetscViewerASCIIPrintf(viewer, "  libCEED Transpose Operator:\n"));
2563933d9a0SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file));
2573933d9a0SJames Wright     }
2583933d9a0SJames Wright   }
2593933d9a0SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
2603933d9a0SJames Wright }
2613933d9a0SJames Wright 
262c8564c30SJames Wright // -----------------------------------------------------------------------------
263c8564c30SJames Wright // MatCeed
264c8564c30SJames Wright // -----------------------------------------------------------------------------
265c8564c30SJames Wright 
266c8564c30SJames Wright /**
267c8564c30SJames Wright   @brief Create PETSc `Mat` from libCEED operators.
268c8564c30SJames Wright 
269c8564c30SJames Wright   Collective across MPI processes.
270c8564c30SJames Wright 
271c8564c30SJames Wright   @param[in]   dm_x                      Input `DM`
272c8564c30SJames Wright   @param[in]   dm_y                      Output `DM`
273c8564c30SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
274c8564c30SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
275c8564c30SJames Wright   @param[out]  mat                        New MatCeed
276c8564c30SJames Wright 
277c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
278c8564c30SJames Wright **/
279c8564c30SJames Wright PetscErrorCode MatCeedCreate(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) {
280c8564c30SJames Wright   PetscInt       X_l_size, X_g_size, Y_l_size, Y_g_size;
281c8564c30SJames Wright   VecType        vec_type;
282c8564c30SJames Wright   MatCeedContext ctx;
283c8564c30SJames Wright 
284c8564c30SJames Wright   PetscFunctionBeginUser;
285c8564c30SJames Wright   PetscCall(MatCeedRegisterLogEvents());
286c8564c30SJames Wright 
287c8564c30SJames Wright   // Collect context data
288c8564c30SJames Wright   PetscCall(DMGetVecType(dm_x, &vec_type));
289c8564c30SJames Wright   {
290c8564c30SJames Wright     Vec X;
291c8564c30SJames Wright 
292c8564c30SJames Wright     PetscCall(DMGetGlobalVector(dm_x, &X));
293c8564c30SJames Wright     PetscCall(VecGetSize(X, &X_g_size));
294c8564c30SJames Wright     PetscCall(VecGetLocalSize(X, &X_l_size));
295c8564c30SJames Wright     PetscCall(DMRestoreGlobalVector(dm_x, &X));
296c8564c30SJames Wright   }
297c8564c30SJames Wright   if (dm_y) {
298c8564c30SJames Wright     Vec Y;
299c8564c30SJames Wright 
300c8564c30SJames Wright     PetscCall(DMGetGlobalVector(dm_y, &Y));
301c8564c30SJames Wright     PetscCall(VecGetSize(Y, &Y_g_size));
302c8564c30SJames Wright     PetscCall(VecGetLocalSize(Y, &Y_l_size));
303c8564c30SJames Wright     PetscCall(DMRestoreGlobalVector(dm_y, &Y));
304c8564c30SJames Wright   } else {
305c8564c30SJames Wright     dm_y     = dm_x;
306c8564c30SJames Wright     Y_g_size = X_g_size;
307c8564c30SJames Wright     Y_l_size = X_l_size;
308c8564c30SJames Wright   }
3095037d55dSJames Wright 
310c8564c30SJames Wright   // Create context
311c8564c30SJames Wright   {
312c8564c30SJames Wright     Vec X_loc, Y_loc_transpose = NULL;
313c8564c30SJames Wright 
314c8564c30SJames Wright     PetscCall(DMCreateLocalVector(dm_x, &X_loc));
315c8564c30SJames Wright     PetscCall(VecZeroEntries(X_loc));
316c8564c30SJames Wright     if (op_mult_transpose) {
317c8564c30SJames Wright       PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose));
318c8564c30SJames Wright       PetscCall(VecZeroEntries(Y_loc_transpose));
319c8564c30SJames Wright     }
320c8564c30SJames Wright     PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE, &ctx));
321c8564c30SJames Wright     PetscCall(VecDestroy(&X_loc));
322c8564c30SJames Wright     PetscCall(VecDestroy(&Y_loc_transpose));
323c8564c30SJames Wright   }
324c8564c30SJames Wright 
325c8564c30SJames Wright   // Create mat
326c8564c30SJames Wright   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat));
327c8564c30SJames Wright   PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED));
328c8564c30SJames Wright   // -- Set block and variable block sizes
329c8564c30SJames Wright   if (dm_x == dm_y) {
330c8564c30SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
331c8564c30SJames Wright     Mat     temp_mat;
332c8564c30SJames Wright 
333c8564c30SJames Wright     PetscCall(DMGetMatType(dm_x, &dm_mat_type));
334c8564c30SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
335c8564c30SJames Wright     PetscCall(DMSetMatType(dm_x, MATAIJ));
336c8564c30SJames Wright     PetscCall(DMCreateMatrix(dm_x, &temp_mat));
337c8564c30SJames Wright     PetscCall(DMSetMatType(dm_x, dm_mat_type_copy));
338c8564c30SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
339c8564c30SJames Wright 
340c8564c30SJames Wright     {
341c8564c30SJames Wright       PetscInt        block_size, num_blocks, max_vblock_size = PETSC_INT_MAX;
342c8564c30SJames Wright       const PetscInt *vblock_sizes;
343c8564c30SJames Wright 
344c8564c30SJames Wright       // -- Get block sizes
345c8564c30SJames Wright       PetscCall(MatGetBlockSize(temp_mat, &block_size));
346c8564c30SJames Wright       PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes));
347c8564c30SJames Wright       {
348c8564c30SJames Wright         PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX};
349c8564c30SJames Wright 
350c8564c30SJames Wright         for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]);
351c8564c30SJames Wright         PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max));
352c8564c30SJames Wright         max_vblock_size = global_min_max[1];
353c8564c30SJames Wright       }
354c8564c30SJames Wright 
355c8564c30SJames Wright       // -- Copy block sizes
356c8564c30SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size));
357c8564c30SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes));
358c8564c30SJames Wright 
359c8564c30SJames Wright       // -- Check libCEED compatibility
360c8564c30SJames Wright       {
361c8564c30SJames Wright         bool is_composite;
362c8564c30SJames Wright 
363c8564c30SJames Wright         ctx->is_ceed_pbd_valid  = PETSC_TRUE;
364c8564c30SJames Wright         ctx->is_ceed_vpbd_valid = PETSC_TRUE;
36554831c5fSJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite));
366c8564c30SJames Wright         if (is_composite) {
367c8564c30SJames Wright           CeedInt       num_sub_operators;
368c8564c30SJames Wright           CeedOperator *sub_operators;
369c8564c30SJames Wright 
37054831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetNumSub(op_mult, &num_sub_operators));
37154831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetSubList(op_mult, &sub_operators));
372c8564c30SJames Wright           for (CeedInt i = 0; i < num_sub_operators; i++) {
373c8564c30SJames Wright             CeedInt                  num_bases, num_comp;
374c8564c30SJames Wright             CeedBasis               *active_bases;
375c8564c30SJames Wright             CeedOperatorAssemblyData assembly_data;
376c8564c30SJames Wright 
37754831c5fSJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data));
37854831c5fSJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
37954831c5fSJames Wright             PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
380c8564c30SJames Wright             if (num_bases > 1) {
381c8564c30SJames Wright               ctx->is_ceed_pbd_valid  = PETSC_FALSE;
382c8564c30SJames Wright               ctx->is_ceed_vpbd_valid = PETSC_FALSE;
383c8564c30SJames Wright             }
384c8564c30SJames Wright             if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
385c8564c30SJames Wright             if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
386c8564c30SJames Wright           }
387c8564c30SJames Wright         } else {
388c8564c30SJames Wright           // LCOV_EXCL_START
389c8564c30SJames Wright           CeedInt                  num_bases, num_comp;
390c8564c30SJames Wright           CeedBasis               *active_bases;
391c8564c30SJames Wright           CeedOperatorAssemblyData assembly_data;
392c8564c30SJames Wright 
39354831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data));
39454831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
39554831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
396c8564c30SJames Wright           if (num_bases > 1) {
397c8564c30SJames Wright             ctx->is_ceed_pbd_valid  = PETSC_FALSE;
398c8564c30SJames Wright             ctx->is_ceed_vpbd_valid = PETSC_FALSE;
399c8564c30SJames Wright           }
400c8564c30SJames Wright           if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
401c8564c30SJames Wright           if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
402c8564c30SJames Wright           // LCOV_EXCL_STOP
403c8564c30SJames Wright         }
404c8564c30SJames Wright         {
405c8564c30SJames Wright           PetscInt local_is_valid[2], global_is_valid[2];
406c8564c30SJames Wright 
407c8564c30SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid;
408c8564c30SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
409c8564c30SJames Wright           ctx->is_ceed_pbd_valid = global_is_valid[0];
410c8564c30SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid;
411c8564c30SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
412c8564c30SJames Wright           ctx->is_ceed_vpbd_valid = global_is_valid[0];
413c8564c30SJames Wright         }
414c8564c30SJames Wright       }
415c8564c30SJames Wright     }
416c8564c30SJames Wright     PetscCall(MatDestroy(&temp_mat));
417c8564c30SJames Wright   }
418c8564c30SJames Wright   // -- Set internal mat type
419c8564c30SJames Wright   {
420c8564c30SJames Wright     VecType vec_type;
4215037d55dSJames Wright     MatType coo_mat_type;
422c8564c30SJames Wright 
423c8564c30SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
4245037d55dSJames Wright     if (strstr(vec_type, VECCUDA)) coo_mat_type = MATAIJCUSPARSE;
4255037d55dSJames Wright     else if (strstr(vec_type, VECKOKKOS)) coo_mat_type = MATAIJKOKKOS;
4265037d55dSJames Wright     else coo_mat_type = MATAIJ;
4275037d55dSJames Wright     PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type));
428c8564c30SJames Wright   }
429c8564c30SJames Wright   // -- Set mat operations
430c8564c30SJames Wright   PetscCall(MatShellSetContextDestroy(*mat, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
4313933d9a0SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (void (*)(void))MatView_Ceed));
432c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (void (*)(void))MatMult_Ceed));
433c8564c30SJames Wright   if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
434c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
435c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
436c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
437c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
438c8564c30SJames Wright   PetscCall(MatShellSetVecType(*mat, vec_type));
439c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
440c8564c30SJames Wright }
441c8564c30SJames Wright 
442c8564c30SJames Wright /**
443c8564c30SJames Wright   @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`.
444c8564c30SJames Wright 
445c8564c30SJames Wright   Collective across MPI processes.
446c8564c30SJames Wright 
447c8564c30SJames Wright   @param[in]   mat_ceed   `MATCEED` to copy from
448c8564c30SJames Wright   @param[out]  mat_other  `MatShell` or `MATCEED` to copy into
449c8564c30SJames Wright 
450c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
451c8564c30SJames Wright **/
452c8564c30SJames Wright PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) {
453c8564c30SJames Wright   PetscFunctionBeginUser;
454c8564c30SJames Wright   PetscCall(MatCeedRegisterLogEvents());
455c8564c30SJames Wright 
456c8564c30SJames Wright   // Check type compatibility
457c8564c30SJames Wright   {
4585037d55dSJames Wright     PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE;
459c8564c30SJames Wright     MatType   mat_type_ceed, mat_type_other;
460c8564c30SJames Wright 
461c8564c30SJames Wright     PetscCall(MatGetType(mat_ceed, &mat_type_ceed));
4625037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
4635037d55dSJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
4645037d55dSJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
4655037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
4665037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matceed));
4675037d55dSJames Wright     PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL);
468c8564c30SJames Wright   }
469c8564c30SJames Wright 
470c8564c30SJames Wright   // Check dimension compatibility
471c8564c30SJames Wright   {
472c8564c30SJames Wright     PetscInt X_l_ceed_size, X_g_ceed_size, Y_l_ceed_size, Y_g_ceed_size, X_l_other_size, X_g_other_size, Y_l_other_size, Y_g_other_size;
473c8564c30SJames Wright 
474c8564c30SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size));
475c8564c30SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size));
476c8564c30SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size));
477c8564c30SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size));
478c8564c30SJames Wright     PetscCheck((Y_g_ceed_size == Y_g_other_size) && (X_g_ceed_size == X_g_other_size) && (Y_l_ceed_size == Y_l_other_size) &&
479c8564c30SJames Wright                    (X_l_ceed_size == X_l_other_size),
480c8564c30SJames Wright                PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
481c8564c30SJames Wright                "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT
482c8564c30SJames Wright                "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT
483c8564c30SJames Wright                ", %" PetscInt_FMT ")",
484c8564c30SJames Wright                Y_g_ceed_size, X_g_ceed_size, Y_l_ceed_size, X_l_ceed_size, Y_g_other_size, X_g_other_size, Y_l_other_size, X_l_other_size);
485c8564c30SJames Wright   }
486c8564c30SJames Wright 
487c8564c30SJames Wright   // Convert
488c8564c30SJames Wright   {
489c8564c30SJames Wright     VecType        vec_type;
490c8564c30SJames Wright     MatCeedContext ctx;
491c8564c30SJames Wright 
492c8564c30SJames Wright     PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED));
493c8564c30SJames Wright     PetscCall(MatShellGetContext(mat_ceed, &ctx));
494c8564c30SJames Wright     PetscCall(MatCeedContextReference(ctx));
495c8564c30SJames Wright     PetscCall(MatShellSetContext(mat_other, ctx));
496c8564c30SJames Wright     PetscCall(MatShellSetContextDestroy(mat_other, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
4973933d9a0SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (void (*)(void))MatView_Ceed));
498c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (void (*)(void))MatMult_Ceed));
499c8564c30SJames Wright     if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
500c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
501c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
502c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
503c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
504c8564c30SJames Wright     {
505c8564c30SJames Wright       PetscInt block_size;
506c8564c30SJames Wright 
507c8564c30SJames Wright       PetscCall(MatGetBlockSize(mat_ceed, &block_size));
508c8564c30SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size));
509c8564c30SJames Wright     }
510c8564c30SJames Wright     {
511c8564c30SJames Wright       PetscInt        num_blocks;
512c8564c30SJames Wright       const PetscInt *block_sizes;
513c8564c30SJames Wright 
514c8564c30SJames Wright       PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes));
515c8564c30SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes));
516c8564c30SJames Wright     }
517c8564c30SJames Wright     PetscCall(DMGetVecType(ctx->dm_x, &vec_type));
518c8564c30SJames Wright     PetscCall(MatShellSetVecType(mat_other, vec_type));
519c8564c30SJames Wright   }
520c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
521c8564c30SJames Wright }
522c8564c30SJames Wright 
523c8564c30SJames Wright /**
5245037d55dSJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
5255037d55dSJames Wright 
5265037d55dSJames Wright   Collective across MPI processes.
5275037d55dSJames Wright 
5285037d55dSJames Wright   @param[in]   mat_ceed  `MATCEED`
5295037d55dSJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
5305037d55dSJames Wright 
5315037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
5325037d55dSJames Wright **/
5335037d55dSJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
5345037d55dSJames Wright   MatCeedContext ctx;
5355037d55dSJames Wright 
5365037d55dSJames Wright   PetscFunctionBeginUser;
5375037d55dSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
5385037d55dSJames Wright 
5395037d55dSJames Wright   PetscCheck(ctx->dm_x == ctx->dm_y, PetscObjectComm((PetscObject)mat_ceed), PETSC_ERR_SUP, "COO assembly only supported for MATCEED on a single DM");
5405037d55dSJames Wright 
5415037d55dSJames Wright   // Check cl mat type
5425037d55dSJames Wright   {
5435037d55dSJames Wright     PetscBool is_coo_mat_type_cl = PETSC_FALSE;
5445037d55dSJames Wright     char      coo_mat_type_cl[64];
5455037d55dSJames Wright 
5465037d55dSJames Wright     // Check for specific CL coo mat type for this Mat
5475037d55dSJames Wright     {
5485037d55dSJames Wright       const char *mat_ceed_prefix = NULL;
5495037d55dSJames Wright 
5505037d55dSJames Wright       PetscCall(MatGetOptionsPrefix(mat_ceed, &mat_ceed_prefix));
5515037d55dSJames Wright       PetscOptionsBegin(PetscObjectComm((PetscObject)mat_ceed), mat_ceed_prefix, "", NULL);
5525037d55dSJames Wright       PetscCall(PetscOptionsFList("-ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
5535037d55dSJames Wright                                   sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
5545037d55dSJames Wright       PetscOptionsEnd();
5555037d55dSJames Wright       if (is_coo_mat_type_cl) {
5565037d55dSJames Wright         PetscCall(PetscFree(ctx->coo_mat_type));
5575037d55dSJames Wright         PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
5585037d55dSJames Wright       }
5595037d55dSJames Wright     }
5605037d55dSJames Wright   }
5615037d55dSJames Wright 
5625037d55dSJames Wright   // Create sparse matrix
5635037d55dSJames Wright   {
5645037d55dSJames Wright     MatType dm_mat_type, dm_mat_type_copy;
5655037d55dSJames Wright 
5665037d55dSJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
5675037d55dSJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
5685037d55dSJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
5695037d55dSJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
5705037d55dSJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
5715037d55dSJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
5725037d55dSJames Wright   }
5735037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
5745037d55dSJames Wright }
5755037d55dSJames Wright 
5765037d55dSJames Wright /**
5775037d55dSJames Wright   @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar.
578c8564c30SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
579c8564c30SJames Wright 
580c8564c30SJames Wright   Collective across MPI processes.
581c8564c30SJames Wright 
582c8564c30SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
583c8564c30SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
584c8564c30SJames Wright 
585c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
586c8564c30SJames Wright **/
5875037d55dSJames Wright PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) {
588c8564c30SJames Wright   MatCeedContext ctx;
589c8564c30SJames Wright 
590c8564c30SJames Wright   PetscFunctionBeginUser;
591c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
592c8564c30SJames Wright 
593c8564c30SJames Wright   {
594c8564c30SJames Wright     PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
595c8564c30SJames Wright     CeedInt      *rows_ceed, *cols_ceed;
596c8564c30SJames Wright     PetscCount    num_entries;
597c8564c30SJames Wright     PetscLogStage stage_amg_setup;
598c8564c30SJames Wright 
599c8564c30SJames Wright     // -- Assemble sparsity pattern if mat hasn't been assembled before
600c8564c30SJames Wright     PetscCall(PetscLogStageGetId("MATCEED Assembly Setup", &stage_amg_setup));
601c8564c30SJames Wright     if (stage_amg_setup == -1) {
602c8564c30SJames Wright       PetscCall(PetscLogStageRegister("MATCEED Assembly Setup", &stage_amg_setup));
603c8564c30SJames Wright     }
604c8564c30SJames Wright     PetscCall(PetscLogStagePush(stage_amg_setup));
60554831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
606d0593705SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
607d0593705SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
608c8564c30SJames Wright     PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
609c8564c30SJames Wright     free(rows_petsc);
610c8564c30SJames Wright     free(cols_petsc);
61154831c5fSJames Wright     if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full));
612c8564c30SJames Wright     PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full));
613c8564c30SJames Wright     ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo;
614c8564c30SJames Wright     PetscCall(PetscLogStagePop());
615c8564c30SJames Wright   }
6165037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
6175037d55dSJames Wright }
6185037d55dSJames Wright 
6195037d55dSJames Wright /**
6205037d55dSJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
6215037d55dSJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
6225037d55dSJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
6235037d55dSJames Wright 
6245037d55dSJames Wright   Collective across MPI processes.
6255037d55dSJames Wright 
6265037d55dSJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
6275037d55dSJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
6285037d55dSJames Wright 
6295037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
6305037d55dSJames Wright **/
6315037d55dSJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
6325037d55dSJames Wright   MatCeedContext ctx;
6335037d55dSJames Wright 
6345037d55dSJames Wright   PetscFunctionBeginUser;
6355037d55dSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
6365037d55dSJames Wright 
6375037d55dSJames Wright   // Set COO pattern if needed
6385037d55dSJames Wright   {
6395037d55dSJames Wright     CeedInt index = -1;
6405037d55dSJames Wright 
6415037d55dSJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
6425037d55dSJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
6435037d55dSJames Wright     }
6445037d55dSJames Wright     if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo));
645c8564c30SJames Wright   }
646c8564c30SJames Wright 
647c8564c30SJames Wright   // Assemble mat_ceed
648c8564c30SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
649c8564c30SJames Wright   {
650c8564c30SJames Wright     const CeedScalar *values;
651c8564c30SJames Wright     MatType           mat_type;
652c8564c30SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
653c8564c30SJames Wright     PetscBool         is_spd, is_spd_known;
654c8564c30SJames Wright 
655c8564c30SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
656c8564c30SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
657c8564c30SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
658c8564c30SJames Wright     else mem_type = CEED_MEM_HOST;
659c8564c30SJames Wright 
66054831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full));
66154831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values));
662c8564c30SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
663c8564c30SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
664c8564c30SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
66554831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values));
666c8564c30SJames Wright   }
667c8564c30SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
668c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
669c8564c30SJames Wright }
670c8564c30SJames Wright 
671c8564c30SJames Wright /**
6725037d55dSJames Wright   @brief Set the current value of a context field for a `MatCEED`.
6735037d55dSJames Wright 
6745037d55dSJames Wright   Not collective across MPI processes.
6755037d55dSJames Wright 
6765037d55dSJames Wright   @param[in,out]  mat    `MatCEED`
6775037d55dSJames Wright   @param[in]      name   Name of the context field
6785037d55dSJames Wright   @param[in]      value  New context field value
6795037d55dSJames Wright 
6805037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
6815037d55dSJames Wright **/
6825037d55dSJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
6835037d55dSJames Wright   PetscBool      was_updated = PETSC_FALSE;
6845037d55dSJames Wright   MatCeedContext ctx;
6855037d55dSJames Wright 
6865037d55dSJames Wright   PetscFunctionBeginUser;
6875037d55dSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
6885037d55dSJames Wright   {
6895037d55dSJames Wright     CeedContextFieldLabel label = NULL;
6905037d55dSJames Wright 
6915037d55dSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label));
6925037d55dSJames Wright     if (label) {
6935037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value));
6945037d55dSJames Wright       was_updated = PETSC_TRUE;
6955037d55dSJames Wright     }
6965037d55dSJames Wright     if (ctx->op_mult_transpose) {
6975037d55dSJames Wright       label = NULL;
6985037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
6995037d55dSJames Wright       if (label) {
7005037d55dSJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
7015037d55dSJames Wright         was_updated = PETSC_TRUE;
7025037d55dSJames Wright       }
7035037d55dSJames Wright     }
7045037d55dSJames Wright   }
7055037d55dSJames Wright   if (was_updated) {
7065037d55dSJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
7075037d55dSJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
7085037d55dSJames Wright   }
7095037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
7105037d55dSJames Wright }
7115037d55dSJames Wright 
7125037d55dSJames Wright /**
713*f965f5c6SJames Wright   @brief Set the current `PetscReal` value of a context field for a `MatCEED`.
714*f965f5c6SJames Wright 
715*f965f5c6SJames Wright   Not collective across MPI processes.
716*f965f5c6SJames Wright 
717*f965f5c6SJames Wright   @param[in,out]  mat    `MatCEED`
718*f965f5c6SJames Wright   @param[in]      name   Name of the context field
719*f965f5c6SJames Wright   @param[in]      value  New context field value
720*f965f5c6SJames Wright 
721*f965f5c6SJames Wright   @return An error code: 0 - success, otherwise - failure
722*f965f5c6SJames Wright **/
723*f965f5c6SJames Wright PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) {
724*f965f5c6SJames Wright   double value_double = value;
725*f965f5c6SJames Wright 
726*f965f5c6SJames Wright   PetscFunctionBeginUser;
727*f965f5c6SJames Wright   PetscCall(MatCeedSetContextDouble(mat, name, value_double));
728*f965f5c6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
729*f965f5c6SJames Wright }
730*f965f5c6SJames Wright 
731*f965f5c6SJames Wright /**
7325037d55dSJames Wright   @brief Get the current value of a context field for a `MatCEED`.
7335037d55dSJames Wright 
7345037d55dSJames Wright   Not collective across MPI processes.
7355037d55dSJames Wright 
7365037d55dSJames Wright   @param[in]   mat    `MatCEED`
7375037d55dSJames Wright   @param[in]   name   Name of the context field
7385037d55dSJames Wright   @param[out]  value  Current context field value
7395037d55dSJames Wright 
7405037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
7415037d55dSJames Wright **/
7425037d55dSJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
7435037d55dSJames Wright   MatCeedContext ctx;
7445037d55dSJames Wright 
7455037d55dSJames Wright   PetscFunctionBeginUser;
7465037d55dSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
7475037d55dSJames Wright   {
7485037d55dSJames Wright     CeedContextFieldLabel label = NULL;
7495037d55dSJames Wright     CeedOperator          op    = ctx->op_mult;
7505037d55dSJames Wright 
7515037d55dSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
7525037d55dSJames Wright     if (!label && ctx->op_mult_transpose) {
7535037d55dSJames Wright       op = ctx->op_mult_transpose;
7545037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
7555037d55dSJames Wright     }
7565037d55dSJames Wright     if (label) {
7575037d55dSJames Wright       PetscSizeT    num_values;
7585037d55dSJames Wright       const double *values_ceed;
7595037d55dSJames Wright 
7605037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
7615037d55dSJames Wright       *value = values_ceed[0];
7625037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
7635037d55dSJames Wright     }
7645037d55dSJames Wright   }
7655037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
7665037d55dSJames Wright }
7675037d55dSJames Wright 
7685037d55dSJames Wright /**
769*f965f5c6SJames Wright   @brief Get the current `PetscReal` value of a context field for a `MatCEED`.
770*f965f5c6SJames Wright 
771*f965f5c6SJames Wright   Not collective across MPI processes.
772*f965f5c6SJames Wright 
773*f965f5c6SJames Wright   @param[in]   mat    `MatCEED`
774*f965f5c6SJames Wright   @param[in]   name   Name of the context field
775*f965f5c6SJames Wright   @param[out]  value  Current context field value
776*f965f5c6SJames Wright 
777*f965f5c6SJames Wright   @return An error code: 0 - success, otherwise - failure
778*f965f5c6SJames Wright **/
779*f965f5c6SJames Wright PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) {
780*f965f5c6SJames Wright   double value_double;
781*f965f5c6SJames Wright 
782*f965f5c6SJames Wright   PetscFunctionBeginUser;
783*f965f5c6SJames Wright   PetscCall(MatCeedGetContextDouble(mat, name, &value_double));
784*f965f5c6SJames Wright   *value = value_double;
785*f965f5c6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
786*f965f5c6SJames Wright }
787*f965f5c6SJames Wright 
788*f965f5c6SJames Wright /**
789c8564c30SJames Wright   @brief Set user context for a `MATCEED`.
790c8564c30SJames Wright 
791c8564c30SJames Wright   Collective across MPI processes.
792c8564c30SJames Wright 
793c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
794c8564c30SJames Wright   @param[in]      f    The context destroy function, or NULL
795c8564c30SJames Wright   @param[in]      ctx  User context, or NULL to unset
796c8564c30SJames Wright 
797c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
798c8564c30SJames Wright **/
799c8564c30SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscErrorCode (*f)(void *), void *ctx) {
800c8564c30SJames Wright   PetscContainer user_ctx = NULL;
801c8564c30SJames Wright 
802c8564c30SJames Wright   PetscFunctionBeginUser;
803c8564c30SJames Wright   if (ctx) {
804c8564c30SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
805c8564c30SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
806c8564c30SJames Wright     PetscCall(PetscContainerSetUserDestroy(user_ctx, f));
807c8564c30SJames Wright   }
808c8564c30SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
809c8564c30SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
810c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
811c8564c30SJames Wright }
812c8564c30SJames Wright 
813c8564c30SJames Wright /**
814c8564c30SJames Wright   @brief Retrieve the user context for a `MATCEED`.
815c8564c30SJames Wright 
816c8564c30SJames Wright   Collective across MPI processes.
817c8564c30SJames Wright 
818c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
819c8564c30SJames Wright   @param[in]      ctx  User context
820c8564c30SJames Wright 
821c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
822c8564c30SJames Wright **/
823c8564c30SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
824c8564c30SJames Wright   PetscContainer user_ctx;
825c8564c30SJames Wright 
826c8564c30SJames Wright   PetscFunctionBeginUser;
827c8564c30SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
828c8564c30SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
829c8564c30SJames Wright   else *(void **)ctx = NULL;
830c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
831c8564c30SJames Wright }
832c8564c30SJames Wright /**
8335037d55dSJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
8345037d55dSJames Wright 
8355037d55dSJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
8365037d55dSJames Wright `MatCeedSetContext()`.
837c8564c30SJames Wright 
838c8564c30SJames Wright   Collective across MPI processes.
839c8564c30SJames Wright 
840c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
8415037d55dSJames Wright   @param[in]      op   Name of the `MatOperation`
8425037d55dSJames Wright   @param[in]      g    Function that provides the operation
843c8564c30SJames Wright 
844c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
845c8564c30SJames Wright **/
8465037d55dSJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
8475037d55dSJames Wright   PetscFunctionBeginUser;
8485037d55dSJames Wright   PetscCall(MatShellSetOperation(mat, op, g));
8495037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
8505037d55dSJames Wright }
8515037d55dSJames Wright 
8525037d55dSJames Wright /**
8535037d55dSJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
8545037d55dSJames Wright 
8555037d55dSJames Wright   Collective across MPI processes.
8565037d55dSJames Wright 
8575037d55dSJames Wright   @param[in,out]  mat   `MATCEED`
8585037d55dSJames Wright   @param[in]      type  COO `MatType` to set
8595037d55dSJames Wright 
8605037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
8615037d55dSJames Wright **/
8625037d55dSJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
863c8564c30SJames Wright   MatCeedContext ctx;
864c8564c30SJames Wright 
865c8564c30SJames Wright   PetscFunctionBeginUser;
866c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
867c8564c30SJames Wright   // Check if same
868c8564c30SJames Wright   {
869c8564c30SJames Wright     size_t    len_old, len_new;
870c8564c30SJames Wright     PetscBool is_same = PETSC_FALSE;
871c8564c30SJames Wright 
8725037d55dSJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
873c8564c30SJames Wright     PetscCall(PetscStrlen(type, &len_new));
8745037d55dSJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
875c8564c30SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
876c8564c30SJames Wright   }
877c8564c30SJames Wright   // Clean up old mats in different format
878c8564c30SJames Wright   // LCOV_EXCL_START
879c8564c30SJames Wright   if (ctx->mat_assembled_full_internal) {
880c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
881c8564c30SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
882c8564c30SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
883c8564c30SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
884c8564c30SJames Wright         }
885c8564c30SJames Wright         ctx->num_mats_assembled_full--;
886c8564c30SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
887c8564c30SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
888c8564c30SJames Wright       }
889c8564c30SJames Wright     }
890c8564c30SJames Wright   }
891c8564c30SJames Wright   if (ctx->mat_assembled_pbd_internal) {
892c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
893c8564c30SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
894c8564c30SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
895c8564c30SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
896c8564c30SJames Wright         }
897c8564c30SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
898c8564c30SJames Wright         ctx->num_mats_assembled_pbd--;
899c8564c30SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
900c8564c30SJames Wright       }
901c8564c30SJames Wright     }
902c8564c30SJames Wright   }
9035037d55dSJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
9045037d55dSJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
905c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
906c8564c30SJames Wright   // LCOV_EXCL_STOP
907c8564c30SJames Wright }
908c8564c30SJames Wright 
909c8564c30SJames Wright /**
9105037d55dSJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
911c8564c30SJames Wright 
912c8564c30SJames Wright   Collective across MPI processes.
913c8564c30SJames Wright 
914c8564c30SJames Wright   @param[in,out]  mat   `MATCEED`
9155037d55dSJames Wright   @param[in]      type  COO `MatType`
916c8564c30SJames Wright 
917c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
918c8564c30SJames Wright **/
9195037d55dSJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
920c8564c30SJames Wright   MatCeedContext ctx;
921c8564c30SJames Wright 
922c8564c30SJames Wright   PetscFunctionBeginUser;
923c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
9245037d55dSJames Wright   *type = ctx->coo_mat_type;
925c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
926c8564c30SJames Wright }
927c8564c30SJames Wright 
928c8564c30SJames Wright /**
929c8564c30SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
930c8564c30SJames Wright 
931c8564c30SJames Wright   Not collective across MPI processes.
932c8564c30SJames Wright 
933c8564c30SJames Wright   @param[in,out]  mat              `MATCEED`
934c8564c30SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
935c8564c30SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
936c8564c30SJames Wright 
937c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
938c8564c30SJames Wright **/
939c8564c30SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
940c8564c30SJames Wright   MatCeedContext ctx;
941c8564c30SJames Wright 
942c8564c30SJames Wright   PetscFunctionBeginUser;
943c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
944c8564c30SJames Wright   if (X_loc) {
945c8564c30SJames Wright     PetscInt len_old, len_new;
946c8564c30SJames Wright 
947c8564c30SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
948c8564c30SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
949c8564c30SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB, "new X_loc length %" PetscInt_FMT " should match old X_loc length %" PetscInt_FMT,
950c8564c30SJames Wright                len_new, len_old);
9515037d55dSJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
952c8564c30SJames Wright   }
953c8564c30SJames Wright   if (Y_loc_transpose) {
954c8564c30SJames Wright     PetscInt len_old, len_new;
955c8564c30SJames Wright 
956c8564c30SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
957c8564c30SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
958c8564c30SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
959c8564c30SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
9605037d55dSJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
961c8564c30SJames Wright   }
962c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
963c8564c30SJames Wright }
964c8564c30SJames Wright 
965c8564c30SJames Wright /**
966c8564c30SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
967c8564c30SJames Wright 
968c8564c30SJames Wright   Not collective across MPI processes.
969c8564c30SJames Wright 
970c8564c30SJames Wright   @param[in,out]  mat              `MATCEED`
971c8564c30SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
972c8564c30SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
973c8564c30SJames Wright 
974c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
975c8564c30SJames Wright **/
976c8564c30SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
977c8564c30SJames Wright   MatCeedContext ctx;
978c8564c30SJames Wright 
979c8564c30SJames Wright   PetscFunctionBeginUser;
980c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
981c8564c30SJames Wright   if (X_loc) {
9825037d55dSJames Wright     *X_loc = NULL;
9835037d55dSJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
984c8564c30SJames Wright   }
985c8564c30SJames Wright   if (Y_loc_transpose) {
9865037d55dSJames Wright     *Y_loc_transpose = NULL;
9875037d55dSJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
988c8564c30SJames Wright   }
989c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
990c8564c30SJames Wright }
991c8564c30SJames Wright 
992c8564c30SJames Wright /**
993c8564c30SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
994c8564c30SJames Wright 
995c8564c30SJames Wright   Not collective across MPI processes.
996c8564c30SJames Wright 
997c8564c30SJames Wright   @param[in,out]  mat              MatCeed
998c8564c30SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
999c8564c30SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
1000c8564c30SJames Wright 
1001c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1002c8564c30SJames Wright **/
1003c8564c30SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
1004c8564c30SJames Wright   PetscFunctionBeginUser;
1005c8564c30SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
1006c8564c30SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
1007c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1008c8564c30SJames Wright }
1009c8564c30SJames Wright 
1010c8564c30SJames Wright /**
1011c8564c30SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
1012c8564c30SJames Wright 
1013c8564c30SJames Wright   Not collective across MPI processes.
1014c8564c30SJames Wright 
1015c8564c30SJames Wright   @param[in,out]  mat                MatCeed
1016c8564c30SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
1017c8564c30SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
1018c8564c30SJames Wright 
1019c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1020c8564c30SJames Wright **/
1021c8564c30SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
1022c8564c30SJames Wright   MatCeedContext ctx;
1023c8564c30SJames Wright 
1024c8564c30SJames Wright   PetscFunctionBeginUser;
1025c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1026c8564c30SJames Wright   if (op_mult) {
1027c8564c30SJames Wright     *op_mult = NULL;
102854831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
1029c8564c30SJames Wright   }
1030c8564c30SJames Wright   if (op_mult_transpose) {
1031c8564c30SJames Wright     *op_mult_transpose = NULL;
103254831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
1033c8564c30SJames Wright   }
1034c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1035c8564c30SJames Wright }
1036c8564c30SJames Wright 
1037c8564c30SJames Wright /**
1038c8564c30SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
1039c8564c30SJames Wright 
1040c8564c30SJames Wright   Not collective across MPI processes.
1041c8564c30SJames Wright 
1042c8564c30SJames Wright   @param[in,out]  mat                MatCeed
1043c8564c30SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
1044c8564c30SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
1045c8564c30SJames Wright 
1046c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1047c8564c30SJames Wright **/
1048c8564c30SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
1049c8564c30SJames Wright   MatCeedContext ctx;
1050c8564c30SJames Wright 
1051c8564c30SJames Wright   PetscFunctionBeginUser;
1052c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
105354831c5fSJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
105454831c5fSJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
1055c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1056c8564c30SJames Wright }
1057c8564c30SJames Wright 
1058c8564c30SJames Wright /**
1059c8564c30SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1060c8564c30SJames Wright 
1061c8564c30SJames Wright   Not collective across MPI processes.
1062c8564c30SJames Wright 
1063c8564c30SJames Wright   @param[in,out]  mat                       MatCeed
1064c8564c30SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
1065c8564c30SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
1066c8564c30SJames Wright 
1067c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1068c8564c30SJames Wright **/
1069c8564c30SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1070c8564c30SJames Wright   MatCeedContext ctx;
1071c8564c30SJames Wright 
1072c8564c30SJames Wright   PetscFunctionBeginUser;
1073c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1074c8564c30SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
1075c8564c30SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
1076c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1077c8564c30SJames Wright }
1078c8564c30SJames Wright 
1079c8564c30SJames Wright /**
1080c8564c30SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1081c8564c30SJames Wright 
1082c8564c30SJames Wright   Not collective across MPI processes.
1083c8564c30SJames Wright 
1084c8564c30SJames Wright   @param[in,out]  mat                       MatCeed
1085c8564c30SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
1086c8564c30SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
1087c8564c30SJames Wright 
1088c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1089c8564c30SJames Wright **/
1090c8564c30SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1091c8564c30SJames Wright   MatCeedContext ctx;
1092c8564c30SJames Wright 
1093c8564c30SJames Wright   PetscFunctionBeginUser;
1094c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1095c8564c30SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
1096c8564c30SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
1097c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1098c8564c30SJames Wright }
1099c8564c30SJames Wright 
1100c8564c30SJames Wright // -----------------------------------------------------------------------------
1101c8564c30SJames Wright // Operator context data
1102c8564c30SJames Wright // -----------------------------------------------------------------------------
1103c8564c30SJames Wright 
1104c8564c30SJames Wright /**
1105c8564c30SJames Wright   @brief Setup context data for operator application.
1106c8564c30SJames Wright 
1107c8564c30SJames Wright   Collective across MPI processes.
1108c8564c30SJames Wright 
1109c8564c30SJames Wright   @param[in]   dm_x                      Input `DM`
1110c8564c30SJames Wright   @param[in]   dm_y                      Output `DM`
1111c8564c30SJames Wright   @param[in]   X_loc                     Input PETSc local vector, or NULL
1112c8564c30SJames Wright   @param[in]   Y_loc_transpose           Input PETSc local vector for transpose operation, or NULL
1113c8564c30SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
1114c8564c30SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
1115c8564c30SJames Wright   @param[in]   log_event_mult            `PetscLogEvent` for forward evaluation
1116c8564c30SJames Wright   @param[in]   log_event_mult_transpose  `PetscLogEvent` for transpose evaluation
1117c8564c30SJames Wright   @param[out]  ctx                       Context data for operator evaluation
1118c8564c30SJames Wright 
1119c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1120c8564c30SJames Wright **/
1121c8564c30SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1122c8564c30SJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, MatCeedContext *ctx) {
1123c8564c30SJames Wright   CeedSize x_loc_len, y_loc_len;
1124c8564c30SJames Wright 
1125c8564c30SJames Wright   PetscFunctionBeginUser;
1126c8564c30SJames Wright 
1127c8564c30SJames Wright   // Allocate
1128c8564c30SJames Wright   PetscCall(PetscNew(ctx));
1129c8564c30SJames Wright   (*ctx)->ref_count = 1;
1130c8564c30SJames Wright 
1131c8564c30SJames Wright   // Logging
1132c8564c30SJames Wright   (*ctx)->log_event_mult           = log_event_mult;
1133c8564c30SJames Wright   (*ctx)->log_event_mult_transpose = log_event_mult_transpose;
1134c8564c30SJames Wright 
1135c8564c30SJames Wright   // PETSc objects
11365037d55dSJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
11375037d55dSJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
11385037d55dSJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
11395037d55dSJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
1140c8564c30SJames Wright 
1141c8564c30SJames Wright   // Memtype
1142c8564c30SJames Wright   {
1143c8564c30SJames Wright     const PetscScalar *x;
1144c8564c30SJames Wright     Vec                X;
1145c8564c30SJames Wright 
1146c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
1147c8564c30SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
1148c8564c30SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
1149c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
1150c8564c30SJames Wright   }
1151c8564c30SJames Wright 
1152c8564c30SJames Wright   // libCEED objects
1153c8564c30SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
1154c8564c30SJames Wright              "retrieving Ceed context object failed");
115554831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedReference((*ctx)->ceed));
115654831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
115754831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
115854831c5fSJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
115954831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
116054831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
1161c8564c30SJames Wright 
1162c8564c30SJames Wright   // Flop counting
1163c8564c30SJames Wright   {
1164c8564c30SJames Wright     CeedSize ceed_flops_estimate = 0;
1165c8564c30SJames Wright 
116654831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
1167c8564c30SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
1168c8564c30SJames Wright     if (op_mult_transpose) {
116954831c5fSJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
1170c8564c30SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
1171c8564c30SJames Wright     }
1172c8564c30SJames Wright   }
1173c8564c30SJames Wright 
1174c8564c30SJames Wright   // Check sizes
1175c8564c30SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
1176c8564c30SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
1177c8564c30SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
1178c8564c30SJames Wright     Vec      dm_X_loc, dm_Y_loc;
1179c8564c30SJames Wright 
1180c8564c30SJames Wright     // -- Input
1181c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
1182c8564c30SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
1183c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
118454831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
1185c86b9822SJames Wright     if (X_loc) {
1186c86b9822SJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
1187c86b9822SJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
1188c86b9822SJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
1189c86b9822SJames Wright     }
1190c86b9822SJames Wright     PetscCheck(x_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, "op (%" CeedSize_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions",
1191c86b9822SJames Wright                x_loc_len, dm_x_loc_len);
1192c86b9822SJames Wright     PetscCheck(x_loc_len == ctx_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, "x_loc (%" CeedSize_FMT ") must match op dimensions (%" CeedSize_FMT ")",
1193c86b9822SJames Wright                x_loc_len, ctx_x_loc_len);
1194c8564c30SJames Wright 
1195c8564c30SJames Wright     // -- Output
1196c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
1197c8564c30SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
1198c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
119954831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
1200c86b9822SJames Wright     PetscCheck(ctx_y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, "op (%" CeedSize_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions",
1201c86b9822SJames Wright                ctx_y_loc_len, dm_y_loc_len);
1202c8564c30SJames Wright 
1203c8564c30SJames Wright     // -- Transpose
1204c8564c30SJames Wright     if (Y_loc_transpose) {
1205c8564c30SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
1206c86b9822SJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
1207c86b9822SJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
1208c8564c30SJames Wright     }
1209c8564c30SJames Wright   }
1210c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1211c8564c30SJames Wright }
1212c8564c30SJames Wright 
1213c8564c30SJames Wright /**
1214c8564c30SJames Wright   @brief Increment reference counter for `MATCEED` context.
1215c8564c30SJames Wright 
1216c8564c30SJames Wright   Not collective across MPI processes.
1217c8564c30SJames Wright 
1218c8564c30SJames Wright   @param[in,out]  ctx  Context data
1219c8564c30SJames Wright 
1220c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1221c8564c30SJames Wright **/
1222c8564c30SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
1223c8564c30SJames Wright   PetscFunctionBeginUser;
1224c8564c30SJames Wright   ctx->ref_count++;
1225c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1226c8564c30SJames Wright }
1227c8564c30SJames Wright 
1228c8564c30SJames Wright /**
1229c8564c30SJames Wright   @brief Copy reference for `MATCEED`.
1230c8564c30SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
1231c8564c30SJames Wright 
1232c8564c30SJames Wright   Not collective across MPI processes.
1233c8564c30SJames Wright 
1234c8564c30SJames Wright   @param[in]   ctx       Context data
1235c8564c30SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
1236c8564c30SJames Wright 
1237c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1238c8564c30SJames Wright **/
1239c8564c30SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
1240c8564c30SJames Wright   PetscFunctionBeginUser;
1241c8564c30SJames Wright   PetscCall(MatCeedContextReference(ctx));
1242c8564c30SJames Wright   PetscCall(MatCeedContextDestroy(*ctx_copy));
1243c8564c30SJames Wright   *ctx_copy = ctx;
1244c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1245c8564c30SJames Wright }
1246c8564c30SJames Wright 
1247c8564c30SJames Wright /**
1248c8564c30SJames Wright   @brief Destroy context data for operator application.
1249c8564c30SJames Wright 
1250c8564c30SJames Wright   Collective across MPI processes.
1251c8564c30SJames Wright 
1252c8564c30SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
1253c8564c30SJames Wright 
1254c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1255c8564c30SJames Wright **/
1256c8564c30SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext ctx) {
1257c8564c30SJames Wright   PetscFunctionBeginUser;
1258c8564c30SJames Wright   if (!ctx || --ctx->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
1259c8564c30SJames Wright 
1260c8564c30SJames Wright   // PETSc objects
1261c8564c30SJames Wright   PetscCall(DMDestroy(&ctx->dm_x));
1262c8564c30SJames Wright   PetscCall(DMDestroy(&ctx->dm_y));
1263c8564c30SJames Wright   PetscCall(VecDestroy(&ctx->X_loc));
1264c8564c30SJames Wright   PetscCall(VecDestroy(&ctx->Y_loc_transpose));
1265c8564c30SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
1266c8564c30SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
12675037d55dSJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
1268c8564c30SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_full));
1269c8564c30SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_pbd));
1270c8564c30SJames Wright 
1271c8564c30SJames Wright   // libCEED objects
127254831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->x_loc));
127354831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->y_loc));
127454831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_full));
127554831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_pbd));
127654831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult));
127754831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult_transpose));
1278c8564c30SJames Wright   PetscCheck(CeedDestroy(&ctx->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
1279c8564c30SJames Wright 
1280c8564c30SJames Wright   // Deallocate
1281c8564c30SJames Wright   ctx->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
1282c8564c30SJames Wright   PetscCall(PetscFree(ctx));
1283c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1284c8564c30SJames Wright }
1285c8564c30SJames Wright 
1286c8564c30SJames Wright /**
1287c8564c30SJames Wright   @brief Compute the diagonal of an operator via libCEED.
1288c8564c30SJames Wright 
1289c8564c30SJames Wright   Collective across MPI processes.
1290c8564c30SJames Wright 
1291c8564c30SJames Wright   @param[in]   A  `MATCEED`
1292c8564c30SJames Wright   @param[out]  D  Vector holding operator diagonal
1293c8564c30SJames Wright 
1294c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1295c8564c30SJames Wright **/
1296c8564c30SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
1297c8564c30SJames Wright   PetscMemType   mem_type;
1298c8564c30SJames Wright   Vec            D_loc;
1299c8564c30SJames Wright   MatCeedContext ctx;
1300c8564c30SJames Wright 
1301c8564c30SJames Wright   PetscFunctionBeginUser;
1302c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1303c8564c30SJames Wright 
1304c8564c30SJames Wright   // Place PETSc vector in libCEED vector
1305c8564c30SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1306d0593705SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
1307c8564c30SJames Wright 
1308c8564c30SJames Wright   // Compute Diagonal
130954831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1310c8564c30SJames Wright 
1311c8564c30SJames Wright   // Restore PETSc vector
1312d0593705SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
1313c8564c30SJames Wright 
1314c8564c30SJames Wright   // Local-to-Global
1315c8564c30SJames Wright   PetscCall(VecZeroEntries(D));
1316c8564c30SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
1317c8564c30SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1318c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1319c8564c30SJames Wright }
1320c8564c30SJames Wright 
1321c8564c30SJames Wright /**
1322c8564c30SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
1323c8564c30SJames Wright 
1324c8564c30SJames Wright   Collective across MPI processes.
1325c8564c30SJames Wright 
1326c8564c30SJames Wright   @param[in]   A  `MATCEED`
1327c8564c30SJames Wright   @param[in]   X  Input PETSc vector
1328c8564c30SJames Wright   @param[out]  Y  Output PETSc vector
1329c8564c30SJames Wright 
1330c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1331c8564c30SJames Wright **/
1332c8564c30SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
1333c8564c30SJames Wright   MatCeedContext ctx;
1334c8564c30SJames Wright 
1335c8564c30SJames Wright   PetscFunctionBeginUser;
1336c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1337c8564c30SJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, 0));
1338c8564c30SJames Wright 
1339c8564c30SJames Wright   {
1340c8564c30SJames Wright     PetscMemType x_mem_type, y_mem_type;
1341c8564c30SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
1342c8564c30SJames Wright 
1343c8564c30SJames Wright     // Get local vectors
1344c8564c30SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
1345c8564c30SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
1346c8564c30SJames Wright 
1347c8564c30SJames Wright     // Global-to-local
1348c8564c30SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
1349c8564c30SJames Wright 
1350c8564c30SJames Wright     // Setup libCEED vectors
1351d0593705SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
1352c8564c30SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1353d0593705SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
1354c8564c30SJames Wright 
1355c8564c30SJames Wright     // Apply libCEED operator
1356c8564c30SJames Wright     PetscCall(PetscLogGpuTimeBegin());
135754831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
1358c8564c30SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1359c8564c30SJames Wright 
1360c8564c30SJames Wright     // Restore PETSc vectors
1361d0593705SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1362d0593705SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1363c8564c30SJames Wright 
1364c8564c30SJames Wright     // Local-to-global
1365c8564c30SJames Wright     PetscCall(VecZeroEntries(Y));
1366c8564c30SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
1367c8564c30SJames Wright 
1368c8564c30SJames Wright     // Restore local vectors, as needed
1369c8564c30SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
1370c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
1371c8564c30SJames Wright   }
1372c8564c30SJames Wright 
1373c8564c30SJames Wright   // Log flops
1374c8564c30SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
1375c8564c30SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult));
1376c8564c30SJames Wright 
1377c8564c30SJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, 0));
1378c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1379c8564c30SJames Wright }
1380c8564c30SJames Wright 
1381c8564c30SJames Wright /**
1382c8564c30SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
1383c8564c30SJames Wright 
1384c8564c30SJames Wright   Collective across MPI processes.
1385c8564c30SJames Wright 
1386c8564c30SJames Wright   @param[in]   A  `MATCEED`
1387c8564c30SJames Wright   @param[in]   Y  Input PETSc vector
1388c8564c30SJames Wright   @param[out]  X  Output PETSc vector
1389c8564c30SJames Wright 
1390c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1391c8564c30SJames Wright **/
1392c8564c30SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
1393c8564c30SJames Wright   MatCeedContext ctx;
1394c8564c30SJames Wright 
1395c8564c30SJames Wright   PetscFunctionBeginUser;
1396c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1397c8564c30SJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, 0));
1398c8564c30SJames Wright 
1399c8564c30SJames Wright   {
1400c8564c30SJames Wright     PetscMemType x_mem_type, y_mem_type;
1401c8564c30SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
1402c8564c30SJames Wright 
1403c8564c30SJames Wright     // Get local vectors
1404c8564c30SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
1405c8564c30SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
1406c8564c30SJames Wright 
1407c8564c30SJames Wright     // Global-to-local
1408c8564c30SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
1409c8564c30SJames Wright 
1410c8564c30SJames Wright     // Setup libCEED vectors
1411d0593705SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
1412c8564c30SJames Wright     PetscCall(VecZeroEntries(X_loc));
1413d0593705SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
1414c8564c30SJames Wright 
1415c8564c30SJames Wright     // Apply libCEED operator
1416c8564c30SJames Wright     PetscCall(PetscLogGpuTimeBegin());
141754831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1418c8564c30SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1419c8564c30SJames Wright 
1420c8564c30SJames Wright     // Restore PETSc vectors
1421d0593705SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1422d0593705SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1423c8564c30SJames Wright 
1424c8564c30SJames Wright     // Local-to-global
1425c8564c30SJames Wright     PetscCall(VecZeroEntries(X));
1426c8564c30SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
1427c8564c30SJames Wright 
1428c8564c30SJames Wright     // Restore local vectors, as needed
1429c8564c30SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
1430c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
1431c8564c30SJames Wright   }
1432c8564c30SJames Wright 
1433c8564c30SJames Wright   // Log flops
1434c8564c30SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
1435c8564c30SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
1436c8564c30SJames Wright 
1437c8564c30SJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, 0));
1438c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1439c8564c30SJames Wright }
1440