xref: /honee/src/mat-ceed.c (revision ae2b091fac884a554e48acc4b4c187524c2a2818)
1*ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2*ae2b091fSJames 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 
1958600ac3SJames Wright PetscClassId  MATCEED_CLASSID;
20c63b910fSJames Wright PetscLogEvent MATCEED_MULT, MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE, MATCEED_MULT_TRANSPOSE_CEEDOP, MATCEED_ASSEMBLE_DIAGONAL,
21c63b910fSJames Wright     MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, MATCEED_SETUP_PBDIAGONAL, MATCEED_SETUP_PBDIAGONAL_CEEDOP, MATCEED_ASSEMBLE_PBDIAGONAL,
22c63b910fSJames Wright     MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, MATCEED_SETUP_FULL, MATCEED_SETUP_FULL_CEEDOP, MATCEED_ASSEMBLE_FULL, MATCEED_ASSEMBLE_FULL_CEEDOP;
2358600ac3SJames Wright 
2458600ac3SJames Wright /**
2558600ac3SJames Wright   @brief Register MATCEED log events.
2658600ac3SJames Wright 
2758600ac3SJames Wright   Not collective across MPI processes.
2858600ac3SJames Wright 
2958600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
3058600ac3SJames Wright **/
3158600ac3SJames Wright static PetscErrorCode MatCeedRegisterLogEvents() {
3240d80af1SJames Wright   static PetscBool registered = PETSC_FALSE;
3358600ac3SJames Wright 
3458600ac3SJames Wright   PetscFunctionBeginUser;
3558600ac3SJames Wright   if (registered) PetscFunctionReturn(PETSC_SUCCESS);
36c63b910fSJames Wright   PetscCall(PetscClassIdRegister("MatCEED", &MATCEED_CLASSID));
37c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMul", MATCEED_CLASSID, &MATCEED_MULT));
38c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulCeed", MATCEED_CLASSID, &MATCEED_MULT_CEEDOP));
39c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulT", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE));
40c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulTCeed", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE_CEEDOP));
41c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmDiag", MATCEED_CLASSID, &MATCEED_ASSEMBLE_DIAGONAL));
42c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSU", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL));
43c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL_CEEDOP));
44c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBD", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL));
45c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP));
46c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSU", MATCEED_CLASSID, &MATCEED_SETUP_FULL));
47c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_FULL_CEEDOP));
48c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsm", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL));
49c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL_CEEDOP));
5040d80af1SJames Wright   registered = PETSC_TRUE;
5158600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
5258600ac3SJames Wright }
5358600ac3SJames Wright 
5458600ac3SJames Wright /**
5558600ac3SJames Wright   @brief Assemble the point block diagonal of a `MATCEED` into a `MATAIJ` or similar.
5658600ac3SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
5758600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
5858600ac3SJames Wright 
5958600ac3SJames Wright   Collective across MPI processes.
6058600ac3SJames Wright 
6158600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
6258600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
6358600ac3SJames Wright 
6458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
6558600ac3SJames Wright **/
6658600ac3SJames Wright static PetscErrorCode MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed, Mat mat_coo) {
6758600ac3SJames Wright   MatCeedContext ctx;
6858600ac3SJames Wright 
6958600ac3SJames Wright   PetscFunctionBeginUser;
7058600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
7158600ac3SJames Wright 
7258600ac3SJames Wright   // Check if COO pattern set
7358600ac3SJames Wright   {
7458600ac3SJames Wright     PetscInt index = -1;
7558600ac3SJames Wright 
7658600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
7758600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == mat_coo) index = i;
7858600ac3SJames Wright     }
7958600ac3SJames Wright     if (index == -1) {
8058600ac3SJames Wright       PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
8158600ac3SJames Wright       CeedInt      *rows_ceed, *cols_ceed;
8258600ac3SJames Wright       PetscCount    num_entries;
8358600ac3SJames Wright       PetscLogStage stage_amg_setup;
8458600ac3SJames Wright 
8558600ac3SJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
86c63b910fSJames Wright       PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
8758600ac3SJames Wright       if (stage_amg_setup == -1) {
88c63b910fSJames Wright         PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
8958600ac3SJames Wright       }
9058600ac3SJames Wright       PetscCall(PetscLogStagePush(stage_amg_setup));
91c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
92c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
9350f50432SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
94c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
95a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
96a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
9758600ac3SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
9858600ac3SJames Wright       free(rows_petsc);
9958600ac3SJames Wright       free(cols_petsc);
10050f50432SJames Wright       if (!ctx->coo_values_pbd) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_pbd));
10158600ac3SJames Wright       PetscCall(PetscRealloc(++ctx->num_mats_assembled_pbd * sizeof(Mat), &ctx->mats_assembled_pbd));
10258600ac3SJames Wright       ctx->mats_assembled_pbd[ctx->num_mats_assembled_pbd - 1] = mat_coo;
103c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
10458600ac3SJames Wright       PetscCall(PetscLogStagePop());
10558600ac3SJames Wright     }
10658600ac3SJames Wright   }
10758600ac3SJames Wright 
10858600ac3SJames Wright   // Assemble mat_ceed
109c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
11058600ac3SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
11158600ac3SJames Wright   {
11258600ac3SJames Wright     const CeedScalar *values;
11358600ac3SJames Wright     MatType           mat_type;
11458600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
11558600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
11658600ac3SJames Wright 
11758600ac3SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
11858600ac3SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
11958600ac3SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
12058600ac3SJames Wright     else mem_type = CEED_MEM_HOST;
12158600ac3SJames Wright 
122c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12350f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonal(ctx->op_mult, ctx->coo_values_pbd, CEED_REQUEST_IMMEDIATE));
124c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12550f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_pbd, mem_type, &values));
12658600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
12758600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
12858600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
12950f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_pbd, &values));
13058600ac3SJames Wright   }
13158600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
132c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
13358600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
13458600ac3SJames Wright }
13558600ac3SJames Wright 
13658600ac3SJames Wright /**
13758600ac3SJames Wright   @brief Assemble inner `Mat` for diagonal `PC` operations
13858600ac3SJames Wright 
13958600ac3SJames Wright   Collective across MPI processes.
14058600ac3SJames Wright 
14158600ac3SJames Wright   @param[in]   mat_ceed      `MATCEED` to invert
14258600ac3SJames Wright   @param[in]   use_ceed_pbd  Boolean flag to use libCEED PBD assembly
14358600ac3SJames Wright   @param[out]  mat_inner     Inner `Mat` for diagonal operations
14458600ac3SJames Wright 
14558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
14658600ac3SJames Wright **/
14758600ac3SJames Wright static PetscErrorCode MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed, PetscBool use_ceed_pbd, Mat *mat_inner) {
14858600ac3SJames Wright   MatCeedContext ctx;
14958600ac3SJames Wright 
15058600ac3SJames Wright   PetscFunctionBeginUser;
15158600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
15258600ac3SJames Wright   if (use_ceed_pbd) {
15358600ac3SJames Wright     // Check if COO pattern set
15440d80af1SJames Wright     if (!ctx->mat_assembled_pbd_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_pbd_internal));
15558600ac3SJames Wright 
15658600ac3SJames Wright     // Assemble mat_assembled_full_internal
15758600ac3SJames Wright     PetscCall(MatCeedAssemblePointBlockDiagonalCOO(mat_ceed, ctx->mat_assembled_pbd_internal));
15858600ac3SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_pbd_internal;
15958600ac3SJames Wright   } else {
16058600ac3SJames Wright     // Check if COO pattern set
16140d80af1SJames Wright     if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
16258600ac3SJames Wright 
16358600ac3SJames Wright     // Assemble mat_assembled_full_internal
16458600ac3SJames Wright     PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
16558600ac3SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_full_internal;
16658600ac3SJames Wright   }
16758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
16858600ac3SJames Wright }
16958600ac3SJames Wright 
17058600ac3SJames Wright /**
17158600ac3SJames Wright   @brief Get `MATCEED` diagonal block for Jacobi.
17258600ac3SJames Wright 
17358600ac3SJames Wright   Collective across MPI processes.
17458600ac3SJames Wright 
17558600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
17658600ac3SJames Wright   @param[out]  mat_block  The diagonal block matrix
17758600ac3SJames Wright 
17858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
17958600ac3SJames Wright **/
18058600ac3SJames Wright static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) {
18158600ac3SJames Wright   Mat            mat_inner = NULL;
18258600ac3SJames Wright   MatCeedContext ctx;
18358600ac3SJames Wright 
18458600ac3SJames Wright   PetscFunctionBeginUser;
18558600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
18658600ac3SJames Wright 
18758600ac3SJames Wright   // Assemble inner mat if needed
18858600ac3SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
18958600ac3SJames Wright 
19058600ac3SJames Wright   // Get block diagonal
19158600ac3SJames Wright   PetscCall(MatGetDiagonalBlock(mat_inner, mat_block));
19258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
19358600ac3SJames Wright }
19458600ac3SJames Wright 
19558600ac3SJames Wright /**
19658600ac3SJames Wright   @brief Invert `MATCEED` diagonal block for Jacobi.
19758600ac3SJames Wright 
19858600ac3SJames Wright   Collective across MPI processes.
19958600ac3SJames Wright 
20058600ac3SJames Wright   @param[in]   mat_ceed  `MATCEED` to invert
20158600ac3SJames Wright   @param[out]  values    The block inverses in column major order
20258600ac3SJames Wright 
20358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
20458600ac3SJames Wright **/
20558600ac3SJames Wright static PetscErrorCode MatInvertBlockDiagonal_Ceed(Mat mat_ceed, const PetscScalar **values) {
20658600ac3SJames Wright   Mat            mat_inner = NULL;
20758600ac3SJames Wright   MatCeedContext ctx;
20858600ac3SJames Wright 
20958600ac3SJames Wright   PetscFunctionBeginUser;
21058600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
21158600ac3SJames Wright 
21258600ac3SJames Wright   // Assemble inner mat if needed
21358600ac3SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
21458600ac3SJames Wright 
21558600ac3SJames Wright   // Invert PB diagonal
21658600ac3SJames Wright   PetscCall(MatInvertBlockDiagonal(mat_inner, values));
21758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
21858600ac3SJames Wright }
21958600ac3SJames Wright 
22058600ac3SJames Wright /**
22158600ac3SJames Wright   @brief Invert `MATCEED` variable diagonal block for Jacobi.
22258600ac3SJames Wright 
22358600ac3SJames Wright   Collective across MPI processes.
22458600ac3SJames Wright 
22558600ac3SJames Wright   @param[in]   mat_ceed     `MATCEED` to invert
22658600ac3SJames Wright   @param[in]   num_blocks   The number of blocks on the process
22758600ac3SJames Wright   @param[in]   block_sizes  The size of each block on the process
22858600ac3SJames Wright   @param[out]  values       The block inverses in column major order
22958600ac3SJames Wright 
23058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
23158600ac3SJames Wright **/
23258600ac3SJames Wright static PetscErrorCode MatInvertVariableBlockDiagonal_Ceed(Mat mat_ceed, PetscInt num_blocks, const PetscInt *block_sizes, PetscScalar *values) {
23358600ac3SJames Wright   Mat            mat_inner = NULL;
23458600ac3SJames Wright   MatCeedContext ctx;
23558600ac3SJames Wright 
23658600ac3SJames Wright   PetscFunctionBeginUser;
23758600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
23858600ac3SJames Wright 
23958600ac3SJames Wright   // Assemble inner mat if needed
24058600ac3SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, &mat_inner));
24158600ac3SJames Wright 
24258600ac3SJames Wright   // Invert PB diagonal
24358600ac3SJames Wright   PetscCall(MatInvertVariableBlockDiagonal(mat_inner, num_blocks, block_sizes, values));
24458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
24558600ac3SJames Wright }
24658600ac3SJames Wright 
247e90c2ceeSJames 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'};
279e90c2ceeSJames Wright     FILE     *file;
280e90c2ceeSJames Wright 
28140d80af1SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n  Default COO MatType:%s\n", ctx->coo_mat_type));
282e90c2ceeSJames Wright     PetscCall(PetscViewerASCIIGetPointer(viewer, &file));
283000d2032SJeremy L Thompson     PetscCall(PetscSNPrintf(rank_string, 16, "on Rank %d", rank));
284000d2032SJeremy L Thompson     PetscCall(PetscViewerASCIIPrintf(viewer, " CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary"));
285000d2032SJeremy L Thompson     if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file));
286000d2032SJeremy L Thompson     else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult, file));
287e90c2ceeSJames Wright     if (ctx->op_mult_transpose) {
288000d2032SJeremy L Thompson       PetscCall(PetscViewerASCIIPrintf(viewer, "  CeedOperator ApplyTranspose %s:\n", is_detailed ? rank_string : "Summary"));
289000d2032SJeremy L Thompson       if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file));
290000d2032SJeremy L Thompson       else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult_transpose, file));
291e90c2ceeSJames Wright     }
292e90c2ceeSJames Wright   }
293e90c2ceeSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
294e90c2ceeSJames Wright }
295e90c2ceeSJames Wright 
29658600ac3SJames Wright // -----------------------------------------------------------------------------
29758600ac3SJames Wright // MatCeed
29858600ac3SJames Wright // -----------------------------------------------------------------------------
29958600ac3SJames Wright 
30058600ac3SJames Wright /**
30158600ac3SJames Wright   @brief Create PETSc `Mat` from libCEED operators.
30258600ac3SJames Wright 
30358600ac3SJames Wright   Collective across MPI processes.
30458600ac3SJames Wright 
30558600ac3SJames Wright   @param[in]   dm_x                      Input `DM`
30658600ac3SJames Wright   @param[in]   dm_y                      Output `DM`
30758600ac3SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
30858600ac3SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
30958600ac3SJames Wright   @param[out]  mat                        New MatCeed
31058600ac3SJames Wright 
31158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
31258600ac3SJames Wright **/
313000d2032SJeremy L Thompson PetscErrorCode MatCreateCeed(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) {
31458600ac3SJames Wright   PetscInt       X_l_size, X_g_size, Y_l_size, Y_g_size;
31558600ac3SJames Wright   VecType        vec_type;
31658600ac3SJames Wright   MatCeedContext ctx;
31758600ac3SJames Wright 
31858600ac3SJames Wright   PetscFunctionBeginUser;
31958600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
32058600ac3SJames Wright 
32158600ac3SJames Wright   // Collect context data
32258600ac3SJames Wright   PetscCall(DMGetVecType(dm_x, &vec_type));
32358600ac3SJames Wright   {
32458600ac3SJames Wright     Vec X;
32558600ac3SJames Wright 
32658600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_x, &X));
32758600ac3SJames Wright     PetscCall(VecGetSize(X, &X_g_size));
32858600ac3SJames Wright     PetscCall(VecGetLocalSize(X, &X_l_size));
32958600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_x, &X));
33058600ac3SJames Wright   }
33158600ac3SJames Wright   if (dm_y) {
33258600ac3SJames Wright     Vec Y;
33358600ac3SJames Wright 
33458600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_y, &Y));
33558600ac3SJames Wright     PetscCall(VecGetSize(Y, &Y_g_size));
33658600ac3SJames Wright     PetscCall(VecGetLocalSize(Y, &Y_l_size));
33758600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_y, &Y));
33858600ac3SJames Wright   } else {
33958600ac3SJames Wright     dm_y     = dm_x;
34058600ac3SJames Wright     Y_g_size = X_g_size;
34158600ac3SJames Wright     Y_l_size = X_l_size;
34258600ac3SJames Wright   }
34340d80af1SJames Wright 
34458600ac3SJames Wright   // Create context
34558600ac3SJames Wright   {
34658600ac3SJames Wright     Vec X_loc, Y_loc_transpose = NULL;
34758600ac3SJames Wright 
34858600ac3SJames Wright     PetscCall(DMCreateLocalVector(dm_x, &X_loc));
34958600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
35058600ac3SJames Wright     if (op_mult_transpose) {
35158600ac3SJames Wright       PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose));
35258600ac3SJames Wright       PetscCall(VecZeroEntries(Y_loc_transpose));
35358600ac3SJames Wright     }
354c63b910fSJames Wright     PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE,
355c63b910fSJames Wright                                    MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE_CEEDOP, &ctx));
35658600ac3SJames Wright     PetscCall(VecDestroy(&X_loc));
35758600ac3SJames Wright     PetscCall(VecDestroy(&Y_loc_transpose));
35858600ac3SJames Wright   }
35958600ac3SJames Wright 
36058600ac3SJames Wright   // Create mat
36158600ac3SJames Wright   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat));
36258600ac3SJames Wright   PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED));
36358600ac3SJames Wright   // -- Set block and variable block sizes
36458600ac3SJames Wright   if (dm_x == dm_y) {
36558600ac3SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
36658600ac3SJames Wright     Mat     temp_mat;
36758600ac3SJames Wright 
36858600ac3SJames Wright     PetscCall(DMGetMatType(dm_x, &dm_mat_type));
36958600ac3SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
37058600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, MATAIJ));
37158600ac3SJames Wright     PetscCall(DMCreateMatrix(dm_x, &temp_mat));
37258600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, dm_mat_type_copy));
37358600ac3SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
37458600ac3SJames Wright 
37558600ac3SJames Wright     {
37658600ac3SJames Wright       PetscInt        block_size, num_blocks, max_vblock_size = PETSC_INT_MAX;
37758600ac3SJames Wright       const PetscInt *vblock_sizes;
37858600ac3SJames Wright 
37958600ac3SJames Wright       // -- Get block sizes
38058600ac3SJames Wright       PetscCall(MatGetBlockSize(temp_mat, &block_size));
38158600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes));
38258600ac3SJames Wright       {
38358600ac3SJames Wright         PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX};
38458600ac3SJames Wright 
38558600ac3SJames Wright         for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]);
38658600ac3SJames Wright         PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max));
38758600ac3SJames Wright         max_vblock_size = global_min_max[1];
38858600ac3SJames Wright       }
38958600ac3SJames Wright 
39058600ac3SJames Wright       // -- Copy block sizes
39158600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size));
39258600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes));
39358600ac3SJames Wright 
39458600ac3SJames Wright       // -- Check libCEED compatibility
39558600ac3SJames Wright       {
39658600ac3SJames Wright         bool is_composite;
39758600ac3SJames Wright 
39858600ac3SJames Wright         ctx->is_ceed_pbd_valid  = PETSC_TRUE;
39958600ac3SJames Wright         ctx->is_ceed_vpbd_valid = PETSC_TRUE;
40050f50432SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite));
40158600ac3SJames Wright         if (is_composite) {
40258600ac3SJames Wright           CeedInt       num_sub_operators;
40358600ac3SJames Wright           CeedOperator *sub_operators;
40458600ac3SJames Wright 
40550f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetNumSub(op_mult, &num_sub_operators));
40650f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetSubList(op_mult, &sub_operators));
40758600ac3SJames Wright           for (CeedInt i = 0; i < num_sub_operators; i++) {
40858600ac3SJames Wright             CeedInt                  num_bases, num_comp;
40958600ac3SJames Wright             CeedBasis               *active_bases;
41058600ac3SJames Wright             CeedOperatorAssemblyData assembly_data;
41158600ac3SJames Wright 
41250f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data));
41350f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
41450f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
41558600ac3SJames Wright             if (num_bases > 1) {
41658600ac3SJames Wright               ctx->is_ceed_pbd_valid  = PETSC_FALSE;
41758600ac3SJames Wright               ctx->is_ceed_vpbd_valid = PETSC_FALSE;
41858600ac3SJames Wright             }
41958600ac3SJames Wright             if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
42058600ac3SJames Wright             if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
42158600ac3SJames Wright           }
42258600ac3SJames Wright         } else {
42358600ac3SJames Wright           // LCOV_EXCL_START
42458600ac3SJames Wright           CeedInt                  num_bases, num_comp;
42558600ac3SJames Wright           CeedBasis               *active_bases;
42658600ac3SJames Wright           CeedOperatorAssemblyData assembly_data;
42758600ac3SJames Wright 
42850f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data));
42950f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
43050f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
43158600ac3SJames Wright           if (num_bases > 1) {
43258600ac3SJames Wright             ctx->is_ceed_pbd_valid  = PETSC_FALSE;
43358600ac3SJames Wright             ctx->is_ceed_vpbd_valid = PETSC_FALSE;
43458600ac3SJames Wright           }
43558600ac3SJames Wright           if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
43658600ac3SJames Wright           if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
43758600ac3SJames Wright           // LCOV_EXCL_STOP
43858600ac3SJames Wright         }
43958600ac3SJames Wright         {
44058600ac3SJames Wright           PetscInt local_is_valid[2], global_is_valid[2];
44158600ac3SJames Wright 
44258600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid;
44358600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
44458600ac3SJames Wright           ctx->is_ceed_pbd_valid = global_is_valid[0];
44558600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid;
44658600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
44758600ac3SJames Wright           ctx->is_ceed_vpbd_valid = global_is_valid[0];
44858600ac3SJames Wright         }
44958600ac3SJames Wright       }
45058600ac3SJames Wright     }
45158600ac3SJames Wright     PetscCall(MatDestroy(&temp_mat));
45258600ac3SJames Wright   }
45358600ac3SJames Wright   // -- Set internal mat type
45458600ac3SJames Wright   {
45558600ac3SJames Wright     VecType vec_type;
45640d80af1SJames Wright     MatType coo_mat_type;
45758600ac3SJames Wright 
45858600ac3SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
45940d80af1SJames Wright     if (strstr(vec_type, VECCUDA)) coo_mat_type = MATAIJCUSPARSE;
46040d80af1SJames Wright     else if (strstr(vec_type, VECKOKKOS)) coo_mat_type = MATAIJKOKKOS;
46140d80af1SJames Wright     else coo_mat_type = MATAIJ;
46240d80af1SJames Wright     PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type));
46358600ac3SJames Wright   }
46458600ac3SJames Wright   // -- Set mat operations
46558600ac3SJames Wright   PetscCall(MatShellSetContextDestroy(*mat, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
466e90c2ceeSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (void (*)(void))MatView_Ceed));
46758600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (void (*)(void))MatMult_Ceed));
46858600ac3SJames Wright   if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
46958600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
47058600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
47158600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
47258600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
47358600ac3SJames Wright   PetscCall(MatShellSetVecType(*mat, vec_type));
47458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
47558600ac3SJames Wright }
47658600ac3SJames Wright 
47758600ac3SJames Wright /**
47858600ac3SJames Wright   @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`.
47958600ac3SJames Wright 
48058600ac3SJames Wright   Collective across MPI processes.
48158600ac3SJames Wright 
48258600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to copy from
48358600ac3SJames Wright   @param[out]  mat_other  `MatShell` or `MATCEED` to copy into
48458600ac3SJames Wright 
48558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
48658600ac3SJames Wright **/
48758600ac3SJames Wright PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) {
48858600ac3SJames Wright   PetscFunctionBeginUser;
48958600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
49058600ac3SJames Wright 
49158600ac3SJames Wright   // Check type compatibility
49258600ac3SJames Wright   {
49340d80af1SJames Wright     PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE;
49458600ac3SJames Wright     MatType   mat_type_ceed, mat_type_other;
49558600ac3SJames Wright 
49658600ac3SJames Wright     PetscCall(MatGetType(mat_ceed, &mat_type_ceed));
49740d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
49840d80af1SJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
49940d80af1SJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
50040d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
50140d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matceed));
50240d80af1SJames Wright     PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL);
50358600ac3SJames Wright   }
50458600ac3SJames Wright 
50558600ac3SJames Wright   // Check dimension compatibility
50658600ac3SJames Wright   {
50758600ac3SJames 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;
50858600ac3SJames Wright 
50958600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size));
51058600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size));
51158600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size));
51258600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size));
51358600ac3SJames 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) &&
51458600ac3SJames Wright                    (X_l_ceed_size == X_l_other_size),
51558600ac3SJames Wright                PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
51658600ac3SJames Wright                "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT
51758600ac3SJames Wright                "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT
51858600ac3SJames Wright                ", %" PetscInt_FMT ")",
51958600ac3SJames 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);
52058600ac3SJames Wright   }
52158600ac3SJames Wright 
52258600ac3SJames Wright   // Convert
52358600ac3SJames Wright   {
52458600ac3SJames Wright     VecType        vec_type;
52558600ac3SJames Wright     MatCeedContext ctx;
52658600ac3SJames Wright 
52758600ac3SJames Wright     PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED));
52858600ac3SJames Wright     PetscCall(MatShellGetContext(mat_ceed, &ctx));
52958600ac3SJames Wright     PetscCall(MatCeedContextReference(ctx));
53058600ac3SJames Wright     PetscCall(MatShellSetContext(mat_other, ctx));
53158600ac3SJames Wright     PetscCall(MatShellSetContextDestroy(mat_other, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
532e90c2ceeSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (void (*)(void))MatView_Ceed));
53358600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (void (*)(void))MatMult_Ceed));
53458600ac3SJames Wright     if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
53558600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
53658600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
53758600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
53858600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
53958600ac3SJames Wright     {
54058600ac3SJames Wright       PetscInt block_size;
54158600ac3SJames Wright 
54258600ac3SJames Wright       PetscCall(MatGetBlockSize(mat_ceed, &block_size));
54358600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size));
54458600ac3SJames Wright     }
54558600ac3SJames Wright     {
54658600ac3SJames Wright       PetscInt        num_blocks;
54758600ac3SJames Wright       const PetscInt *block_sizes;
54858600ac3SJames Wright 
54958600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes));
55058600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes));
55158600ac3SJames Wright     }
55258600ac3SJames Wright     PetscCall(DMGetVecType(ctx->dm_x, &vec_type));
55358600ac3SJames Wright     PetscCall(MatShellSetVecType(mat_other, vec_type));
55458600ac3SJames Wright   }
55558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
55658600ac3SJames Wright }
55758600ac3SJames Wright 
55858600ac3SJames Wright /**
559ba95ebb4SJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly for a `MatCEED`.
560000d2032SJeremy L Thompson 
561000d2032SJeremy L Thompson   Collective across MPI processes.
562000d2032SJeremy L Thompson 
563000d2032SJeremy L Thompson   @param[in]   mat_ceed       `MATCEED`
564000d2032SJeremy L Thompson   @param[out]  update_needed  Boolean flag indicating `CeedQFunction` update needed
565000d2032SJeremy L Thompson 
566000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
567000d2032SJeremy L Thompson **/
568000d2032SJeremy L Thompson PetscErrorCode MatCeedSetAssemblyDataUpdateNeeded(Mat mat_ceed, PetscBool update_needed) {
569000d2032SJeremy L Thompson   MatCeedContext ctx;
570000d2032SJeremy L Thompson 
571000d2032SJeremy L Thompson   PetscFunctionBeginUser;
572000d2032SJeremy L Thompson   PetscCall(MatShellGetContext(mat_ceed, &ctx));
573000d2032SJeremy L Thompson   PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult, update_needed));
574000d2032SJeremy L Thompson   if (ctx->op_mult_transpose) {
575000d2032SJeremy L Thompson     PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult_transpose, update_needed));
576000d2032SJeremy L Thompson   }
577397c0187SJeremy L Thompson   if (update_needed) {
578397c0187SJeremy L Thompson     PetscCall(MatAssemblyBegin(mat_ceed, MAT_FINAL_ASSEMBLY));
579397c0187SJeremy L Thompson     PetscCall(MatAssemblyEnd(mat_ceed, MAT_FINAL_ASSEMBLY));
580397c0187SJeremy L Thompson   }
581000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
582000d2032SJeremy L Thompson }
583000d2032SJeremy L Thompson 
584000d2032SJeremy L Thompson /**
58540d80af1SJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
58640d80af1SJames Wright 
58740d80af1SJames Wright   Collective across MPI processes.
58840d80af1SJames Wright 
58940d80af1SJames Wright   @param[in]   mat_ceed  `MATCEED`
59040d80af1SJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
59140d80af1SJames Wright 
59240d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
59340d80af1SJames Wright **/
59440d80af1SJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
59540d80af1SJames Wright   MatCeedContext ctx;
59640d80af1SJames Wright 
59740d80af1SJames Wright   PetscFunctionBeginUser;
59840d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
59940d80af1SJames Wright 
60040d80af1SJames 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");
60140d80af1SJames Wright 
60240d80af1SJames Wright   // Check cl mat type
60340d80af1SJames Wright   {
60440d80af1SJames Wright     PetscBool is_coo_mat_type_cl = PETSC_FALSE;
60540d80af1SJames Wright     char      coo_mat_type_cl[64];
60640d80af1SJames Wright 
60740d80af1SJames Wright     // Check for specific CL coo mat type for this Mat
60840d80af1SJames Wright     {
60940d80af1SJames Wright       const char *mat_ceed_prefix = NULL;
61040d80af1SJames Wright 
61140d80af1SJames Wright       PetscCall(MatGetOptionsPrefix(mat_ceed, &mat_ceed_prefix));
61240d80af1SJames Wright       PetscOptionsBegin(PetscObjectComm((PetscObject)mat_ceed), mat_ceed_prefix, "", NULL);
61340d80af1SJames Wright       PetscCall(PetscOptionsFList("-ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
61440d80af1SJames Wright                                   sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
61540d80af1SJames Wright       PetscOptionsEnd();
61640d80af1SJames Wright       if (is_coo_mat_type_cl) {
61740d80af1SJames Wright         PetscCall(PetscFree(ctx->coo_mat_type));
61840d80af1SJames Wright         PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
61940d80af1SJames Wright       }
62040d80af1SJames Wright     }
62140d80af1SJames Wright   }
62240d80af1SJames Wright 
62340d80af1SJames Wright   // Create sparse matrix
62440d80af1SJames Wright   {
62540d80af1SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
62640d80af1SJames Wright 
62740d80af1SJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
62840d80af1SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
62940d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
63040d80af1SJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
63140d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
63240d80af1SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
63340d80af1SJames Wright   }
63440d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
63540d80af1SJames Wright }
63640d80af1SJames Wright 
63740d80af1SJames Wright /**
63840d80af1SJames Wright   @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar.
63958600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
64058600ac3SJames Wright 
64158600ac3SJames Wright   Collective across MPI processes.
64258600ac3SJames Wright 
64358600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
64458600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
64558600ac3SJames Wright 
64658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
64758600ac3SJames Wright **/
64840d80af1SJames Wright PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) {
64958600ac3SJames Wright   MatCeedContext ctx;
65058600ac3SJames Wright 
65158600ac3SJames Wright   PetscFunctionBeginUser;
65258600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
65358600ac3SJames Wright 
65458600ac3SJames Wright   {
65558600ac3SJames Wright     PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
65658600ac3SJames Wright     CeedInt      *rows_ceed, *cols_ceed;
65758600ac3SJames Wright     PetscCount    num_entries;
65858600ac3SJames Wright     PetscLogStage stage_amg_setup;
65958600ac3SJames Wright 
66058600ac3SJames Wright     // -- Assemble sparsity pattern if mat hasn't been assembled before
661c63b910fSJames Wright     PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
66258600ac3SJames Wright     if (stage_amg_setup == -1) {
663c63b910fSJames Wright       PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
66458600ac3SJames Wright     }
66558600ac3SJames Wright     PetscCall(PetscLogStagePush(stage_amg_setup));
666c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
667c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
66850f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
669c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
670a7dac1d5SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
671a7dac1d5SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
67258600ac3SJames Wright     PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
67358600ac3SJames Wright     free(rows_petsc);
67458600ac3SJames Wright     free(cols_petsc);
67550f50432SJames Wright     if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full));
67658600ac3SJames Wright     PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full));
67758600ac3SJames Wright     ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo;
678c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
67958600ac3SJames Wright     PetscCall(PetscLogStagePop());
68058600ac3SJames Wright   }
68140d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
68240d80af1SJames Wright }
68340d80af1SJames Wright 
68440d80af1SJames Wright /**
68540d80af1SJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
68640d80af1SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
68740d80af1SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
68840d80af1SJames Wright 
68940d80af1SJames Wright   Collective across MPI processes.
69040d80af1SJames Wright 
69140d80af1SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
69240d80af1SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
69340d80af1SJames Wright 
69440d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
69540d80af1SJames Wright **/
69640d80af1SJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
69740d80af1SJames Wright   MatCeedContext ctx;
69840d80af1SJames Wright 
69940d80af1SJames Wright   PetscFunctionBeginUser;
70040d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
70140d80af1SJames Wright 
70240d80af1SJames Wright   // Set COO pattern if needed
70340d80af1SJames Wright   {
70440d80af1SJames Wright     CeedInt index = -1;
70540d80af1SJames Wright 
70640d80af1SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
70740d80af1SJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
70840d80af1SJames Wright     }
70940d80af1SJames Wright     if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo));
71058600ac3SJames Wright   }
71158600ac3SJames Wright 
71258600ac3SJames Wright   // Assemble mat_ceed
713c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
71458600ac3SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
71558600ac3SJames Wright   {
71658600ac3SJames Wright     const CeedScalar *values;
71758600ac3SJames Wright     MatType           mat_type;
71858600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
71958600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
72058600ac3SJames Wright 
72158600ac3SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
72258600ac3SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
72358600ac3SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
72458600ac3SJames Wright     else mem_type = CEED_MEM_HOST;
72558600ac3SJames Wright 
726c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
72750f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full));
728c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
72950f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values));
73058600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
73158600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
73258600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
73350f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values));
73458600ac3SJames Wright   }
73558600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
736c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
73758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
73858600ac3SJames Wright }
73958600ac3SJames Wright 
74058600ac3SJames Wright /**
74140d80af1SJames Wright   @brief Set the current value of a context field for a `MatCEED`.
74240d80af1SJames Wright 
74340d80af1SJames Wright   Not collective across MPI processes.
74440d80af1SJames Wright 
74540d80af1SJames Wright   @param[in,out]  mat    `MatCEED`
74640d80af1SJames Wright   @param[in]      name   Name of the context field
74740d80af1SJames Wright   @param[in]      value  New context field value
74840d80af1SJames Wright 
74940d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
75040d80af1SJames Wright **/
75140d80af1SJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
75240d80af1SJames Wright   PetscBool      was_updated = PETSC_FALSE;
75340d80af1SJames Wright   MatCeedContext ctx;
75440d80af1SJames Wright 
75540d80af1SJames Wright   PetscFunctionBeginUser;
75640d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
75740d80af1SJames Wright   {
75840d80af1SJames Wright     CeedContextFieldLabel label = NULL;
75940d80af1SJames Wright 
76040d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label));
76140d80af1SJames Wright     if (label) {
762000d2032SJeremy L Thompson       double set_value = 2 * value + 1.0;
763000d2032SJeremy L Thompson 
764000d2032SJeremy L Thompson       PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
765000d2032SJeremy L Thompson       if (set_value != value) {
76640d80af1SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value));
76740d80af1SJames Wright         was_updated = PETSC_TRUE;
76840d80af1SJames Wright       }
769000d2032SJeremy L Thompson     }
77040d80af1SJames Wright     if (ctx->op_mult_transpose) {
77140d80af1SJames Wright       label = NULL;
77240d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
77340d80af1SJames Wright       if (label) {
774000d2032SJeremy L Thompson         double set_value = 2 * value + 1.0;
775000d2032SJeremy L Thompson 
776000d2032SJeremy L Thompson         PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
777000d2032SJeremy L Thompson         if (set_value != value) {
77840d80af1SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
77940d80af1SJames Wright           was_updated = PETSC_TRUE;
78040d80af1SJames Wright         }
78140d80af1SJames Wright       }
78240d80af1SJames Wright     }
783000d2032SJeremy L Thompson   }
78440d80af1SJames Wright   if (was_updated) {
78540d80af1SJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
78640d80af1SJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
78740d80af1SJames Wright   }
78840d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
78940d80af1SJames Wright }
79040d80af1SJames Wright 
79140d80af1SJames Wright /**
79240d80af1SJames Wright   @brief Get the current value of a context field for a `MatCEED`.
79340d80af1SJames Wright 
79440d80af1SJames Wright   Not collective across MPI processes.
79540d80af1SJames Wright 
79640d80af1SJames Wright   @param[in]   mat    `MatCEED`
79740d80af1SJames Wright   @param[in]   name   Name of the context field
79840d80af1SJames Wright   @param[out]  value  Current context field value
79940d80af1SJames Wright 
80040d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
80140d80af1SJames Wright **/
80240d80af1SJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
80340d80af1SJames Wright   MatCeedContext ctx;
80440d80af1SJames Wright 
80540d80af1SJames Wright   PetscFunctionBeginUser;
80640d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
80740d80af1SJames Wright   {
80840d80af1SJames Wright     CeedContextFieldLabel label = NULL;
80940d80af1SJames Wright     CeedOperator          op    = ctx->op_mult;
81040d80af1SJames Wright 
81140d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
81240d80af1SJames Wright     if (!label && ctx->op_mult_transpose) {
81340d80af1SJames Wright       op = ctx->op_mult_transpose;
81440d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
81540d80af1SJames Wright     }
81640d80af1SJames Wright     if (label) {
81740d80af1SJames Wright       PetscSizeT    num_values;
81840d80af1SJames Wright       const double *values_ceed;
81940d80af1SJames Wright 
82040d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
82140d80af1SJames Wright       *value = values_ceed[0];
82240d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
82340d80af1SJames Wright     }
82440d80af1SJames Wright   }
82540d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
82640d80af1SJames Wright }
82740d80af1SJames Wright 
82840d80af1SJames Wright /**
829000d2032SJeremy L Thompson   @brief Set the current `PetscReal` value of a context field for a `MatCEED`.
830000d2032SJeremy L Thompson 
831000d2032SJeremy L Thompson   Not collective across MPI processes.
832000d2032SJeremy L Thompson 
833000d2032SJeremy L Thompson   @param[in,out]  mat    `MatCEED`
834000d2032SJeremy L Thompson   @param[in]      name   Name of the context field
835000d2032SJeremy L Thompson   @param[in]      value  New context field value
836000d2032SJeremy L Thompson 
837000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
838000d2032SJeremy L Thompson **/
839000d2032SJeremy L Thompson PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) {
840000d2032SJeremy L Thompson   double value_double = value;
841000d2032SJeremy L Thompson 
842000d2032SJeremy L Thompson   PetscFunctionBeginUser;
843000d2032SJeremy L Thompson   PetscCall(MatCeedSetContextDouble(mat, name, value_double));
844000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
845000d2032SJeremy L Thompson }
846000d2032SJeremy L Thompson 
847000d2032SJeremy L Thompson /**
84851bb547fSJames Wright   @brief Get the current `PetscReal` value of a context field for a `MatCEED`.
84951bb547fSJames Wright 
85051bb547fSJames Wright   Not collective across MPI processes.
85151bb547fSJames Wright 
85251bb547fSJames Wright   @param[in]   mat    `MatCEED`
85351bb547fSJames Wright   @param[in]   name   Name of the context field
85451bb547fSJames Wright   @param[out]  value  Current context field value
85551bb547fSJames Wright 
85651bb547fSJames Wright   @return An error code: 0 - success, otherwise - failure
85751bb547fSJames Wright **/
85851bb547fSJames Wright PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) {
85987d3884fSJeremy L Thompson   double value_double = 0.0;
86051bb547fSJames Wright 
86151bb547fSJames Wright   PetscFunctionBeginUser;
86251bb547fSJames Wright   PetscCall(MatCeedGetContextDouble(mat, name, &value_double));
86351bb547fSJames Wright   *value = value_double;
86451bb547fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
86551bb547fSJames Wright }
86651bb547fSJames Wright 
86751bb547fSJames Wright /**
868000d2032SJeremy L Thompson   @brief Set the current time for a `MatCEED`.
869000d2032SJeremy L Thompson 
870000d2032SJeremy L Thompson   Not collective across MPI processes.
871000d2032SJeremy L Thompson 
872000d2032SJeremy L Thompson   @param[in,out]  mat   `MatCEED`
873000d2032SJeremy L Thompson   @param[in]      time  Current time
874000d2032SJeremy L Thompson 
875000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
876000d2032SJeremy L Thompson **/
877000d2032SJeremy L Thompson PetscErrorCode MatCeedSetTime(Mat mat, PetscReal time) {
878000d2032SJeremy L Thompson   PetscFunctionBeginUser;
879000d2032SJeremy L Thompson   {
880000d2032SJeremy L Thompson     double time_ceed = time;
881000d2032SJeremy L Thompson 
882000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "time", time_ceed));
883000d2032SJeremy L Thompson   }
884000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
885000d2032SJeremy L Thompson }
886000d2032SJeremy L Thompson 
887000d2032SJeremy L Thompson /**
888000d2032SJeremy L Thompson   @brief Get the current time for a `MatCEED`.
889000d2032SJeremy L Thompson 
890000d2032SJeremy L Thompson   Not collective across MPI processes.
891000d2032SJeremy L Thompson 
892000d2032SJeremy L Thompson   @param[in]   mat   `MatCEED`
893000d2032SJeremy L Thompson   @param[out]  time  Current time, or -1.0 if the boundary evaluator has no time field
894000d2032SJeremy L Thompson 
895000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
896000d2032SJeremy L Thompson **/
897000d2032SJeremy L Thompson PetscErrorCode MatCeedGetTime(Mat mat, PetscReal *time) {
898000d2032SJeremy L Thompson   PetscFunctionBeginUser;
899000d2032SJeremy L Thompson   *time = -1.0;
900000d2032SJeremy L Thompson   {
901000d2032SJeremy L Thompson     double time_ceed = -1.0;
902000d2032SJeremy L Thompson 
903000d2032SJeremy L Thompson     PetscCall(MatCeedGetContextDouble(mat, "time", &time_ceed));
904000d2032SJeremy L Thompson     *time = time_ceed;
905000d2032SJeremy L Thompson   }
906000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
907000d2032SJeremy L Thompson }
908000d2032SJeremy L Thompson 
909000d2032SJeremy L Thompson /**
910000d2032SJeremy L Thompson   @brief Set the current time step for a `MatCEED`.
911000d2032SJeremy L Thompson 
912000d2032SJeremy L Thompson   Not collective across MPI processes.
913000d2032SJeremy L Thompson 
914000d2032SJeremy L Thompson   @param[in,out]  mat  `MatCEED`
915000d2032SJeremy L Thompson   @param[in]      dt   Current time step
916000d2032SJeremy L Thompson 
917000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
918000d2032SJeremy L Thompson **/
919000d2032SJeremy L Thompson PetscErrorCode MatCeedSetDt(Mat mat, PetscReal dt) {
920000d2032SJeremy L Thompson   PetscFunctionBeginUser;
921000d2032SJeremy L Thompson   {
922000d2032SJeremy L Thompson     double dt_ceed = dt;
923000d2032SJeremy L Thompson 
924000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "dt", dt_ceed));
925000d2032SJeremy L Thompson   }
926000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
927000d2032SJeremy L Thompson }
928000d2032SJeremy L Thompson 
929000d2032SJeremy L Thompson /**
930000d2032SJeremy L Thompson   @brief Set the Jacobian shifts for a `MatCEED`.
931000d2032SJeremy L Thompson 
932000d2032SJeremy L Thompson   Not collective across MPI processes.
933000d2032SJeremy L Thompson 
934000d2032SJeremy L Thompson   @param[in,out]  mat      `MatCEED`
935000d2032SJeremy L Thompson   @param[in]      shift_v  Velocity shift
936000d2032SJeremy L Thompson   @param[in]      shift_a  Acceleration shift
937000d2032SJeremy L Thompson 
938000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
939000d2032SJeremy L Thompson **/
940000d2032SJeremy L Thompson PetscErrorCode MatCeedSetShifts(Mat mat, PetscReal shift_v, PetscReal shift_a) {
941000d2032SJeremy L Thompson   PetscFunctionBeginUser;
942000d2032SJeremy L Thompson   {
943000d2032SJeremy L Thompson     double shift_v_ceed = shift_v;
944000d2032SJeremy L Thompson 
945000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift v", shift_v_ceed));
946000d2032SJeremy L Thompson   }
947000d2032SJeremy L Thompson   if (shift_a) {
948000d2032SJeremy L Thompson     double shift_a_ceed = shift_a;
949000d2032SJeremy L Thompson 
950000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift a", shift_a_ceed));
951000d2032SJeremy L Thompson   }
952000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
953000d2032SJeremy L Thompson }
954000d2032SJeremy L Thompson 
955000d2032SJeremy L Thompson /**
95658600ac3SJames Wright   @brief Set user context for a `MATCEED`.
95758600ac3SJames Wright 
95858600ac3SJames Wright   Collective across MPI processes.
95958600ac3SJames Wright 
96058600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
96158600ac3SJames Wright   @param[in]      f    The context destroy function, or NULL
96258600ac3SJames Wright   @param[in]      ctx  User context, or NULL to unset
96358600ac3SJames Wright 
96458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
96558600ac3SJames Wright **/
96658600ac3SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscErrorCode (*f)(void *), void *ctx) {
96758600ac3SJames Wright   PetscContainer user_ctx = NULL;
96858600ac3SJames Wright 
96958600ac3SJames Wright   PetscFunctionBeginUser;
97058600ac3SJames Wright   if (ctx) {
97158600ac3SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
97258600ac3SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
97358600ac3SJames Wright     PetscCall(PetscContainerSetUserDestroy(user_ctx, f));
97458600ac3SJames Wright   }
97558600ac3SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
97658600ac3SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
97758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
97858600ac3SJames Wright }
97958600ac3SJames Wright 
98058600ac3SJames Wright /**
98158600ac3SJames Wright   @brief Retrieve the user context for a `MATCEED`.
98258600ac3SJames Wright 
98358600ac3SJames Wright   Collective across MPI processes.
98458600ac3SJames Wright 
98558600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
98658600ac3SJames Wright   @param[in]      ctx  User context
98758600ac3SJames Wright 
98858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
98958600ac3SJames Wright **/
99058600ac3SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
99158600ac3SJames Wright   PetscContainer user_ctx;
99258600ac3SJames Wright 
99358600ac3SJames Wright   PetscFunctionBeginUser;
99458600ac3SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
99558600ac3SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
99658600ac3SJames Wright   else *(void **)ctx = NULL;
99758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
99858600ac3SJames Wright }
99958600ac3SJames Wright /**
100040d80af1SJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
100140d80af1SJames Wright 
100240d80af1SJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
100340d80af1SJames Wright `MatCeedSetContext()`.
100458600ac3SJames Wright 
100558600ac3SJames Wright   Collective across MPI processes.
100658600ac3SJames Wright 
100758600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
100840d80af1SJames Wright   @param[in]      op   Name of the `MatOperation`
100940d80af1SJames Wright   @param[in]      g    Function that provides the operation
101058600ac3SJames Wright 
101158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
101258600ac3SJames Wright **/
101340d80af1SJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
101440d80af1SJames Wright   PetscFunctionBeginUser;
101540d80af1SJames Wright   PetscCall(MatShellSetOperation(mat, op, g));
101640d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
101740d80af1SJames Wright }
101840d80af1SJames Wright 
101940d80af1SJames Wright /**
102040d80af1SJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
102140d80af1SJames Wright 
102240d80af1SJames Wright   Collective across MPI processes.
102340d80af1SJames Wright 
102440d80af1SJames Wright   @param[in,out]  mat   `MATCEED`
102540d80af1SJames Wright   @param[in]      type  COO `MatType` to set
102640d80af1SJames Wright 
102740d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
102840d80af1SJames Wright **/
102940d80af1SJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
103058600ac3SJames Wright   MatCeedContext ctx;
103158600ac3SJames Wright 
103258600ac3SJames Wright   PetscFunctionBeginUser;
103358600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
103458600ac3SJames Wright   // Check if same
103558600ac3SJames Wright   {
103658600ac3SJames Wright     size_t    len_old, len_new;
103758600ac3SJames Wright     PetscBool is_same = PETSC_FALSE;
103858600ac3SJames Wright 
103940d80af1SJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
104058600ac3SJames Wright     PetscCall(PetscStrlen(type, &len_new));
104140d80af1SJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
104258600ac3SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
104358600ac3SJames Wright   }
104458600ac3SJames Wright   // Clean up old mats in different format
104558600ac3SJames Wright   // LCOV_EXCL_START
104658600ac3SJames Wright   if (ctx->mat_assembled_full_internal) {
104758600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
104858600ac3SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
104958600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
105058600ac3SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
105158600ac3SJames Wright         }
105258600ac3SJames Wright         ctx->num_mats_assembled_full--;
105358600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
105458600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
105558600ac3SJames Wright       }
105658600ac3SJames Wright     }
105758600ac3SJames Wright   }
105858600ac3SJames Wright   if (ctx->mat_assembled_pbd_internal) {
105958600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
106058600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
106158600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
106258600ac3SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
106358600ac3SJames Wright         }
106458600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
106558600ac3SJames Wright         ctx->num_mats_assembled_pbd--;
106658600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
106758600ac3SJames Wright       }
106858600ac3SJames Wright     }
106958600ac3SJames Wright   }
107040d80af1SJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
107140d80af1SJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
107258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
107358600ac3SJames Wright   // LCOV_EXCL_STOP
107458600ac3SJames Wright }
107558600ac3SJames Wright 
107658600ac3SJames Wright /**
107740d80af1SJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
107858600ac3SJames Wright 
107958600ac3SJames Wright   Collective across MPI processes.
108058600ac3SJames Wright 
108158600ac3SJames Wright   @param[in,out]  mat   `MATCEED`
108240d80af1SJames Wright   @param[in]      type  COO `MatType`
108358600ac3SJames Wright 
108458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
108558600ac3SJames Wright **/
108640d80af1SJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
108758600ac3SJames Wright   MatCeedContext ctx;
108858600ac3SJames Wright 
108958600ac3SJames Wright   PetscFunctionBeginUser;
109058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
109140d80af1SJames Wright   *type = ctx->coo_mat_type;
109258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
109358600ac3SJames Wright }
109458600ac3SJames Wright 
109558600ac3SJames Wright /**
109658600ac3SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
109758600ac3SJames Wright 
109858600ac3SJames Wright   Not collective across MPI processes.
109958600ac3SJames Wright 
110058600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
110158600ac3SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
110258600ac3SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
110358600ac3SJames Wright 
110458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
110558600ac3SJames Wright **/
110658600ac3SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
110758600ac3SJames Wright   MatCeedContext ctx;
110858600ac3SJames Wright 
110958600ac3SJames Wright   PetscFunctionBeginUser;
111058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
111158600ac3SJames Wright   if (X_loc) {
111258600ac3SJames Wright     PetscInt len_old, len_new;
111358600ac3SJames Wright 
111458600ac3SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
111558600ac3SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
111658600ac3SJames 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,
111758600ac3SJames Wright                len_new, len_old);
111840d80af1SJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
111958600ac3SJames Wright   }
112058600ac3SJames Wright   if (Y_loc_transpose) {
112158600ac3SJames Wright     PetscInt len_old, len_new;
112258600ac3SJames Wright 
112358600ac3SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
112458600ac3SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
112558600ac3SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
112658600ac3SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
112740d80af1SJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
112858600ac3SJames Wright   }
112958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
113058600ac3SJames Wright }
113158600ac3SJames Wright 
113258600ac3SJames Wright /**
113358600ac3SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
113458600ac3SJames Wright 
113558600ac3SJames Wright   Not collective across MPI processes.
113658600ac3SJames Wright 
113758600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
113858600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
113958600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
114058600ac3SJames Wright 
114158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
114258600ac3SJames Wright **/
114358600ac3SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
114458600ac3SJames Wright   MatCeedContext ctx;
114558600ac3SJames Wright 
114658600ac3SJames Wright   PetscFunctionBeginUser;
114758600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
114858600ac3SJames Wright   if (X_loc) {
114940d80af1SJames Wright     *X_loc = NULL;
115040d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
115158600ac3SJames Wright   }
115258600ac3SJames Wright   if (Y_loc_transpose) {
115340d80af1SJames Wright     *Y_loc_transpose = NULL;
115440d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
115558600ac3SJames Wright   }
115658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
115758600ac3SJames Wright }
115858600ac3SJames Wright 
115958600ac3SJames Wright /**
116058600ac3SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
116158600ac3SJames Wright 
116258600ac3SJames Wright   Not collective across MPI processes.
116358600ac3SJames Wright 
116458600ac3SJames Wright   @param[in,out]  mat              MatCeed
116558600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
116658600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
116758600ac3SJames Wright 
116858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
116958600ac3SJames Wright **/
117058600ac3SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
117158600ac3SJames Wright   PetscFunctionBeginUser;
117258600ac3SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
117358600ac3SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
117458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
117558600ac3SJames Wright }
117658600ac3SJames Wright 
117758600ac3SJames Wright /**
117858600ac3SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
117958600ac3SJames Wright 
118058600ac3SJames Wright   Not collective across MPI processes.
118158600ac3SJames Wright 
118258600ac3SJames Wright   @param[in,out]  mat                MatCeed
118358600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
118458600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
118558600ac3SJames Wright 
118658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
118758600ac3SJames Wright **/
118858600ac3SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
118958600ac3SJames Wright   MatCeedContext ctx;
119058600ac3SJames Wright 
119158600ac3SJames Wright   PetscFunctionBeginUser;
119258600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
119358600ac3SJames Wright   if (op_mult) {
119458600ac3SJames Wright     *op_mult = NULL;
119550f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
119658600ac3SJames Wright   }
119758600ac3SJames Wright   if (op_mult_transpose) {
119858600ac3SJames Wright     *op_mult_transpose = NULL;
119950f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
120058600ac3SJames Wright   }
120158600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
120258600ac3SJames Wright }
120358600ac3SJames Wright 
120458600ac3SJames Wright /**
120558600ac3SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
120658600ac3SJames Wright 
120758600ac3SJames Wright   Not collective across MPI processes.
120858600ac3SJames Wright 
120958600ac3SJames Wright   @param[in,out]  mat                MatCeed
121058600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
121158600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
121258600ac3SJames Wright 
121358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
121458600ac3SJames Wright **/
121558600ac3SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
121658600ac3SJames Wright   MatCeedContext ctx;
121758600ac3SJames Wright 
121858600ac3SJames Wright   PetscFunctionBeginUser;
121958600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
122050f50432SJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
122150f50432SJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
122258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
122358600ac3SJames Wright }
122458600ac3SJames Wright 
122558600ac3SJames Wright /**
122658600ac3SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
122758600ac3SJames Wright 
122858600ac3SJames Wright   Not collective across MPI processes.
122958600ac3SJames Wright 
123058600ac3SJames Wright   @param[in,out]  mat                       MatCeed
123158600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
123258600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
123358600ac3SJames Wright 
123458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
123558600ac3SJames Wright **/
123658600ac3SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
123758600ac3SJames Wright   MatCeedContext ctx;
123858600ac3SJames Wright 
123958600ac3SJames Wright   PetscFunctionBeginUser;
124058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
124158600ac3SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
124258600ac3SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
124358600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
124458600ac3SJames Wright }
124558600ac3SJames Wright 
124658600ac3SJames Wright /**
124758600ac3SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
124858600ac3SJames Wright 
124958600ac3SJames Wright   Not collective across MPI processes.
125058600ac3SJames Wright 
125158600ac3SJames Wright   @param[in,out]  mat                       MatCeed
125258600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
125358600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
125458600ac3SJames Wright 
125558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
125658600ac3SJames Wright **/
125758600ac3SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
125858600ac3SJames Wright   MatCeedContext ctx;
125958600ac3SJames Wright 
126058600ac3SJames Wright   PetscFunctionBeginUser;
126158600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
126258600ac3SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
126358600ac3SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
126458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
126558600ac3SJames Wright }
126658600ac3SJames Wright 
1267c63b910fSJames Wright /**
1268c63b910fSJames Wright   @brief Set `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1269c63b910fSJames Wright 
1270c63b910fSJames Wright   Not collective across MPI processes.
1271c63b910fSJames Wright 
1272c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1273c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1274c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1275c63b910fSJames Wright 
1276c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1277c63b910fSJames Wright **/
1278c63b910fSJames Wright PetscErrorCode MatCeedSetCeedOperatorLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1279c63b910fSJames Wright   MatCeedContext ctx;
1280c63b910fSJames Wright 
1281c63b910fSJames Wright   PetscFunctionBeginUser;
1282c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1283c63b910fSJames Wright   if (log_event_mult) ctx->log_event_ceed_mult = log_event_mult;
1284c63b910fSJames Wright   if (log_event_mult_transpose) ctx->log_event_ceed_mult_transpose = log_event_mult_transpose;
1285c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1286c63b910fSJames Wright }
1287c63b910fSJames Wright 
1288c63b910fSJames Wright /**
1289c63b910fSJames Wright   @brief Get `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1290c63b910fSJames Wright 
1291c63b910fSJames Wright   Not collective across MPI processes.
1292c63b910fSJames Wright 
1293c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1294c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1295c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1296c63b910fSJames Wright 
1297c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1298c63b910fSJames Wright **/
1299c63b910fSJames Wright PetscErrorCode MatCeedGetCeedOperatorLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1300c63b910fSJames Wright   MatCeedContext ctx;
1301c63b910fSJames Wright 
1302c63b910fSJames Wright   PetscFunctionBeginUser;
1303c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1304c63b910fSJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_ceed_mult;
1305c63b910fSJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_ceed_mult_transpose;
1306c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1307c63b910fSJames Wright }
1308c63b910fSJames Wright 
130958600ac3SJames Wright // -----------------------------------------------------------------------------
131058600ac3SJames Wright // Operator context data
131158600ac3SJames Wright // -----------------------------------------------------------------------------
131258600ac3SJames Wright 
131358600ac3SJames Wright /**
131458600ac3SJames Wright   @brief Setup context data for operator application.
131558600ac3SJames Wright 
131658600ac3SJames Wright   Collective across MPI processes.
131758600ac3SJames Wright 
131858600ac3SJames Wright   @param[in]   dm_x                           Input `DM`
131958600ac3SJames Wright   @param[in]   dm_y                           Output `DM`
132058600ac3SJames Wright   @param[in]   X_loc                          Input PETSc local vector, or NULL
132158600ac3SJames Wright   @param[in]   Y_loc_transpose                Input PETSc local vector for transpose operation, or NULL
132258600ac3SJames Wright   @param[in]   op_mult                        `CeedOperator` for forward evaluation
132358600ac3SJames Wright   @param[in]   op_mult_transpose              `CeedOperator` for transpose evaluation
132458600ac3SJames Wright   @param[in]   log_event_mult                 `PetscLogEvent` for forward evaluation
132558600ac3SJames Wright   @param[in]   log_event_mult_transpose       `PetscLogEvent` for transpose evaluation
1326c63b910fSJames Wright   @param[in]   log_event_ceed_mult            `PetscLogEvent` for forward `CeedOperator` evaluation
1327c63b910fSJames Wright   @param[in]   log_event_ceed_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation
132858600ac3SJames Wright   @param[out]  ctx                            Context data for operator evaluation
132958600ac3SJames Wright 
133058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
133158600ac3SJames Wright **/
133258600ac3SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1333c63b910fSJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, PetscLogEvent log_event_ceed_mult,
1334c63b910fSJames Wright                                     PetscLogEvent log_event_ceed_mult_transpose, MatCeedContext *ctx) {
133558600ac3SJames Wright   CeedSize x_loc_len, y_loc_len;
133658600ac3SJames Wright 
133758600ac3SJames Wright   PetscFunctionBeginUser;
133858600ac3SJames Wright 
133958600ac3SJames Wright   // Allocate
134058600ac3SJames Wright   PetscCall(PetscNew(ctx));
134158600ac3SJames Wright   (*ctx)->ref_count = 1;
134258600ac3SJames Wright 
134358600ac3SJames Wright   // Logging
134458600ac3SJames Wright   (*ctx)->log_event_mult                = log_event_mult;
134558600ac3SJames Wright   (*ctx)->log_event_mult_transpose      = log_event_mult_transpose;
1346c63b910fSJames Wright   (*ctx)->log_event_ceed_mult           = log_event_ceed_mult;
1347c63b910fSJames Wright   (*ctx)->log_event_ceed_mult_transpose = log_event_ceed_mult_transpose;
134858600ac3SJames Wright 
134958600ac3SJames Wright   // PETSc objects
135040d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
135140d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
135240d80af1SJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
135340d80af1SJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
135458600ac3SJames Wright 
135558600ac3SJames Wright   // Memtype
135658600ac3SJames Wright   {
135758600ac3SJames Wright     const PetscScalar *x;
135858600ac3SJames Wright     Vec                X;
135958600ac3SJames Wright 
136058600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
136158600ac3SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
136258600ac3SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
136358600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
136458600ac3SJames Wright   }
136558600ac3SJames Wright 
136658600ac3SJames Wright   // libCEED objects
136758600ac3SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
136858600ac3SJames Wright              "retrieving Ceed context object failed");
136950f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedReference((*ctx)->ceed));
137050f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
137150f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
137250f50432SJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
137350f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
137450f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
137558600ac3SJames Wright 
137658600ac3SJames Wright   // Flop counting
137758600ac3SJames Wright   {
137858600ac3SJames Wright     CeedSize ceed_flops_estimate = 0;
137958600ac3SJames Wright 
138050f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
138158600ac3SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
138258600ac3SJames Wright     if (op_mult_transpose) {
138350f50432SJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
138458600ac3SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
138558600ac3SJames Wright     }
138658600ac3SJames Wright   }
138758600ac3SJames Wright 
138858600ac3SJames Wright   // Check sizes
138958600ac3SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
139058600ac3SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
139158600ac3SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
139258600ac3SJames Wright     Vec      dm_X_loc, dm_Y_loc;
139358600ac3SJames Wright 
139458600ac3SJames Wright     // -- Input
139558600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
139658600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
139758600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
139850f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
13994c17272bSJames Wright     if (X_loc) {
14004c17272bSJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
14014c17272bSJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14024c17272bSJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
14034c17272bSJames Wright     }
14044c17272bSJames 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",
14054c17272bSJames Wright                x_loc_len, dm_x_loc_len);
14064c17272bSJames 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 ")",
14074c17272bSJames Wright                x_loc_len, ctx_x_loc_len);
140858600ac3SJames Wright 
140958600ac3SJames Wright     // -- Output
141058600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
141158600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
141258600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
141350f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
14144c17272bSJames 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",
14154c17272bSJames Wright                ctx_y_loc_len, dm_y_loc_len);
141658600ac3SJames Wright 
141758600ac3SJames Wright     // -- Transpose
141858600ac3SJames Wright     if (Y_loc_transpose) {
141958600ac3SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
14204c17272bSJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14214c17272bSJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
142258600ac3SJames Wright     }
142358600ac3SJames Wright   }
142458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
142558600ac3SJames Wright }
142658600ac3SJames Wright 
142758600ac3SJames Wright /**
142858600ac3SJames Wright   @brief Increment reference counter for `MATCEED` context.
142958600ac3SJames Wright 
143058600ac3SJames Wright   Not collective across MPI processes.
143158600ac3SJames Wright 
143258600ac3SJames Wright   @param[in,out]  ctx  Context data
143358600ac3SJames Wright 
143458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
143558600ac3SJames Wright **/
143658600ac3SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
143758600ac3SJames Wright   PetscFunctionBeginUser;
143858600ac3SJames Wright   ctx->ref_count++;
143958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
144058600ac3SJames Wright }
144158600ac3SJames Wright 
144258600ac3SJames Wright /**
144358600ac3SJames Wright   @brief Copy reference for `MATCEED`.
144458600ac3SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
144558600ac3SJames Wright 
144658600ac3SJames Wright   Not collective across MPI processes.
144758600ac3SJames Wright 
144858600ac3SJames Wright   @param[in]   ctx       Context data
144958600ac3SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
145058600ac3SJames Wright 
145158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
145258600ac3SJames Wright **/
145358600ac3SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
145458600ac3SJames Wright   PetscFunctionBeginUser;
145558600ac3SJames Wright   PetscCall(MatCeedContextReference(ctx));
145658600ac3SJames Wright   PetscCall(MatCeedContextDestroy(*ctx_copy));
145758600ac3SJames Wright   *ctx_copy = ctx;
145858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
145958600ac3SJames Wright }
146058600ac3SJames Wright 
146158600ac3SJames Wright /**
146258600ac3SJames Wright   @brief Destroy context data for operator application.
146358600ac3SJames Wright 
146458600ac3SJames Wright   Collective across MPI processes.
146558600ac3SJames Wright 
146658600ac3SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
146758600ac3SJames Wright 
146858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
146958600ac3SJames Wright **/
147058600ac3SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext ctx) {
147158600ac3SJames Wright   PetscFunctionBeginUser;
147258600ac3SJames Wright   if (!ctx || --ctx->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
147358600ac3SJames Wright 
147458600ac3SJames Wright   // PETSc objects
147558600ac3SJames Wright   PetscCall(DMDestroy(&ctx->dm_x));
147658600ac3SJames Wright   PetscCall(DMDestroy(&ctx->dm_y));
147758600ac3SJames Wright   PetscCall(VecDestroy(&ctx->X_loc));
147858600ac3SJames Wright   PetscCall(VecDestroy(&ctx->Y_loc_transpose));
147958600ac3SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
148058600ac3SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
148140d80af1SJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
148258600ac3SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_full));
148358600ac3SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_pbd));
148458600ac3SJames Wright 
148558600ac3SJames Wright   // libCEED objects
148650f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->x_loc));
148750f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->y_loc));
148850f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_full));
148950f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_pbd));
149050f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult));
149150f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult_transpose));
149258600ac3SJames Wright   PetscCheck(CeedDestroy(&ctx->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
149358600ac3SJames Wright 
149458600ac3SJames Wright   // Deallocate
149558600ac3SJames Wright   ctx->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
149658600ac3SJames Wright   PetscCall(PetscFree(ctx));
149758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
149858600ac3SJames Wright }
149958600ac3SJames Wright 
150058600ac3SJames Wright /**
150158600ac3SJames Wright   @brief Compute the diagonal of an operator via libCEED.
150258600ac3SJames Wright 
150358600ac3SJames Wright   Collective across MPI processes.
150458600ac3SJames Wright 
150558600ac3SJames Wright   @param[in]   A  `MATCEED`
150658600ac3SJames Wright   @param[out]  D  Vector holding operator diagonal
150758600ac3SJames Wright 
150858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
150958600ac3SJames Wright **/
151058600ac3SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
151158600ac3SJames Wright   PetscMemType   mem_type;
151258600ac3SJames Wright   Vec            D_loc;
151358600ac3SJames Wright   MatCeedContext ctx;
151458600ac3SJames Wright 
151558600ac3SJames Wright   PetscFunctionBeginUser;
151658600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
151758600ac3SJames Wright 
151858600ac3SJames Wright   // Place PETSc vector in libCEED vector
1519c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
152058600ac3SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1521a7dac1d5SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
152258600ac3SJames Wright 
152358600ac3SJames Wright   // Compute Diagonal
1524c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
152550f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1526c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
152758600ac3SJames Wright 
152858600ac3SJames Wright   // Restore PETSc vector
1529a7dac1d5SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
153058600ac3SJames Wright 
153158600ac3SJames Wright   // Local-to-Global
153258600ac3SJames Wright   PetscCall(VecZeroEntries(D));
153358600ac3SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
153458600ac3SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1535c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
153658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
153758600ac3SJames Wright }
153858600ac3SJames Wright 
153958600ac3SJames Wright /**
154058600ac3SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
154158600ac3SJames Wright 
154258600ac3SJames Wright   Collective across MPI processes.
154358600ac3SJames Wright 
154458600ac3SJames Wright   @param[in]   A  `MATCEED`
154558600ac3SJames Wright   @param[in]   X  Input PETSc vector
154658600ac3SJames Wright   @param[out]  Y  Output PETSc vector
154758600ac3SJames Wright 
154858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
154958600ac3SJames Wright **/
155058600ac3SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
155158600ac3SJames Wright   MatCeedContext ctx;
155258600ac3SJames Wright 
155358600ac3SJames Wright   PetscFunctionBeginUser;
155458600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1555c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, NULL));
155658600ac3SJames Wright 
155758600ac3SJames Wright   {
155858600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
155958600ac3SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
156058600ac3SJames Wright 
156158600ac3SJames Wright     // Get local vectors
156258600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
156358600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
156458600ac3SJames Wright 
156558600ac3SJames Wright     // Global-to-local
156658600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
156758600ac3SJames Wright 
156858600ac3SJames Wright     // Setup libCEED vectors
1569a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
157058600ac3SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1571a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
157258600ac3SJames Wright 
157358600ac3SJames Wright     // Apply libCEED operator
157458600ac3SJames Wright     PetscCall(PetscLogGpuTimeBegin());
1575c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult, A, X, Y, NULL));
157650f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
1577c63b910fSJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult, A, X, Y, NULL));
157858600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
157958600ac3SJames Wright 
158058600ac3SJames Wright     // Restore PETSc vectors
1581a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1582a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
158358600ac3SJames Wright 
158458600ac3SJames Wright     // Local-to-global
158558600ac3SJames Wright     PetscCall(VecZeroEntries(Y));
158658600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
158758600ac3SJames Wright 
158858600ac3SJames Wright     // Restore local vectors, as needed
158958600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
159058600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
159158600ac3SJames Wright   }
159258600ac3SJames Wright 
159358600ac3SJames Wright   // Log flops
159458600ac3SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
159558600ac3SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult));
1596c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, NULL));
159758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
159858600ac3SJames Wright }
159958600ac3SJames Wright 
160058600ac3SJames Wright /**
160158600ac3SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
160258600ac3SJames Wright 
160358600ac3SJames Wright   Collective across MPI processes.
160458600ac3SJames Wright 
160558600ac3SJames Wright   @param[in]   A  `MATCEED`
160658600ac3SJames Wright   @param[in]   Y  Input PETSc vector
160758600ac3SJames Wright   @param[out]  X  Output PETSc vector
160858600ac3SJames Wright 
160958600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
161058600ac3SJames Wright **/
161158600ac3SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
161258600ac3SJames Wright   MatCeedContext ctx;
161358600ac3SJames Wright 
161458600ac3SJames Wright   PetscFunctionBeginUser;
161558600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1616c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, NULL));
161758600ac3SJames Wright 
161858600ac3SJames Wright   {
161958600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
162058600ac3SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
162158600ac3SJames Wright 
162258600ac3SJames Wright     // Get local vectors
162358600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
162458600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
162558600ac3SJames Wright 
162658600ac3SJames Wright     // Global-to-local
162758600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
162858600ac3SJames Wright 
162958600ac3SJames Wright     // Setup libCEED vectors
1630a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
163158600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
1632a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
163358600ac3SJames Wright 
163458600ac3SJames Wright     // Apply libCEED operator
163558600ac3SJames Wright     PetscCall(PetscLogGpuTimeBegin());
1636c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
163750f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1638c63b910fSJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
163958600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
164058600ac3SJames Wright 
164158600ac3SJames Wright     // Restore PETSc vectors
1642a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1643a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
164458600ac3SJames Wright 
164558600ac3SJames Wright     // Local-to-global
164658600ac3SJames Wright     PetscCall(VecZeroEntries(X));
164758600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
164858600ac3SJames Wright 
164958600ac3SJames Wright     // Restore local vectors, as needed
165058600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
165158600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
165258600ac3SJames Wright   }
165358600ac3SJames Wright 
165458600ac3SJames Wright   // Log flops
165558600ac3SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
165658600ac3SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
1657c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, NULL));
165858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
165958600ac3SJames Wright }
1660