xref: /libCEED/examples/fluids/src/mat-ceed.c (revision 5037d55df331588b72bed903a854832c66414480)
1c8564c30SJames Wright /// @file
2*5037d55dSJames 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>
8*5037d55dSJames Wright #include <petsc-ceed-utils.h>
9*5037d55dSJames 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() {
25*5037d55dSJames 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));
32*5037d55dSJames 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
128*5037d55dSJames 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
135*5037d55dSJames 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 
250*5037d55dSJames 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   }
309*5037d55dSJames 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;
421*5037d55dSJames Wright     MatType coo_mat_type;
422c8564c30SJames Wright 
423c8564c30SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
424*5037d55dSJames Wright     if (strstr(vec_type, VECCUDA)) coo_mat_type = MATAIJCUSPARSE;
425*5037d55dSJames Wright     else if (strstr(vec_type, VECKOKKOS)) coo_mat_type = MATAIJKOKKOS;
426*5037d55dSJames Wright     else coo_mat_type = MATAIJ;
427*5037d55dSJames 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   {
458*5037d55dSJames 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));
462*5037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
463*5037d55dSJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
464*5037d55dSJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
465*5037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
466*5037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matceed));
467*5037d55dSJames 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 /**
524*5037d55dSJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
525*5037d55dSJames Wright 
526*5037d55dSJames Wright   Collective across MPI processes.
527*5037d55dSJames Wright 
528*5037d55dSJames Wright   @param[in]   mat_ceed  `MATCEED`
529*5037d55dSJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
530*5037d55dSJames Wright 
531*5037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
532*5037d55dSJames Wright **/
533*5037d55dSJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
534*5037d55dSJames Wright   MatCeedContext ctx;
535*5037d55dSJames Wright 
536*5037d55dSJames Wright   PetscFunctionBeginUser;
537*5037d55dSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
538*5037d55dSJames Wright 
539*5037d55dSJames 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");
540*5037d55dSJames Wright 
541*5037d55dSJames Wright   // Check cl mat type
542*5037d55dSJames Wright   {
543*5037d55dSJames Wright     PetscBool is_coo_mat_type_cl = PETSC_FALSE;
544*5037d55dSJames Wright     char      coo_mat_type_cl[64];
545*5037d55dSJames Wright 
546*5037d55dSJames Wright     // Check for specific CL coo mat type for this Mat
547*5037d55dSJames Wright     {
548*5037d55dSJames Wright       const char *mat_ceed_prefix = NULL;
549*5037d55dSJames Wright 
550*5037d55dSJames Wright       PetscCall(MatGetOptionsPrefix(mat_ceed, &mat_ceed_prefix));
551*5037d55dSJames Wright       PetscOptionsBegin(PetscObjectComm((PetscObject)mat_ceed), mat_ceed_prefix, "", NULL);
552*5037d55dSJames Wright       PetscCall(PetscOptionsFList("-ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
553*5037d55dSJames Wright                                   sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
554*5037d55dSJames Wright       PetscOptionsEnd();
555*5037d55dSJames Wright       if (is_coo_mat_type_cl) {
556*5037d55dSJames Wright         PetscCall(PetscFree(ctx->coo_mat_type));
557*5037d55dSJames Wright         PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
558*5037d55dSJames Wright       }
559*5037d55dSJames Wright     }
560*5037d55dSJames Wright   }
561*5037d55dSJames Wright 
562*5037d55dSJames Wright   // Create sparse matrix
563*5037d55dSJames Wright   {
564*5037d55dSJames Wright     MatType dm_mat_type, dm_mat_type_copy;
565*5037d55dSJames Wright 
566*5037d55dSJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
567*5037d55dSJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
568*5037d55dSJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
569*5037d55dSJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
570*5037d55dSJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
571*5037d55dSJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
572*5037d55dSJames Wright   }
573*5037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
574*5037d55dSJames Wright }
575*5037d55dSJames Wright 
576*5037d55dSJames Wright /**
577*5037d55dSJames 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 **/
587*5037d55dSJames 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   }
616*5037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
617*5037d55dSJames Wright }
618*5037d55dSJames Wright 
619*5037d55dSJames Wright /**
620*5037d55dSJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
621*5037d55dSJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
622*5037d55dSJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
623*5037d55dSJames Wright 
624*5037d55dSJames Wright   Collective across MPI processes.
625*5037d55dSJames Wright 
626*5037d55dSJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
627*5037d55dSJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
628*5037d55dSJames Wright 
629*5037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
630*5037d55dSJames Wright **/
631*5037d55dSJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
632*5037d55dSJames Wright   MatCeedContext ctx;
633*5037d55dSJames Wright 
634*5037d55dSJames Wright   PetscFunctionBeginUser;
635*5037d55dSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
636*5037d55dSJames Wright 
637*5037d55dSJames Wright   // Set COO pattern if needed
638*5037d55dSJames Wright   {
639*5037d55dSJames Wright     CeedInt index = -1;
640*5037d55dSJames Wright 
641*5037d55dSJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
642*5037d55dSJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
643*5037d55dSJames Wright     }
644*5037d55dSJames 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 /**
672*5037d55dSJames Wright   @brief Set the current value of a context field for a `MatCEED`.
673*5037d55dSJames Wright 
674*5037d55dSJames Wright   Not collective across MPI processes.
675*5037d55dSJames Wright 
676*5037d55dSJames Wright   @param[in,out]  mat    `MatCEED`
677*5037d55dSJames Wright   @param[in]      name   Name of the context field
678*5037d55dSJames Wright   @param[in]      value  New context field value
679*5037d55dSJames Wright 
680*5037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
681*5037d55dSJames Wright **/
682*5037d55dSJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
683*5037d55dSJames Wright   PetscBool      was_updated = PETSC_FALSE;
684*5037d55dSJames Wright   MatCeedContext ctx;
685*5037d55dSJames Wright 
686*5037d55dSJames Wright   PetscFunctionBeginUser;
687*5037d55dSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
688*5037d55dSJames Wright   {
689*5037d55dSJames Wright     CeedContextFieldLabel label = NULL;
690*5037d55dSJames Wright 
691*5037d55dSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label));
692*5037d55dSJames Wright     if (label) {
693*5037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value));
694*5037d55dSJames Wright       was_updated = PETSC_TRUE;
695*5037d55dSJames Wright     }
696*5037d55dSJames Wright     if (ctx->op_mult_transpose) {
697*5037d55dSJames Wright       label = NULL;
698*5037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
699*5037d55dSJames Wright       if (label) {
700*5037d55dSJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
701*5037d55dSJames Wright         was_updated = PETSC_TRUE;
702*5037d55dSJames Wright       }
703*5037d55dSJames Wright     }
704*5037d55dSJames Wright   }
705*5037d55dSJames Wright   if (was_updated) {
706*5037d55dSJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
707*5037d55dSJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
708*5037d55dSJames Wright   }
709*5037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
710*5037d55dSJames Wright }
711*5037d55dSJames Wright 
712*5037d55dSJames Wright /**
713*5037d55dSJames Wright   @brief Get the current value of a context field for a `MatCEED`.
714*5037d55dSJames Wright 
715*5037d55dSJames Wright   Not collective across MPI processes.
716*5037d55dSJames Wright 
717*5037d55dSJames Wright   @param[in]   mat    `MatCEED`
718*5037d55dSJames Wright   @param[in]   name   Name of the context field
719*5037d55dSJames Wright   @param[out]  value  Current context field value
720*5037d55dSJames Wright 
721*5037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
722*5037d55dSJames Wright **/
723*5037d55dSJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
724*5037d55dSJames Wright   MatCeedContext ctx;
725*5037d55dSJames Wright 
726*5037d55dSJames Wright   PetscFunctionBeginUser;
727*5037d55dSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
728*5037d55dSJames Wright   {
729*5037d55dSJames Wright     CeedContextFieldLabel label = NULL;
730*5037d55dSJames Wright     CeedOperator          op    = ctx->op_mult;
731*5037d55dSJames Wright 
732*5037d55dSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
733*5037d55dSJames Wright     if (!label && ctx->op_mult_transpose) {
734*5037d55dSJames Wright       op = ctx->op_mult_transpose;
735*5037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
736*5037d55dSJames Wright     }
737*5037d55dSJames Wright     if (label) {
738*5037d55dSJames Wright       PetscSizeT    num_values;
739*5037d55dSJames Wright       const double *values_ceed;
740*5037d55dSJames Wright 
741*5037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
742*5037d55dSJames Wright       *value = values_ceed[0];
743*5037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
744*5037d55dSJames Wright     }
745*5037d55dSJames Wright   }
746*5037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
747*5037d55dSJames Wright }
748*5037d55dSJames Wright 
749*5037d55dSJames Wright /**
750c8564c30SJames Wright   @brief Set user context for a `MATCEED`.
751c8564c30SJames Wright 
752c8564c30SJames Wright   Collective across MPI processes.
753c8564c30SJames Wright 
754c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
755c8564c30SJames Wright   @param[in]      f    The context destroy function, or NULL
756c8564c30SJames Wright   @param[in]      ctx  User context, or NULL to unset
757c8564c30SJames Wright 
758c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
759c8564c30SJames Wright **/
760c8564c30SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscErrorCode (*f)(void *), void *ctx) {
761c8564c30SJames Wright   PetscContainer user_ctx = NULL;
762c8564c30SJames Wright 
763c8564c30SJames Wright   PetscFunctionBeginUser;
764c8564c30SJames Wright   if (ctx) {
765c8564c30SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
766c8564c30SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
767c8564c30SJames Wright     PetscCall(PetscContainerSetUserDestroy(user_ctx, f));
768c8564c30SJames Wright   }
769c8564c30SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
770c8564c30SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
771c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
772c8564c30SJames Wright }
773c8564c30SJames Wright 
774c8564c30SJames Wright /**
775c8564c30SJames Wright   @brief Retrieve the user context for a `MATCEED`.
776c8564c30SJames Wright 
777c8564c30SJames Wright   Collective across MPI processes.
778c8564c30SJames Wright 
779c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
780c8564c30SJames Wright   @param[in]      ctx  User context
781c8564c30SJames Wright 
782c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
783c8564c30SJames Wright **/
784c8564c30SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
785c8564c30SJames Wright   PetscContainer user_ctx;
786c8564c30SJames Wright 
787c8564c30SJames Wright   PetscFunctionBeginUser;
788c8564c30SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
789c8564c30SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
790c8564c30SJames Wright   else *(void **)ctx = NULL;
791c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
792c8564c30SJames Wright }
793c8564c30SJames Wright /**
794*5037d55dSJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
795*5037d55dSJames Wright 
796*5037d55dSJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
797*5037d55dSJames Wright `MatCeedSetContext()`.
798c8564c30SJames Wright 
799c8564c30SJames Wright   Collective across MPI processes.
800c8564c30SJames Wright 
801c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
802*5037d55dSJames Wright   @param[in]      op   Name of the `MatOperation`
803*5037d55dSJames Wright   @param[in]      g    Function that provides the operation
804c8564c30SJames Wright 
805c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
806c8564c30SJames Wright **/
807*5037d55dSJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
808*5037d55dSJames Wright   PetscFunctionBeginUser;
809*5037d55dSJames Wright   PetscCall(MatShellSetOperation(mat, op, g));
810*5037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
811*5037d55dSJames Wright }
812*5037d55dSJames Wright 
813*5037d55dSJames Wright /**
814*5037d55dSJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
815*5037d55dSJames Wright 
816*5037d55dSJames Wright   Collective across MPI processes.
817*5037d55dSJames Wright 
818*5037d55dSJames Wright   @param[in,out]  mat   `MATCEED`
819*5037d55dSJames Wright   @param[in]      type  COO `MatType` to set
820*5037d55dSJames Wright 
821*5037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
822*5037d55dSJames Wright **/
823*5037d55dSJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
824c8564c30SJames Wright   MatCeedContext ctx;
825c8564c30SJames Wright 
826c8564c30SJames Wright   PetscFunctionBeginUser;
827c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
828c8564c30SJames Wright   // Check if same
829c8564c30SJames Wright   {
830c8564c30SJames Wright     size_t    len_old, len_new;
831c8564c30SJames Wright     PetscBool is_same = PETSC_FALSE;
832c8564c30SJames Wright 
833*5037d55dSJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
834c8564c30SJames Wright     PetscCall(PetscStrlen(type, &len_new));
835*5037d55dSJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
836c8564c30SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
837c8564c30SJames Wright   }
838c8564c30SJames Wright   // Clean up old mats in different format
839c8564c30SJames Wright   // LCOV_EXCL_START
840c8564c30SJames Wright   if (ctx->mat_assembled_full_internal) {
841c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
842c8564c30SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
843c8564c30SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
844c8564c30SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
845c8564c30SJames Wright         }
846c8564c30SJames Wright         ctx->num_mats_assembled_full--;
847c8564c30SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
848c8564c30SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
849c8564c30SJames Wright       }
850c8564c30SJames Wright     }
851c8564c30SJames Wright   }
852c8564c30SJames Wright   if (ctx->mat_assembled_pbd_internal) {
853c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
854c8564c30SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
855c8564c30SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
856c8564c30SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
857c8564c30SJames Wright         }
858c8564c30SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
859c8564c30SJames Wright         ctx->num_mats_assembled_pbd--;
860c8564c30SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
861c8564c30SJames Wright       }
862c8564c30SJames Wright     }
863c8564c30SJames Wright   }
864*5037d55dSJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
865*5037d55dSJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
866c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
867c8564c30SJames Wright   // LCOV_EXCL_STOP
868c8564c30SJames Wright }
869c8564c30SJames Wright 
870c8564c30SJames Wright /**
871*5037d55dSJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
872c8564c30SJames Wright 
873c8564c30SJames Wright   Collective across MPI processes.
874c8564c30SJames Wright 
875c8564c30SJames Wright   @param[in,out]  mat   `MATCEED`
876*5037d55dSJames Wright   @param[in]      type  COO `MatType`
877c8564c30SJames Wright 
878c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
879c8564c30SJames Wright **/
880*5037d55dSJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
881c8564c30SJames Wright   MatCeedContext ctx;
882c8564c30SJames Wright 
883c8564c30SJames Wright   PetscFunctionBeginUser;
884c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
885*5037d55dSJames Wright   *type = ctx->coo_mat_type;
886c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
887c8564c30SJames Wright }
888c8564c30SJames Wright 
889c8564c30SJames Wright /**
890c8564c30SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
891c8564c30SJames Wright 
892c8564c30SJames Wright   Not collective across MPI processes.
893c8564c30SJames Wright 
894c8564c30SJames Wright   @param[in,out]  mat              `MATCEED`
895c8564c30SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
896c8564c30SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
897c8564c30SJames Wright 
898c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
899c8564c30SJames Wright **/
900c8564c30SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
901c8564c30SJames Wright   MatCeedContext ctx;
902c8564c30SJames Wright 
903c8564c30SJames Wright   PetscFunctionBeginUser;
904c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
905c8564c30SJames Wright   if (X_loc) {
906c8564c30SJames Wright     PetscInt len_old, len_new;
907c8564c30SJames Wright 
908c8564c30SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
909c8564c30SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
910c8564c30SJames 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,
911c8564c30SJames Wright                len_new, len_old);
912*5037d55dSJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
913c8564c30SJames Wright   }
914c8564c30SJames Wright   if (Y_loc_transpose) {
915c8564c30SJames Wright     PetscInt len_old, len_new;
916c8564c30SJames Wright 
917c8564c30SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
918c8564c30SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
919c8564c30SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
920c8564c30SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
921*5037d55dSJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
922c8564c30SJames Wright   }
923c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
924c8564c30SJames Wright }
925c8564c30SJames Wright 
926c8564c30SJames Wright /**
927c8564c30SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
928c8564c30SJames Wright 
929c8564c30SJames Wright   Not collective across MPI processes.
930c8564c30SJames Wright 
931c8564c30SJames Wright   @param[in,out]  mat              `MATCEED`
932c8564c30SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
933c8564c30SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
934c8564c30SJames Wright 
935c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
936c8564c30SJames Wright **/
937c8564c30SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
938c8564c30SJames Wright   MatCeedContext ctx;
939c8564c30SJames Wright 
940c8564c30SJames Wright   PetscFunctionBeginUser;
941c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
942c8564c30SJames Wright   if (X_loc) {
943*5037d55dSJames Wright     *X_loc = NULL;
944*5037d55dSJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
945c8564c30SJames Wright   }
946c8564c30SJames Wright   if (Y_loc_transpose) {
947*5037d55dSJames Wright     *Y_loc_transpose = NULL;
948*5037d55dSJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
949c8564c30SJames Wright   }
950c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
951c8564c30SJames Wright }
952c8564c30SJames Wright 
953c8564c30SJames Wright /**
954c8564c30SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
955c8564c30SJames Wright 
956c8564c30SJames Wright   Not collective across MPI processes.
957c8564c30SJames Wright 
958c8564c30SJames Wright   @param[in,out]  mat              MatCeed
959c8564c30SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
960c8564c30SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
961c8564c30SJames Wright 
962c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
963c8564c30SJames Wright **/
964c8564c30SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
965c8564c30SJames Wright   PetscFunctionBeginUser;
966c8564c30SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
967c8564c30SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
968c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
969c8564c30SJames Wright }
970c8564c30SJames Wright 
971c8564c30SJames Wright /**
972c8564c30SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
973c8564c30SJames Wright 
974c8564c30SJames Wright   Not collective across MPI processes.
975c8564c30SJames Wright 
976c8564c30SJames Wright   @param[in,out]  mat                MatCeed
977c8564c30SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
978c8564c30SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
979c8564c30SJames Wright 
980c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
981c8564c30SJames Wright **/
982c8564c30SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
983c8564c30SJames Wright   MatCeedContext ctx;
984c8564c30SJames Wright 
985c8564c30SJames Wright   PetscFunctionBeginUser;
986c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
987c8564c30SJames Wright   if (op_mult) {
988c8564c30SJames Wright     *op_mult = NULL;
98954831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
990c8564c30SJames Wright   }
991c8564c30SJames Wright   if (op_mult_transpose) {
992c8564c30SJames Wright     *op_mult_transpose = NULL;
99354831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
994c8564c30SJames Wright   }
995c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
996c8564c30SJames Wright }
997c8564c30SJames Wright 
998c8564c30SJames Wright /**
999c8564c30SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
1000c8564c30SJames Wright 
1001c8564c30SJames Wright   Not collective across MPI processes.
1002c8564c30SJames Wright 
1003c8564c30SJames Wright   @param[in,out]  mat                MatCeed
1004c8564c30SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
1005c8564c30SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
1006c8564c30SJames Wright 
1007c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1008c8564c30SJames Wright **/
1009c8564c30SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
1010c8564c30SJames Wright   MatCeedContext ctx;
1011c8564c30SJames Wright 
1012c8564c30SJames Wright   PetscFunctionBeginUser;
1013c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
101454831c5fSJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
101554831c5fSJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
1016c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1017c8564c30SJames Wright }
1018c8564c30SJames Wright 
1019c8564c30SJames Wright /**
1020c8564c30SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1021c8564c30SJames Wright 
1022c8564c30SJames Wright   Not collective across MPI processes.
1023c8564c30SJames Wright 
1024c8564c30SJames Wright   @param[in,out]  mat                       MatCeed
1025c8564c30SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
1026c8564c30SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
1027c8564c30SJames Wright 
1028c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1029c8564c30SJames Wright **/
1030c8564c30SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1031c8564c30SJames Wright   MatCeedContext ctx;
1032c8564c30SJames Wright 
1033c8564c30SJames Wright   PetscFunctionBeginUser;
1034c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1035c8564c30SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
1036c8564c30SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
1037c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1038c8564c30SJames Wright }
1039c8564c30SJames Wright 
1040c8564c30SJames Wright /**
1041c8564c30SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1042c8564c30SJames Wright 
1043c8564c30SJames Wright   Not collective across MPI processes.
1044c8564c30SJames Wright 
1045c8564c30SJames Wright   @param[in,out]  mat                       MatCeed
1046c8564c30SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
1047c8564c30SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
1048c8564c30SJames Wright 
1049c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1050c8564c30SJames Wright **/
1051c8564c30SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1052c8564c30SJames Wright   MatCeedContext ctx;
1053c8564c30SJames Wright 
1054c8564c30SJames Wright   PetscFunctionBeginUser;
1055c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1056c8564c30SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
1057c8564c30SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
1058c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1059c8564c30SJames Wright }
1060c8564c30SJames Wright 
1061c8564c30SJames Wright // -----------------------------------------------------------------------------
1062c8564c30SJames Wright // Operator context data
1063c8564c30SJames Wright // -----------------------------------------------------------------------------
1064c8564c30SJames Wright 
1065c8564c30SJames Wright /**
1066c8564c30SJames Wright   @brief Setup context data for operator application.
1067c8564c30SJames Wright 
1068c8564c30SJames Wright   Collective across MPI processes.
1069c8564c30SJames Wright 
1070c8564c30SJames Wright   @param[in]   dm_x                      Input `DM`
1071c8564c30SJames Wright   @param[in]   dm_y                      Output `DM`
1072c8564c30SJames Wright   @param[in]   X_loc                     Input PETSc local vector, or NULL
1073c8564c30SJames Wright   @param[in]   Y_loc_transpose           Input PETSc local vector for transpose operation, or NULL
1074c8564c30SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
1075c8564c30SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
1076c8564c30SJames Wright   @param[in]   log_event_mult            `PetscLogEvent` for forward evaluation
1077c8564c30SJames Wright   @param[in]   log_event_mult_transpose  `PetscLogEvent` for transpose evaluation
1078c8564c30SJames Wright   @param[out]  ctx                       Context data for operator evaluation
1079c8564c30SJames Wright 
1080c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1081c8564c30SJames Wright **/
1082c8564c30SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1083c8564c30SJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, MatCeedContext *ctx) {
1084c8564c30SJames Wright   CeedSize x_loc_len, y_loc_len;
1085c8564c30SJames Wright 
1086c8564c30SJames Wright   PetscFunctionBeginUser;
1087c8564c30SJames Wright 
1088c8564c30SJames Wright   // Allocate
1089c8564c30SJames Wright   PetscCall(PetscNew(ctx));
1090c8564c30SJames Wright   (*ctx)->ref_count = 1;
1091c8564c30SJames Wright 
1092c8564c30SJames Wright   // Logging
1093c8564c30SJames Wright   (*ctx)->log_event_mult           = log_event_mult;
1094c8564c30SJames Wright   (*ctx)->log_event_mult_transpose = log_event_mult_transpose;
1095c8564c30SJames Wright 
1096c8564c30SJames Wright   // PETSc objects
1097*5037d55dSJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
1098*5037d55dSJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
1099*5037d55dSJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
1100*5037d55dSJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
1101c8564c30SJames Wright 
1102c8564c30SJames Wright   // Memtype
1103c8564c30SJames Wright   {
1104c8564c30SJames Wright     const PetscScalar *x;
1105c8564c30SJames Wright     Vec                X;
1106c8564c30SJames Wright 
1107c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
1108c8564c30SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
1109c8564c30SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
1110c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
1111c8564c30SJames Wright   }
1112c8564c30SJames Wright 
1113c8564c30SJames Wright   // libCEED objects
1114c8564c30SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
1115c8564c30SJames Wright              "retrieving Ceed context object failed");
111654831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedReference((*ctx)->ceed));
111754831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
111854831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
111954831c5fSJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
112054831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
112154831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
1122c8564c30SJames Wright 
1123c8564c30SJames Wright   // Flop counting
1124c8564c30SJames Wright   {
1125c8564c30SJames Wright     CeedSize ceed_flops_estimate = 0;
1126c8564c30SJames Wright 
112754831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
1128c8564c30SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
1129c8564c30SJames Wright     if (op_mult_transpose) {
113054831c5fSJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
1131c8564c30SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
1132c8564c30SJames Wright     }
1133c8564c30SJames Wright   }
1134c8564c30SJames Wright 
1135c8564c30SJames Wright   // Check sizes
1136c8564c30SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
1137c8564c30SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
1138c8564c30SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
1139c8564c30SJames Wright     Vec      dm_X_loc, dm_Y_loc;
1140c8564c30SJames Wright 
1141c8564c30SJames Wright     // -- Input
1142c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
1143c8564c30SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
1144c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
114554831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
1146c86b9822SJames Wright     if (X_loc) {
1147c86b9822SJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
1148c86b9822SJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
1149c86b9822SJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
1150c86b9822SJames Wright     }
1151c86b9822SJames 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",
1152c86b9822SJames Wright                x_loc_len, dm_x_loc_len);
1153c86b9822SJames 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 ")",
1154c86b9822SJames Wright                x_loc_len, ctx_x_loc_len);
1155c8564c30SJames Wright 
1156c8564c30SJames Wright     // -- Output
1157c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
1158c8564c30SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
1159c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
116054831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
1161c86b9822SJames 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",
1162c86b9822SJames Wright                ctx_y_loc_len, dm_y_loc_len);
1163c8564c30SJames Wright 
1164c8564c30SJames Wright     // -- Transpose
1165c8564c30SJames Wright     if (Y_loc_transpose) {
1166c8564c30SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
1167c86b9822SJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
1168c86b9822SJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
1169c8564c30SJames Wright     }
1170c8564c30SJames Wright   }
1171c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1172c8564c30SJames Wright }
1173c8564c30SJames Wright 
1174c8564c30SJames Wright /**
1175c8564c30SJames Wright   @brief Increment reference counter for `MATCEED` context.
1176c8564c30SJames Wright 
1177c8564c30SJames Wright   Not collective across MPI processes.
1178c8564c30SJames Wright 
1179c8564c30SJames Wright   @param[in,out]  ctx  Context data
1180c8564c30SJames Wright 
1181c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1182c8564c30SJames Wright **/
1183c8564c30SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
1184c8564c30SJames Wright   PetscFunctionBeginUser;
1185c8564c30SJames Wright   ctx->ref_count++;
1186c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1187c8564c30SJames Wright }
1188c8564c30SJames Wright 
1189c8564c30SJames Wright /**
1190c8564c30SJames Wright   @brief Copy reference for `MATCEED`.
1191c8564c30SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
1192c8564c30SJames Wright 
1193c8564c30SJames Wright   Not collective across MPI processes.
1194c8564c30SJames Wright 
1195c8564c30SJames Wright   @param[in]   ctx       Context data
1196c8564c30SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
1197c8564c30SJames Wright 
1198c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1199c8564c30SJames Wright **/
1200c8564c30SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
1201c8564c30SJames Wright   PetscFunctionBeginUser;
1202c8564c30SJames Wright   PetscCall(MatCeedContextReference(ctx));
1203c8564c30SJames Wright   PetscCall(MatCeedContextDestroy(*ctx_copy));
1204c8564c30SJames Wright   *ctx_copy = ctx;
1205c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1206c8564c30SJames Wright }
1207c8564c30SJames Wright 
1208c8564c30SJames Wright /**
1209c8564c30SJames Wright   @brief Destroy context data for operator application.
1210c8564c30SJames Wright 
1211c8564c30SJames Wright   Collective across MPI processes.
1212c8564c30SJames Wright 
1213c8564c30SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
1214c8564c30SJames Wright 
1215c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1216c8564c30SJames Wright **/
1217c8564c30SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext ctx) {
1218c8564c30SJames Wright   PetscFunctionBeginUser;
1219c8564c30SJames Wright   if (!ctx || --ctx->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
1220c8564c30SJames Wright 
1221c8564c30SJames Wright   // PETSc objects
1222c8564c30SJames Wright   PetscCall(DMDestroy(&ctx->dm_x));
1223c8564c30SJames Wright   PetscCall(DMDestroy(&ctx->dm_y));
1224c8564c30SJames Wright   PetscCall(VecDestroy(&ctx->X_loc));
1225c8564c30SJames Wright   PetscCall(VecDestroy(&ctx->Y_loc_transpose));
1226c8564c30SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
1227c8564c30SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
1228*5037d55dSJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
1229c8564c30SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_full));
1230c8564c30SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_pbd));
1231c8564c30SJames Wright 
1232c8564c30SJames Wright   // libCEED objects
123354831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->x_loc));
123454831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->y_loc));
123554831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_full));
123654831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_pbd));
123754831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult));
123854831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult_transpose));
1239c8564c30SJames Wright   PetscCheck(CeedDestroy(&ctx->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
1240c8564c30SJames Wright 
1241c8564c30SJames Wright   // Deallocate
1242c8564c30SJames Wright   ctx->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
1243c8564c30SJames Wright   PetscCall(PetscFree(ctx));
1244c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1245c8564c30SJames Wright }
1246c8564c30SJames Wright 
1247c8564c30SJames Wright /**
1248c8564c30SJames Wright   @brief Compute the diagonal of an operator via libCEED.
1249c8564c30SJames Wright 
1250c8564c30SJames Wright   Collective across MPI processes.
1251c8564c30SJames Wright 
1252c8564c30SJames Wright   @param[in]   A  `MATCEED`
1253c8564c30SJames Wright   @param[out]  D  Vector holding operator diagonal
1254c8564c30SJames Wright 
1255c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1256c8564c30SJames Wright **/
1257c8564c30SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
1258c8564c30SJames Wright   PetscMemType   mem_type;
1259c8564c30SJames Wright   Vec            D_loc;
1260c8564c30SJames Wright   MatCeedContext ctx;
1261c8564c30SJames Wright 
1262c8564c30SJames Wright   PetscFunctionBeginUser;
1263c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1264c8564c30SJames Wright 
1265c8564c30SJames Wright   // Place PETSc vector in libCEED vector
1266c8564c30SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1267d0593705SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
1268c8564c30SJames Wright 
1269c8564c30SJames Wright   // Compute Diagonal
127054831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1271c8564c30SJames Wright 
1272c8564c30SJames Wright   // Restore PETSc vector
1273d0593705SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
1274c8564c30SJames Wright 
1275c8564c30SJames Wright   // Local-to-Global
1276c8564c30SJames Wright   PetscCall(VecZeroEntries(D));
1277c8564c30SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
1278c8564c30SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1279c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1280c8564c30SJames Wright }
1281c8564c30SJames Wright 
1282c8564c30SJames Wright /**
1283c8564c30SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
1284c8564c30SJames Wright 
1285c8564c30SJames Wright   Collective across MPI processes.
1286c8564c30SJames Wright 
1287c8564c30SJames Wright   @param[in]   A  `MATCEED`
1288c8564c30SJames Wright   @param[in]   X  Input PETSc vector
1289c8564c30SJames Wright   @param[out]  Y  Output PETSc vector
1290c8564c30SJames Wright 
1291c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1292c8564c30SJames Wright **/
1293c8564c30SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
1294c8564c30SJames Wright   MatCeedContext ctx;
1295c8564c30SJames Wright 
1296c8564c30SJames Wright   PetscFunctionBeginUser;
1297c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1298c8564c30SJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, 0));
1299c8564c30SJames Wright 
1300c8564c30SJames Wright   {
1301c8564c30SJames Wright     PetscMemType x_mem_type, y_mem_type;
1302c8564c30SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
1303c8564c30SJames Wright 
1304c8564c30SJames Wright     // Get local vectors
1305c8564c30SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
1306c8564c30SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
1307c8564c30SJames Wright 
1308c8564c30SJames Wright     // Global-to-local
1309c8564c30SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
1310c8564c30SJames Wright 
1311c8564c30SJames Wright     // Setup libCEED vectors
1312d0593705SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
1313c8564c30SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1314d0593705SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
1315c8564c30SJames Wright 
1316c8564c30SJames Wright     // Apply libCEED operator
1317c8564c30SJames Wright     PetscCall(PetscLogGpuTimeBegin());
131854831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
1319c8564c30SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1320c8564c30SJames Wright 
1321c8564c30SJames Wright     // Restore PETSc vectors
1322d0593705SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1323d0593705SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1324c8564c30SJames Wright 
1325c8564c30SJames Wright     // Local-to-global
1326c8564c30SJames Wright     PetscCall(VecZeroEntries(Y));
1327c8564c30SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
1328c8564c30SJames Wright 
1329c8564c30SJames Wright     // Restore local vectors, as needed
1330c8564c30SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
1331c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
1332c8564c30SJames Wright   }
1333c8564c30SJames Wright 
1334c8564c30SJames Wright   // Log flops
1335c8564c30SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
1336c8564c30SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult));
1337c8564c30SJames Wright 
1338c8564c30SJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, 0));
1339c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1340c8564c30SJames Wright }
1341c8564c30SJames Wright 
1342c8564c30SJames Wright /**
1343c8564c30SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
1344c8564c30SJames Wright 
1345c8564c30SJames Wright   Collective across MPI processes.
1346c8564c30SJames Wright 
1347c8564c30SJames Wright   @param[in]   A  `MATCEED`
1348c8564c30SJames Wright   @param[in]   Y  Input PETSc vector
1349c8564c30SJames Wright   @param[out]  X  Output PETSc vector
1350c8564c30SJames Wright 
1351c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1352c8564c30SJames Wright **/
1353c8564c30SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
1354c8564c30SJames Wright   MatCeedContext ctx;
1355c8564c30SJames Wright 
1356c8564c30SJames Wright   PetscFunctionBeginUser;
1357c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1358c8564c30SJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, 0));
1359c8564c30SJames Wright 
1360c8564c30SJames Wright   {
1361c8564c30SJames Wright     PetscMemType x_mem_type, y_mem_type;
1362c8564c30SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
1363c8564c30SJames Wright 
1364c8564c30SJames Wright     // Get local vectors
1365c8564c30SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
1366c8564c30SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
1367c8564c30SJames Wright 
1368c8564c30SJames Wright     // Global-to-local
1369c8564c30SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
1370c8564c30SJames Wright 
1371c8564c30SJames Wright     // Setup libCEED vectors
1372d0593705SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
1373c8564c30SJames Wright     PetscCall(VecZeroEntries(X_loc));
1374d0593705SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
1375c8564c30SJames Wright 
1376c8564c30SJames Wright     // Apply libCEED operator
1377c8564c30SJames Wright     PetscCall(PetscLogGpuTimeBegin());
137854831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1379c8564c30SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1380c8564c30SJames Wright 
1381c8564c30SJames Wright     // Restore PETSc vectors
1382d0593705SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1383d0593705SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1384c8564c30SJames Wright 
1385c8564c30SJames Wright     // Local-to-global
1386c8564c30SJames Wright     PetscCall(VecZeroEntries(X));
1387c8564c30SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
1388c8564c30SJames Wright 
1389c8564c30SJames Wright     // Restore local vectors, as needed
1390c8564c30SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
1391c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
1392c8564c30SJames Wright   }
1393c8564c30SJames Wright 
1394c8564c30SJames Wright   // Log flops
1395c8564c30SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
1396c8564c30SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
1397c8564c30SJames Wright 
1398c8564c30SJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, 0));
1399c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1400c8564c30SJames Wright }
1401