xref: /honee/src/mat-ceed.c (revision b846ad1a1e67df1cd8de79c4b7b2bdbbd91ea3d7)
1ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
358600ac3SJames Wright /// @file
440d80af1SJames Wright /// MatCEED implementation
558600ac3SJames Wright 
658600ac3SJames Wright #include <ceed.h>
758600ac3SJames Wright #include <ceed/backend.h>
858600ac3SJames Wright #include <mat-ceed-impl.h>
958600ac3SJames Wright #include <mat-ceed.h>
1040d80af1SJames Wright #include <petsc-ceed-utils.h>
1140d80af1SJames Wright #include <petsc-ceed.h>
12000d2032SJeremy L Thompson #include <petscdm.h>
13000d2032SJeremy L Thompson #include <petscmat.h>
14000d2032SJeremy L Thompson #include <stdbool.h>
15000d2032SJeremy L Thompson #include <stdio.h>
1658600ac3SJames Wright #include <stdlib.h>
1758600ac3SJames Wright #include <string.h>
1858600ac3SJames Wright 
19*b846ad1aSJames Wright #if PETSC_VERSION_LT(3, 24, 0)
20*b846ad1aSJames Wright typedef void (*MatSetOpFn)(void);
21*b846ad1aSJames Wright #else
22*b846ad1aSJames Wright typedef PetscErrorCodeFn *MatSetOpFn;
23*b846ad1aSJames Wright #endif
24*b846ad1aSJames Wright 
2558600ac3SJames Wright PetscClassId  MATCEED_CLASSID;
26c63b910fSJames Wright PetscLogEvent MATCEED_MULT, MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE, MATCEED_MULT_TRANSPOSE_CEEDOP, MATCEED_ASSEMBLE_DIAGONAL,
27c63b910fSJames Wright     MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, MATCEED_SETUP_PBDIAGONAL, MATCEED_SETUP_PBDIAGONAL_CEEDOP, MATCEED_ASSEMBLE_PBDIAGONAL,
28c63b910fSJames Wright     MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, MATCEED_SETUP_FULL, MATCEED_SETUP_FULL_CEEDOP, MATCEED_ASSEMBLE_FULL, MATCEED_ASSEMBLE_FULL_CEEDOP;
2958600ac3SJames Wright 
3058600ac3SJames Wright /**
3158600ac3SJames Wright   @brief Register MATCEED log events.
3258600ac3SJames Wright 
3358600ac3SJames Wright   Not collective across MPI processes.
3458600ac3SJames Wright 
3558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
3658600ac3SJames Wright **/
3758600ac3SJames Wright static PetscErrorCode MatCeedRegisterLogEvents() {
3840d80af1SJames Wright   static PetscBool registered = PETSC_FALSE;
3958600ac3SJames Wright 
4058600ac3SJames Wright   PetscFunctionBeginUser;
4158600ac3SJames Wright   if (registered) PetscFunctionReturn(PETSC_SUCCESS);
42c63b910fSJames Wright   PetscCall(PetscClassIdRegister("MatCEED", &MATCEED_CLASSID));
43c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMul", MATCEED_CLASSID, &MATCEED_MULT));
44c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulCeed", MATCEED_CLASSID, &MATCEED_MULT_CEEDOP));
45c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulT", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE));
46c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulTCeed", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE_CEEDOP));
47c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmDiag", MATCEED_CLASSID, &MATCEED_ASSEMBLE_DIAGONAL));
48c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSU", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL));
49c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL_CEEDOP));
50c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBD", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL));
51c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP));
52c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSU", MATCEED_CLASSID, &MATCEED_SETUP_FULL));
53c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_FULL_CEEDOP));
54c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsm", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL));
55c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL_CEEDOP));
5640d80af1SJames Wright   registered = PETSC_TRUE;
5758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
5858600ac3SJames Wright }
5958600ac3SJames Wright 
6058600ac3SJames Wright /**
6158600ac3SJames Wright   @brief Assemble the point block diagonal of a `MATCEED` into a `MATAIJ` or similar.
6258600ac3SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
6358600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
6458600ac3SJames Wright 
6558600ac3SJames Wright   Collective across MPI processes.
6658600ac3SJames Wright 
6758600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
6858600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
6958600ac3SJames Wright 
7058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
7158600ac3SJames Wright **/
7258600ac3SJames Wright static PetscErrorCode MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed, Mat mat_coo) {
7358600ac3SJames Wright   MatCeedContext ctx;
7458600ac3SJames Wright 
7558600ac3SJames Wright   PetscFunctionBeginUser;
7658600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
7758600ac3SJames Wright 
7858600ac3SJames Wright   // Check if COO pattern set
7958600ac3SJames Wright   {
8058600ac3SJames Wright     PetscInt index = -1;
8158600ac3SJames Wright 
8258600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
8358600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == mat_coo) index = i;
8458600ac3SJames Wright     }
8558600ac3SJames Wright     if (index == -1) {
8658600ac3SJames Wright       PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
8758600ac3SJames Wright       CeedInt      *rows_ceed, *cols_ceed;
8858600ac3SJames Wright       PetscCount    num_entries;
8958600ac3SJames Wright       PetscLogStage stage_amg_setup;
9058600ac3SJames Wright 
9158600ac3SJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
92c63b910fSJames Wright       PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
9358600ac3SJames Wright       if (stage_amg_setup == -1) {
94c63b910fSJames Wright         PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
9558600ac3SJames Wright       }
9658600ac3SJames Wright       PetscCall(PetscLogStagePush(stage_amg_setup));
97c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
98c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
9950f50432SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
100c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
101a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
102a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
10358600ac3SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
10458600ac3SJames Wright       free(rows_petsc);
10558600ac3SJames Wright       free(cols_petsc);
10650f50432SJames Wright       if (!ctx->coo_values_pbd) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_pbd));
10758600ac3SJames Wright       PetscCall(PetscRealloc(++ctx->num_mats_assembled_pbd * sizeof(Mat), &ctx->mats_assembled_pbd));
10858600ac3SJames Wright       ctx->mats_assembled_pbd[ctx->num_mats_assembled_pbd - 1] = mat_coo;
109c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
11058600ac3SJames Wright       PetscCall(PetscLogStagePop());
11158600ac3SJames Wright     }
11258600ac3SJames Wright   }
11358600ac3SJames Wright 
11458600ac3SJames Wright   // Assemble mat_ceed
115c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
11658600ac3SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
11758600ac3SJames Wright   {
11858600ac3SJames Wright     const CeedScalar *values;
119ed5c6999SJames Wright     PetscMemType      mem_type_petsc;
12058600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
12158600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
12258600ac3SJames Wright 
1232da92326SJames Wright     PetscCall(MatGetMemTypeFromVecType(mat_coo, &mem_type_petsc));
124ed5c6999SJames Wright     mem_type = MemTypePetscToCeed(mem_type_petsc);
125c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12650f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonal(ctx->op_mult, ctx->coo_values_pbd, CEED_REQUEST_IMMEDIATE));
127c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12850f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_pbd, mem_type, &values));
12958600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
13058600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
13158600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
13250f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_pbd, &values));
13358600ac3SJames Wright   }
13458600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
135c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
13658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
13758600ac3SJames Wright }
13858600ac3SJames Wright 
13958600ac3SJames Wright /**
14058600ac3SJames Wright   @brief Assemble inner `Mat` for diagonal `PC` operations
14158600ac3SJames Wright 
14258600ac3SJames Wright   Collective across MPI processes.
14358600ac3SJames Wright 
14458600ac3SJames Wright   @param[in]   mat_ceed      `MATCEED` to invert
14558600ac3SJames Wright   @param[in]   use_ceed_pbd  Boolean flag to use libCEED PBD assembly
14658600ac3SJames Wright   @param[out]  mat_inner     Inner `Mat` for diagonal operations
14758600ac3SJames Wright 
14858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
14958600ac3SJames Wright **/
15058600ac3SJames Wright static PetscErrorCode MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed, PetscBool use_ceed_pbd, Mat *mat_inner) {
15158600ac3SJames Wright   MatCeedContext ctx;
15258600ac3SJames Wright 
15358600ac3SJames Wright   PetscFunctionBeginUser;
15458600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
15558600ac3SJames Wright   if (use_ceed_pbd) {
15658600ac3SJames Wright     // Check if COO pattern set
15740d80af1SJames Wright     if (!ctx->mat_assembled_pbd_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_pbd_internal));
15858600ac3SJames Wright 
15958600ac3SJames Wright     // Assemble mat_assembled_full_internal
16058600ac3SJames Wright     PetscCall(MatCeedAssemblePointBlockDiagonalCOO(mat_ceed, ctx->mat_assembled_pbd_internal));
16158600ac3SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_pbd_internal;
16258600ac3SJames Wright   } else {
16358600ac3SJames Wright     // Check if COO pattern set
16440d80af1SJames Wright     if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
16558600ac3SJames Wright 
16658600ac3SJames Wright     // Assemble mat_assembled_full_internal
16758600ac3SJames Wright     PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
16858600ac3SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_full_internal;
16958600ac3SJames Wright   }
17058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
17158600ac3SJames Wright }
17258600ac3SJames Wright 
17358600ac3SJames Wright /**
174e8ff1987SJames Wright   @brief Get `MATCEED` variable block diagonal for Jacobi.
175e8ff1987SJames Wright 
176e8ff1987SJames Wright   Collective across MPI processes.
177e8ff1987SJames Wright 
178e8ff1987SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
179e8ff1987SJames Wright   @param[out]  mat_vblock  The variable diagonal block matrix
180e8ff1987SJames Wright 
181e8ff1987SJames Wright   @return An error code: 0 - success, otherwise - failure
182e8ff1987SJames Wright **/
183e8ff1987SJames Wright static PetscErrorCode MatGetVariableBlockDiagonal_Ceed(Mat mat_ceed, Mat *mat_vblock) {
184e8ff1987SJames Wright   MatCeedContext ctx;
185e8ff1987SJames Wright 
186e8ff1987SJames Wright   PetscFunctionBeginUser;
187e8ff1987SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
188e8ff1987SJames Wright 
189e8ff1987SJames Wright   // Assemble inner mat if needed
190e8ff1987SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, mat_vblock));
191e8ff1987SJames Wright   PetscCall(PetscObjectReference((PetscObject)*mat_vblock));
192e8ff1987SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
193e8ff1987SJames Wright }
194e8ff1987SJames Wright 
195e8ff1987SJames Wright /**
196e8ff1987SJames Wright   @brief Get `MATCEED` block diagonal for Jacobi.
197e8ff1987SJames Wright 
198e8ff1987SJames Wright   Collective across MPI processes.
199e8ff1987SJames Wright 
200e8ff1987SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
201e8ff1987SJames Wright   @param[out]  mat_block  The variable diagonal block matrix
202e8ff1987SJames Wright 
203e8ff1987SJames Wright   @return An error code: 0 - success, otherwise - failure
204e8ff1987SJames Wright **/
205e8ff1987SJames Wright static PetscErrorCode MatGetBlockDiagonal_Ceed(Mat mat_ceed, Mat *mat_block) {
206e8ff1987SJames Wright   MatCeedContext ctx;
207e8ff1987SJames Wright 
208e8ff1987SJames Wright   PetscFunctionBeginUser;
209e8ff1987SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
210e8ff1987SJames Wright 
211e8ff1987SJames Wright   // Assemble inner mat if needed
212e8ff1987SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, mat_block));
213e8ff1987SJames Wright   PetscCall(PetscObjectReference((PetscObject)*mat_block));
214e8ff1987SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
215e8ff1987SJames Wright }
216e8ff1987SJames Wright 
217e8ff1987SJames Wright /**
218c1bdbf00SJames Wright   @brief Get on-process diagonal block of `MATCEED`
219c1bdbf00SJames Wright 
220c1bdbf00SJames Wright   This is a block per-process of the diagonal of the global matrix.
221c1bdbf00SJames Wright   This is NOT the diagonal blocks associated with the block size of the matrix (i.e. `MatSetBlockSize()` has no effect on this function).
22258600ac3SJames Wright 
22358600ac3SJames Wright   Collective across MPI processes.
22458600ac3SJames Wright 
22558600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
22658600ac3SJames Wright   @param[out]  mat_block  The diagonal block matrix
22758600ac3SJames Wright 
22858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
22958600ac3SJames Wright **/
23058600ac3SJames Wright static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) {
23158600ac3SJames Wright   MatCeedContext ctx;
23258600ac3SJames Wright 
23358600ac3SJames Wright   PetscFunctionBeginUser;
23458600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
23558600ac3SJames Wright 
236c1bdbf00SJames Wright   // Check if COO pattern set
237c1bdbf00SJames Wright   if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
23858600ac3SJames Wright 
239c1bdbf00SJames Wright   // Assemble mat_assembled_full_internal
240c1bdbf00SJames Wright   PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
241c1bdbf00SJames Wright 
242c1bdbf00SJames Wright   // Get diagonal block
243c1bdbf00SJames Wright   PetscCall(MatGetDiagonalBlock(ctx->mat_assembled_full_internal, mat_block));
24458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
24558600ac3SJames Wright }
24658600ac3SJames Wright 
24758600ac3SJames Wright /**
248e90c2ceeSJames Wright   @brief View `MATCEED`.
249e90c2ceeSJames Wright 
250e90c2ceeSJames Wright   Collective across MPI processes.
251e90c2ceeSJames Wright 
252e90c2ceeSJames Wright   @param[in]   mat_ceed  `MATCEED` to view
253e90c2ceeSJames Wright   @param[in]   viewer    The visualization context
254e90c2ceeSJames Wright 
255e90c2ceeSJames Wright   @return An error code: 0 - success, otherwise - failure
256e90c2ceeSJames Wright **/
257e90c2ceeSJames Wright static PetscErrorCode MatView_Ceed(Mat mat_ceed, PetscViewer viewer) {
258e90c2ceeSJames Wright   PetscBool         is_ascii;
259e90c2ceeSJames Wright   PetscViewerFormat format;
260000d2032SJeremy L Thompson   PetscMPIInt       size, rank;
261e90c2ceeSJames Wright   MatCeedContext    ctx;
262e90c2ceeSJames Wright 
263e90c2ceeSJames Wright   PetscFunctionBeginUser;
264e90c2ceeSJames Wright   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
265e90c2ceeSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
266e90c2ceeSJames Wright   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat_ceed), &viewer));
267e90c2ceeSJames Wright 
268e90c2ceeSJames Wright   PetscCall(PetscViewerGetFormat(viewer, &format));
269e90c2ceeSJames Wright   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat_ceed), &size));
270e90c2ceeSJames Wright   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
271e90c2ceeSJames Wright 
272000d2032SJeremy L Thompson   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat_ceed), &rank));
273000d2032SJeremy L Thompson   if (rank != 0) PetscFunctionReturn(PETSC_SUCCESS);
274000d2032SJeremy L Thompson 
275e90c2ceeSJames Wright   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii));
276e90c2ceeSJames Wright   {
277000d2032SJeremy L Thompson     PetscBool is_detailed     = format == PETSC_VIEWER_ASCII_INFO_DETAIL;
278000d2032SJeremy L Thompson     char      rank_string[16] = {'\0'};
279*b846ad1aSJames Wright     PetscInt  num_tabs        = 0;
280e90c2ceeSJames Wright     FILE     *file;
281e90c2ceeSJames Wright 
282dfdd2b92SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n"));
283537ec908SJames Wright     PetscCall(PetscViewerASCIIPushTab(viewer));  // MatCEED
284dfdd2b92SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "Default COO MatType: %s\n", ctx->coo_mat_type));
285000d2032SJeremy L Thompson     PetscCall(PetscSNPrintf(rank_string, 16, "on Rank %d", rank));
286000d2032SJeremy L Thompson     PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary"));
287e8ff1987SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "libCEED PB Diagonal Assembly: %s\n", ctx->is_ceed_pbd_valid ? "True" : "False"));
288e8ff1987SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "libCEED VPB Diagonal Assembly: %s\n", ctx->is_ceed_vpbd_valid ? "True" : "False"));
289*b846ad1aSJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary"));
290537ec908SJames Wright     PetscCall(PetscViewerASCIIGetPointer(viewer, &file));
291537ec908SJames Wright     PetscCall(PetscViewerASCIIPushTab(viewer));  // CeedOperator
292*b846ad1aSJames Wright     PetscCall(PetscViewerASCIIGetTab(viewer, &num_tabs));
293*b846ad1aSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult, num_tabs));
294000d2032SJeremy L Thompson     if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file));
295000d2032SJeremy L Thompson     else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult, file));
296*b846ad1aSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult, 0));
297537ec908SJames Wright     PetscCall(PetscViewerASCIIPopTab(viewer));  // CeedOperator
298e90c2ceeSJames Wright     if (ctx->op_mult_transpose) {
299000d2032SJeremy L Thompson       PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator ApplyTranspose %s:\n", is_detailed ? rank_string : "Summary"));
300537ec908SJames Wright       PetscCall(PetscViewerASCIIPushTab(viewer));  // CeedOperator
301*b846ad1aSJames Wright       PetscCall(PetscViewerASCIIGetTab(viewer, &num_tabs));
302*b846ad1aSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult_transpose, num_tabs));
303000d2032SJeremy L Thompson       if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file));
304000d2032SJeremy L Thompson       else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult_transpose, file));
305*b846ad1aSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult_transpose, 0));
306537ec908SJames Wright       PetscCall(PetscViewerASCIIPopTab(viewer));  // CeedOperator
307e90c2ceeSJames Wright     }
308537ec908SJames Wright     PetscCall(PetscViewerASCIIPopTab(viewer));  // MatCEED
309e90c2ceeSJames Wright   }
310e90c2ceeSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
311e90c2ceeSJames Wright }
312e90c2ceeSJames Wright 
313*b846ad1aSJames Wright /**
314*b846ad1aSJames Wright   @brief Set options for MatCeed from command-line iterface
315*b846ad1aSJames Wright 
316*b846ad1aSJames Wright   @note This is a PETSc interface, thus the odd signature
317*b846ad1aSJames Wright   @note The name of the second parameter must be `PetscOptionsObject` due to abuse of PETSc macros
318*b846ad1aSJames Wright 
319*b846ad1aSJames Wright   Collective across MPI processes.
320*b846ad1aSJames Wright 
321*b846ad1aSJames Wright   @param[in]  mat_ceed            `Mat` object to set up
322*b846ad1aSJames Wright   @param[in]  PetscOptionsObject  `PetscOptionItems` object to read options from
323*b846ad1aSJames Wright 
324*b846ad1aSJames Wright   @return An error code: 0 - success, otherwise - failure
325*b846ad1aSJames Wright **/
326*b846ad1aSJames Wright static PetscErrorCode MatSetFromOptions_Ceed(Mat mat_ceed, PetscOptionItems PetscOptionsObject) {
327*b846ad1aSJames Wright   MatCeedContext ctx;
328*b846ad1aSJames Wright   char           coo_mat_type_cl[PETSC_MAX_OPTION_NAME];
329*b846ad1aSJames Wright   PetscBool      is_coo_mat_type_cl;
330*b846ad1aSJames Wright 
331*b846ad1aSJames Wright   PetscFunctionBegin;
332*b846ad1aSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
333*b846ad1aSJames Wright 
334*b846ad1aSJames Wright   PetscOptionsHeadBegin(PetscOptionsObject, "MATCEED options");
335*b846ad1aSJames Wright   // Check for specific CL coo mat type for this Mat
336*b846ad1aSJames Wright   PetscCall(PetscOptionsFList("-mat_ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
337*b846ad1aSJames Wright                               sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
338*b846ad1aSJames Wright   if (is_coo_mat_type_cl) {
339*b846ad1aSJames Wright     PetscCall(PetscFree(ctx->coo_mat_type));
340*b846ad1aSJames Wright     PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
341*b846ad1aSJames Wright   }
342*b846ad1aSJames Wright   // Check for COO mat reuse flag
343*b846ad1aSJames Wright   PetscCall(PetscOptionsBool("-mat_ceed_coo_reuse_preallocation",
344*b846ad1aSJames Wright                              "Flag to allow the MatCeed to reuse existing COO preallocations, even if not set by this MatCeed", NULL,
345*b846ad1aSJames Wright                              ctx->coo_reuse_preallocation, &ctx->coo_reuse_preallocation, NULL));
346*b846ad1aSJames Wright   PetscOptionsHeadEnd();
347*b846ad1aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
348*b846ad1aSJames Wright }
349*b846ad1aSJames Wright 
35058600ac3SJames Wright // -----------------------------------------------------------------------------
35158600ac3SJames Wright // MatCeed
35258600ac3SJames Wright // -----------------------------------------------------------------------------
35358600ac3SJames Wright 
35458600ac3SJames Wright /**
35558600ac3SJames Wright   @brief Create PETSc `Mat` from libCEED operators.
35658600ac3SJames Wright 
35758600ac3SJames Wright   Collective across MPI processes.
35858600ac3SJames Wright 
35958600ac3SJames Wright   @param[in]   dm_x                      Input `DM`
36058600ac3SJames Wright   @param[in]   dm_y                      Output `DM`
36158600ac3SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
36258600ac3SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
36358600ac3SJames Wright   @param[out]  mat                        New MatCeed
36458600ac3SJames Wright 
36558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
36658600ac3SJames Wright **/
367000d2032SJeremy L Thompson PetscErrorCode MatCreateCeed(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) {
36858600ac3SJames Wright   PetscInt       X_l_size, X_g_size, Y_l_size, Y_g_size;
36958600ac3SJames Wright   VecType        vec_type;
37058600ac3SJames Wright   MatCeedContext ctx;
37158600ac3SJames Wright 
37258600ac3SJames Wright   PetscFunctionBeginUser;
37358600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
37458600ac3SJames Wright 
37558600ac3SJames Wright   // Collect context data
37658600ac3SJames Wright   PetscCall(DMGetVecType(dm_x, &vec_type));
37758600ac3SJames Wright   {
37858600ac3SJames Wright     Vec X;
37958600ac3SJames Wright 
38058600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_x, &X));
38158600ac3SJames Wright     PetscCall(VecGetSize(X, &X_g_size));
38258600ac3SJames Wright     PetscCall(VecGetLocalSize(X, &X_l_size));
38358600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_x, &X));
38458600ac3SJames Wright   }
38558600ac3SJames Wright   if (dm_y) {
38658600ac3SJames Wright     Vec Y;
38758600ac3SJames Wright 
38858600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_y, &Y));
38958600ac3SJames Wright     PetscCall(VecGetSize(Y, &Y_g_size));
39058600ac3SJames Wright     PetscCall(VecGetLocalSize(Y, &Y_l_size));
39158600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_y, &Y));
39258600ac3SJames Wright   } else {
39358600ac3SJames Wright     dm_y     = dm_x;
39458600ac3SJames Wright     Y_g_size = X_g_size;
39558600ac3SJames Wright     Y_l_size = X_l_size;
39658600ac3SJames Wright   }
39740d80af1SJames Wright 
39858600ac3SJames Wright   // Create context
39958600ac3SJames Wright   {
40058600ac3SJames Wright     Vec X_loc, Y_loc_transpose = NULL;
40158600ac3SJames Wright 
40258600ac3SJames Wright     PetscCall(DMCreateLocalVector(dm_x, &X_loc));
40358600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
40458600ac3SJames Wright     if (op_mult_transpose) {
40558600ac3SJames Wright       PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose));
40658600ac3SJames Wright       PetscCall(VecZeroEntries(Y_loc_transpose));
40758600ac3SJames Wright     }
408c63b910fSJames Wright     PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE,
409c63b910fSJames Wright                                    MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE_CEEDOP, &ctx));
41058600ac3SJames Wright     PetscCall(VecDestroy(&X_loc));
41158600ac3SJames Wright     PetscCall(VecDestroy(&Y_loc_transpose));
41258600ac3SJames Wright   }
41358600ac3SJames Wright 
41458600ac3SJames Wright   // Create mat
41558600ac3SJames Wright   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat));
41658600ac3SJames Wright   PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED));
41758600ac3SJames Wright   // -- Set block and variable block sizes
41858600ac3SJames Wright   if (dm_x == dm_y) {
41958600ac3SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
42058600ac3SJames Wright     Mat     temp_mat;
42158600ac3SJames Wright 
42258600ac3SJames Wright     PetscCall(DMGetMatType(dm_x, &dm_mat_type));
42358600ac3SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
42458600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, MATAIJ));
42558600ac3SJames Wright     PetscCall(DMCreateMatrix(dm_x, &temp_mat));
42658600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, dm_mat_type_copy));
42758600ac3SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
42858600ac3SJames Wright 
42958600ac3SJames Wright     {
43058600ac3SJames Wright       PetscInt        block_size, num_blocks, max_vblock_size = PETSC_INT_MAX;
43158600ac3SJames Wright       const PetscInt *vblock_sizes;
43258600ac3SJames Wright 
43358600ac3SJames Wright       // -- Get block sizes
43458600ac3SJames Wright       PetscCall(MatGetBlockSize(temp_mat, &block_size));
43558600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes));
43658600ac3SJames Wright       {
43758600ac3SJames Wright         PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX};
43858600ac3SJames Wright 
43958600ac3SJames Wright         for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]);
44058600ac3SJames Wright         PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max));
44158600ac3SJames Wright         max_vblock_size = global_min_max[1];
44258600ac3SJames Wright       }
44358600ac3SJames Wright 
44458600ac3SJames Wright       // -- Copy block sizes
44558600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size));
44658600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes));
44758600ac3SJames Wright 
44858600ac3SJames Wright       // -- Check libCEED compatibility
44958600ac3SJames Wright       {
45058600ac3SJames Wright         bool is_composite;
45158600ac3SJames Wright 
45258600ac3SJames Wright         ctx->is_ceed_pbd_valid  = PETSC_TRUE;
45358600ac3SJames Wright         ctx->is_ceed_vpbd_valid = PETSC_TRUE;
45450f50432SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite));
45558600ac3SJames Wright         if (is_composite) {
45658600ac3SJames Wright           CeedInt       num_sub_operators;
45758600ac3SJames Wright           CeedOperator *sub_operators;
45858600ac3SJames Wright 
459da7f3a07SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorCompositeGetNumSub(op_mult, &num_sub_operators));
460da7f3a07SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorCompositeGetSubList(op_mult, &sub_operators));
46158600ac3SJames Wright           for (CeedInt i = 0; i < num_sub_operators; i++) {
46258600ac3SJames Wright             CeedInt                  num_bases, num_comp;
46358600ac3SJames Wright             CeedBasis               *active_bases;
46458600ac3SJames Wright             CeedOperatorAssemblyData assembly_data;
46558600ac3SJames Wright 
46650f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data));
46750f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
46850f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
46958600ac3SJames Wright             if (num_bases > 1) {
47058600ac3SJames Wright               ctx->is_ceed_pbd_valid  = PETSC_FALSE;
47158600ac3SJames Wright               ctx->is_ceed_vpbd_valid = PETSC_FALSE;
47258600ac3SJames Wright             }
47358600ac3SJames Wright             if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
47458600ac3SJames Wright             if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
47558600ac3SJames Wright           }
47658600ac3SJames Wright         } else {
47758600ac3SJames Wright           // LCOV_EXCL_START
47858600ac3SJames Wright           CeedInt                  num_bases, num_comp;
47958600ac3SJames Wright           CeedBasis               *active_bases;
48058600ac3SJames Wright           CeedOperatorAssemblyData assembly_data;
48158600ac3SJames Wright 
48250f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data));
48350f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
48450f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
48558600ac3SJames Wright           if (num_bases > 1) {
48658600ac3SJames Wright             ctx->is_ceed_pbd_valid  = PETSC_FALSE;
48758600ac3SJames Wright             ctx->is_ceed_vpbd_valid = PETSC_FALSE;
48858600ac3SJames Wright           }
48958600ac3SJames Wright           if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
49058600ac3SJames Wright           if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
49158600ac3SJames Wright           // LCOV_EXCL_STOP
49258600ac3SJames Wright         }
49358600ac3SJames Wright         {
49458600ac3SJames Wright           PetscInt local_is_valid[2], global_is_valid[2];
49558600ac3SJames Wright 
49658600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid;
49758600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
49858600ac3SJames Wright           ctx->is_ceed_pbd_valid = global_is_valid[0];
49958600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid;
50058600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
50158600ac3SJames Wright           ctx->is_ceed_vpbd_valid = global_is_valid[0];
50258600ac3SJames Wright         }
50358600ac3SJames Wright       }
50458600ac3SJames Wright     }
50558600ac3SJames Wright     PetscCall(MatDestroy(&temp_mat));
50658600ac3SJames Wright   }
50758600ac3SJames Wright   // -- Set internal mat type
50858600ac3SJames Wright   {
50958600ac3SJames Wright     VecType vec_type;
51040d80af1SJames Wright     MatType coo_mat_type;
51158600ac3SJames Wright 
51258600ac3SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
513ed5c6999SJames Wright     PetscCall(DefaultMatTypeFromVecType(vec_type, &coo_mat_type));
51440d80af1SJames Wright     PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type));
51558600ac3SJames Wright   }
51658600ac3SJames Wright   // -- Set mat operations
51767aa9f91SJames Wright   PetscCall(MatShellSetContextDestroy(*mat, (PetscCtxDestroyFn *)MatCeedContextDestroy));
518*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (MatSetOpFn)MatView_Ceed));
519*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (MatSetOpFn)MatMult_Ceed));
520*b846ad1aSJames Wright   if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (MatSetOpFn)MatMultTranspose_Ceed));
521*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (MatSetOpFn)MatGetDiagonal_Ceed));
522*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (MatSetOpFn)MatGetDiagonalBlock_Ceed));
523*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_BLOCK_DIAGONAL, (MatSetOpFn)MatGetBlockDiagonal_Ceed));
524*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_VBLOCK_DIAGONAL, (MatSetOpFn)MatGetVariableBlockDiagonal_Ceed));
525*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_SET_FROM_OPTIONS, (MatSetOpFn)MatSetFromOptions_Ceed));
52658600ac3SJames Wright   PetscCall(MatShellSetVecType(*mat, vec_type));
52758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
52858600ac3SJames Wright }
52958600ac3SJames Wright 
53058600ac3SJames Wright /**
53158600ac3SJames Wright   @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`.
53258600ac3SJames Wright 
53358600ac3SJames Wright   Collective across MPI processes.
53458600ac3SJames Wright 
53558600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to copy from
53658600ac3SJames Wright   @param[out]  mat_other  `MatShell` or `MATCEED` to copy into
53758600ac3SJames Wright 
53858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
53958600ac3SJames Wright **/
54058600ac3SJames Wright PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) {
54158600ac3SJames Wright   PetscFunctionBeginUser;
54258600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
54358600ac3SJames Wright 
54458600ac3SJames Wright   // Check type compatibility
54558600ac3SJames Wright   {
54640d80af1SJames Wright     PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE;
54758600ac3SJames Wright     MatType   mat_type_ceed, mat_type_other;
54858600ac3SJames Wright 
54958600ac3SJames Wright     PetscCall(MatGetType(mat_ceed, &mat_type_ceed));
55040d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
55140d80af1SJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
55240d80af1SJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
55340d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
554*b846ad1aSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matshell));
55540d80af1SJames Wright     PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL);
55658600ac3SJames Wright   }
55758600ac3SJames Wright 
55858600ac3SJames Wright   // Check dimension compatibility
55958600ac3SJames Wright   {
56058600ac3SJames 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;
56158600ac3SJames Wright 
56258600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size));
56358600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size));
56458600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size));
56558600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size));
56658600ac3SJames 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) &&
56758600ac3SJames Wright                    (X_l_ceed_size == X_l_other_size),
56858600ac3SJames Wright                PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
56958600ac3SJames Wright                "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT
57058600ac3SJames Wright                "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT
57158600ac3SJames Wright                ", %" PetscInt_FMT ")",
57258600ac3SJames 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);
57358600ac3SJames Wright   }
57458600ac3SJames Wright 
57558600ac3SJames Wright   // Convert
57658600ac3SJames Wright   {
57758600ac3SJames Wright     VecType        vec_type;
57858600ac3SJames Wright     MatCeedContext ctx;
57958600ac3SJames Wright 
58058600ac3SJames Wright     PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED));
58158600ac3SJames Wright     PetscCall(MatShellGetContext(mat_ceed, &ctx));
58258600ac3SJames Wright     PetscCall(MatCeedContextReference(ctx));
58358600ac3SJames Wright     PetscCall(MatShellSetContext(mat_other, ctx));
58467aa9f91SJames Wright     PetscCall(MatShellSetContextDestroy(mat_other, (PetscCtxDestroyFn *)MatCeedContextDestroy));
585*b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (MatSetOpFn)MatView_Ceed));
586*b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (MatSetOpFn)MatMult_Ceed));
587*b846ad1aSJames Wright     if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (MatSetOpFn)MatMultTranspose_Ceed));
588*b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (MatSetOpFn)MatGetDiagonal_Ceed));
589*b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (MatSetOpFn)MatGetDiagonalBlock_Ceed));
590*b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_BLOCK_DIAGONAL, (MatSetOpFn)MatGetBlockDiagonal_Ceed));
591*b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_VBLOCK_DIAGONAL, (MatSetOpFn)MatGetVariableBlockDiagonal_Ceed));
59258600ac3SJames Wright     {
59358600ac3SJames Wright       PetscInt block_size;
59458600ac3SJames Wright 
59558600ac3SJames Wright       PetscCall(MatGetBlockSize(mat_ceed, &block_size));
59658600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size));
59758600ac3SJames Wright     }
59858600ac3SJames Wright     {
59958600ac3SJames Wright       PetscInt        num_blocks;
60058600ac3SJames Wright       const PetscInt *block_sizes;
60158600ac3SJames Wright 
60258600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes));
60358600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes));
60458600ac3SJames Wright     }
60558600ac3SJames Wright     PetscCall(DMGetVecType(ctx->dm_x, &vec_type));
60658600ac3SJames Wright     PetscCall(MatShellSetVecType(mat_other, vec_type));
60758600ac3SJames Wright   }
60858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
60958600ac3SJames Wright }
61058600ac3SJames Wright 
61158600ac3SJames Wright /**
612ba95ebb4SJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly for a `MatCEED`.
613000d2032SJeremy L Thompson 
614000d2032SJeremy L Thompson   Collective across MPI processes.
615000d2032SJeremy L Thompson 
616000d2032SJeremy L Thompson   @param[in]   mat_ceed       `MATCEED`
617000d2032SJeremy L Thompson   @param[out]  update_needed  Boolean flag indicating `CeedQFunction` update needed
618000d2032SJeremy L Thompson 
619000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
620000d2032SJeremy L Thompson **/
621000d2032SJeremy L Thompson PetscErrorCode MatCeedSetAssemblyDataUpdateNeeded(Mat mat_ceed, PetscBool update_needed) {
622000d2032SJeremy L Thompson   MatCeedContext ctx;
623000d2032SJeremy L Thompson 
624000d2032SJeremy L Thompson   PetscFunctionBeginUser;
625000d2032SJeremy L Thompson   PetscCall(MatShellGetContext(mat_ceed, &ctx));
626000d2032SJeremy L Thompson   PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult, update_needed));
627000d2032SJeremy L Thompson   if (ctx->op_mult_transpose) {
628000d2032SJeremy L Thompson     PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult_transpose, update_needed));
629000d2032SJeremy L Thompson   }
630397c0187SJeremy L Thompson   if (update_needed) {
631397c0187SJeremy L Thompson     PetscCall(MatAssemblyBegin(mat_ceed, MAT_FINAL_ASSEMBLY));
632397c0187SJeremy L Thompson     PetscCall(MatAssemblyEnd(mat_ceed, MAT_FINAL_ASSEMBLY));
633397c0187SJeremy L Thompson   }
634000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
635000d2032SJeremy L Thompson }
636000d2032SJeremy L Thompson 
637000d2032SJeremy L Thompson /**
63840d80af1SJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
63940d80af1SJames Wright 
64040d80af1SJames Wright   Collective across MPI processes.
64140d80af1SJames Wright 
64240d80af1SJames Wright   @param[in]   mat_ceed  `MATCEED`
64340d80af1SJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
64440d80af1SJames Wright 
64540d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
64640d80af1SJames Wright **/
64740d80af1SJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
64840d80af1SJames Wright   MatCeedContext ctx;
64940d80af1SJames Wright 
65040d80af1SJames Wright   PetscFunctionBeginUser;
65140d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
65240d80af1SJames Wright 
65340d80af1SJames 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");
65440d80af1SJames Wright 
65540d80af1SJames Wright   // Create sparse matrix
65640d80af1SJames Wright   {
65740d80af1SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
65840d80af1SJames Wright 
65940d80af1SJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
66040d80af1SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
66140d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
66240d80af1SJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
66340d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
66440d80af1SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
66540d80af1SJames Wright   }
66640d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
66740d80af1SJames Wright }
66840d80af1SJames Wright 
66940d80af1SJames Wright /**
67040d80af1SJames Wright   @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar.
67158600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
67258600ac3SJames Wright 
67358600ac3SJames Wright   Collective across MPI processes.
67458600ac3SJames Wright 
67558600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
67658600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
67758600ac3SJames Wright 
67858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
67958600ac3SJames Wright **/
68040d80af1SJames Wright PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) {
68158600ac3SJames Wright   MatCeedContext ctx;
68258600ac3SJames Wright 
68358600ac3SJames Wright   PetscFunctionBeginUser;
68458600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
68558600ac3SJames Wright 
68658600ac3SJames Wright   {
68758600ac3SJames Wright     PetscCount    num_entries;
68858600ac3SJames Wright     PetscLogStage stage_amg_setup;
689*b846ad1aSJames Wright     PetscObject   coo_struct;
69058600ac3SJames Wright 
691c63b910fSJames Wright     PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
69258600ac3SJames Wright     if (stage_amg_setup == -1) {
693c63b910fSJames Wright       PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
69458600ac3SJames Wright     }
69558600ac3SJames Wright     PetscCall(PetscLogStagePush(stage_amg_setup));
696c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
697*b846ad1aSJames Wright     PetscCall(PetscObjectQuery((PetscObject)mat_coo, "__PETSc_MatCOOStruct_Host", (PetscObject *)&coo_struct));
698*b846ad1aSJames Wright     // -- Check for existing assembly data
699*b846ad1aSJames Wright     if (!ctx->coo_reuse_preallocation || !coo_struct) {
700*b846ad1aSJames Wright       PetscInt *rows_petsc = NULL, *cols_petsc = NULL;
701*b846ad1aSJames Wright       CeedInt  *rows_ceed, *cols_ceed;
702*b846ad1aSJames Wright 
703*b846ad1aSJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
704c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
70550f50432SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
706c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
707a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
708a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
70958600ac3SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
71058600ac3SJames Wright       free(rows_petsc);
71158600ac3SJames Wright       free(cols_petsc);
712*b846ad1aSJames Wright     } else {
713*b846ad1aSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleGetNumEntries(ctx->op_mult, &num_entries));
714*b846ad1aSJames Wright     }
715*b846ad1aSJames Wright 
71650f50432SJames Wright     if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full));
71758600ac3SJames Wright     PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full));
71858600ac3SJames Wright     ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo;
719c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
72058600ac3SJames Wright     PetscCall(PetscLogStagePop());
72158600ac3SJames Wright   }
72240d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
72340d80af1SJames Wright }
72440d80af1SJames Wright 
72540d80af1SJames Wright /**
72640d80af1SJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
72740d80af1SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
72840d80af1SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
72940d80af1SJames Wright 
73040d80af1SJames Wright   Collective across MPI processes.
73140d80af1SJames Wright 
73240d80af1SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
73340d80af1SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
73440d80af1SJames Wright 
73540d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
73640d80af1SJames Wright **/
73740d80af1SJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
73840d80af1SJames Wright   MatCeedContext ctx;
73940d80af1SJames Wright 
74040d80af1SJames Wright   PetscFunctionBeginUser;
74140d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
74240d80af1SJames Wright 
74340d80af1SJames Wright   // Set COO pattern if needed
74440d80af1SJames Wright   {
74540d80af1SJames Wright     CeedInt index = -1;
74640d80af1SJames Wright 
74740d80af1SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
74840d80af1SJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
74940d80af1SJames Wright     }
75040d80af1SJames Wright     if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo));
75158600ac3SJames Wright   }
75258600ac3SJames Wright 
75358600ac3SJames Wright   // Assemble mat_ceed
754c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
75558600ac3SJames Wright   {
75658600ac3SJames Wright     const CeedScalar *values;
75758600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
75858600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
759ed5c6999SJames Wright     PetscMemType      mem_type_petsc;
76058600ac3SJames Wright 
7612da92326SJames Wright     PetscCall(MatGetMemTypeFromVecType(mat_coo, &mem_type_petsc));
762ed5c6999SJames Wright     mem_type = MemTypePetscToCeed(mem_type_petsc);
763c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
76450f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full));
765c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
76650f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values));
76758600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
76858600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
76958600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
77050f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values));
77158600ac3SJames Wright   }
772*b846ad1aSJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
77358600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
774c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
77558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
77658600ac3SJames Wright }
77758600ac3SJames Wright 
77858600ac3SJames Wright /**
77940d80af1SJames Wright   @brief Set the current value of a context field for a `MatCEED`.
78040d80af1SJames Wright 
78140d80af1SJames Wright   Not collective across MPI processes.
78240d80af1SJames Wright 
78340d80af1SJames Wright   @param[in,out]  mat    `MatCEED`
78440d80af1SJames Wright   @param[in]      name   Name of the context field
78540d80af1SJames Wright   @param[in]      value  New context field value
78640d80af1SJames Wright 
78740d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
78840d80af1SJames Wright **/
78940d80af1SJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
79040d80af1SJames Wright   PetscBool      was_updated = PETSC_FALSE;
79140d80af1SJames Wright   MatCeedContext ctx;
79240d80af1SJames Wright 
79340d80af1SJames Wright   PetscFunctionBeginUser;
79440d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
79540d80af1SJames Wright   {
79640d80af1SJames Wright     CeedContextFieldLabel label = NULL;
79740d80af1SJames Wright 
79840d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label));
79940d80af1SJames Wright     if (label) {
800000d2032SJeremy L Thompson       double set_value = 2 * value + 1.0;
801000d2032SJeremy L Thompson 
802000d2032SJeremy L Thompson       PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
803000d2032SJeremy L Thompson       if (set_value != value) {
80440d80af1SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value));
80540d80af1SJames Wright         was_updated = PETSC_TRUE;
80640d80af1SJames Wright       }
807000d2032SJeremy L Thompson     }
80840d80af1SJames Wright     if (ctx->op_mult_transpose) {
80940d80af1SJames Wright       label = NULL;
81040d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
81140d80af1SJames Wright       if (label) {
812000d2032SJeremy L Thompson         double set_value = 2 * value + 1.0;
813000d2032SJeremy L Thompson 
814000d2032SJeremy L Thompson         PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
815000d2032SJeremy L Thompson         if (set_value != value) {
81640d80af1SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
81740d80af1SJames Wright           was_updated = PETSC_TRUE;
81840d80af1SJames Wright         }
81940d80af1SJames Wright       }
82040d80af1SJames Wright     }
821000d2032SJeremy L Thompson   }
82240d80af1SJames Wright   if (was_updated) {
82340d80af1SJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
82440d80af1SJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
82540d80af1SJames Wright   }
82640d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
82740d80af1SJames Wright }
82840d80af1SJames Wright 
82940d80af1SJames Wright /**
83040d80af1SJames Wright   @brief Get the current value of a context field for a `MatCEED`.
83140d80af1SJames Wright 
83240d80af1SJames Wright   Not collective across MPI processes.
83340d80af1SJames Wright 
83440d80af1SJames Wright   @param[in]   mat    `MatCEED`
83540d80af1SJames Wright   @param[in]   name   Name of the context field
83640d80af1SJames Wright   @param[out]  value  Current context field value
83740d80af1SJames Wright 
83840d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
83940d80af1SJames Wright **/
84040d80af1SJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
84140d80af1SJames Wright   MatCeedContext ctx;
84240d80af1SJames Wright 
84340d80af1SJames Wright   PetscFunctionBeginUser;
84440d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
84540d80af1SJames Wright   {
84640d80af1SJames Wright     CeedContextFieldLabel label = NULL;
84740d80af1SJames Wright     CeedOperator          op    = ctx->op_mult;
84840d80af1SJames Wright 
84940d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
85040d80af1SJames Wright     if (!label && ctx->op_mult_transpose) {
85140d80af1SJames Wright       op = ctx->op_mult_transpose;
85240d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
85340d80af1SJames Wright     }
85440d80af1SJames Wright     if (label) {
85540d80af1SJames Wright       PetscSizeT    num_values;
85640d80af1SJames Wright       const double *values_ceed;
85740d80af1SJames Wright 
85840d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
85940d80af1SJames Wright       *value = values_ceed[0];
86040d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
86140d80af1SJames Wright     }
86240d80af1SJames Wright   }
86340d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
86440d80af1SJames Wright }
86540d80af1SJames Wright 
86640d80af1SJames Wright /**
867000d2032SJeremy L Thompson   @brief Set the current `PetscReal` value of a context field for a `MatCEED`.
868000d2032SJeremy L Thompson 
869000d2032SJeremy L Thompson   Not collective across MPI processes.
870000d2032SJeremy L Thompson 
871000d2032SJeremy L Thompson   @param[in,out]  mat    `MatCEED`
872000d2032SJeremy L Thompson   @param[in]      name   Name of the context field
873000d2032SJeremy L Thompson   @param[in]      value  New context field value
874000d2032SJeremy L Thompson 
875000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
876000d2032SJeremy L Thompson **/
877000d2032SJeremy L Thompson PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) {
878000d2032SJeremy L Thompson   double value_double = value;
879000d2032SJeremy L Thompson 
880000d2032SJeremy L Thompson   PetscFunctionBeginUser;
881000d2032SJeremy L Thompson   PetscCall(MatCeedSetContextDouble(mat, name, value_double));
882000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
883000d2032SJeremy L Thompson }
884000d2032SJeremy L Thompson 
885000d2032SJeremy L Thompson /**
88651bb547fSJames Wright   @brief Get the current `PetscReal` value of a context field for a `MatCEED`.
88751bb547fSJames Wright 
88851bb547fSJames Wright   Not collective across MPI processes.
88951bb547fSJames Wright 
89051bb547fSJames Wright   @param[in]   mat    `MatCEED`
89151bb547fSJames Wright   @param[in]   name   Name of the context field
89251bb547fSJames Wright   @param[out]  value  Current context field value
89351bb547fSJames Wright 
89451bb547fSJames Wright   @return An error code: 0 - success, otherwise - failure
89551bb547fSJames Wright **/
89651bb547fSJames Wright PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) {
89787d3884fSJeremy L Thompson   double value_double = 0.0;
89851bb547fSJames Wright 
89951bb547fSJames Wright   PetscFunctionBeginUser;
90051bb547fSJames Wright   PetscCall(MatCeedGetContextDouble(mat, name, &value_double));
90151bb547fSJames Wright   *value = value_double;
90251bb547fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
90351bb547fSJames Wright }
90451bb547fSJames Wright 
90551bb547fSJames Wright /**
906000d2032SJeremy L Thompson   @brief Set the current time for a `MatCEED`.
907000d2032SJeremy L Thompson 
908000d2032SJeremy L Thompson   Not collective across MPI processes.
909000d2032SJeremy L Thompson 
910000d2032SJeremy L Thompson   @param[in,out]  mat   `MatCEED`
911000d2032SJeremy L Thompson   @param[in]      time  Current time
912000d2032SJeremy L Thompson 
913000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
914000d2032SJeremy L Thompson **/
915000d2032SJeremy L Thompson PetscErrorCode MatCeedSetTime(Mat mat, PetscReal time) {
916000d2032SJeremy L Thompson   PetscFunctionBeginUser;
917000d2032SJeremy L Thompson   {
918000d2032SJeremy L Thompson     double time_ceed = time;
919000d2032SJeremy L Thompson 
920000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "time", time_ceed));
921000d2032SJeremy L Thompson   }
922000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
923000d2032SJeremy L Thompson }
924000d2032SJeremy L Thompson 
925000d2032SJeremy L Thompson /**
926000d2032SJeremy L Thompson   @brief Get the current time for a `MatCEED`.
927000d2032SJeremy L Thompson 
928000d2032SJeremy L Thompson   Not collective across MPI processes.
929000d2032SJeremy L Thompson 
930000d2032SJeremy L Thompson   @param[in]   mat   `MatCEED`
931000d2032SJeremy L Thompson   @param[out]  time  Current time, or -1.0 if the boundary evaluator has no time field
932000d2032SJeremy L Thompson 
933000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
934000d2032SJeremy L Thompson **/
935000d2032SJeremy L Thompson PetscErrorCode MatCeedGetTime(Mat mat, PetscReal *time) {
936000d2032SJeremy L Thompson   PetscFunctionBeginUser;
937000d2032SJeremy L Thompson   *time = -1.0;
938000d2032SJeremy L Thompson   {
939000d2032SJeremy L Thompson     double time_ceed = -1.0;
940000d2032SJeremy L Thompson 
941000d2032SJeremy L Thompson     PetscCall(MatCeedGetContextDouble(mat, "time", &time_ceed));
942000d2032SJeremy L Thompson     *time = time_ceed;
943000d2032SJeremy L Thompson   }
944000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
945000d2032SJeremy L Thompson }
946000d2032SJeremy L Thompson 
947000d2032SJeremy L Thompson /**
948000d2032SJeremy L Thompson   @brief Set the current time step for a `MatCEED`.
949000d2032SJeremy L Thompson 
950000d2032SJeremy L Thompson   Not collective across MPI processes.
951000d2032SJeremy L Thompson 
952000d2032SJeremy L Thompson   @param[in,out]  mat  `MatCEED`
953000d2032SJeremy L Thompson   @param[in]      dt   Current time step
954000d2032SJeremy L Thompson 
955000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
956000d2032SJeremy L Thompson **/
957000d2032SJeremy L Thompson PetscErrorCode MatCeedSetDt(Mat mat, PetscReal dt) {
958000d2032SJeremy L Thompson   PetscFunctionBeginUser;
959000d2032SJeremy L Thompson   {
960000d2032SJeremy L Thompson     double dt_ceed = dt;
961000d2032SJeremy L Thompson 
962000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "dt", dt_ceed));
963000d2032SJeremy L Thompson   }
964000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
965000d2032SJeremy L Thompson }
966000d2032SJeremy L Thompson 
967000d2032SJeremy L Thompson /**
968000d2032SJeremy L Thompson   @brief Set the Jacobian shifts for a `MatCEED`.
969000d2032SJeremy L Thompson 
970000d2032SJeremy L Thompson   Not collective across MPI processes.
971000d2032SJeremy L Thompson 
972000d2032SJeremy L Thompson   @param[in,out]  mat      `MatCEED`
973000d2032SJeremy L Thompson   @param[in]      shift_v  Velocity shift
974000d2032SJeremy L Thompson   @param[in]      shift_a  Acceleration shift
975000d2032SJeremy L Thompson 
976000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
977000d2032SJeremy L Thompson **/
978000d2032SJeremy L Thompson PetscErrorCode MatCeedSetShifts(Mat mat, PetscReal shift_v, PetscReal shift_a) {
979000d2032SJeremy L Thompson   PetscFunctionBeginUser;
980000d2032SJeremy L Thompson   {
981000d2032SJeremy L Thompson     double shift_v_ceed = shift_v;
982000d2032SJeremy L Thompson 
983000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift v", shift_v_ceed));
984000d2032SJeremy L Thompson   }
985000d2032SJeremy L Thompson   if (shift_a) {
986000d2032SJeremy L Thompson     double shift_a_ceed = shift_a;
987000d2032SJeremy L Thompson 
988000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift a", shift_a_ceed));
989000d2032SJeremy L Thompson   }
990000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
991000d2032SJeremy L Thompson }
992000d2032SJeremy L Thompson 
993000d2032SJeremy L Thompson /**
99458600ac3SJames Wright   @brief Set user context for a `MATCEED`.
99558600ac3SJames Wright 
99658600ac3SJames Wright   Collective across MPI processes.
99758600ac3SJames Wright 
99858600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
99958600ac3SJames Wright   @param[in]      f    The context destroy function, or NULL
100058600ac3SJames Wright   @param[in]      ctx  User context, or NULL to unset
100158600ac3SJames Wright 
100258600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
100358600ac3SJames Wright **/
100467aa9f91SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscCtxDestroyFn f, void *ctx) {
100558600ac3SJames Wright   PetscContainer user_ctx = NULL;
100658600ac3SJames Wright 
100758600ac3SJames Wright   PetscFunctionBeginUser;
100858600ac3SJames Wright   if (ctx) {
100958600ac3SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
101058600ac3SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
101167aa9f91SJames Wright     PetscCall(PetscContainerSetCtxDestroy(user_ctx, f));
101258600ac3SJames Wright   }
101358600ac3SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
101458600ac3SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
101558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
101658600ac3SJames Wright }
101758600ac3SJames Wright 
101858600ac3SJames Wright /**
101958600ac3SJames Wright   @brief Retrieve the user context for a `MATCEED`.
102058600ac3SJames Wright 
102158600ac3SJames Wright   Collective across MPI processes.
102258600ac3SJames Wright 
102358600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
102458600ac3SJames Wright   @param[in]      ctx  User context
102558600ac3SJames Wright 
102658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
102758600ac3SJames Wright **/
102858600ac3SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
102958600ac3SJames Wright   PetscContainer user_ctx;
103058600ac3SJames Wright 
103158600ac3SJames Wright   PetscFunctionBeginUser;
103258600ac3SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
103358600ac3SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
103458600ac3SJames Wright   else *(void **)ctx = NULL;
103558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
103658600ac3SJames Wright }
103758600ac3SJames Wright /**
103840d80af1SJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
103940d80af1SJames Wright 
104040d80af1SJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
104140d80af1SJames Wright `MatCeedSetContext()`.
104258600ac3SJames Wright 
104358600ac3SJames Wright   Collective across MPI processes.
104458600ac3SJames Wright 
104558600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
104640d80af1SJames Wright   @param[in]      op   Name of the `MatOperation`
104740d80af1SJames Wright   @param[in]      g    Function that provides the operation
104858600ac3SJames Wright 
104958600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
105058600ac3SJames Wright **/
1051*b846ad1aSJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
105240d80af1SJames Wright   PetscFunctionBeginUser;
1053*b846ad1aSJames Wright   PetscCall(MatShellSetOperation(mat, op, (MatSetOpFn)g));
1054*b846ad1aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1055*b846ad1aSJames Wright }
1056*b846ad1aSJames Wright 
1057*b846ad1aSJames Wright /**
1058*b846ad1aSJames Wright   @brief Set the flag for whether the `MATCEED` should reuse a COO matrix, even if not created by this `MATCEED`.
1059*b846ad1aSJames Wright 
1060*b846ad1aSJames Wright   @note Only set this flag if you are certain that the COO layout is properly set on incoming matrices.
1061*b846ad1aSJames Wright 
1062*b846ad1aSJames Wright   Collective across MPI processes.
1063*b846ad1aSJames Wright 
1064*b846ad1aSJames Wright   @param[in,out]  mat                      `MATCEED`
1065*b846ad1aSJames Wright   @param[in]      coo_reuse_preallocation  Flag value to set
1066*b846ad1aSJames Wright 
1067*b846ad1aSJames Wright   @return An error code: 0 - success, otherwise - failure
1068*b846ad1aSJames Wright **/
1069*b846ad1aSJames Wright PetscErrorCode MatCeedSetReusePreallocationCOO(Mat mat, PetscBool coo_reuse_preallocation) {
1070*b846ad1aSJames Wright   MatCeedContext ctx;
1071*b846ad1aSJames Wright 
1072*b846ad1aSJames Wright   PetscFunctionBeginUser;
1073*b846ad1aSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1074*b846ad1aSJames Wright   ctx->coo_reuse_preallocation = coo_reuse_preallocation;
1075*b846ad1aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1076*b846ad1aSJames Wright }
1077*b846ad1aSJames Wright 
1078*b846ad1aSJames Wright /**
1079*b846ad1aSJames Wright   @brief Gets the flag for whether the `MATCEED` should reuse a COO matrix, even if not created by this `MATCEED`.
1080*b846ad1aSJames Wright 
1081*b846ad1aSJames Wright   Collective across MPI processes.
1082*b846ad1aSJames Wright 
1083*b846ad1aSJames Wright   @param[in]  mat                      `MATCEED`
1084*b846ad1aSJames Wright   @param[in]  coo_reuse_preallocation  Address to store current flag value
1085*b846ad1aSJames Wright 
1086*b846ad1aSJames Wright   @return An error code: 0 - success, otherwise - failure
1087*b846ad1aSJames Wright **/
1088*b846ad1aSJames Wright PetscErrorCode MatCeedGetReusePreallocationCOO(Mat mat, PetscBool *coo_reuse_preallocation) {
1089*b846ad1aSJames Wright   MatCeedContext ctx;
1090*b846ad1aSJames Wright 
1091*b846ad1aSJames Wright   PetscFunctionBeginUser;
1092*b846ad1aSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1093*b846ad1aSJames Wright   *coo_reuse_preallocation = ctx->coo_reuse_preallocation;
109440d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
109540d80af1SJames Wright }
109640d80af1SJames Wright 
109740d80af1SJames Wright /**
109840d80af1SJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
109940d80af1SJames Wright 
110040d80af1SJames Wright   Collective across MPI processes.
110140d80af1SJames Wright 
110240d80af1SJames Wright   @param[in,out]  mat   `MATCEED`
110340d80af1SJames Wright   @param[in]      type  COO `MatType` to set
110440d80af1SJames Wright 
110540d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
110640d80af1SJames Wright **/
110740d80af1SJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
110858600ac3SJames Wright   MatCeedContext ctx;
110958600ac3SJames Wright 
111058600ac3SJames Wright   PetscFunctionBeginUser;
111158600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
111258600ac3SJames Wright   // Check if same
111358600ac3SJames Wright   {
111458600ac3SJames Wright     size_t    len_old, len_new;
111558600ac3SJames Wright     PetscBool is_same = PETSC_FALSE;
111658600ac3SJames Wright 
111740d80af1SJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
111858600ac3SJames Wright     PetscCall(PetscStrlen(type, &len_new));
111940d80af1SJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
112058600ac3SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
112158600ac3SJames Wright   }
112258600ac3SJames Wright   // Clean up old mats in different format
112358600ac3SJames Wright   // LCOV_EXCL_START
112458600ac3SJames Wright   if (ctx->mat_assembled_full_internal) {
112558600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
112658600ac3SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
112758600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
112858600ac3SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
112958600ac3SJames Wright         }
113058600ac3SJames Wright         ctx->num_mats_assembled_full--;
113158600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
113258600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
113358600ac3SJames Wright       }
113458600ac3SJames Wright     }
113558600ac3SJames Wright   }
113658600ac3SJames Wright   if (ctx->mat_assembled_pbd_internal) {
113758600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
113858600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
113958600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
114058600ac3SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
114158600ac3SJames Wright         }
114258600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
114358600ac3SJames Wright         ctx->num_mats_assembled_pbd--;
114458600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
114558600ac3SJames Wright       }
114658600ac3SJames Wright     }
114758600ac3SJames Wright   }
114840d80af1SJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
114940d80af1SJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
115058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
115158600ac3SJames Wright   // LCOV_EXCL_STOP
115258600ac3SJames Wright }
115358600ac3SJames Wright 
115458600ac3SJames Wright /**
115540d80af1SJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
115658600ac3SJames Wright 
115758600ac3SJames Wright   Collective across MPI processes.
115858600ac3SJames Wright 
115958600ac3SJames Wright   @param[in,out]  mat   `MATCEED`
116040d80af1SJames Wright   @param[in]      type  COO `MatType`
116158600ac3SJames Wright 
116258600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
116358600ac3SJames Wright **/
116440d80af1SJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
116558600ac3SJames Wright   MatCeedContext ctx;
116658600ac3SJames Wright 
116758600ac3SJames Wright   PetscFunctionBeginUser;
116858600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
116940d80af1SJames Wright   *type = ctx->coo_mat_type;
117058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
117158600ac3SJames Wright }
117258600ac3SJames Wright 
117358600ac3SJames Wright /**
117458600ac3SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
117558600ac3SJames Wright 
117658600ac3SJames Wright   Not collective across MPI processes.
117758600ac3SJames Wright 
117858600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
117958600ac3SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
118058600ac3SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
118158600ac3SJames Wright 
118258600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
118358600ac3SJames Wright **/
118458600ac3SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
118558600ac3SJames Wright   MatCeedContext ctx;
118658600ac3SJames Wright 
118758600ac3SJames Wright   PetscFunctionBeginUser;
118858600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
118958600ac3SJames Wright   if (X_loc) {
119058600ac3SJames Wright     PetscInt len_old, len_new;
119158600ac3SJames Wright 
119258600ac3SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
119358600ac3SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
119458600ac3SJames 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,
119558600ac3SJames Wright                len_new, len_old);
119640d80af1SJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
119758600ac3SJames Wright   }
119858600ac3SJames Wright   if (Y_loc_transpose) {
119958600ac3SJames Wright     PetscInt len_old, len_new;
120058600ac3SJames Wright 
120158600ac3SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
120258600ac3SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
120358600ac3SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
120458600ac3SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
120540d80af1SJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
120658600ac3SJames Wright   }
120758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
120858600ac3SJames Wright }
120958600ac3SJames Wright 
121058600ac3SJames Wright /**
121158600ac3SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
121258600ac3SJames Wright 
121358600ac3SJames Wright   Not collective across MPI processes.
121458600ac3SJames Wright 
121558600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
121658600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
121758600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
121858600ac3SJames Wright 
121958600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
122058600ac3SJames Wright **/
122158600ac3SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
122258600ac3SJames Wright   MatCeedContext ctx;
122358600ac3SJames Wright 
122458600ac3SJames Wright   PetscFunctionBeginUser;
122558600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
122658600ac3SJames Wright   if (X_loc) {
122740d80af1SJames Wright     *X_loc = NULL;
122840d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
122958600ac3SJames Wright   }
123058600ac3SJames Wright   if (Y_loc_transpose) {
123140d80af1SJames Wright     *Y_loc_transpose = NULL;
123240d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
123358600ac3SJames Wright   }
123458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
123558600ac3SJames Wright }
123658600ac3SJames Wright 
123758600ac3SJames Wright /**
123858600ac3SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
123958600ac3SJames Wright 
124058600ac3SJames Wright   Not collective across MPI processes.
124158600ac3SJames Wright 
124258600ac3SJames Wright   @param[in,out]  mat              MatCeed
124358600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
124458600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
124558600ac3SJames Wright 
124658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
124758600ac3SJames Wright **/
124858600ac3SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
124958600ac3SJames Wright   PetscFunctionBeginUser;
125058600ac3SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
125158600ac3SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
125258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
125358600ac3SJames Wright }
125458600ac3SJames Wright 
125558600ac3SJames Wright /**
125658600ac3SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
125758600ac3SJames Wright 
125858600ac3SJames Wright   Not collective across MPI processes.
125958600ac3SJames Wright 
126058600ac3SJames Wright   @param[in,out]  mat                MatCeed
126158600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
126258600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
126358600ac3SJames Wright 
126458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
126558600ac3SJames Wright **/
126658600ac3SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
126758600ac3SJames Wright   MatCeedContext ctx;
126858600ac3SJames Wright 
126958600ac3SJames Wright   PetscFunctionBeginUser;
127058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
127158600ac3SJames Wright   if (op_mult) {
127258600ac3SJames Wright     *op_mult = NULL;
127350f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
127458600ac3SJames Wright   }
127558600ac3SJames Wright   if (op_mult_transpose) {
127658600ac3SJames Wright     *op_mult_transpose = NULL;
127750f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
127858600ac3SJames Wright   }
127958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
128058600ac3SJames Wright }
128158600ac3SJames Wright 
128258600ac3SJames Wright /**
128358600ac3SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
128458600ac3SJames Wright 
128558600ac3SJames Wright   Not collective across MPI processes.
128658600ac3SJames Wright 
128758600ac3SJames Wright   @param[in,out]  mat                MatCeed
128858600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
128958600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
129058600ac3SJames Wright 
129158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
129258600ac3SJames Wright **/
129358600ac3SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
129458600ac3SJames Wright   MatCeedContext ctx;
129558600ac3SJames Wright 
129658600ac3SJames Wright   PetscFunctionBeginUser;
129758600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
129850f50432SJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
129950f50432SJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
130058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
130158600ac3SJames Wright }
130258600ac3SJames Wright 
130358600ac3SJames Wright /**
130458600ac3SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
130558600ac3SJames Wright 
130658600ac3SJames Wright   Not collective across MPI processes.
130758600ac3SJames Wright 
130858600ac3SJames Wright   @param[in,out]  mat                       MatCeed
130958600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
131058600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
131158600ac3SJames Wright 
131258600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
131358600ac3SJames Wright **/
131458600ac3SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
131558600ac3SJames Wright   MatCeedContext ctx;
131658600ac3SJames Wright 
131758600ac3SJames Wright   PetscFunctionBeginUser;
131858600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
131958600ac3SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
132058600ac3SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
132158600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
132258600ac3SJames Wright }
132358600ac3SJames Wright 
132458600ac3SJames Wright /**
132558600ac3SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
132658600ac3SJames Wright 
132758600ac3SJames Wright   Not collective across MPI processes.
132858600ac3SJames Wright 
132958600ac3SJames Wright   @param[in,out]  mat                       MatCeed
133058600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
133158600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
133258600ac3SJames Wright 
133358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
133458600ac3SJames Wright **/
133558600ac3SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
133658600ac3SJames Wright   MatCeedContext ctx;
133758600ac3SJames Wright 
133858600ac3SJames Wright   PetscFunctionBeginUser;
133958600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
134058600ac3SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
134158600ac3SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
134258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
134358600ac3SJames Wright }
134458600ac3SJames Wright 
1345c63b910fSJames Wright /**
1346c63b910fSJames Wright   @brief Set `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1347c63b910fSJames Wright 
1348c63b910fSJames Wright   Not collective across MPI processes.
1349c63b910fSJames Wright 
1350c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1351c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1352c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1353c63b910fSJames Wright 
1354c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1355c63b910fSJames Wright **/
1356c63b910fSJames Wright PetscErrorCode MatCeedSetCeedOperatorLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1357c63b910fSJames Wright   MatCeedContext ctx;
1358c63b910fSJames Wright 
1359c63b910fSJames Wright   PetscFunctionBeginUser;
1360c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1361c63b910fSJames Wright   if (log_event_mult) ctx->log_event_ceed_mult = log_event_mult;
1362c63b910fSJames Wright   if (log_event_mult_transpose) ctx->log_event_ceed_mult_transpose = log_event_mult_transpose;
1363c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1364c63b910fSJames Wright }
1365c63b910fSJames Wright 
1366c63b910fSJames Wright /**
1367c63b910fSJames Wright   @brief Get `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1368c63b910fSJames Wright 
1369c63b910fSJames Wright   Not collective across MPI processes.
1370c63b910fSJames Wright 
1371c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1372c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1373c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1374c63b910fSJames Wright 
1375c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1376c63b910fSJames Wright **/
1377c63b910fSJames Wright PetscErrorCode MatCeedGetCeedOperatorLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1378c63b910fSJames Wright   MatCeedContext ctx;
1379c63b910fSJames Wright 
1380c63b910fSJames Wright   PetscFunctionBeginUser;
1381c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1382c63b910fSJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_ceed_mult;
1383c63b910fSJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_ceed_mult_transpose;
1384c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1385c63b910fSJames Wright }
1386c63b910fSJames Wright 
138758600ac3SJames Wright // -----------------------------------------------------------------------------
138858600ac3SJames Wright // Operator context data
138958600ac3SJames Wright // -----------------------------------------------------------------------------
139058600ac3SJames Wright 
139158600ac3SJames Wright /**
139258600ac3SJames Wright   @brief Setup context data for operator application.
139358600ac3SJames Wright 
139458600ac3SJames Wright   Collective across MPI processes.
139558600ac3SJames Wright 
139658600ac3SJames Wright   @param[in]   dm_x                           Input `DM`
139758600ac3SJames Wright   @param[in]   dm_y                           Output `DM`
139858600ac3SJames Wright   @param[in]   X_loc                          Input PETSc local vector, or NULL
139958600ac3SJames Wright   @param[in]   Y_loc_transpose                Input PETSc local vector for transpose operation, or NULL
140058600ac3SJames Wright   @param[in]   op_mult                        `CeedOperator` for forward evaluation
140158600ac3SJames Wright   @param[in]   op_mult_transpose              `CeedOperator` for transpose evaluation
140258600ac3SJames Wright   @param[in]   log_event_mult                 `PetscLogEvent` for forward evaluation
140358600ac3SJames Wright   @param[in]   log_event_mult_transpose       `PetscLogEvent` for transpose evaluation
1404c63b910fSJames Wright   @param[in]   log_event_ceed_mult            `PetscLogEvent` for forward `CeedOperator` evaluation
1405c63b910fSJames Wright   @param[in]   log_event_ceed_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation
140658600ac3SJames Wright   @param[out]  ctx                            Context data for operator evaluation
140758600ac3SJames Wright 
140858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
140958600ac3SJames Wright **/
141058600ac3SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1411c63b910fSJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, PetscLogEvent log_event_ceed_mult,
1412c63b910fSJames Wright                                     PetscLogEvent log_event_ceed_mult_transpose, MatCeedContext *ctx) {
141358600ac3SJames Wright   CeedSize x_loc_len, y_loc_len;
141458600ac3SJames Wright 
141558600ac3SJames Wright   PetscFunctionBeginUser;
141658600ac3SJames Wright   // Allocate
141758600ac3SJames Wright   PetscCall(PetscNew(ctx));
141858600ac3SJames Wright   (*ctx)->ref_count = 1;
141958600ac3SJames Wright 
142058600ac3SJames Wright   // Logging
142158600ac3SJames Wright   (*ctx)->log_event_mult                = log_event_mult;
142258600ac3SJames Wright   (*ctx)->log_event_mult_transpose      = log_event_mult_transpose;
1423c63b910fSJames Wright   (*ctx)->log_event_ceed_mult           = log_event_ceed_mult;
1424c63b910fSJames Wright   (*ctx)->log_event_ceed_mult_transpose = log_event_ceed_mult_transpose;
142558600ac3SJames Wright 
142658600ac3SJames Wright   // PETSc objects
142740d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
142840d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
142940d80af1SJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
143040d80af1SJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
143158600ac3SJames Wright 
143258600ac3SJames Wright   // Memtype
143358600ac3SJames Wright   {
143458600ac3SJames Wright     const PetscScalar *x;
143558600ac3SJames Wright     Vec                X;
143658600ac3SJames Wright 
143758600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
143858600ac3SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
143958600ac3SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
144058600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
144158600ac3SJames Wright   }
144258600ac3SJames Wright 
144358600ac3SJames Wright   // libCEED objects
144458600ac3SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
144558600ac3SJames Wright              "retrieving Ceed context object failed");
144650f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
144750f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
144850f50432SJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
1449*b846ad1aSJames Wright   if (x_loc_len == -1) x_loc_len = 0;
145050f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
1451*b846ad1aSJames Wright   if (y_loc_len == -1) y_loc_len = 0;
145250f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
145358600ac3SJames Wright 
145458600ac3SJames Wright   // Flop counting
145558600ac3SJames Wright   {
145658600ac3SJames Wright     CeedSize ceed_flops_estimate = 0;
145758600ac3SJames Wright 
145850f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
145958600ac3SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
146058600ac3SJames Wright     if (op_mult_transpose) {
146150f50432SJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
146258600ac3SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
146358600ac3SJames Wright     }
146458600ac3SJames Wright   }
146558600ac3SJames Wright 
146658600ac3SJames Wright   // Check sizes
146758600ac3SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
146858600ac3SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
146958600ac3SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
147058600ac3SJames Wright     Vec      dm_X_loc, dm_Y_loc;
147158600ac3SJames Wright 
147258600ac3SJames Wright     // -- Input
147358600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
147458600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
147558600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
147650f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
14774c17272bSJames Wright     if (X_loc) {
14784c17272bSJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
14794c17272bSJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14804c17272bSJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
14814c17272bSJames Wright     }
14824c17272bSJames 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",
14834c17272bSJames Wright                x_loc_len, dm_x_loc_len);
14844c17272bSJames 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 ")",
14854c17272bSJames Wright                x_loc_len, ctx_x_loc_len);
148658600ac3SJames Wright 
148758600ac3SJames Wright     // -- Output
148858600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
148958600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
149058600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
149150f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
14924c17272bSJames 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",
14934c17272bSJames Wright                ctx_y_loc_len, dm_y_loc_len);
149458600ac3SJames Wright 
149558600ac3SJames Wright     // -- Transpose
149658600ac3SJames Wright     if (Y_loc_transpose) {
149758600ac3SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
14984c17272bSJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14994c17272bSJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
150058600ac3SJames Wright     }
150158600ac3SJames Wright   }
150258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
150358600ac3SJames Wright }
150458600ac3SJames Wright 
150558600ac3SJames Wright /**
150658600ac3SJames Wright   @brief Increment reference counter for `MATCEED` context.
150758600ac3SJames Wright 
150858600ac3SJames Wright   Not collective across MPI processes.
150958600ac3SJames Wright 
151058600ac3SJames Wright   @param[in,out]  ctx  Context data
151158600ac3SJames Wright 
151258600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
151358600ac3SJames Wright **/
151458600ac3SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
151558600ac3SJames Wright   PetscFunctionBeginUser;
151658600ac3SJames Wright   ctx->ref_count++;
151758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
151858600ac3SJames Wright }
151958600ac3SJames Wright 
152058600ac3SJames Wright /**
152158600ac3SJames Wright   @brief Copy reference for `MATCEED`.
152258600ac3SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
152358600ac3SJames Wright 
152458600ac3SJames Wright   Not collective across MPI processes.
152558600ac3SJames Wright 
152658600ac3SJames Wright   @param[in]   ctx       Context data
152758600ac3SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
152858600ac3SJames Wright 
152958600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
153058600ac3SJames Wright **/
153158600ac3SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
153258600ac3SJames Wright   PetscFunctionBeginUser;
153358600ac3SJames Wright   PetscCall(MatCeedContextReference(ctx));
153467aa9f91SJames Wright   PetscCall(MatCeedContextDestroy(ctx_copy));
153558600ac3SJames Wright   *ctx_copy = ctx;
153658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
153758600ac3SJames Wright }
153858600ac3SJames Wright 
153958600ac3SJames Wright /**
154058600ac3SJames Wright   @brief Destroy context data for operator application.
154158600ac3SJames Wright 
154258600ac3SJames Wright   Collective across MPI processes.
154358600ac3SJames Wright 
154458600ac3SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
154558600ac3SJames Wright 
154658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
154758600ac3SJames Wright **/
154867aa9f91SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext *ctx) {
154958600ac3SJames Wright   PetscFunctionBeginUser;
155067aa9f91SJames Wright   if (!ctx || --(*ctx)->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
155158600ac3SJames Wright 
155258600ac3SJames Wright   // PETSc objects
155367aa9f91SJames Wright   PetscCall(DMDestroy(&(*ctx)->dm_x));
155467aa9f91SJames Wright   PetscCall(DMDestroy(&(*ctx)->dm_y));
155567aa9f91SJames Wright   PetscCall(VecDestroy(&(*ctx)->X_loc));
155667aa9f91SJames Wright   PetscCall(VecDestroy(&(*ctx)->Y_loc_transpose));
155767aa9f91SJames Wright   PetscCall(MatDestroy(&(*ctx)->mat_assembled_full_internal));
155867aa9f91SJames Wright   PetscCall(MatDestroy(&(*ctx)->mat_assembled_pbd_internal));
155967aa9f91SJames Wright   PetscCall(PetscFree((*ctx)->coo_mat_type));
156067aa9f91SJames Wright   PetscCall(PetscFree((*ctx)->mats_assembled_full));
156167aa9f91SJames Wright   PetscCall(PetscFree((*ctx)->mats_assembled_pbd));
156258600ac3SJames Wright 
156358600ac3SJames Wright   // libCEED objects
156467aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->x_loc));
156567aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->y_loc));
156667aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->coo_values_full));
156767aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->coo_values_pbd));
156867aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorDestroy(&(*ctx)->op_mult));
156967aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorDestroy(&(*ctx)->op_mult_transpose));
157067aa9f91SJames Wright   PetscCheck(CeedDestroy(&(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
157158600ac3SJames Wright 
157258600ac3SJames Wright   // Deallocate
157367aa9f91SJames Wright   (*ctx)->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
157467aa9f91SJames Wright   PetscCall(PetscFree(*ctx));
157558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
157658600ac3SJames Wright }
157758600ac3SJames Wright 
157858600ac3SJames Wright /**
157958600ac3SJames Wright   @brief Compute the diagonal of an operator via libCEED.
158058600ac3SJames Wright 
158158600ac3SJames Wright   Collective across MPI processes.
158258600ac3SJames Wright 
158358600ac3SJames Wright   @param[in]   A  `MATCEED`
158458600ac3SJames Wright   @param[out]  D  Vector holding operator diagonal
158558600ac3SJames Wright 
158658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
158758600ac3SJames Wright **/
158858600ac3SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
158958600ac3SJames Wright   PetscMemType   mem_type;
159058600ac3SJames Wright   Vec            D_loc;
159158600ac3SJames Wright   MatCeedContext ctx;
159258600ac3SJames Wright 
159358600ac3SJames Wright   PetscFunctionBeginUser;
159458600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
159558600ac3SJames Wright 
159658600ac3SJames Wright   // Place PETSc vector in libCEED vector
1597c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
159858600ac3SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1599a7dac1d5SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
160058600ac3SJames Wright 
160158600ac3SJames Wright   // Compute Diagonal
1602c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
160350f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1604c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
160558600ac3SJames Wright 
160658600ac3SJames Wright   // Restore PETSc vector
1607a7dac1d5SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
160858600ac3SJames Wright 
160958600ac3SJames Wright   // Local-to-Global
161058600ac3SJames Wright   PetscCall(VecZeroEntries(D));
161158600ac3SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
161258600ac3SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1613c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
161458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
161558600ac3SJames Wright }
161658600ac3SJames Wright 
161758600ac3SJames Wright /**
161858600ac3SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
161958600ac3SJames Wright 
162058600ac3SJames Wright   Collective across MPI processes.
162158600ac3SJames Wright 
162258600ac3SJames Wright   @param[in]   A  `MATCEED`
162358600ac3SJames Wright   @param[in]   X  Input PETSc vector
162458600ac3SJames Wright   @param[out]  Y  Output PETSc vector
162558600ac3SJames Wright 
162658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
162758600ac3SJames Wright **/
162858600ac3SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
162958600ac3SJames Wright   MatCeedContext ctx;
163058600ac3SJames Wright 
163158600ac3SJames Wright   PetscFunctionBeginUser;
163258600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1633c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, NULL));
163458600ac3SJames Wright 
163558600ac3SJames Wright   {
163658600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
163758600ac3SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
163858600ac3SJames Wright 
163958600ac3SJames Wright     // Get local vectors
164058600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
164158600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
164258600ac3SJames Wright 
164358600ac3SJames Wright     // Global-to-local
164458600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
164558600ac3SJames Wright 
164658600ac3SJames Wright     // Setup libCEED vectors
1647a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
164858600ac3SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1649a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
165058600ac3SJames Wright 
165158600ac3SJames Wright     // Apply libCEED operator
1652c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult, A, X, Y, NULL));
1653537ec908SJames Wright     PetscCall(PetscLogGpuTimeBegin());
165450f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
1655ed5c6999SJames Wright     // Log flops
1656ed5c6999SJames Wright     if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
1657ed5c6999SJames Wright     else PetscCall(PetscLogFlops(ctx->flops_mult));
165858600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1659537ec908SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult, A, X, Y, NULL));
166058600ac3SJames Wright 
166158600ac3SJames Wright     // Restore PETSc vectors
1662a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1663a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
166458600ac3SJames Wright 
166558600ac3SJames Wright     // Local-to-global
166658600ac3SJames Wright     PetscCall(VecZeroEntries(Y));
166758600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
166858600ac3SJames Wright 
166958600ac3SJames Wright     // Restore local vectors, as needed
167058600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
167158600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
167258600ac3SJames Wright   }
167358600ac3SJames Wright 
1674c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, NULL));
167558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
167658600ac3SJames Wright }
167758600ac3SJames Wright 
167858600ac3SJames Wright /**
167958600ac3SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
168058600ac3SJames Wright 
168158600ac3SJames Wright   Collective across MPI processes.
168258600ac3SJames Wright 
168358600ac3SJames Wright   @param[in]   A  `MATCEED`
168458600ac3SJames Wright   @param[in]   Y  Input PETSc vector
168558600ac3SJames Wright   @param[out]  X  Output PETSc vector
168658600ac3SJames Wright 
168758600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
168858600ac3SJames Wright **/
168958600ac3SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
169058600ac3SJames Wright   MatCeedContext ctx;
169158600ac3SJames Wright 
169258600ac3SJames Wright   PetscFunctionBeginUser;
169358600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1694c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, NULL));
169558600ac3SJames Wright 
169658600ac3SJames Wright   {
169758600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
169858600ac3SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
169958600ac3SJames Wright 
170058600ac3SJames Wright     // Get local vectors
170158600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
170258600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
170358600ac3SJames Wright 
170458600ac3SJames Wright     // Global-to-local
170558600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
170658600ac3SJames Wright 
170758600ac3SJames Wright     // Setup libCEED vectors
1708a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
170958600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
1710a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
171158600ac3SJames Wright 
171258600ac3SJames Wright     // Apply libCEED operator
1713c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
1714537ec908SJames Wright     PetscCall(PetscLogGpuTimeBegin());
171550f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1716ed5c6999SJames Wright     // Log flops
1717ed5c6999SJames Wright     if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
1718ed5c6999SJames Wright     else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
171958600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1720537ec908SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
172158600ac3SJames Wright 
172258600ac3SJames Wright     // Restore PETSc vectors
1723a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1724a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
172558600ac3SJames Wright 
172658600ac3SJames Wright     // Local-to-global
172758600ac3SJames Wright     PetscCall(VecZeroEntries(X));
172858600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
172958600ac3SJames Wright 
173058600ac3SJames Wright     // Restore local vectors, as needed
173158600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
173258600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
173358600ac3SJames Wright   }
173458600ac3SJames Wright 
1735c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, NULL));
173658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
173758600ac3SJames Wright }
1738