xref: /libCEED/examples/fluids/src/mat-ceed.c (revision 43327b86957a0a83ddc40b554a65a2ea63a53aee)
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;
15*43327b86SJames Wright PetscLogEvent MATCEED_MULT, MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE, MATCEED_MULT_TRANSPOSE_CEEDOP, MATCEED_ASSEMBLE_DIAGONAL,
16*43327b86SJames Wright     MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, MATCEED_SETUP_PBDIAGONAL, MATCEED_SETUP_PBDIAGONAL_CEEDOP, MATCEED_ASSEMBLE_PBDIAGONAL,
17*43327b86SJames Wright     MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, MATCEED_SETUP_FULL, MATCEED_SETUP_FULL_CEEDOP, MATCEED_ASSEMBLE_FULL, MATCEED_ASSEMBLE_FULL_CEEDOP;
18c8564c30SJames Wright 
19c8564c30SJames Wright /**
20c8564c30SJames Wright   @brief Register MATCEED log events.
21c8564c30SJames Wright 
22c8564c30SJames Wright   Not collective across MPI processes.
23c8564c30SJames Wright 
24c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
25c8564c30SJames Wright **/
26c8564c30SJames Wright static PetscErrorCode MatCeedRegisterLogEvents() {
275037d55dSJames Wright   static PetscBool registered = PETSC_FALSE;
28c8564c30SJames Wright 
29c8564c30SJames Wright   PetscFunctionBeginUser;
30c8564c30SJames Wright   if (registered) PetscFunctionReturn(PETSC_SUCCESS);
31*43327b86SJames Wright   PetscCall(PetscClassIdRegister("MatCEED", &MATCEED_CLASSID));
32*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMul", MATCEED_CLASSID, &MATCEED_MULT));
33*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulCeed", MATCEED_CLASSID, &MATCEED_MULT_CEEDOP));
34*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulT", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE));
35*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulTCeed", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE_CEEDOP));
36*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmDiag", MATCEED_CLASSID, &MATCEED_ASSEMBLE_DIAGONAL));
37*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSU", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL));
38*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL_CEEDOP));
39*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBD", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL));
40*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP));
41*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSU", MATCEED_CLASSID, &MATCEED_SETUP_FULL));
42*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_FULL_CEEDOP));
43*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsm", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL));
44*43327b86SJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL_CEEDOP));
455037d55dSJames Wright   registered = PETSC_TRUE;
46c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
47c8564c30SJames Wright }
48c8564c30SJames Wright 
49c8564c30SJames Wright /**
50c8564c30SJames Wright   @brief Assemble the point block diagonal of a `MATCEED` into a `MATAIJ` or similar.
51c8564c30SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
52c8564c30SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
53c8564c30SJames Wright 
54c8564c30SJames Wright   Collective across MPI processes.
55c8564c30SJames Wright 
56c8564c30SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
57c8564c30SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
58c8564c30SJames Wright 
59c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
60c8564c30SJames Wright **/
61c8564c30SJames Wright static PetscErrorCode MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed, Mat mat_coo) {
62c8564c30SJames Wright   MatCeedContext ctx;
63c8564c30SJames Wright 
64c8564c30SJames Wright   PetscFunctionBeginUser;
65c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
66c8564c30SJames Wright 
67c8564c30SJames Wright   // Check if COO pattern set
68c8564c30SJames Wright   {
69c8564c30SJames Wright     PetscInt index = -1;
70c8564c30SJames Wright 
71c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
72c8564c30SJames Wright       if (ctx->mats_assembled_pbd[i] == mat_coo) index = i;
73c8564c30SJames Wright     }
74c8564c30SJames Wright     if (index == -1) {
75c8564c30SJames Wright       PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
76c8564c30SJames Wright       CeedInt      *rows_ceed, *cols_ceed;
77c8564c30SJames Wright       PetscCount    num_entries;
78c8564c30SJames Wright       PetscLogStage stage_amg_setup;
79c8564c30SJames Wright 
80c8564c30SJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
81*43327b86SJames Wright       PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
82c8564c30SJames Wright       if (stage_amg_setup == -1) {
83*43327b86SJames Wright         PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
84c8564c30SJames Wright       }
85c8564c30SJames Wright       PetscCall(PetscLogStagePush(stage_amg_setup));
86*43327b86SJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
87*43327b86SJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
8854831c5fSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
89*43327b86SJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
90d0593705SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
91d0593705SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
92c8564c30SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
93c8564c30SJames Wright       free(rows_petsc);
94c8564c30SJames Wright       free(cols_petsc);
9554831c5fSJames Wright       if (!ctx->coo_values_pbd) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_pbd));
96c8564c30SJames Wright       PetscCall(PetscRealloc(++ctx->num_mats_assembled_pbd * sizeof(Mat), &ctx->mats_assembled_pbd));
97c8564c30SJames Wright       ctx->mats_assembled_pbd[ctx->num_mats_assembled_pbd - 1] = mat_coo;
98*43327b86SJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
99c8564c30SJames Wright       PetscCall(PetscLogStagePop());
100c8564c30SJames Wright     }
101c8564c30SJames Wright   }
102c8564c30SJames Wright 
103c8564c30SJames Wright   // Assemble mat_ceed
104*43327b86SJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
105c8564c30SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
106c8564c30SJames Wright   {
107c8564c30SJames Wright     const CeedScalar *values;
108c8564c30SJames Wright     MatType           mat_type;
109c8564c30SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
110c8564c30SJames Wright     PetscBool         is_spd, is_spd_known;
111c8564c30SJames Wright 
112c8564c30SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
113c8564c30SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
114c8564c30SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
115c8564c30SJames Wright     else mem_type = CEED_MEM_HOST;
116c8564c30SJames Wright 
117*43327b86SJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
11854831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonal(ctx->op_mult, ctx->coo_values_pbd, CEED_REQUEST_IMMEDIATE));
119*43327b86SJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12054831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_pbd, mem_type, &values));
121c8564c30SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
122c8564c30SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
123c8564c30SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
12454831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_pbd, &values));
125c8564c30SJames Wright   }
126c8564c30SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
127*43327b86SJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
128c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
129c8564c30SJames Wright }
130c8564c30SJames Wright 
131c8564c30SJames Wright /**
132c8564c30SJames Wright   @brief Assemble inner `Mat` for diagonal `PC` operations
133c8564c30SJames Wright 
134c8564c30SJames Wright   Collective across MPI processes.
135c8564c30SJames Wright 
136c8564c30SJames Wright   @param[in]   mat_ceed      `MATCEED` to invert
137c8564c30SJames Wright   @param[in]   use_ceed_pbd  Boolean flag to use libCEED PBD assembly
138c8564c30SJames Wright   @param[out]  mat_inner     Inner `Mat` for diagonal operations
139c8564c30SJames Wright 
140c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
141c8564c30SJames Wright **/
142c8564c30SJames Wright static PetscErrorCode MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed, PetscBool use_ceed_pbd, Mat *mat_inner) {
143c8564c30SJames Wright   MatCeedContext ctx;
144c8564c30SJames Wright 
145c8564c30SJames Wright   PetscFunctionBeginUser;
146c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
147c8564c30SJames Wright   if (use_ceed_pbd) {
148c8564c30SJames Wright     // Check if COO pattern set
1495037d55dSJames Wright     if (!ctx->mat_assembled_pbd_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_pbd_internal));
150c8564c30SJames Wright 
151c8564c30SJames Wright     // Assemble mat_assembled_full_internal
152c8564c30SJames Wright     PetscCall(MatCeedAssemblePointBlockDiagonalCOO(mat_ceed, ctx->mat_assembled_pbd_internal));
153c8564c30SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_pbd_internal;
154c8564c30SJames Wright   } else {
155c8564c30SJames Wright     // Check if COO pattern set
1565037d55dSJames Wright     if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
157c8564c30SJames Wright 
158c8564c30SJames Wright     // Assemble mat_assembled_full_internal
159c8564c30SJames Wright     PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
160c8564c30SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_full_internal;
161c8564c30SJames Wright   }
162c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
163c8564c30SJames Wright }
164c8564c30SJames Wright 
165c8564c30SJames Wright /**
166c8564c30SJames Wright   @brief Get `MATCEED` diagonal block for Jacobi.
167c8564c30SJames Wright 
168c8564c30SJames Wright   Collective across MPI processes.
169c8564c30SJames Wright 
170c8564c30SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
171c8564c30SJames Wright   @param[out]  mat_block  The diagonal block matrix
172c8564c30SJames Wright 
173c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
174c8564c30SJames Wright **/
175c8564c30SJames Wright static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) {
176c8564c30SJames Wright   Mat            mat_inner = NULL;
177c8564c30SJames Wright   MatCeedContext ctx;
178c8564c30SJames Wright 
179c8564c30SJames Wright   PetscFunctionBeginUser;
180c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
181c8564c30SJames Wright 
182c8564c30SJames Wright   // Assemble inner mat if needed
183c8564c30SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
184c8564c30SJames Wright 
185c8564c30SJames Wright   // Get block diagonal
186c8564c30SJames Wright   PetscCall(MatGetDiagonalBlock(mat_inner, mat_block));
187c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
188c8564c30SJames Wright }
189c8564c30SJames Wright 
190c8564c30SJames Wright /**
191c8564c30SJames Wright   @brief Invert `MATCEED` diagonal block for Jacobi.
192c8564c30SJames Wright 
193c8564c30SJames Wright   Collective across MPI processes.
194c8564c30SJames Wright 
195c8564c30SJames Wright   @param[in]   mat_ceed  `MATCEED` to invert
196c8564c30SJames Wright   @param[out]  values    The block inverses in column major order
197c8564c30SJames Wright 
198c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
199c8564c30SJames Wright **/
200c8564c30SJames Wright static PetscErrorCode MatInvertBlockDiagonal_Ceed(Mat mat_ceed, const PetscScalar **values) {
201c8564c30SJames Wright   Mat            mat_inner = NULL;
202c8564c30SJames Wright   MatCeedContext ctx;
203c8564c30SJames Wright 
204c8564c30SJames Wright   PetscFunctionBeginUser;
205c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
206c8564c30SJames Wright 
207c8564c30SJames Wright   // Assemble inner mat if needed
208c8564c30SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
209c8564c30SJames Wright 
210c8564c30SJames Wright   // Invert PB diagonal
211c8564c30SJames Wright   PetscCall(MatInvertBlockDiagonal(mat_inner, values));
212c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
213c8564c30SJames Wright }
214c8564c30SJames Wright 
215c8564c30SJames Wright /**
216c8564c30SJames Wright   @brief Invert `MATCEED` variable diagonal block for Jacobi.
217c8564c30SJames Wright 
218c8564c30SJames Wright   Collective across MPI processes.
219c8564c30SJames Wright 
220c8564c30SJames Wright   @param[in]   mat_ceed     `MATCEED` to invert
221c8564c30SJames Wright   @param[in]   num_blocks   The number of blocks on the process
222c8564c30SJames Wright   @param[in]   block_sizes  The size of each block on the process
223c8564c30SJames Wright   @param[out]  values       The block inverses in column major order
224c8564c30SJames Wright 
225c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
226c8564c30SJames Wright **/
227c8564c30SJames Wright static PetscErrorCode MatInvertVariableBlockDiagonal_Ceed(Mat mat_ceed, PetscInt num_blocks, const PetscInt *block_sizes, PetscScalar *values) {
228c8564c30SJames Wright   Mat            mat_inner = NULL;
229c8564c30SJames Wright   MatCeedContext ctx;
230c8564c30SJames Wright 
231c8564c30SJames Wright   PetscFunctionBeginUser;
232c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
233c8564c30SJames Wright 
234c8564c30SJames Wright   // Assemble inner mat if needed
235c8564c30SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, &mat_inner));
236c8564c30SJames Wright 
237c8564c30SJames Wright   // Invert PB diagonal
238c8564c30SJames Wright   PetscCall(MatInvertVariableBlockDiagonal(mat_inner, num_blocks, block_sizes, values));
239c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
240c8564c30SJames Wright }
241c8564c30SJames Wright 
2423933d9a0SJames Wright /**
2433933d9a0SJames Wright   @brief View `MATCEED`.
2443933d9a0SJames Wright 
2453933d9a0SJames Wright   Collective across MPI processes.
2463933d9a0SJames Wright 
2473933d9a0SJames Wright   @param[in]   mat_ceed  `MATCEED` to view
2483933d9a0SJames Wright   @param[in]   viewer    The visualization context
2493933d9a0SJames Wright 
2503933d9a0SJames Wright   @return An error code: 0 - success, otherwise - failure
2513933d9a0SJames Wright **/
2523933d9a0SJames Wright static PetscErrorCode MatView_Ceed(Mat mat_ceed, PetscViewer viewer) {
2533933d9a0SJames Wright   PetscBool         is_ascii;
2543933d9a0SJames Wright   PetscViewerFormat format;
2553933d9a0SJames Wright   PetscMPIInt       size;
2563933d9a0SJames Wright   MatCeedContext    ctx;
2573933d9a0SJames Wright 
2583933d9a0SJames Wright   PetscFunctionBeginUser;
2593933d9a0SJames Wright   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2603933d9a0SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
2613933d9a0SJames Wright   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat_ceed), &viewer));
2623933d9a0SJames Wright 
2633933d9a0SJames Wright   PetscCall(PetscViewerGetFormat(viewer, &format));
2643933d9a0SJames Wright   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat_ceed), &size));
2653933d9a0SJames Wright   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
2663933d9a0SJames Wright 
2673933d9a0SJames Wright   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii));
2683933d9a0SJames Wright   {
2693933d9a0SJames Wright     FILE *file;
2703933d9a0SJames Wright 
2715037d55dSJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n  Default COO MatType:%s\n", ctx->coo_mat_type));
2723933d9a0SJames Wright     PetscCall(PetscViewerASCIIGetPointer(viewer, &file));
2733933d9a0SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, " libCEED Operator:\n"));
2743933d9a0SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file));
2753933d9a0SJames Wright     if (ctx->op_mult_transpose) {
2763933d9a0SJames Wright       PetscCall(PetscViewerASCIIPrintf(viewer, "  libCEED Transpose Operator:\n"));
2773933d9a0SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file));
2783933d9a0SJames Wright     }
2793933d9a0SJames Wright   }
2803933d9a0SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
2813933d9a0SJames Wright }
2823933d9a0SJames Wright 
283c8564c30SJames Wright // -----------------------------------------------------------------------------
284c8564c30SJames Wright // MatCeed
285c8564c30SJames Wright // -----------------------------------------------------------------------------
286c8564c30SJames Wright 
287c8564c30SJames Wright /**
288c8564c30SJames Wright   @brief Create PETSc `Mat` from libCEED operators.
289c8564c30SJames Wright 
290c8564c30SJames Wright   Collective across MPI processes.
291c8564c30SJames Wright 
292c8564c30SJames Wright   @param[in]   dm_x                      Input `DM`
293c8564c30SJames Wright   @param[in]   dm_y                      Output `DM`
294c8564c30SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
295c8564c30SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
296c8564c30SJames Wright   @param[out]  mat                        New MatCeed
297c8564c30SJames Wright 
298c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
299c8564c30SJames Wright **/
300c8564c30SJames Wright PetscErrorCode MatCeedCreate(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) {
301c8564c30SJames Wright   PetscInt       X_l_size, X_g_size, Y_l_size, Y_g_size;
302c8564c30SJames Wright   VecType        vec_type;
303c8564c30SJames Wright   MatCeedContext ctx;
304c8564c30SJames Wright 
305c8564c30SJames Wright   PetscFunctionBeginUser;
306c8564c30SJames Wright   PetscCall(MatCeedRegisterLogEvents());
307c8564c30SJames Wright 
308c8564c30SJames Wright   // Collect context data
309c8564c30SJames Wright   PetscCall(DMGetVecType(dm_x, &vec_type));
310c8564c30SJames Wright   {
311c8564c30SJames Wright     Vec X;
312c8564c30SJames Wright 
313c8564c30SJames Wright     PetscCall(DMGetGlobalVector(dm_x, &X));
314c8564c30SJames Wright     PetscCall(VecGetSize(X, &X_g_size));
315c8564c30SJames Wright     PetscCall(VecGetLocalSize(X, &X_l_size));
316c8564c30SJames Wright     PetscCall(DMRestoreGlobalVector(dm_x, &X));
317c8564c30SJames Wright   }
318c8564c30SJames Wright   if (dm_y) {
319c8564c30SJames Wright     Vec Y;
320c8564c30SJames Wright 
321c8564c30SJames Wright     PetscCall(DMGetGlobalVector(dm_y, &Y));
322c8564c30SJames Wright     PetscCall(VecGetSize(Y, &Y_g_size));
323c8564c30SJames Wright     PetscCall(VecGetLocalSize(Y, &Y_l_size));
324c8564c30SJames Wright     PetscCall(DMRestoreGlobalVector(dm_y, &Y));
325c8564c30SJames Wright   } else {
326c8564c30SJames Wright     dm_y     = dm_x;
327c8564c30SJames Wright     Y_g_size = X_g_size;
328c8564c30SJames Wright     Y_l_size = X_l_size;
329c8564c30SJames Wright   }
3305037d55dSJames Wright 
331c8564c30SJames Wright   // Create context
332c8564c30SJames Wright   {
333c8564c30SJames Wright     Vec X_loc, Y_loc_transpose = NULL;
334c8564c30SJames Wright 
335c8564c30SJames Wright     PetscCall(DMCreateLocalVector(dm_x, &X_loc));
336c8564c30SJames Wright     PetscCall(VecZeroEntries(X_loc));
337c8564c30SJames Wright     if (op_mult_transpose) {
338c8564c30SJames Wright       PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose));
339c8564c30SJames Wright       PetscCall(VecZeroEntries(Y_loc_transpose));
340c8564c30SJames Wright     }
341*43327b86SJames Wright     PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE,
342*43327b86SJames Wright                                    MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE_CEEDOP, &ctx));
343c8564c30SJames Wright     PetscCall(VecDestroy(&X_loc));
344c8564c30SJames Wright     PetscCall(VecDestroy(&Y_loc_transpose));
345c8564c30SJames Wright   }
346c8564c30SJames Wright 
347c8564c30SJames Wright   // Create mat
348c8564c30SJames Wright   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat));
349c8564c30SJames Wright   PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED));
350c8564c30SJames Wright   // -- Set block and variable block sizes
351c8564c30SJames Wright   if (dm_x == dm_y) {
352c8564c30SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
353c8564c30SJames Wright     Mat     temp_mat;
354c8564c30SJames Wright 
355c8564c30SJames Wright     PetscCall(DMGetMatType(dm_x, &dm_mat_type));
356c8564c30SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
357c8564c30SJames Wright     PetscCall(DMSetMatType(dm_x, MATAIJ));
358c8564c30SJames Wright     PetscCall(DMCreateMatrix(dm_x, &temp_mat));
359c8564c30SJames Wright     PetscCall(DMSetMatType(dm_x, dm_mat_type_copy));
360c8564c30SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
361c8564c30SJames Wright 
362c8564c30SJames Wright     {
363c8564c30SJames Wright       PetscInt        block_size, num_blocks, max_vblock_size = PETSC_INT_MAX;
364c8564c30SJames Wright       const PetscInt *vblock_sizes;
365c8564c30SJames Wright 
366c8564c30SJames Wright       // -- Get block sizes
367c8564c30SJames Wright       PetscCall(MatGetBlockSize(temp_mat, &block_size));
368c8564c30SJames Wright       PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes));
369c8564c30SJames Wright       {
370c8564c30SJames Wright         PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX};
371c8564c30SJames Wright 
372c8564c30SJames Wright         for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]);
373c8564c30SJames Wright         PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max));
374c8564c30SJames Wright         max_vblock_size = global_min_max[1];
375c8564c30SJames Wright       }
376c8564c30SJames Wright 
377c8564c30SJames Wright       // -- Copy block sizes
378c8564c30SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size));
379c8564c30SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes));
380c8564c30SJames Wright 
381c8564c30SJames Wright       // -- Check libCEED compatibility
382c8564c30SJames Wright       {
383c8564c30SJames Wright         bool is_composite;
384c8564c30SJames Wright 
385c8564c30SJames Wright         ctx->is_ceed_pbd_valid  = PETSC_TRUE;
386c8564c30SJames Wright         ctx->is_ceed_vpbd_valid = PETSC_TRUE;
38754831c5fSJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite));
388c8564c30SJames Wright         if (is_composite) {
389c8564c30SJames Wright           CeedInt       num_sub_operators;
390c8564c30SJames Wright           CeedOperator *sub_operators;
391c8564c30SJames Wright 
39254831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetNumSub(op_mult, &num_sub_operators));
39354831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetSubList(op_mult, &sub_operators));
394c8564c30SJames Wright           for (CeedInt i = 0; i < num_sub_operators; i++) {
395c8564c30SJames Wright             CeedInt                  num_bases, num_comp;
396c8564c30SJames Wright             CeedBasis               *active_bases;
397c8564c30SJames Wright             CeedOperatorAssemblyData assembly_data;
398c8564c30SJames Wright 
39954831c5fSJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data));
40054831c5fSJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
40154831c5fSJames Wright             PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
402c8564c30SJames Wright             if (num_bases > 1) {
403c8564c30SJames Wright               ctx->is_ceed_pbd_valid  = PETSC_FALSE;
404c8564c30SJames Wright               ctx->is_ceed_vpbd_valid = PETSC_FALSE;
405c8564c30SJames Wright             }
406c8564c30SJames Wright             if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
407c8564c30SJames Wright             if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
408c8564c30SJames Wright           }
409c8564c30SJames Wright         } else {
410c8564c30SJames Wright           // LCOV_EXCL_START
411c8564c30SJames Wright           CeedInt                  num_bases, num_comp;
412c8564c30SJames Wright           CeedBasis               *active_bases;
413c8564c30SJames Wright           CeedOperatorAssemblyData assembly_data;
414c8564c30SJames Wright 
41554831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data));
41654831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
41754831c5fSJames Wright           PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
418c8564c30SJames Wright           if (num_bases > 1) {
419c8564c30SJames Wright             ctx->is_ceed_pbd_valid  = PETSC_FALSE;
420c8564c30SJames Wright             ctx->is_ceed_vpbd_valid = PETSC_FALSE;
421c8564c30SJames Wright           }
422c8564c30SJames Wright           if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
423c8564c30SJames Wright           if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
424c8564c30SJames Wright           // LCOV_EXCL_STOP
425c8564c30SJames Wright         }
426c8564c30SJames Wright         {
427c8564c30SJames Wright           PetscInt local_is_valid[2], global_is_valid[2];
428c8564c30SJames Wright 
429c8564c30SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid;
430c8564c30SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
431c8564c30SJames Wright           ctx->is_ceed_pbd_valid = global_is_valid[0];
432c8564c30SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid;
433c8564c30SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
434c8564c30SJames Wright           ctx->is_ceed_vpbd_valid = global_is_valid[0];
435c8564c30SJames Wright         }
436c8564c30SJames Wright       }
437c8564c30SJames Wright     }
438c8564c30SJames Wright     PetscCall(MatDestroy(&temp_mat));
439c8564c30SJames Wright   }
440c8564c30SJames Wright   // -- Set internal mat type
441c8564c30SJames Wright   {
442c8564c30SJames Wright     VecType vec_type;
4435037d55dSJames Wright     MatType coo_mat_type;
444c8564c30SJames Wright 
445c8564c30SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
4465037d55dSJames Wright     if (strstr(vec_type, VECCUDA)) coo_mat_type = MATAIJCUSPARSE;
4475037d55dSJames Wright     else if (strstr(vec_type, VECKOKKOS)) coo_mat_type = MATAIJKOKKOS;
4485037d55dSJames Wright     else coo_mat_type = MATAIJ;
4495037d55dSJames Wright     PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type));
450c8564c30SJames Wright   }
451c8564c30SJames Wright   // -- Set mat operations
452c8564c30SJames Wright   PetscCall(MatShellSetContextDestroy(*mat, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
4533933d9a0SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (void (*)(void))MatView_Ceed));
454c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (void (*)(void))MatMult_Ceed));
455c8564c30SJames Wright   if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
456c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
457c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
458c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
459c8564c30SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
460c8564c30SJames Wright   PetscCall(MatShellSetVecType(*mat, vec_type));
461c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
462c8564c30SJames Wright }
463c8564c30SJames Wright 
464c8564c30SJames Wright /**
465c8564c30SJames Wright   @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`.
466c8564c30SJames Wright 
467c8564c30SJames Wright   Collective across MPI processes.
468c8564c30SJames Wright 
469c8564c30SJames Wright   @param[in]   mat_ceed   `MATCEED` to copy from
470c8564c30SJames Wright   @param[out]  mat_other  `MatShell` or `MATCEED` to copy into
471c8564c30SJames Wright 
472c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
473c8564c30SJames Wright **/
474c8564c30SJames Wright PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) {
475c8564c30SJames Wright   PetscFunctionBeginUser;
476c8564c30SJames Wright   PetscCall(MatCeedRegisterLogEvents());
477c8564c30SJames Wright 
478c8564c30SJames Wright   // Check type compatibility
479c8564c30SJames Wright   {
4805037d55dSJames Wright     PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE;
481c8564c30SJames Wright     MatType   mat_type_ceed, mat_type_other;
482c8564c30SJames Wright 
483c8564c30SJames Wright     PetscCall(MatGetType(mat_ceed, &mat_type_ceed));
4845037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
4855037d55dSJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
4865037d55dSJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
4875037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
4885037d55dSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matceed));
4895037d55dSJames Wright     PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL);
490c8564c30SJames Wright   }
491c8564c30SJames Wright 
492c8564c30SJames Wright   // Check dimension compatibility
493c8564c30SJames Wright   {
494c8564c30SJames 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;
495c8564c30SJames Wright 
496c8564c30SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size));
497c8564c30SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size));
498c8564c30SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size));
499c8564c30SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size));
500c8564c30SJames 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) &&
501c8564c30SJames Wright                    (X_l_ceed_size == X_l_other_size),
502c8564c30SJames Wright                PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
503c8564c30SJames Wright                "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT
504c8564c30SJames Wright                "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT
505c8564c30SJames Wright                ", %" PetscInt_FMT ")",
506c8564c30SJames 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);
507c8564c30SJames Wright   }
508c8564c30SJames Wright 
509c8564c30SJames Wright   // Convert
510c8564c30SJames Wright   {
511c8564c30SJames Wright     VecType        vec_type;
512c8564c30SJames Wright     MatCeedContext ctx;
513c8564c30SJames Wright 
514c8564c30SJames Wright     PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED));
515c8564c30SJames Wright     PetscCall(MatShellGetContext(mat_ceed, &ctx));
516c8564c30SJames Wright     PetscCall(MatCeedContextReference(ctx));
517c8564c30SJames Wright     PetscCall(MatShellSetContext(mat_other, ctx));
518c8564c30SJames Wright     PetscCall(MatShellSetContextDestroy(mat_other, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
5193933d9a0SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (void (*)(void))MatView_Ceed));
520c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (void (*)(void))MatMult_Ceed));
521c8564c30SJames Wright     if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
522c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
523c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
524c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
525c8564c30SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
526c8564c30SJames Wright     {
527c8564c30SJames Wright       PetscInt block_size;
528c8564c30SJames Wright 
529c8564c30SJames Wright       PetscCall(MatGetBlockSize(mat_ceed, &block_size));
530c8564c30SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size));
531c8564c30SJames Wright     }
532c8564c30SJames Wright     {
533c8564c30SJames Wright       PetscInt        num_blocks;
534c8564c30SJames Wright       const PetscInt *block_sizes;
535c8564c30SJames Wright 
536c8564c30SJames Wright       PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes));
537c8564c30SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes));
538c8564c30SJames Wright     }
539c8564c30SJames Wright     PetscCall(DMGetVecType(ctx->dm_x, &vec_type));
540c8564c30SJames Wright     PetscCall(MatShellSetVecType(mat_other, vec_type));
541c8564c30SJames Wright   }
542c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
543c8564c30SJames Wright }
544c8564c30SJames Wright 
545c8564c30SJames Wright /**
5465037d55dSJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
5475037d55dSJames Wright 
5485037d55dSJames Wright   Collective across MPI processes.
5495037d55dSJames Wright 
5505037d55dSJames Wright   @param[in]   mat_ceed  `MATCEED`
5515037d55dSJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
5525037d55dSJames Wright 
5535037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
5545037d55dSJames Wright **/
5555037d55dSJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
5565037d55dSJames Wright   MatCeedContext ctx;
5575037d55dSJames Wright 
5585037d55dSJames Wright   PetscFunctionBeginUser;
5595037d55dSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
5605037d55dSJames Wright 
5615037d55dSJames 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");
5625037d55dSJames Wright 
5635037d55dSJames Wright   // Check cl mat type
5645037d55dSJames Wright   {
5655037d55dSJames Wright     PetscBool is_coo_mat_type_cl = PETSC_FALSE;
5665037d55dSJames Wright     char      coo_mat_type_cl[64];
5675037d55dSJames Wright 
5685037d55dSJames Wright     // Check for specific CL coo mat type for this Mat
5695037d55dSJames Wright     {
5705037d55dSJames Wright       const char *mat_ceed_prefix = NULL;
5715037d55dSJames Wright 
5725037d55dSJames Wright       PetscCall(MatGetOptionsPrefix(mat_ceed, &mat_ceed_prefix));
5735037d55dSJames Wright       PetscOptionsBegin(PetscObjectComm((PetscObject)mat_ceed), mat_ceed_prefix, "", NULL);
5745037d55dSJames Wright       PetscCall(PetscOptionsFList("-ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
5755037d55dSJames Wright                                   sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
5765037d55dSJames Wright       PetscOptionsEnd();
5775037d55dSJames Wright       if (is_coo_mat_type_cl) {
5785037d55dSJames Wright         PetscCall(PetscFree(ctx->coo_mat_type));
5795037d55dSJames Wright         PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
5805037d55dSJames Wright       }
5815037d55dSJames Wright     }
5825037d55dSJames Wright   }
5835037d55dSJames Wright 
5845037d55dSJames Wright   // Create sparse matrix
5855037d55dSJames Wright   {
5865037d55dSJames Wright     MatType dm_mat_type, dm_mat_type_copy;
5875037d55dSJames Wright 
5885037d55dSJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
5895037d55dSJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
5905037d55dSJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
5915037d55dSJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
5925037d55dSJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
5935037d55dSJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
5945037d55dSJames Wright   }
5955037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
5965037d55dSJames Wright }
5975037d55dSJames Wright 
5985037d55dSJames Wright /**
5995037d55dSJames Wright   @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar.
600c8564c30SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
601c8564c30SJames Wright 
602c8564c30SJames Wright   Collective across MPI processes.
603c8564c30SJames Wright 
604c8564c30SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
605c8564c30SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
606c8564c30SJames Wright 
607c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
608c8564c30SJames Wright **/
6095037d55dSJames Wright PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) {
610c8564c30SJames Wright   MatCeedContext ctx;
611c8564c30SJames Wright 
612c8564c30SJames Wright   PetscFunctionBeginUser;
613c8564c30SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
614c8564c30SJames Wright 
615c8564c30SJames Wright   {
616c8564c30SJames Wright     PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
617c8564c30SJames Wright     CeedInt      *rows_ceed, *cols_ceed;
618c8564c30SJames Wright     PetscCount    num_entries;
619c8564c30SJames Wright     PetscLogStage stage_amg_setup;
620c8564c30SJames Wright 
621c8564c30SJames Wright     // -- Assemble sparsity pattern if mat hasn't been assembled before
622*43327b86SJames Wright     PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
623c8564c30SJames Wright     if (stage_amg_setup == -1) {
624*43327b86SJames Wright       PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
625c8564c30SJames Wright     }
626c8564c30SJames Wright     PetscCall(PetscLogStagePush(stage_amg_setup));
627*43327b86SJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
628*43327b86SJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
62954831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
630*43327b86SJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
631d0593705SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
632d0593705SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
633c8564c30SJames Wright     PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
634c8564c30SJames Wright     free(rows_petsc);
635c8564c30SJames Wright     free(cols_petsc);
63654831c5fSJames Wright     if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full));
637c8564c30SJames Wright     PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full));
638c8564c30SJames Wright     ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo;
639*43327b86SJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
640c8564c30SJames Wright     PetscCall(PetscLogStagePop());
641c8564c30SJames Wright   }
6425037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
6435037d55dSJames Wright }
6445037d55dSJames Wright 
6455037d55dSJames Wright /**
6465037d55dSJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
6475037d55dSJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
6485037d55dSJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
6495037d55dSJames Wright 
6505037d55dSJames Wright   Collective across MPI processes.
6515037d55dSJames Wright 
6525037d55dSJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
6535037d55dSJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
6545037d55dSJames Wright 
6555037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
6565037d55dSJames Wright **/
6575037d55dSJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
6585037d55dSJames Wright   MatCeedContext ctx;
6595037d55dSJames Wright 
6605037d55dSJames Wright   PetscFunctionBeginUser;
6615037d55dSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
6625037d55dSJames Wright 
6635037d55dSJames Wright   // Set COO pattern if needed
6645037d55dSJames Wright   {
6655037d55dSJames Wright     CeedInt index = -1;
6665037d55dSJames Wright 
6675037d55dSJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
6685037d55dSJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
6695037d55dSJames Wright     }
6705037d55dSJames Wright     if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo));
671c8564c30SJames Wright   }
672c8564c30SJames Wright 
673c8564c30SJames Wright   // Assemble mat_ceed
674*43327b86SJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
675c8564c30SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
676c8564c30SJames Wright   {
677c8564c30SJames Wright     const CeedScalar *values;
678c8564c30SJames Wright     MatType           mat_type;
679c8564c30SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
680c8564c30SJames Wright     PetscBool         is_spd, is_spd_known;
681c8564c30SJames Wright 
682c8564c30SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
683c8564c30SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
684c8564c30SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
685c8564c30SJames Wright     else mem_type = CEED_MEM_HOST;
686c8564c30SJames Wright 
687*43327b86SJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
68854831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full));
689*43327b86SJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
69054831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values));
691c8564c30SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
692c8564c30SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
693c8564c30SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
69454831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values));
695c8564c30SJames Wright   }
696c8564c30SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
697*43327b86SJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
698c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
699c8564c30SJames Wright }
700c8564c30SJames Wright 
701c8564c30SJames Wright /**
7025037d55dSJames Wright   @brief Set the current value of a context field for a `MatCEED`.
7035037d55dSJames Wright 
7045037d55dSJames Wright   Not collective across MPI processes.
7055037d55dSJames Wright 
7065037d55dSJames Wright   @param[in,out]  mat    `MatCEED`
7075037d55dSJames Wright   @param[in]      name   Name of the context field
7085037d55dSJames Wright   @param[in]      value  New context field value
7095037d55dSJames Wright 
7105037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
7115037d55dSJames Wright **/
7125037d55dSJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
7135037d55dSJames Wright   PetscBool      was_updated = PETSC_FALSE;
7145037d55dSJames Wright   MatCeedContext ctx;
7155037d55dSJames Wright 
7165037d55dSJames Wright   PetscFunctionBeginUser;
7175037d55dSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
7185037d55dSJames Wright   {
7195037d55dSJames Wright     CeedContextFieldLabel label = NULL;
7205037d55dSJames Wright 
7215037d55dSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label));
7225037d55dSJames Wright     if (label) {
7235037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value));
7245037d55dSJames Wright       was_updated = PETSC_TRUE;
7255037d55dSJames Wright     }
7265037d55dSJames Wright     if (ctx->op_mult_transpose) {
7275037d55dSJames Wright       label = NULL;
7285037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
7295037d55dSJames Wright       if (label) {
7305037d55dSJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
7315037d55dSJames Wright         was_updated = PETSC_TRUE;
7325037d55dSJames Wright       }
7335037d55dSJames Wright     }
7345037d55dSJames Wright   }
7355037d55dSJames Wright   if (was_updated) {
7365037d55dSJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
7375037d55dSJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
7385037d55dSJames Wright   }
7395037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
7405037d55dSJames Wright }
7415037d55dSJames Wright 
7425037d55dSJames Wright /**
743f965f5c6SJames Wright   @brief Set the current `PetscReal` value of a context field for a `MatCEED`.
744f965f5c6SJames Wright 
745f965f5c6SJames Wright   Not collective across MPI processes.
746f965f5c6SJames Wright 
747f965f5c6SJames Wright   @param[in,out]  mat    `MatCEED`
748f965f5c6SJames Wright   @param[in]      name   Name of the context field
749f965f5c6SJames Wright   @param[in]      value  New context field value
750f965f5c6SJames Wright 
751f965f5c6SJames Wright   @return An error code: 0 - success, otherwise - failure
752f965f5c6SJames Wright **/
753f965f5c6SJames Wright PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) {
754f965f5c6SJames Wright   double value_double = value;
755f965f5c6SJames Wright 
756f965f5c6SJames Wright   PetscFunctionBeginUser;
757f965f5c6SJames Wright   PetscCall(MatCeedSetContextDouble(mat, name, value_double));
758f965f5c6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
759f965f5c6SJames Wright }
760f965f5c6SJames Wright 
761f965f5c6SJames Wright /**
7625037d55dSJames Wright   @brief Get the current value of a context field for a `MatCEED`.
7635037d55dSJames Wright 
7645037d55dSJames Wright   Not collective across MPI processes.
7655037d55dSJames Wright 
7665037d55dSJames Wright   @param[in]   mat    `MatCEED`
7675037d55dSJames Wright   @param[in]   name   Name of the context field
7685037d55dSJames Wright   @param[out]  value  Current context field value
7695037d55dSJames Wright 
7705037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
7715037d55dSJames Wright **/
7725037d55dSJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
7735037d55dSJames Wright   MatCeedContext ctx;
7745037d55dSJames Wright 
7755037d55dSJames Wright   PetscFunctionBeginUser;
7765037d55dSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
7775037d55dSJames Wright   {
7785037d55dSJames Wright     CeedContextFieldLabel label = NULL;
7795037d55dSJames Wright     CeedOperator          op    = ctx->op_mult;
7805037d55dSJames Wright 
7815037d55dSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
7825037d55dSJames Wright     if (!label && ctx->op_mult_transpose) {
7835037d55dSJames Wright       op = ctx->op_mult_transpose;
7845037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
7855037d55dSJames Wright     }
7865037d55dSJames Wright     if (label) {
7875037d55dSJames Wright       PetscSizeT    num_values;
7885037d55dSJames Wright       const double *values_ceed;
7895037d55dSJames Wright 
7905037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
7915037d55dSJames Wright       *value = values_ceed[0];
7925037d55dSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
7935037d55dSJames Wright     }
7945037d55dSJames Wright   }
7955037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
7965037d55dSJames Wright }
7975037d55dSJames Wright 
7985037d55dSJames Wright /**
799f965f5c6SJames Wright   @brief Get the current `PetscReal` value of a context field for a `MatCEED`.
800f965f5c6SJames Wright 
801f965f5c6SJames Wright   Not collective across MPI processes.
802f965f5c6SJames Wright 
803f965f5c6SJames Wright   @param[in]   mat    `MatCEED`
804f965f5c6SJames Wright   @param[in]   name   Name of the context field
805f965f5c6SJames Wright   @param[out]  value  Current context field value
806f965f5c6SJames Wright 
807f965f5c6SJames Wright   @return An error code: 0 - success, otherwise - failure
808f965f5c6SJames Wright **/
809f965f5c6SJames Wright PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) {
810f965f5c6SJames Wright   double value_double;
811f965f5c6SJames Wright 
812f965f5c6SJames Wright   PetscFunctionBeginUser;
813f965f5c6SJames Wright   PetscCall(MatCeedGetContextDouble(mat, name, &value_double));
814f965f5c6SJames Wright   *value = value_double;
815f965f5c6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
816f965f5c6SJames Wright }
817f965f5c6SJames Wright 
818f965f5c6SJames Wright /**
819c8564c30SJames Wright   @brief Set user context for a `MATCEED`.
820c8564c30SJames Wright 
821c8564c30SJames Wright   Collective across MPI processes.
822c8564c30SJames Wright 
823c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
824c8564c30SJames Wright   @param[in]      f    The context destroy function, or NULL
825c8564c30SJames Wright   @param[in]      ctx  User context, or NULL to unset
826c8564c30SJames Wright 
827c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
828c8564c30SJames Wright **/
829c8564c30SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscErrorCode (*f)(void *), void *ctx) {
830c8564c30SJames Wright   PetscContainer user_ctx = NULL;
831c8564c30SJames Wright 
832c8564c30SJames Wright   PetscFunctionBeginUser;
833c8564c30SJames Wright   if (ctx) {
834c8564c30SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
835c8564c30SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
836c8564c30SJames Wright     PetscCall(PetscContainerSetUserDestroy(user_ctx, f));
837c8564c30SJames Wright   }
838c8564c30SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
839c8564c30SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
840c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
841c8564c30SJames Wright }
842c8564c30SJames Wright 
843c8564c30SJames Wright /**
844c8564c30SJames Wright   @brief Retrieve the user context for a `MATCEED`.
845c8564c30SJames Wright 
846c8564c30SJames Wright   Collective across MPI processes.
847c8564c30SJames Wright 
848c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
849c8564c30SJames Wright   @param[in]      ctx  User context
850c8564c30SJames Wright 
851c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
852c8564c30SJames Wright **/
853c8564c30SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
854c8564c30SJames Wright   PetscContainer user_ctx;
855c8564c30SJames Wright 
856c8564c30SJames Wright   PetscFunctionBeginUser;
857c8564c30SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
858c8564c30SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
859c8564c30SJames Wright   else *(void **)ctx = NULL;
860c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
861c8564c30SJames Wright }
862c8564c30SJames Wright /**
8635037d55dSJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
8645037d55dSJames Wright 
8655037d55dSJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
8665037d55dSJames Wright `MatCeedSetContext()`.
867c8564c30SJames Wright 
868c8564c30SJames Wright   Collective across MPI processes.
869c8564c30SJames Wright 
870c8564c30SJames Wright   @param[in,out]  mat  `MATCEED`
8715037d55dSJames Wright   @param[in]      op   Name of the `MatOperation`
8725037d55dSJames Wright   @param[in]      g    Function that provides the operation
873c8564c30SJames Wright 
874c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
875c8564c30SJames Wright **/
8765037d55dSJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
8775037d55dSJames Wright   PetscFunctionBeginUser;
8785037d55dSJames Wright   PetscCall(MatShellSetOperation(mat, op, g));
8795037d55dSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
8805037d55dSJames Wright }
8815037d55dSJames Wright 
8825037d55dSJames Wright /**
8835037d55dSJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
8845037d55dSJames Wright 
8855037d55dSJames Wright   Collective across MPI processes.
8865037d55dSJames Wright 
8875037d55dSJames Wright   @param[in,out]  mat   `MATCEED`
8885037d55dSJames Wright   @param[in]      type  COO `MatType` to set
8895037d55dSJames Wright 
8905037d55dSJames Wright   @return An error code: 0 - success, otherwise - failure
8915037d55dSJames Wright **/
8925037d55dSJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
893c8564c30SJames Wright   MatCeedContext ctx;
894c8564c30SJames Wright 
895c8564c30SJames Wright   PetscFunctionBeginUser;
896c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
897c8564c30SJames Wright   // Check if same
898c8564c30SJames Wright   {
899c8564c30SJames Wright     size_t    len_old, len_new;
900c8564c30SJames Wright     PetscBool is_same = PETSC_FALSE;
901c8564c30SJames Wright 
9025037d55dSJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
903c8564c30SJames Wright     PetscCall(PetscStrlen(type, &len_new));
9045037d55dSJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
905c8564c30SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
906c8564c30SJames Wright   }
907c8564c30SJames Wright   // Clean up old mats in different format
908c8564c30SJames Wright   // LCOV_EXCL_START
909c8564c30SJames Wright   if (ctx->mat_assembled_full_internal) {
910c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
911c8564c30SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
912c8564c30SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
913c8564c30SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
914c8564c30SJames Wright         }
915c8564c30SJames Wright         ctx->num_mats_assembled_full--;
916c8564c30SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
917c8564c30SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
918c8564c30SJames Wright       }
919c8564c30SJames Wright     }
920c8564c30SJames Wright   }
921c8564c30SJames Wright   if (ctx->mat_assembled_pbd_internal) {
922c8564c30SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
923c8564c30SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
924c8564c30SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
925c8564c30SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
926c8564c30SJames Wright         }
927c8564c30SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
928c8564c30SJames Wright         ctx->num_mats_assembled_pbd--;
929c8564c30SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
930c8564c30SJames Wright       }
931c8564c30SJames Wright     }
932c8564c30SJames Wright   }
9335037d55dSJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
9345037d55dSJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
935c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
936c8564c30SJames Wright   // LCOV_EXCL_STOP
937c8564c30SJames Wright }
938c8564c30SJames Wright 
939c8564c30SJames Wright /**
9405037d55dSJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
941c8564c30SJames Wright 
942c8564c30SJames Wright   Collective across MPI processes.
943c8564c30SJames Wright 
944c8564c30SJames Wright   @param[in,out]  mat   `MATCEED`
9455037d55dSJames Wright   @param[in]      type  COO `MatType`
946c8564c30SJames Wright 
947c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
948c8564c30SJames Wright **/
9495037d55dSJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
950c8564c30SJames Wright   MatCeedContext ctx;
951c8564c30SJames Wright 
952c8564c30SJames Wright   PetscFunctionBeginUser;
953c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
9545037d55dSJames Wright   *type = ctx->coo_mat_type;
955c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
956c8564c30SJames Wright }
957c8564c30SJames Wright 
958c8564c30SJames Wright /**
959c8564c30SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
960c8564c30SJames Wright 
961c8564c30SJames Wright   Not collective across MPI processes.
962c8564c30SJames Wright 
963c8564c30SJames Wright   @param[in,out]  mat              `MATCEED`
964c8564c30SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
965c8564c30SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
966c8564c30SJames Wright 
967c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
968c8564c30SJames Wright **/
969c8564c30SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
970c8564c30SJames Wright   MatCeedContext ctx;
971c8564c30SJames Wright 
972c8564c30SJames Wright   PetscFunctionBeginUser;
973c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
974c8564c30SJames Wright   if (X_loc) {
975c8564c30SJames Wright     PetscInt len_old, len_new;
976c8564c30SJames Wright 
977c8564c30SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
978c8564c30SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
979c8564c30SJames 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,
980c8564c30SJames Wright                len_new, len_old);
9815037d55dSJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
982c8564c30SJames Wright   }
983c8564c30SJames Wright   if (Y_loc_transpose) {
984c8564c30SJames Wright     PetscInt len_old, len_new;
985c8564c30SJames Wright 
986c8564c30SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
987c8564c30SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
988c8564c30SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
989c8564c30SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
9905037d55dSJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
991c8564c30SJames Wright   }
992c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
993c8564c30SJames Wright }
994c8564c30SJames Wright 
995c8564c30SJames Wright /**
996c8564c30SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
997c8564c30SJames Wright 
998c8564c30SJames Wright   Not collective across MPI processes.
999c8564c30SJames Wright 
1000c8564c30SJames Wright   @param[in,out]  mat              `MATCEED`
1001c8564c30SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
1002c8564c30SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
1003c8564c30SJames Wright 
1004c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1005c8564c30SJames Wright **/
1006c8564c30SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
1007c8564c30SJames Wright   MatCeedContext ctx;
1008c8564c30SJames Wright 
1009c8564c30SJames Wright   PetscFunctionBeginUser;
1010c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1011c8564c30SJames Wright   if (X_loc) {
10125037d55dSJames Wright     *X_loc = NULL;
10135037d55dSJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
1014c8564c30SJames Wright   }
1015c8564c30SJames Wright   if (Y_loc_transpose) {
10165037d55dSJames Wright     *Y_loc_transpose = NULL;
10175037d55dSJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
1018c8564c30SJames Wright   }
1019c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1020c8564c30SJames Wright }
1021c8564c30SJames Wright 
1022c8564c30SJames Wright /**
1023c8564c30SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
1024c8564c30SJames Wright 
1025c8564c30SJames Wright   Not collective across MPI processes.
1026c8564c30SJames Wright 
1027c8564c30SJames Wright   @param[in,out]  mat              MatCeed
1028c8564c30SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
1029c8564c30SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
1030c8564c30SJames Wright 
1031c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1032c8564c30SJames Wright **/
1033c8564c30SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
1034c8564c30SJames Wright   PetscFunctionBeginUser;
1035c8564c30SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
1036c8564c30SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
1037c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1038c8564c30SJames Wright }
1039c8564c30SJames Wright 
1040c8564c30SJames Wright /**
1041c8564c30SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
1042c8564c30SJames Wright 
1043c8564c30SJames Wright   Not collective across MPI processes.
1044c8564c30SJames Wright 
1045c8564c30SJames Wright   @param[in,out]  mat                MatCeed
1046c8564c30SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
1047c8564c30SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
1048c8564c30SJames Wright 
1049c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1050c8564c30SJames Wright **/
1051c8564c30SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
1052c8564c30SJames Wright   MatCeedContext ctx;
1053c8564c30SJames Wright 
1054c8564c30SJames Wright   PetscFunctionBeginUser;
1055c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1056c8564c30SJames Wright   if (op_mult) {
1057c8564c30SJames Wright     *op_mult = NULL;
105854831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
1059c8564c30SJames Wright   }
1060c8564c30SJames Wright   if (op_mult_transpose) {
1061c8564c30SJames Wright     *op_mult_transpose = NULL;
106254831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
1063c8564c30SJames Wright   }
1064c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1065c8564c30SJames Wright }
1066c8564c30SJames Wright 
1067c8564c30SJames Wright /**
1068c8564c30SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
1069c8564c30SJames Wright 
1070c8564c30SJames Wright   Not collective across MPI processes.
1071c8564c30SJames Wright 
1072c8564c30SJames Wright   @param[in,out]  mat                MatCeed
1073c8564c30SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
1074c8564c30SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
1075c8564c30SJames Wright 
1076c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1077c8564c30SJames Wright **/
1078c8564c30SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
1079c8564c30SJames Wright   MatCeedContext ctx;
1080c8564c30SJames Wright 
1081c8564c30SJames Wright   PetscFunctionBeginUser;
1082c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
108354831c5fSJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
108454831c5fSJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
1085c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1086c8564c30SJames Wright }
1087c8564c30SJames Wright 
1088c8564c30SJames Wright /**
1089c8564c30SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1090c8564c30SJames Wright 
1091c8564c30SJames Wright   Not collective across MPI processes.
1092c8564c30SJames Wright 
1093c8564c30SJames Wright   @param[in,out]  mat                       MatCeed
1094c8564c30SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
1095c8564c30SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
1096c8564c30SJames Wright 
1097c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1098c8564c30SJames Wright **/
1099c8564c30SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1100c8564c30SJames Wright   MatCeedContext ctx;
1101c8564c30SJames Wright 
1102c8564c30SJames Wright   PetscFunctionBeginUser;
1103c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1104c8564c30SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
1105c8564c30SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
1106c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1107c8564c30SJames Wright }
1108c8564c30SJames Wright 
1109c8564c30SJames Wright /**
1110c8564c30SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1111c8564c30SJames Wright 
1112c8564c30SJames Wright   Not collective across MPI processes.
1113c8564c30SJames Wright 
1114c8564c30SJames Wright   @param[in,out]  mat                       MatCeed
1115c8564c30SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
1116c8564c30SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
1117c8564c30SJames Wright 
1118c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1119c8564c30SJames Wright **/
1120c8564c30SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1121c8564c30SJames Wright   MatCeedContext ctx;
1122c8564c30SJames Wright 
1123c8564c30SJames Wright   PetscFunctionBeginUser;
1124c8564c30SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1125c8564c30SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
1126c8564c30SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
1127c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1128c8564c30SJames Wright }
1129c8564c30SJames Wright 
1130*43327b86SJames Wright /**
1131*43327b86SJames Wright   @brief Set `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1132*43327b86SJames Wright 
1133*43327b86SJames Wright   Not collective across MPI processes.
1134*43327b86SJames Wright 
1135*43327b86SJames Wright   @param[in,out]  mat                       MatCeed
1136*43327b86SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1137*43327b86SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1138*43327b86SJames Wright 
1139*43327b86SJames Wright   @return An error code: 0 - success, otherwise - failure
1140*43327b86SJames Wright **/
1141*43327b86SJames Wright PetscErrorCode MatCeedSetCeedOperatorLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1142*43327b86SJames Wright   MatCeedContext ctx;
1143*43327b86SJames Wright 
1144*43327b86SJames Wright   PetscFunctionBeginUser;
1145*43327b86SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1146*43327b86SJames Wright   if (log_event_mult) ctx->log_event_ceed_mult = log_event_mult;
1147*43327b86SJames Wright   if (log_event_mult_transpose) ctx->log_event_ceed_mult_transpose = log_event_mult_transpose;
1148*43327b86SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1149*43327b86SJames Wright }
1150*43327b86SJames Wright 
1151*43327b86SJames Wright /**
1152*43327b86SJames Wright   @brief Get `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1153*43327b86SJames Wright 
1154*43327b86SJames Wright   Not collective across MPI processes.
1155*43327b86SJames Wright 
1156*43327b86SJames Wright   @param[in,out]  mat                       MatCeed
1157*43327b86SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1158*43327b86SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1159*43327b86SJames Wright 
1160*43327b86SJames Wright   @return An error code: 0 - success, otherwise - failure
1161*43327b86SJames Wright **/
1162*43327b86SJames Wright PetscErrorCode MatCeedGetCeedOperatorLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1163*43327b86SJames Wright   MatCeedContext ctx;
1164*43327b86SJames Wright 
1165*43327b86SJames Wright   PetscFunctionBeginUser;
1166*43327b86SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1167*43327b86SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_ceed_mult;
1168*43327b86SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_ceed_mult_transpose;
1169*43327b86SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1170*43327b86SJames Wright }
1171*43327b86SJames Wright 
1172c8564c30SJames Wright // -----------------------------------------------------------------------------
1173c8564c30SJames Wright // Operator context data
1174c8564c30SJames Wright // -----------------------------------------------------------------------------
1175c8564c30SJames Wright 
1176c8564c30SJames Wright /**
1177c8564c30SJames Wright   @brief Setup context data for operator application.
1178c8564c30SJames Wright 
1179c8564c30SJames Wright   Collective across MPI processes.
1180c8564c30SJames Wright 
1181c8564c30SJames Wright   @param[in]   dm_x                           Input `DM`
1182c8564c30SJames Wright   @param[in]   dm_y                           Output `DM`
1183c8564c30SJames Wright   @param[in]   X_loc                          Input PETSc local vector, or NULL
1184c8564c30SJames Wright   @param[in]   Y_loc_transpose                Input PETSc local vector for transpose operation, or NULL
1185c8564c30SJames Wright   @param[in]   op_mult                        `CeedOperator` for forward evaluation
1186c8564c30SJames Wright   @param[in]   op_mult_transpose              `CeedOperator` for transpose evaluation
1187c8564c30SJames Wright   @param[in]   log_event_mult                 `PetscLogEvent` for forward evaluation
1188c8564c30SJames Wright   @param[in]   log_event_mult_transpose       `PetscLogEvent` for transpose evaluation
1189*43327b86SJames Wright   @param[in]   log_event_ceed_mult            `PetscLogEvent` for forward `CeedOperator` evaluation
1190*43327b86SJames Wright   @param[in]   log_event_ceed_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation
1191c8564c30SJames Wright   @param[out]  ctx                            Context data for operator evaluation
1192c8564c30SJames Wright 
1193c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1194c8564c30SJames Wright **/
1195c8564c30SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1196*43327b86SJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, PetscLogEvent log_event_ceed_mult,
1197*43327b86SJames Wright                                     PetscLogEvent log_event_ceed_mult_transpose, MatCeedContext *ctx) {
1198c8564c30SJames Wright   CeedSize x_loc_len, y_loc_len;
1199c8564c30SJames Wright 
1200c8564c30SJames Wright   PetscFunctionBeginUser;
1201c8564c30SJames Wright 
1202c8564c30SJames Wright   // Allocate
1203c8564c30SJames Wright   PetscCall(PetscNew(ctx));
1204c8564c30SJames Wright   (*ctx)->ref_count = 1;
1205c8564c30SJames Wright 
1206c8564c30SJames Wright   // Logging
1207c8564c30SJames Wright   (*ctx)->log_event_mult                = log_event_mult;
1208c8564c30SJames Wright   (*ctx)->log_event_mult_transpose      = log_event_mult_transpose;
1209*43327b86SJames Wright   (*ctx)->log_event_ceed_mult           = log_event_ceed_mult;
1210*43327b86SJames Wright   (*ctx)->log_event_ceed_mult_transpose = log_event_ceed_mult_transpose;
1211c8564c30SJames Wright 
1212c8564c30SJames Wright   // PETSc objects
12135037d55dSJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
12145037d55dSJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
12155037d55dSJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
12165037d55dSJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
1217c8564c30SJames Wright 
1218c8564c30SJames Wright   // Memtype
1219c8564c30SJames Wright   {
1220c8564c30SJames Wright     const PetscScalar *x;
1221c8564c30SJames Wright     Vec                X;
1222c8564c30SJames Wright 
1223c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
1224c8564c30SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
1225c8564c30SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
1226c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
1227c8564c30SJames Wright   }
1228c8564c30SJames Wright 
1229c8564c30SJames Wright   // libCEED objects
1230c8564c30SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
1231c8564c30SJames Wright              "retrieving Ceed context object failed");
123254831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedReference((*ctx)->ceed));
123354831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
123454831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
123554831c5fSJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
123654831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
123754831c5fSJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
1238c8564c30SJames Wright 
1239c8564c30SJames Wright   // Flop counting
1240c8564c30SJames Wright   {
1241c8564c30SJames Wright     CeedSize ceed_flops_estimate = 0;
1242c8564c30SJames Wright 
124354831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
1244c8564c30SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
1245c8564c30SJames Wright     if (op_mult_transpose) {
124654831c5fSJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
1247c8564c30SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
1248c8564c30SJames Wright     }
1249c8564c30SJames Wright   }
1250c8564c30SJames Wright 
1251c8564c30SJames Wright   // Check sizes
1252c8564c30SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
1253c8564c30SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
1254c8564c30SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
1255c8564c30SJames Wright     Vec      dm_X_loc, dm_Y_loc;
1256c8564c30SJames Wright 
1257c8564c30SJames Wright     // -- Input
1258c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
1259c8564c30SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
1260c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
126154831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
1262c86b9822SJames Wright     if (X_loc) {
1263c86b9822SJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
1264c86b9822SJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
1265c86b9822SJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
1266c86b9822SJames Wright     }
1267c86b9822SJames 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",
1268c86b9822SJames Wright                x_loc_len, dm_x_loc_len);
1269c86b9822SJames 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 ")",
1270c86b9822SJames Wright                x_loc_len, ctx_x_loc_len);
1271c8564c30SJames Wright 
1272c8564c30SJames Wright     // -- Output
1273c8564c30SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
1274c8564c30SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
1275c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
127654831c5fSJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
1277c86b9822SJames 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",
1278c86b9822SJames Wright                ctx_y_loc_len, dm_y_loc_len);
1279c8564c30SJames Wright 
1280c8564c30SJames Wright     // -- Transpose
1281c8564c30SJames Wright     if (Y_loc_transpose) {
1282c8564c30SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
1283c86b9822SJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
1284c86b9822SJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
1285c8564c30SJames Wright     }
1286c8564c30SJames Wright   }
1287c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1288c8564c30SJames Wright }
1289c8564c30SJames Wright 
1290c8564c30SJames Wright /**
1291c8564c30SJames Wright   @brief Increment reference counter for `MATCEED` context.
1292c8564c30SJames Wright 
1293c8564c30SJames Wright   Not collective across MPI processes.
1294c8564c30SJames Wright 
1295c8564c30SJames Wright   @param[in,out]  ctx  Context data
1296c8564c30SJames Wright 
1297c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1298c8564c30SJames Wright **/
1299c8564c30SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
1300c8564c30SJames Wright   PetscFunctionBeginUser;
1301c8564c30SJames Wright   ctx->ref_count++;
1302c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1303c8564c30SJames Wright }
1304c8564c30SJames Wright 
1305c8564c30SJames Wright /**
1306c8564c30SJames Wright   @brief Copy reference for `MATCEED`.
1307c8564c30SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
1308c8564c30SJames Wright 
1309c8564c30SJames Wright   Not collective across MPI processes.
1310c8564c30SJames Wright 
1311c8564c30SJames Wright   @param[in]   ctx       Context data
1312c8564c30SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
1313c8564c30SJames Wright 
1314c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1315c8564c30SJames Wright **/
1316c8564c30SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
1317c8564c30SJames Wright   PetscFunctionBeginUser;
1318c8564c30SJames Wright   PetscCall(MatCeedContextReference(ctx));
1319c8564c30SJames Wright   PetscCall(MatCeedContextDestroy(*ctx_copy));
1320c8564c30SJames Wright   *ctx_copy = ctx;
1321c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1322c8564c30SJames Wright }
1323c8564c30SJames Wright 
1324c8564c30SJames Wright /**
1325c8564c30SJames Wright   @brief Destroy context data for operator application.
1326c8564c30SJames Wright 
1327c8564c30SJames Wright   Collective across MPI processes.
1328c8564c30SJames Wright 
1329c8564c30SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
1330c8564c30SJames Wright 
1331c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1332c8564c30SJames Wright **/
1333c8564c30SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext ctx) {
1334c8564c30SJames Wright   PetscFunctionBeginUser;
1335c8564c30SJames Wright   if (!ctx || --ctx->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
1336c8564c30SJames Wright 
1337c8564c30SJames Wright   // PETSc objects
1338c8564c30SJames Wright   PetscCall(DMDestroy(&ctx->dm_x));
1339c8564c30SJames Wright   PetscCall(DMDestroy(&ctx->dm_y));
1340c8564c30SJames Wright   PetscCall(VecDestroy(&ctx->X_loc));
1341c8564c30SJames Wright   PetscCall(VecDestroy(&ctx->Y_loc_transpose));
1342c8564c30SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
1343c8564c30SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
13445037d55dSJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
1345c8564c30SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_full));
1346c8564c30SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_pbd));
1347c8564c30SJames Wright 
1348c8564c30SJames Wright   // libCEED objects
134954831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->x_loc));
135054831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->y_loc));
135154831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_full));
135254831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_pbd));
135354831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult));
135454831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult_transpose));
1355c8564c30SJames Wright   PetscCheck(CeedDestroy(&ctx->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
1356c8564c30SJames Wright 
1357c8564c30SJames Wright   // Deallocate
1358c8564c30SJames Wright   ctx->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
1359c8564c30SJames Wright   PetscCall(PetscFree(ctx));
1360c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1361c8564c30SJames Wright }
1362c8564c30SJames Wright 
1363c8564c30SJames Wright /**
1364c8564c30SJames Wright   @brief Compute the diagonal of an operator via libCEED.
1365c8564c30SJames Wright 
1366c8564c30SJames Wright   Collective across MPI processes.
1367c8564c30SJames Wright 
1368c8564c30SJames Wright   @param[in]   A  `MATCEED`
1369c8564c30SJames Wright   @param[out]  D  Vector holding operator diagonal
1370c8564c30SJames Wright 
1371c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1372c8564c30SJames Wright **/
1373c8564c30SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
1374c8564c30SJames Wright   PetscMemType   mem_type;
1375c8564c30SJames Wright   Vec            D_loc;
1376c8564c30SJames Wright   MatCeedContext ctx;
1377c8564c30SJames Wright 
1378c8564c30SJames Wright   PetscFunctionBeginUser;
1379c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1380c8564c30SJames Wright 
1381c8564c30SJames Wright   // Place PETSc vector in libCEED vector
1382*43327b86SJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
1383c8564c30SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1384d0593705SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
1385c8564c30SJames Wright 
1386c8564c30SJames Wright   // Compute Diagonal
1387*43327b86SJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
138854831c5fSJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1389*43327b86SJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
1390c8564c30SJames Wright 
1391c8564c30SJames Wright   // Restore PETSc vector
1392d0593705SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
1393c8564c30SJames Wright 
1394c8564c30SJames Wright   // Local-to-Global
1395c8564c30SJames Wright   PetscCall(VecZeroEntries(D));
1396c8564c30SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
1397c8564c30SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1398*43327b86SJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
1399c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1400c8564c30SJames Wright }
1401c8564c30SJames Wright 
1402c8564c30SJames Wright /**
1403c8564c30SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
1404c8564c30SJames Wright 
1405c8564c30SJames Wright   Collective across MPI processes.
1406c8564c30SJames Wright 
1407c8564c30SJames Wright   @param[in]   A  `MATCEED`
1408c8564c30SJames Wright   @param[in]   X  Input PETSc vector
1409c8564c30SJames Wright   @param[out]  Y  Output PETSc vector
1410c8564c30SJames Wright 
1411c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1412c8564c30SJames Wright **/
1413c8564c30SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
1414c8564c30SJames Wright   MatCeedContext ctx;
1415c8564c30SJames Wright 
1416c8564c30SJames Wright   PetscFunctionBeginUser;
1417c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1418*43327b86SJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, NULL));
1419c8564c30SJames Wright 
1420c8564c30SJames Wright   {
1421c8564c30SJames Wright     PetscMemType x_mem_type, y_mem_type;
1422c8564c30SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
1423c8564c30SJames Wright 
1424c8564c30SJames Wright     // Get local vectors
1425c8564c30SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
1426c8564c30SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
1427c8564c30SJames Wright 
1428c8564c30SJames Wright     // Global-to-local
1429c8564c30SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
1430c8564c30SJames Wright 
1431c8564c30SJames Wright     // Setup libCEED vectors
1432d0593705SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
1433c8564c30SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1434d0593705SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
1435c8564c30SJames Wright 
1436c8564c30SJames Wright     // Apply libCEED operator
1437c8564c30SJames Wright     PetscCall(PetscLogGpuTimeBegin());
1438*43327b86SJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult, A, X, Y, NULL));
143954831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
1440*43327b86SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult, A, X, Y, NULL));
1441c8564c30SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1442c8564c30SJames Wright 
1443c8564c30SJames Wright     // Restore PETSc vectors
1444d0593705SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1445d0593705SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1446c8564c30SJames Wright 
1447c8564c30SJames Wright     // Local-to-global
1448c8564c30SJames Wright     PetscCall(VecZeroEntries(Y));
1449c8564c30SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
1450c8564c30SJames Wright 
1451c8564c30SJames Wright     // Restore local vectors, as needed
1452c8564c30SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
1453c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
1454c8564c30SJames Wright   }
1455c8564c30SJames Wright 
1456c8564c30SJames Wright   // Log flops
1457c8564c30SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
1458c8564c30SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult));
1459*43327b86SJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, NULL));
1460c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1461c8564c30SJames Wright }
1462c8564c30SJames Wright 
1463c8564c30SJames Wright /**
1464c8564c30SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
1465c8564c30SJames Wright 
1466c8564c30SJames Wright   Collective across MPI processes.
1467c8564c30SJames Wright 
1468c8564c30SJames Wright   @param[in]   A  `MATCEED`
1469c8564c30SJames Wright   @param[in]   Y  Input PETSc vector
1470c8564c30SJames Wright   @param[out]  X  Output PETSc vector
1471c8564c30SJames Wright 
1472c8564c30SJames Wright   @return An error code: 0 - success, otherwise - failure
1473c8564c30SJames Wright **/
1474c8564c30SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
1475c8564c30SJames Wright   MatCeedContext ctx;
1476c8564c30SJames Wright 
1477c8564c30SJames Wright   PetscFunctionBeginUser;
1478c8564c30SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1479*43327b86SJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, NULL));
1480c8564c30SJames Wright 
1481c8564c30SJames Wright   {
1482c8564c30SJames Wright     PetscMemType x_mem_type, y_mem_type;
1483c8564c30SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
1484c8564c30SJames Wright 
1485c8564c30SJames Wright     // Get local vectors
1486c8564c30SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
1487c8564c30SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
1488c8564c30SJames Wright 
1489c8564c30SJames Wright     // Global-to-local
1490c8564c30SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
1491c8564c30SJames Wright 
1492c8564c30SJames Wright     // Setup libCEED vectors
1493d0593705SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
1494c8564c30SJames Wright     PetscCall(VecZeroEntries(X_loc));
1495d0593705SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
1496c8564c30SJames Wright 
1497c8564c30SJames Wright     // Apply libCEED operator
1498c8564c30SJames Wright     PetscCall(PetscLogGpuTimeBegin());
1499*43327b86SJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
150054831c5fSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1501*43327b86SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
1502c8564c30SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1503c8564c30SJames Wright 
1504c8564c30SJames Wright     // Restore PETSc vectors
1505d0593705SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1506d0593705SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1507c8564c30SJames Wright 
1508c8564c30SJames Wright     // Local-to-global
1509c8564c30SJames Wright     PetscCall(VecZeroEntries(X));
1510c8564c30SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
1511c8564c30SJames Wright 
1512c8564c30SJames Wright     // Restore local vectors, as needed
1513c8564c30SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
1514c8564c30SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
1515c8564c30SJames Wright   }
1516c8564c30SJames Wright 
1517c8564c30SJames Wright   // Log flops
1518c8564c30SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
1519c8564c30SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
1520*43327b86SJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, NULL));
1521c8564c30SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1522c8564c30SJames Wright }
1523