xref: /honee/src/mat-ceed.c (revision dfdd2b92c47737c13e412ceefeabe0da7d3e1056)
1ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
358600ac3SJames Wright /// @file
440d80af1SJames Wright /// MatCEED implementation
558600ac3SJames Wright 
658600ac3SJames Wright #include <ceed.h>
758600ac3SJames Wright #include <ceed/backend.h>
858600ac3SJames Wright #include <mat-ceed-impl.h>
958600ac3SJames Wright #include <mat-ceed.h>
1040d80af1SJames Wright #include <petsc-ceed-utils.h>
1140d80af1SJames Wright #include <petsc-ceed.h>
12000d2032SJeremy L Thompson #include <petscdm.h>
13000d2032SJeremy L Thompson #include <petscmat.h>
14000d2032SJeremy L Thompson #include <stdbool.h>
15000d2032SJeremy L Thompson #include <stdio.h>
1658600ac3SJames Wright #include <stdlib.h>
1758600ac3SJames Wright #include <string.h>
1858600ac3SJames Wright 
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 /**
171c1bdbf00SJames Wright   @brief Get on-process diagonal block of `MATCEED`
172c1bdbf00SJames Wright 
173c1bdbf00SJames Wright   This is a block per-process of the diagonal of the global matrix.
174c1bdbf00SJames Wright   This is NOT the diagonal blocks associated with the block size of the matrix (i.e. `MatSetBlockSize()` has no effect on this function).
17558600ac3SJames Wright 
17658600ac3SJames Wright   Collective across MPI processes.
17758600ac3SJames Wright 
17858600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to invert
17958600ac3SJames Wright   @param[out]  mat_block  The diagonal block matrix
18058600ac3SJames Wright 
18158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
18258600ac3SJames Wright **/
18358600ac3SJames Wright static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) {
18458600ac3SJames Wright   MatCeedContext ctx;
18558600ac3SJames Wright 
18658600ac3SJames Wright   PetscFunctionBeginUser;
18758600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
18858600ac3SJames Wright 
189c1bdbf00SJames Wright   // Check if COO pattern set
190c1bdbf00SJames Wright   if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
19158600ac3SJames Wright 
192c1bdbf00SJames Wright   // Assemble mat_assembled_full_internal
193c1bdbf00SJames Wright   PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
194c1bdbf00SJames Wright 
195c1bdbf00SJames Wright   // Get diagonal block
196c1bdbf00SJames Wright   PetscCall(MatGetDiagonalBlock(ctx->mat_assembled_full_internal, mat_block));
19758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
19858600ac3SJames Wright }
19958600ac3SJames Wright 
20058600ac3SJames Wright /**
20158600ac3SJames Wright   @brief Invert `MATCEED` diagonal block for Jacobi.
20258600ac3SJames Wright 
20358600ac3SJames Wright   Collective across MPI processes.
20458600ac3SJames Wright 
20558600ac3SJames Wright   @param[in]   mat_ceed  `MATCEED` to invert
20658600ac3SJames Wright   @param[out]  values    The block inverses in column major order
20758600ac3SJames Wright 
20858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
20958600ac3SJames Wright **/
21058600ac3SJames Wright static PetscErrorCode MatInvertBlockDiagonal_Ceed(Mat mat_ceed, const PetscScalar **values) {
21158600ac3SJames Wright   Mat            mat_inner = NULL;
21258600ac3SJames Wright   MatCeedContext ctx;
21358600ac3SJames Wright 
21458600ac3SJames Wright   PetscFunctionBeginUser;
21558600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
21658600ac3SJames Wright 
21758600ac3SJames Wright   // Assemble inner mat if needed
21858600ac3SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, &mat_inner));
21958600ac3SJames Wright 
22058600ac3SJames Wright   // Invert PB diagonal
22158600ac3SJames Wright   PetscCall(MatInvertBlockDiagonal(mat_inner, values));
22258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
22358600ac3SJames Wright }
22458600ac3SJames Wright 
22558600ac3SJames Wright /**
22658600ac3SJames Wright   @brief Invert `MATCEED` variable diagonal block for Jacobi.
22758600ac3SJames Wright 
22858600ac3SJames Wright   Collective across MPI processes.
22958600ac3SJames Wright 
23058600ac3SJames Wright   @param[in]   mat_ceed     `MATCEED` to invert
23158600ac3SJames Wright   @param[in]   num_blocks   The number of blocks on the process
23258600ac3SJames Wright   @param[in]   block_sizes  The size of each block on the process
23358600ac3SJames Wright   @param[out]  values       The block inverses in column major order
23458600ac3SJames Wright 
23558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
23658600ac3SJames Wright **/
23758600ac3SJames Wright static PetscErrorCode MatInvertVariableBlockDiagonal_Ceed(Mat mat_ceed, PetscInt num_blocks, const PetscInt *block_sizes, PetscScalar *values) {
23858600ac3SJames Wright   Mat            mat_inner = NULL;
23958600ac3SJames Wright   MatCeedContext ctx;
24058600ac3SJames Wright 
24158600ac3SJames Wright   PetscFunctionBeginUser;
24258600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
24358600ac3SJames Wright 
24458600ac3SJames Wright   // Assemble inner mat if needed
24558600ac3SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, &mat_inner));
24658600ac3SJames Wright 
24758600ac3SJames Wright   // Invert PB diagonal
24858600ac3SJames Wright   PetscCall(MatInvertVariableBlockDiagonal(mat_inner, num_blocks, block_sizes, values));
24958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
25058600ac3SJames Wright }
25158600ac3SJames Wright 
252e90c2ceeSJames Wright /**
253e90c2ceeSJames Wright   @brief View `MATCEED`.
254e90c2ceeSJames Wright 
255e90c2ceeSJames Wright   Collective across MPI processes.
256e90c2ceeSJames Wright 
257e90c2ceeSJames Wright   @param[in]   mat_ceed  `MATCEED` to view
258e90c2ceeSJames Wright   @param[in]   viewer    The visualization context
259e90c2ceeSJames Wright 
260e90c2ceeSJames Wright   @return An error code: 0 - success, otherwise - failure
261e90c2ceeSJames Wright **/
262e90c2ceeSJames Wright static PetscErrorCode MatView_Ceed(Mat mat_ceed, PetscViewer viewer) {
263e90c2ceeSJames Wright   PetscBool         is_ascii;
264e90c2ceeSJames Wright   PetscViewerFormat format;
265000d2032SJeremy L Thompson   PetscMPIInt       size, rank;
266e90c2ceeSJames Wright   MatCeedContext    ctx;
267e90c2ceeSJames Wright 
268e90c2ceeSJames Wright   PetscFunctionBeginUser;
269e90c2ceeSJames Wright   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
270e90c2ceeSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
271e90c2ceeSJames Wright   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat_ceed), &viewer));
272e90c2ceeSJames Wright 
273e90c2ceeSJames Wright   PetscCall(PetscViewerGetFormat(viewer, &format));
274e90c2ceeSJames Wright   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat_ceed), &size));
275e90c2ceeSJames Wright   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
276e90c2ceeSJames Wright 
277000d2032SJeremy L Thompson   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat_ceed), &rank));
278000d2032SJeremy L Thompson   if (rank != 0) PetscFunctionReturn(PETSC_SUCCESS);
279000d2032SJeremy L Thompson 
280e90c2ceeSJames Wright   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii));
281e90c2ceeSJames Wright   {
282000d2032SJeremy L Thompson     PetscBool is_detailed     = format == PETSC_VIEWER_ASCII_INFO_DETAIL;
283000d2032SJeremy L Thompson     char      rank_string[16] = {'\0'};
284e90c2ceeSJames Wright     FILE     *file;
285e90c2ceeSJames Wright 
286*dfdd2b92SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n"));
287537ec908SJames Wright     PetscCall(PetscViewerASCIIPushTab(viewer));  // MatCEED
288*dfdd2b92SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "Default COO MatType: %s\n", ctx->coo_mat_type));
289000d2032SJeremy L Thompson     PetscCall(PetscSNPrintf(rank_string, 16, "on Rank %d", rank));
290000d2032SJeremy L Thompson     PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary"));
291537ec908SJames Wright     PetscCall(PetscViewerASCIIGetPointer(viewer, &file));
292537ec908SJames Wright     PetscCall(PetscViewerASCIIPushTab(viewer));  // CeedOperator
293000d2032SJeremy L Thompson     if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file));
294000d2032SJeremy L Thompson     else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult, file));
295537ec908SJames Wright     PetscCall(PetscViewerASCIIPopTab(viewer));  // CeedOperator
296e90c2ceeSJames Wright     if (ctx->op_mult_transpose) {
297000d2032SJeremy L Thompson       PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator ApplyTranspose %s:\n", is_detailed ? rank_string : "Summary"));
298537ec908SJames Wright       PetscCall(PetscViewerASCIIPushTab(viewer));  // CeedOperator
299000d2032SJeremy L Thompson       if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file));
300000d2032SJeremy L Thompson       else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult_transpose, file));
301537ec908SJames Wright       PetscCall(PetscViewerASCIIPopTab(viewer));  // CeedOperator
302e90c2ceeSJames Wright     }
303537ec908SJames Wright     PetscCall(PetscViewerASCIIPopTab(viewer));  // MatCEED
304e90c2ceeSJames Wright   }
305e90c2ceeSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
306e90c2ceeSJames Wright }
307e90c2ceeSJames Wright 
30858600ac3SJames Wright // -----------------------------------------------------------------------------
30958600ac3SJames Wright // MatCeed
31058600ac3SJames Wright // -----------------------------------------------------------------------------
31158600ac3SJames Wright 
31258600ac3SJames Wright /**
31358600ac3SJames Wright   @brief Create PETSc `Mat` from libCEED operators.
31458600ac3SJames Wright 
31558600ac3SJames Wright   Collective across MPI processes.
31658600ac3SJames Wright 
31758600ac3SJames Wright   @param[in]   dm_x                      Input `DM`
31858600ac3SJames Wright   @param[in]   dm_y                      Output `DM`
31958600ac3SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
32058600ac3SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
32158600ac3SJames Wright   @param[out]  mat                        New MatCeed
32258600ac3SJames Wright 
32358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
32458600ac3SJames Wright **/
325000d2032SJeremy L Thompson PetscErrorCode MatCreateCeed(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) {
32658600ac3SJames Wright   PetscInt       X_l_size, X_g_size, Y_l_size, Y_g_size;
32758600ac3SJames Wright   VecType        vec_type;
32858600ac3SJames Wright   MatCeedContext ctx;
32958600ac3SJames Wright 
33058600ac3SJames Wright   PetscFunctionBeginUser;
33158600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
33258600ac3SJames Wright 
33358600ac3SJames Wright   // Collect context data
33458600ac3SJames Wright   PetscCall(DMGetVecType(dm_x, &vec_type));
33558600ac3SJames Wright   {
33658600ac3SJames Wright     Vec X;
33758600ac3SJames Wright 
33858600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_x, &X));
33958600ac3SJames Wright     PetscCall(VecGetSize(X, &X_g_size));
34058600ac3SJames Wright     PetscCall(VecGetLocalSize(X, &X_l_size));
34158600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_x, &X));
34258600ac3SJames Wright   }
34358600ac3SJames Wright   if (dm_y) {
34458600ac3SJames Wright     Vec Y;
34558600ac3SJames Wright 
34658600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_y, &Y));
34758600ac3SJames Wright     PetscCall(VecGetSize(Y, &Y_g_size));
34858600ac3SJames Wright     PetscCall(VecGetLocalSize(Y, &Y_l_size));
34958600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_y, &Y));
35058600ac3SJames Wright   } else {
35158600ac3SJames Wright     dm_y     = dm_x;
35258600ac3SJames Wright     Y_g_size = X_g_size;
35358600ac3SJames Wright     Y_l_size = X_l_size;
35458600ac3SJames Wright   }
35540d80af1SJames Wright 
35658600ac3SJames Wright   // Create context
35758600ac3SJames Wright   {
35858600ac3SJames Wright     Vec X_loc, Y_loc_transpose = NULL;
35958600ac3SJames Wright 
36058600ac3SJames Wright     PetscCall(DMCreateLocalVector(dm_x, &X_loc));
36158600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
36258600ac3SJames Wright     if (op_mult_transpose) {
36358600ac3SJames Wright       PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose));
36458600ac3SJames Wright       PetscCall(VecZeroEntries(Y_loc_transpose));
36558600ac3SJames Wright     }
366c63b910fSJames Wright     PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE,
367c63b910fSJames Wright                                    MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE_CEEDOP, &ctx));
36858600ac3SJames Wright     PetscCall(VecDestroy(&X_loc));
36958600ac3SJames Wright     PetscCall(VecDestroy(&Y_loc_transpose));
37058600ac3SJames Wright   }
37158600ac3SJames Wright 
37258600ac3SJames Wright   // Create mat
37358600ac3SJames Wright   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat));
37458600ac3SJames Wright   PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED));
37558600ac3SJames Wright   // -- Set block and variable block sizes
37658600ac3SJames Wright   if (dm_x == dm_y) {
37758600ac3SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
37858600ac3SJames Wright     Mat     temp_mat;
37958600ac3SJames Wright 
38058600ac3SJames Wright     PetscCall(DMGetMatType(dm_x, &dm_mat_type));
38158600ac3SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
38258600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, MATAIJ));
38358600ac3SJames Wright     PetscCall(DMCreateMatrix(dm_x, &temp_mat));
38458600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, dm_mat_type_copy));
38558600ac3SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
38658600ac3SJames Wright 
38758600ac3SJames Wright     {
38858600ac3SJames Wright       PetscInt        block_size, num_blocks, max_vblock_size = PETSC_INT_MAX;
38958600ac3SJames Wright       const PetscInt *vblock_sizes;
39058600ac3SJames Wright 
39158600ac3SJames Wright       // -- Get block sizes
39258600ac3SJames Wright       PetscCall(MatGetBlockSize(temp_mat, &block_size));
39358600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes));
39458600ac3SJames Wright       {
39558600ac3SJames Wright         PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX};
39658600ac3SJames Wright 
39758600ac3SJames Wright         for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]);
39858600ac3SJames Wright         PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max));
39958600ac3SJames Wright         max_vblock_size = global_min_max[1];
40058600ac3SJames Wright       }
40158600ac3SJames Wright 
40258600ac3SJames Wright       // -- Copy block sizes
40358600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size));
40458600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes));
40558600ac3SJames Wright 
40658600ac3SJames Wright       // -- Check libCEED compatibility
40758600ac3SJames Wright       {
40858600ac3SJames Wright         bool is_composite;
40958600ac3SJames Wright 
41058600ac3SJames Wright         ctx->is_ceed_pbd_valid  = PETSC_TRUE;
41158600ac3SJames Wright         ctx->is_ceed_vpbd_valid = PETSC_TRUE;
41250f50432SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite));
41358600ac3SJames Wright         if (is_composite) {
41458600ac3SJames Wright           CeedInt       num_sub_operators;
41558600ac3SJames Wright           CeedOperator *sub_operators;
41658600ac3SJames Wright 
41750f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetNumSub(op_mult, &num_sub_operators));
41850f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetSubList(op_mult, &sub_operators));
41958600ac3SJames Wright           for (CeedInt i = 0; i < num_sub_operators; i++) {
42058600ac3SJames Wright             CeedInt                  num_bases, num_comp;
42158600ac3SJames Wright             CeedBasis               *active_bases;
42258600ac3SJames Wright             CeedOperatorAssemblyData assembly_data;
42358600ac3SJames Wright 
42450f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data));
42550f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
42650f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
42758600ac3SJames Wright             if (num_bases > 1) {
42858600ac3SJames Wright               ctx->is_ceed_pbd_valid  = PETSC_FALSE;
42958600ac3SJames Wright               ctx->is_ceed_vpbd_valid = PETSC_FALSE;
43058600ac3SJames Wright             }
43158600ac3SJames Wright             if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
43258600ac3SJames Wright             if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
43358600ac3SJames Wright           }
43458600ac3SJames Wright         } else {
43558600ac3SJames Wright           // LCOV_EXCL_START
43658600ac3SJames Wright           CeedInt                  num_bases, num_comp;
43758600ac3SJames Wright           CeedBasis               *active_bases;
43858600ac3SJames Wright           CeedOperatorAssemblyData assembly_data;
43958600ac3SJames Wright 
44050f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data));
44150f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
44250f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
44358600ac3SJames Wright           if (num_bases > 1) {
44458600ac3SJames Wright             ctx->is_ceed_pbd_valid  = PETSC_FALSE;
44558600ac3SJames Wright             ctx->is_ceed_vpbd_valid = PETSC_FALSE;
44658600ac3SJames Wright           }
44758600ac3SJames Wright           if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
44858600ac3SJames Wright           if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
44958600ac3SJames Wright           // LCOV_EXCL_STOP
45058600ac3SJames Wright         }
45158600ac3SJames Wright         {
45258600ac3SJames Wright           PetscInt local_is_valid[2], global_is_valid[2];
45358600ac3SJames Wright 
45458600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid;
45558600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
45658600ac3SJames Wright           ctx->is_ceed_pbd_valid = global_is_valid[0];
45758600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid;
45858600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
45958600ac3SJames Wright           ctx->is_ceed_vpbd_valid = global_is_valid[0];
46058600ac3SJames Wright         }
46158600ac3SJames Wright       }
46258600ac3SJames Wright     }
46358600ac3SJames Wright     PetscCall(MatDestroy(&temp_mat));
46458600ac3SJames Wright   }
46558600ac3SJames Wright   // -- Set internal mat type
46658600ac3SJames Wright   {
46758600ac3SJames Wright     VecType vec_type;
46840d80af1SJames Wright     MatType coo_mat_type;
46958600ac3SJames Wright 
47058600ac3SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
47140d80af1SJames Wright     if (strstr(vec_type, VECCUDA)) coo_mat_type = MATAIJCUSPARSE;
47240d80af1SJames Wright     else if (strstr(vec_type, VECKOKKOS)) coo_mat_type = MATAIJKOKKOS;
47340d80af1SJames Wright     else coo_mat_type = MATAIJ;
47440d80af1SJames Wright     PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type));
47558600ac3SJames Wright   }
47658600ac3SJames Wright   // -- Set mat operations
47758600ac3SJames Wright   PetscCall(MatShellSetContextDestroy(*mat, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
478e90c2ceeSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (void (*)(void))MatView_Ceed));
47958600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (void (*)(void))MatMult_Ceed));
48058600ac3SJames Wright   if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
48158600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
48258600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
48358600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
48458600ac3SJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
48558600ac3SJames Wright   PetscCall(MatShellSetVecType(*mat, vec_type));
48658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
48758600ac3SJames Wright }
48858600ac3SJames Wright 
48958600ac3SJames Wright /**
49058600ac3SJames Wright   @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`.
49158600ac3SJames Wright 
49258600ac3SJames Wright   Collective across MPI processes.
49358600ac3SJames Wright 
49458600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to copy from
49558600ac3SJames Wright   @param[out]  mat_other  `MatShell` or `MATCEED` to copy into
49658600ac3SJames Wright 
49758600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
49858600ac3SJames Wright **/
49958600ac3SJames Wright PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) {
50058600ac3SJames Wright   PetscFunctionBeginUser;
50158600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
50258600ac3SJames Wright 
50358600ac3SJames Wright   // Check type compatibility
50458600ac3SJames Wright   {
50540d80af1SJames Wright     PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE;
50658600ac3SJames Wright     MatType   mat_type_ceed, mat_type_other;
50758600ac3SJames Wright 
50858600ac3SJames Wright     PetscCall(MatGetType(mat_ceed, &mat_type_ceed));
50940d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
51040d80af1SJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
51140d80af1SJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
51240d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
51340d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matceed));
51440d80af1SJames Wright     PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL);
51558600ac3SJames Wright   }
51658600ac3SJames Wright 
51758600ac3SJames Wright   // Check dimension compatibility
51858600ac3SJames Wright   {
51958600ac3SJames 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;
52058600ac3SJames Wright 
52158600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size));
52258600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size));
52358600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size));
52458600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size));
52558600ac3SJames 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) &&
52658600ac3SJames Wright                    (X_l_ceed_size == X_l_other_size),
52758600ac3SJames Wright                PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
52858600ac3SJames Wright                "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT
52958600ac3SJames Wright                "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT
53058600ac3SJames Wright                ", %" PetscInt_FMT ")",
53158600ac3SJames 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);
53258600ac3SJames Wright   }
53358600ac3SJames Wright 
53458600ac3SJames Wright   // Convert
53558600ac3SJames Wright   {
53658600ac3SJames Wright     VecType        vec_type;
53758600ac3SJames Wright     MatCeedContext ctx;
53858600ac3SJames Wright 
53958600ac3SJames Wright     PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED));
54058600ac3SJames Wright     PetscCall(MatShellGetContext(mat_ceed, &ctx));
54158600ac3SJames Wright     PetscCall(MatCeedContextReference(ctx));
54258600ac3SJames Wright     PetscCall(MatShellSetContext(mat_other, ctx));
54358600ac3SJames Wright     PetscCall(MatShellSetContextDestroy(mat_other, (PetscErrorCode(*)(void *))MatCeedContextDestroy));
544e90c2ceeSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (void (*)(void))MatView_Ceed));
54558600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (void (*)(void))MatMult_Ceed));
54658600ac3SJames Wright     if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed));
54758600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed));
54858600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed));
54958600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_BLOCK_DIAGONAL, (void (*)(void))MatInvertBlockDiagonal_Ceed));
55058600ac3SJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_INVERT_VBLOCK_DIAGONAL, (void (*)(void))MatInvertVariableBlockDiagonal_Ceed));
55158600ac3SJames Wright     {
55258600ac3SJames Wright       PetscInt block_size;
55358600ac3SJames Wright 
55458600ac3SJames Wright       PetscCall(MatGetBlockSize(mat_ceed, &block_size));
55558600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size));
55658600ac3SJames Wright     }
55758600ac3SJames Wright     {
55858600ac3SJames Wright       PetscInt        num_blocks;
55958600ac3SJames Wright       const PetscInt *block_sizes;
56058600ac3SJames Wright 
56158600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes));
56258600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes));
56358600ac3SJames Wright     }
56458600ac3SJames Wright     PetscCall(DMGetVecType(ctx->dm_x, &vec_type));
56558600ac3SJames Wright     PetscCall(MatShellSetVecType(mat_other, vec_type));
56658600ac3SJames Wright   }
56758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
56858600ac3SJames Wright }
56958600ac3SJames Wright 
57058600ac3SJames Wright /**
571ba95ebb4SJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly for a `MatCEED`.
572000d2032SJeremy L Thompson 
573000d2032SJeremy L Thompson   Collective across MPI processes.
574000d2032SJeremy L Thompson 
575000d2032SJeremy L Thompson   @param[in]   mat_ceed       `MATCEED`
576000d2032SJeremy L Thompson   @param[out]  update_needed  Boolean flag indicating `CeedQFunction` update needed
577000d2032SJeremy L Thompson 
578000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
579000d2032SJeremy L Thompson **/
580000d2032SJeremy L Thompson PetscErrorCode MatCeedSetAssemblyDataUpdateNeeded(Mat mat_ceed, PetscBool update_needed) {
581000d2032SJeremy L Thompson   MatCeedContext ctx;
582000d2032SJeremy L Thompson 
583000d2032SJeremy L Thompson   PetscFunctionBeginUser;
584000d2032SJeremy L Thompson   PetscCall(MatShellGetContext(mat_ceed, &ctx));
585000d2032SJeremy L Thompson   PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult, update_needed));
586000d2032SJeremy L Thompson   if (ctx->op_mult_transpose) {
587000d2032SJeremy L Thompson     PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult_transpose, update_needed));
588000d2032SJeremy L Thompson   }
589397c0187SJeremy L Thompson   if (update_needed) {
590397c0187SJeremy L Thompson     PetscCall(MatAssemblyBegin(mat_ceed, MAT_FINAL_ASSEMBLY));
591397c0187SJeremy L Thompson     PetscCall(MatAssemblyEnd(mat_ceed, MAT_FINAL_ASSEMBLY));
592397c0187SJeremy L Thompson   }
593000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
594000d2032SJeremy L Thompson }
595000d2032SJeremy L Thompson 
596000d2032SJeremy L Thompson /**
59740d80af1SJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
59840d80af1SJames Wright 
59940d80af1SJames Wright   Collective across MPI processes.
60040d80af1SJames Wright 
60140d80af1SJames Wright   @param[in]   mat_ceed  `MATCEED`
60240d80af1SJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
60340d80af1SJames Wright 
60440d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
60540d80af1SJames Wright **/
60640d80af1SJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
60740d80af1SJames Wright   MatCeedContext ctx;
60840d80af1SJames Wright 
60940d80af1SJames Wright   PetscFunctionBeginUser;
61040d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
61140d80af1SJames Wright 
61240d80af1SJames 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");
61340d80af1SJames Wright 
61440d80af1SJames Wright   // Check cl mat type
61540d80af1SJames Wright   {
61640d80af1SJames Wright     PetscBool is_coo_mat_type_cl = PETSC_FALSE;
61740d80af1SJames Wright     char      coo_mat_type_cl[64];
61840d80af1SJames Wright 
61940d80af1SJames Wright     // Check for specific CL coo mat type for this Mat
62040d80af1SJames Wright     {
62140d80af1SJames Wright       const char *mat_ceed_prefix = NULL;
62240d80af1SJames Wright 
62340d80af1SJames Wright       PetscCall(MatGetOptionsPrefix(mat_ceed, &mat_ceed_prefix));
62440d80af1SJames Wright       PetscOptionsBegin(PetscObjectComm((PetscObject)mat_ceed), mat_ceed_prefix, "", NULL);
62540d80af1SJames Wright       PetscCall(PetscOptionsFList("-ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
62640d80af1SJames Wright                                   sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
62740d80af1SJames Wright       PetscOptionsEnd();
62840d80af1SJames Wright       if (is_coo_mat_type_cl) {
62940d80af1SJames Wright         PetscCall(PetscFree(ctx->coo_mat_type));
63040d80af1SJames Wright         PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
63140d80af1SJames Wright       }
63240d80af1SJames Wright     }
63340d80af1SJames Wright   }
63440d80af1SJames Wright 
63540d80af1SJames Wright   // Create sparse matrix
63640d80af1SJames Wright   {
63740d80af1SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
63840d80af1SJames Wright 
63940d80af1SJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
64040d80af1SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
64140d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
64240d80af1SJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
64340d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
64440d80af1SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
64540d80af1SJames Wright   }
64640d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
64740d80af1SJames Wright }
64840d80af1SJames Wright 
64940d80af1SJames Wright /**
65040d80af1SJames Wright   @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar.
65158600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
65258600ac3SJames Wright 
65358600ac3SJames Wright   Collective across MPI processes.
65458600ac3SJames Wright 
65558600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
65658600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
65758600ac3SJames Wright 
65858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
65958600ac3SJames Wright **/
66040d80af1SJames Wright PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) {
66158600ac3SJames Wright   MatCeedContext ctx;
66258600ac3SJames Wright 
66358600ac3SJames Wright   PetscFunctionBeginUser;
66458600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
66558600ac3SJames Wright 
66658600ac3SJames Wright   {
66758600ac3SJames Wright     PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
66858600ac3SJames Wright     CeedInt      *rows_ceed, *cols_ceed;
66958600ac3SJames Wright     PetscCount    num_entries;
67058600ac3SJames Wright     PetscLogStage stage_amg_setup;
67158600ac3SJames Wright 
67258600ac3SJames Wright     // -- Assemble sparsity pattern if mat hasn't been assembled before
673c63b910fSJames Wright     PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
67458600ac3SJames Wright     if (stage_amg_setup == -1) {
675c63b910fSJames Wright       PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
67658600ac3SJames Wright     }
67758600ac3SJames Wright     PetscCall(PetscLogStagePush(stage_amg_setup));
678c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
679c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
68050f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
681c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
682a7dac1d5SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
683a7dac1d5SJames Wright     PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
68458600ac3SJames Wright     PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
68558600ac3SJames Wright     free(rows_petsc);
68658600ac3SJames Wright     free(cols_petsc);
68750f50432SJames Wright     if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full));
68858600ac3SJames Wright     PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full));
68958600ac3SJames Wright     ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo;
690c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
69158600ac3SJames Wright     PetscCall(PetscLogStagePop());
69258600ac3SJames Wright   }
69340d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
69440d80af1SJames Wright }
69540d80af1SJames Wright 
69640d80af1SJames Wright /**
69740d80af1SJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
69840d80af1SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
69940d80af1SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
70040d80af1SJames Wright 
70140d80af1SJames Wright   Collective across MPI processes.
70240d80af1SJames Wright 
70340d80af1SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
70440d80af1SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
70540d80af1SJames Wright 
70640d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
70740d80af1SJames Wright **/
70840d80af1SJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
70940d80af1SJames Wright   MatCeedContext ctx;
71040d80af1SJames Wright 
71140d80af1SJames Wright   PetscFunctionBeginUser;
71240d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
71340d80af1SJames Wright 
71440d80af1SJames Wright   // Set COO pattern if needed
71540d80af1SJames Wright   {
71640d80af1SJames Wright     CeedInt index = -1;
71740d80af1SJames Wright 
71840d80af1SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
71940d80af1SJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
72040d80af1SJames Wright     }
72140d80af1SJames Wright     if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo));
72258600ac3SJames Wright   }
72358600ac3SJames Wright 
72458600ac3SJames Wright   // Assemble mat_ceed
725c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
72658600ac3SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
72758600ac3SJames Wright   {
72858600ac3SJames Wright     const CeedScalar *values;
72958600ac3SJames Wright     MatType           mat_type;
73058600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
73158600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
73258600ac3SJames Wright 
73358600ac3SJames Wright     PetscCall(MatGetType(mat_coo, &mat_type));
73458600ac3SJames Wright     if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE;
73558600ac3SJames Wright     else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE;
73658600ac3SJames Wright     else mem_type = CEED_MEM_HOST;
73758600ac3SJames Wright 
738c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
73950f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full));
740c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
74150f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values));
74258600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
74358600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
74458600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
74550f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values));
74658600ac3SJames Wright   }
74758600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
748c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
74958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
75058600ac3SJames Wright }
75158600ac3SJames Wright 
75258600ac3SJames Wright /**
75340d80af1SJames Wright   @brief Set the current value of a context field for a `MatCEED`.
75440d80af1SJames Wright 
75540d80af1SJames Wright   Not collective across MPI processes.
75640d80af1SJames Wright 
75740d80af1SJames Wright   @param[in,out]  mat    `MatCEED`
75840d80af1SJames Wright   @param[in]      name   Name of the context field
75940d80af1SJames Wright   @param[in]      value  New context field value
76040d80af1SJames Wright 
76140d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
76240d80af1SJames Wright **/
76340d80af1SJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
76440d80af1SJames Wright   PetscBool      was_updated = PETSC_FALSE;
76540d80af1SJames Wright   MatCeedContext ctx;
76640d80af1SJames Wright 
76740d80af1SJames Wright   PetscFunctionBeginUser;
76840d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
76940d80af1SJames Wright   {
77040d80af1SJames Wright     CeedContextFieldLabel label = NULL;
77140d80af1SJames Wright 
77240d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, 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, label, &value));
77940d80af1SJames Wright         was_updated = PETSC_TRUE;
78040d80af1SJames Wright       }
781000d2032SJeremy L Thompson     }
78240d80af1SJames Wright     if (ctx->op_mult_transpose) {
78340d80af1SJames Wright       label = NULL;
78440d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
78540d80af1SJames Wright       if (label) {
786000d2032SJeremy L Thompson         double set_value = 2 * value + 1.0;
787000d2032SJeremy L Thompson 
788000d2032SJeremy L Thompson         PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
789000d2032SJeremy L Thompson         if (set_value != value) {
79040d80af1SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
79140d80af1SJames Wright           was_updated = PETSC_TRUE;
79240d80af1SJames Wright         }
79340d80af1SJames Wright       }
79440d80af1SJames Wright     }
795000d2032SJeremy L Thompson   }
79640d80af1SJames Wright   if (was_updated) {
79740d80af1SJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
79840d80af1SJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
79940d80af1SJames Wright   }
80040d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
80140d80af1SJames Wright }
80240d80af1SJames Wright 
80340d80af1SJames Wright /**
80440d80af1SJames Wright   @brief Get the current value of a context field for a `MatCEED`.
80540d80af1SJames Wright 
80640d80af1SJames Wright   Not collective across MPI processes.
80740d80af1SJames Wright 
80840d80af1SJames Wright   @param[in]   mat    `MatCEED`
80940d80af1SJames Wright   @param[in]   name   Name of the context field
81040d80af1SJames Wright   @param[out]  value  Current context field value
81140d80af1SJames Wright 
81240d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
81340d80af1SJames Wright **/
81440d80af1SJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
81540d80af1SJames Wright   MatCeedContext ctx;
81640d80af1SJames Wright 
81740d80af1SJames Wright   PetscFunctionBeginUser;
81840d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
81940d80af1SJames Wright   {
82040d80af1SJames Wright     CeedContextFieldLabel label = NULL;
82140d80af1SJames Wright     CeedOperator          op    = ctx->op_mult;
82240d80af1SJames Wright 
82340d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
82440d80af1SJames Wright     if (!label && ctx->op_mult_transpose) {
82540d80af1SJames Wright       op = ctx->op_mult_transpose;
82640d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
82740d80af1SJames Wright     }
82840d80af1SJames Wright     if (label) {
82940d80af1SJames Wright       PetscSizeT    num_values;
83040d80af1SJames Wright       const double *values_ceed;
83140d80af1SJames Wright 
83240d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
83340d80af1SJames Wright       *value = values_ceed[0];
83440d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
83540d80af1SJames Wright     }
83640d80af1SJames Wright   }
83740d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
83840d80af1SJames Wright }
83940d80af1SJames Wright 
84040d80af1SJames Wright /**
841000d2032SJeremy L Thompson   @brief Set the current `PetscReal` value of a context field for a `MatCEED`.
842000d2032SJeremy L Thompson 
843000d2032SJeremy L Thompson   Not collective across MPI processes.
844000d2032SJeremy L Thompson 
845000d2032SJeremy L Thompson   @param[in,out]  mat    `MatCEED`
846000d2032SJeremy L Thompson   @param[in]      name   Name of the context field
847000d2032SJeremy L Thompson   @param[in]      value  New context field value
848000d2032SJeremy L Thompson 
849000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
850000d2032SJeremy L Thompson **/
851000d2032SJeremy L Thompson PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) {
852000d2032SJeremy L Thompson   double value_double = value;
853000d2032SJeremy L Thompson 
854000d2032SJeremy L Thompson   PetscFunctionBeginUser;
855000d2032SJeremy L Thompson   PetscCall(MatCeedSetContextDouble(mat, name, value_double));
856000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
857000d2032SJeremy L Thompson }
858000d2032SJeremy L Thompson 
859000d2032SJeremy L Thompson /**
86051bb547fSJames Wright   @brief Get the current `PetscReal` value of a context field for a `MatCEED`.
86151bb547fSJames Wright 
86251bb547fSJames Wright   Not collective across MPI processes.
86351bb547fSJames Wright 
86451bb547fSJames Wright   @param[in]   mat    `MatCEED`
86551bb547fSJames Wright   @param[in]   name   Name of the context field
86651bb547fSJames Wright   @param[out]  value  Current context field value
86751bb547fSJames Wright 
86851bb547fSJames Wright   @return An error code: 0 - success, otherwise - failure
86951bb547fSJames Wright **/
87051bb547fSJames Wright PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) {
87187d3884fSJeremy L Thompson   double value_double = 0.0;
87251bb547fSJames Wright 
87351bb547fSJames Wright   PetscFunctionBeginUser;
87451bb547fSJames Wright   PetscCall(MatCeedGetContextDouble(mat, name, &value_double));
87551bb547fSJames Wright   *value = value_double;
87651bb547fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
87751bb547fSJames Wright }
87851bb547fSJames Wright 
87951bb547fSJames Wright /**
880000d2032SJeremy L Thompson   @brief Set the current time for a `MatCEED`.
881000d2032SJeremy L Thompson 
882000d2032SJeremy L Thompson   Not collective across MPI processes.
883000d2032SJeremy L Thompson 
884000d2032SJeremy L Thompson   @param[in,out]  mat   `MatCEED`
885000d2032SJeremy L Thompson   @param[in]      time  Current time
886000d2032SJeremy L Thompson 
887000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
888000d2032SJeremy L Thompson **/
889000d2032SJeremy L Thompson PetscErrorCode MatCeedSetTime(Mat mat, PetscReal time) {
890000d2032SJeremy L Thompson   PetscFunctionBeginUser;
891000d2032SJeremy L Thompson   {
892000d2032SJeremy L Thompson     double time_ceed = time;
893000d2032SJeremy L Thompson 
894000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "time", time_ceed));
895000d2032SJeremy L Thompson   }
896000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
897000d2032SJeremy L Thompson }
898000d2032SJeremy L Thompson 
899000d2032SJeremy L Thompson /**
900000d2032SJeremy L Thompson   @brief Get the current time for a `MatCEED`.
901000d2032SJeremy L Thompson 
902000d2032SJeremy L Thompson   Not collective across MPI processes.
903000d2032SJeremy L Thompson 
904000d2032SJeremy L Thompson   @param[in]   mat   `MatCEED`
905000d2032SJeremy L Thompson   @param[out]  time  Current time, or -1.0 if the boundary evaluator has no time field
906000d2032SJeremy L Thompson 
907000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
908000d2032SJeremy L Thompson **/
909000d2032SJeremy L Thompson PetscErrorCode MatCeedGetTime(Mat mat, PetscReal *time) {
910000d2032SJeremy L Thompson   PetscFunctionBeginUser;
911000d2032SJeremy L Thompson   *time = -1.0;
912000d2032SJeremy L Thompson   {
913000d2032SJeremy L Thompson     double time_ceed = -1.0;
914000d2032SJeremy L Thompson 
915000d2032SJeremy L Thompson     PetscCall(MatCeedGetContextDouble(mat, "time", &time_ceed));
916000d2032SJeremy L Thompson     *time = time_ceed;
917000d2032SJeremy L Thompson   }
918000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
919000d2032SJeremy L Thompson }
920000d2032SJeremy L Thompson 
921000d2032SJeremy L Thompson /**
922000d2032SJeremy L Thompson   @brief Set the current time step for a `MatCEED`.
923000d2032SJeremy L Thompson 
924000d2032SJeremy L Thompson   Not collective across MPI processes.
925000d2032SJeremy L Thompson 
926000d2032SJeremy L Thompson   @param[in,out]  mat  `MatCEED`
927000d2032SJeremy L Thompson   @param[in]      dt   Current time step
928000d2032SJeremy L Thompson 
929000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
930000d2032SJeremy L Thompson **/
931000d2032SJeremy L Thompson PetscErrorCode MatCeedSetDt(Mat mat, PetscReal dt) {
932000d2032SJeremy L Thompson   PetscFunctionBeginUser;
933000d2032SJeremy L Thompson   {
934000d2032SJeremy L Thompson     double dt_ceed = dt;
935000d2032SJeremy L Thompson 
936000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "dt", dt_ceed));
937000d2032SJeremy L Thompson   }
938000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
939000d2032SJeremy L Thompson }
940000d2032SJeremy L Thompson 
941000d2032SJeremy L Thompson /**
942000d2032SJeremy L Thompson   @brief Set the Jacobian shifts for a `MatCEED`.
943000d2032SJeremy L Thompson 
944000d2032SJeremy L Thompson   Not collective across MPI processes.
945000d2032SJeremy L Thompson 
946000d2032SJeremy L Thompson   @param[in,out]  mat      `MatCEED`
947000d2032SJeremy L Thompson   @param[in]      shift_v  Velocity shift
948000d2032SJeremy L Thompson   @param[in]      shift_a  Acceleration shift
949000d2032SJeremy L Thompson 
950000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
951000d2032SJeremy L Thompson **/
952000d2032SJeremy L Thompson PetscErrorCode MatCeedSetShifts(Mat mat, PetscReal shift_v, PetscReal shift_a) {
953000d2032SJeremy L Thompson   PetscFunctionBeginUser;
954000d2032SJeremy L Thompson   {
955000d2032SJeremy L Thompson     double shift_v_ceed = shift_v;
956000d2032SJeremy L Thompson 
957000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift v", shift_v_ceed));
958000d2032SJeremy L Thompson   }
959000d2032SJeremy L Thompson   if (shift_a) {
960000d2032SJeremy L Thompson     double shift_a_ceed = shift_a;
961000d2032SJeremy L Thompson 
962000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift a", shift_a_ceed));
963000d2032SJeremy L Thompson   }
964000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
965000d2032SJeremy L Thompson }
966000d2032SJeremy L Thompson 
967000d2032SJeremy L Thompson /**
96858600ac3SJames Wright   @brief Set user context for a `MATCEED`.
96958600ac3SJames Wright 
97058600ac3SJames Wright   Collective across MPI processes.
97158600ac3SJames Wright 
97258600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
97358600ac3SJames Wright   @param[in]      f    The context destroy function, or NULL
97458600ac3SJames Wright   @param[in]      ctx  User context, or NULL to unset
97558600ac3SJames Wright 
97658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
97758600ac3SJames Wright **/
97858600ac3SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscErrorCode (*f)(void *), void *ctx) {
97958600ac3SJames Wright   PetscContainer user_ctx = NULL;
98058600ac3SJames Wright 
98158600ac3SJames Wright   PetscFunctionBeginUser;
98258600ac3SJames Wright   if (ctx) {
98358600ac3SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
98458600ac3SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
98558600ac3SJames Wright     PetscCall(PetscContainerSetUserDestroy(user_ctx, f));
98658600ac3SJames Wright   }
98758600ac3SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
98858600ac3SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
98958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
99058600ac3SJames Wright }
99158600ac3SJames Wright 
99258600ac3SJames Wright /**
99358600ac3SJames Wright   @brief Retrieve the user context for a `MATCEED`.
99458600ac3SJames Wright 
99558600ac3SJames Wright   Collective across MPI processes.
99658600ac3SJames Wright 
99758600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
99858600ac3SJames Wright   @param[in]      ctx  User context
99958600ac3SJames Wright 
100058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
100158600ac3SJames Wright **/
100258600ac3SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
100358600ac3SJames Wright   PetscContainer user_ctx;
100458600ac3SJames Wright 
100558600ac3SJames Wright   PetscFunctionBeginUser;
100658600ac3SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
100758600ac3SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
100858600ac3SJames Wright   else *(void **)ctx = NULL;
100958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
101058600ac3SJames Wright }
101158600ac3SJames Wright /**
101240d80af1SJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
101340d80af1SJames Wright 
101440d80af1SJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
101540d80af1SJames Wright `MatCeedSetContext()`.
101658600ac3SJames Wright 
101758600ac3SJames Wright   Collective across MPI processes.
101858600ac3SJames Wright 
101958600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
102040d80af1SJames Wright   @param[in]      op   Name of the `MatOperation`
102140d80af1SJames Wright   @param[in]      g    Function that provides the operation
102258600ac3SJames Wright 
102358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
102458600ac3SJames Wright **/
102540d80af1SJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
102640d80af1SJames Wright   PetscFunctionBeginUser;
102740d80af1SJames Wright   PetscCall(MatShellSetOperation(mat, op, g));
102840d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
102940d80af1SJames Wright }
103040d80af1SJames Wright 
103140d80af1SJames Wright /**
103240d80af1SJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
103340d80af1SJames Wright 
103440d80af1SJames Wright   Collective across MPI processes.
103540d80af1SJames Wright 
103640d80af1SJames Wright   @param[in,out]  mat   `MATCEED`
103740d80af1SJames Wright   @param[in]      type  COO `MatType` to set
103840d80af1SJames Wright 
103940d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
104040d80af1SJames Wright **/
104140d80af1SJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
104258600ac3SJames Wright   MatCeedContext ctx;
104358600ac3SJames Wright 
104458600ac3SJames Wright   PetscFunctionBeginUser;
104558600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
104658600ac3SJames Wright   // Check if same
104758600ac3SJames Wright   {
104858600ac3SJames Wright     size_t    len_old, len_new;
104958600ac3SJames Wright     PetscBool is_same = PETSC_FALSE;
105058600ac3SJames Wright 
105140d80af1SJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
105258600ac3SJames Wright     PetscCall(PetscStrlen(type, &len_new));
105340d80af1SJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
105458600ac3SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
105558600ac3SJames Wright   }
105658600ac3SJames Wright   // Clean up old mats in different format
105758600ac3SJames Wright   // LCOV_EXCL_START
105858600ac3SJames Wright   if (ctx->mat_assembled_full_internal) {
105958600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
106058600ac3SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
106158600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
106258600ac3SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
106358600ac3SJames Wright         }
106458600ac3SJames Wright         ctx->num_mats_assembled_full--;
106558600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
106658600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
106758600ac3SJames Wright       }
106858600ac3SJames Wright     }
106958600ac3SJames Wright   }
107058600ac3SJames Wright   if (ctx->mat_assembled_pbd_internal) {
107158600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
107258600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
107358600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
107458600ac3SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
107558600ac3SJames Wright         }
107658600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
107758600ac3SJames Wright         ctx->num_mats_assembled_pbd--;
107858600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
107958600ac3SJames Wright       }
108058600ac3SJames Wright     }
108158600ac3SJames Wright   }
108240d80af1SJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
108340d80af1SJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
108458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
108558600ac3SJames Wright   // LCOV_EXCL_STOP
108658600ac3SJames Wright }
108758600ac3SJames Wright 
108858600ac3SJames Wright /**
108940d80af1SJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
109058600ac3SJames Wright 
109158600ac3SJames Wright   Collective across MPI processes.
109258600ac3SJames Wright 
109358600ac3SJames Wright   @param[in,out]  mat   `MATCEED`
109440d80af1SJames Wright   @param[in]      type  COO `MatType`
109558600ac3SJames Wright 
109658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
109758600ac3SJames Wright **/
109840d80af1SJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
109958600ac3SJames Wright   MatCeedContext ctx;
110058600ac3SJames Wright 
110158600ac3SJames Wright   PetscFunctionBeginUser;
110258600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
110340d80af1SJames Wright   *type = ctx->coo_mat_type;
110458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
110558600ac3SJames Wright }
110658600ac3SJames Wright 
110758600ac3SJames Wright /**
110858600ac3SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
110958600ac3SJames Wright 
111058600ac3SJames Wright   Not collective across MPI processes.
111158600ac3SJames Wright 
111258600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
111358600ac3SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
111458600ac3SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
111558600ac3SJames Wright 
111658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
111758600ac3SJames Wright **/
111858600ac3SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
111958600ac3SJames Wright   MatCeedContext ctx;
112058600ac3SJames Wright 
112158600ac3SJames Wright   PetscFunctionBeginUser;
112258600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
112358600ac3SJames Wright   if (X_loc) {
112458600ac3SJames Wright     PetscInt len_old, len_new;
112558600ac3SJames Wright 
112658600ac3SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
112758600ac3SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
112858600ac3SJames 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,
112958600ac3SJames Wright                len_new, len_old);
113040d80af1SJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
113158600ac3SJames Wright   }
113258600ac3SJames Wright   if (Y_loc_transpose) {
113358600ac3SJames Wright     PetscInt len_old, len_new;
113458600ac3SJames Wright 
113558600ac3SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
113658600ac3SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
113758600ac3SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
113858600ac3SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
113940d80af1SJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
114058600ac3SJames Wright   }
114158600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
114258600ac3SJames Wright }
114358600ac3SJames Wright 
114458600ac3SJames Wright /**
114558600ac3SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
114658600ac3SJames Wright 
114758600ac3SJames Wright   Not collective across MPI processes.
114858600ac3SJames Wright 
114958600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
115058600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
115158600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
115258600ac3SJames Wright 
115358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
115458600ac3SJames Wright **/
115558600ac3SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
115658600ac3SJames Wright   MatCeedContext ctx;
115758600ac3SJames Wright 
115858600ac3SJames Wright   PetscFunctionBeginUser;
115958600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
116058600ac3SJames Wright   if (X_loc) {
116140d80af1SJames Wright     *X_loc = NULL;
116240d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
116358600ac3SJames Wright   }
116458600ac3SJames Wright   if (Y_loc_transpose) {
116540d80af1SJames Wright     *Y_loc_transpose = NULL;
116640d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
116758600ac3SJames Wright   }
116858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
116958600ac3SJames Wright }
117058600ac3SJames Wright 
117158600ac3SJames Wright /**
117258600ac3SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
117358600ac3SJames Wright 
117458600ac3SJames Wright   Not collective across MPI processes.
117558600ac3SJames Wright 
117658600ac3SJames Wright   @param[in,out]  mat              MatCeed
117758600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
117858600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
117958600ac3SJames Wright 
118058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
118158600ac3SJames Wright **/
118258600ac3SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
118358600ac3SJames Wright   PetscFunctionBeginUser;
118458600ac3SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
118558600ac3SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
118658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
118758600ac3SJames Wright }
118858600ac3SJames Wright 
118958600ac3SJames Wright /**
119058600ac3SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
119158600ac3SJames Wright 
119258600ac3SJames Wright   Not collective across MPI processes.
119358600ac3SJames Wright 
119458600ac3SJames Wright   @param[in,out]  mat                MatCeed
119558600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
119658600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
119758600ac3SJames Wright 
119858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
119958600ac3SJames Wright **/
120058600ac3SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
120158600ac3SJames Wright   MatCeedContext ctx;
120258600ac3SJames Wright 
120358600ac3SJames Wright   PetscFunctionBeginUser;
120458600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
120558600ac3SJames Wright   if (op_mult) {
120658600ac3SJames Wright     *op_mult = NULL;
120750f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
120858600ac3SJames Wright   }
120958600ac3SJames Wright   if (op_mult_transpose) {
121058600ac3SJames Wright     *op_mult_transpose = NULL;
121150f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
121258600ac3SJames Wright   }
121358600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
121458600ac3SJames Wright }
121558600ac3SJames Wright 
121658600ac3SJames Wright /**
121758600ac3SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
121858600ac3SJames Wright 
121958600ac3SJames Wright   Not collective across MPI processes.
122058600ac3SJames Wright 
122158600ac3SJames Wright   @param[in,out]  mat                MatCeed
122258600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
122358600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
122458600ac3SJames Wright 
122558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
122658600ac3SJames Wright **/
122758600ac3SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
122858600ac3SJames Wright   MatCeedContext ctx;
122958600ac3SJames Wright 
123058600ac3SJames Wright   PetscFunctionBeginUser;
123158600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
123250f50432SJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
123350f50432SJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
123458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
123558600ac3SJames Wright }
123658600ac3SJames Wright 
123758600ac3SJames Wright /**
123858600ac3SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
123958600ac3SJames Wright 
124058600ac3SJames Wright   Not collective across MPI processes.
124158600ac3SJames Wright 
124258600ac3SJames Wright   @param[in,out]  mat                       MatCeed
124358600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
124458600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
124558600ac3SJames Wright 
124658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
124758600ac3SJames Wright **/
124858600ac3SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
124958600ac3SJames Wright   MatCeedContext ctx;
125058600ac3SJames Wright 
125158600ac3SJames Wright   PetscFunctionBeginUser;
125258600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
125358600ac3SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
125458600ac3SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
125558600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
125658600ac3SJames Wright }
125758600ac3SJames Wright 
125858600ac3SJames Wright /**
125958600ac3SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
126058600ac3SJames Wright 
126158600ac3SJames Wright   Not collective across MPI processes.
126258600ac3SJames Wright 
126358600ac3SJames Wright   @param[in,out]  mat                       MatCeed
126458600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
126558600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
126658600ac3SJames Wright 
126758600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
126858600ac3SJames Wright **/
126958600ac3SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
127058600ac3SJames Wright   MatCeedContext ctx;
127158600ac3SJames Wright 
127258600ac3SJames Wright   PetscFunctionBeginUser;
127358600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
127458600ac3SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
127558600ac3SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
127658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
127758600ac3SJames Wright }
127858600ac3SJames Wright 
1279c63b910fSJames Wright /**
1280c63b910fSJames Wright   @brief Set `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1281c63b910fSJames Wright 
1282c63b910fSJames Wright   Not collective across MPI processes.
1283c63b910fSJames Wright 
1284c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1285c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1286c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1287c63b910fSJames Wright 
1288c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1289c63b910fSJames Wright **/
1290c63b910fSJames Wright PetscErrorCode MatCeedSetCeedOperatorLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1291c63b910fSJames Wright   MatCeedContext ctx;
1292c63b910fSJames Wright 
1293c63b910fSJames Wright   PetscFunctionBeginUser;
1294c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1295c63b910fSJames Wright   if (log_event_mult) ctx->log_event_ceed_mult = log_event_mult;
1296c63b910fSJames Wright   if (log_event_mult_transpose) ctx->log_event_ceed_mult_transpose = log_event_mult_transpose;
1297c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1298c63b910fSJames Wright }
1299c63b910fSJames Wright 
1300c63b910fSJames Wright /**
1301c63b910fSJames Wright   @brief Get `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1302c63b910fSJames Wright 
1303c63b910fSJames Wright   Not collective across MPI processes.
1304c63b910fSJames Wright 
1305c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1306c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1307c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1308c63b910fSJames Wright 
1309c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1310c63b910fSJames Wright **/
1311c63b910fSJames Wright PetscErrorCode MatCeedGetCeedOperatorLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1312c63b910fSJames Wright   MatCeedContext ctx;
1313c63b910fSJames Wright 
1314c63b910fSJames Wright   PetscFunctionBeginUser;
1315c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1316c63b910fSJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_ceed_mult;
1317c63b910fSJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_ceed_mult_transpose;
1318c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1319c63b910fSJames Wright }
1320c63b910fSJames Wright 
132158600ac3SJames Wright // -----------------------------------------------------------------------------
132258600ac3SJames Wright // Operator context data
132358600ac3SJames Wright // -----------------------------------------------------------------------------
132458600ac3SJames Wright 
132558600ac3SJames Wright /**
132658600ac3SJames Wright   @brief Setup context data for operator application.
132758600ac3SJames Wright 
132858600ac3SJames Wright   Collective across MPI processes.
132958600ac3SJames Wright 
133058600ac3SJames Wright   @param[in]   dm_x                           Input `DM`
133158600ac3SJames Wright   @param[in]   dm_y                           Output `DM`
133258600ac3SJames Wright   @param[in]   X_loc                          Input PETSc local vector, or NULL
133358600ac3SJames Wright   @param[in]   Y_loc_transpose                Input PETSc local vector for transpose operation, or NULL
133458600ac3SJames Wright   @param[in]   op_mult                        `CeedOperator` for forward evaluation
133558600ac3SJames Wright   @param[in]   op_mult_transpose              `CeedOperator` for transpose evaluation
133658600ac3SJames Wright   @param[in]   log_event_mult                 `PetscLogEvent` for forward evaluation
133758600ac3SJames Wright   @param[in]   log_event_mult_transpose       `PetscLogEvent` for transpose evaluation
1338c63b910fSJames Wright   @param[in]   log_event_ceed_mult            `PetscLogEvent` for forward `CeedOperator` evaluation
1339c63b910fSJames Wright   @param[in]   log_event_ceed_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation
134058600ac3SJames Wright   @param[out]  ctx                            Context data for operator evaluation
134158600ac3SJames Wright 
134258600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
134358600ac3SJames Wright **/
134458600ac3SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1345c63b910fSJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, PetscLogEvent log_event_ceed_mult,
1346c63b910fSJames Wright                                     PetscLogEvent log_event_ceed_mult_transpose, MatCeedContext *ctx) {
134758600ac3SJames Wright   CeedSize x_loc_len, y_loc_len;
134858600ac3SJames Wright 
134958600ac3SJames Wright   PetscFunctionBeginUser;
135058600ac3SJames Wright 
135158600ac3SJames Wright   // Allocate
135258600ac3SJames Wright   PetscCall(PetscNew(ctx));
135358600ac3SJames Wright   (*ctx)->ref_count = 1;
135458600ac3SJames Wright 
135558600ac3SJames Wright   // Logging
135658600ac3SJames Wright   (*ctx)->log_event_mult                = log_event_mult;
135758600ac3SJames Wright   (*ctx)->log_event_mult_transpose      = log_event_mult_transpose;
1358c63b910fSJames Wright   (*ctx)->log_event_ceed_mult           = log_event_ceed_mult;
1359c63b910fSJames Wright   (*ctx)->log_event_ceed_mult_transpose = log_event_ceed_mult_transpose;
136058600ac3SJames Wright 
136158600ac3SJames Wright   // PETSc objects
136240d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
136340d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
136440d80af1SJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
136540d80af1SJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
136658600ac3SJames Wright 
136758600ac3SJames Wright   // Memtype
136858600ac3SJames Wright   {
136958600ac3SJames Wright     const PetscScalar *x;
137058600ac3SJames Wright     Vec                X;
137158600ac3SJames Wright 
137258600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
137358600ac3SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
137458600ac3SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
137558600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
137658600ac3SJames Wright   }
137758600ac3SJames Wright 
137858600ac3SJames Wright   // libCEED objects
137958600ac3SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
138058600ac3SJames Wright              "retrieving Ceed context object failed");
138150f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedReference((*ctx)->ceed));
138250f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
138350f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
138450f50432SJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
138550f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
138650f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
138758600ac3SJames Wright 
138858600ac3SJames Wright   // Flop counting
138958600ac3SJames Wright   {
139058600ac3SJames Wright     CeedSize ceed_flops_estimate = 0;
139158600ac3SJames Wright 
139250f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
139358600ac3SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
139458600ac3SJames Wright     if (op_mult_transpose) {
139550f50432SJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
139658600ac3SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
139758600ac3SJames Wright     }
139858600ac3SJames Wright   }
139958600ac3SJames Wright 
140058600ac3SJames Wright   // Check sizes
140158600ac3SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
140258600ac3SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
140358600ac3SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
140458600ac3SJames Wright     Vec      dm_X_loc, dm_Y_loc;
140558600ac3SJames Wright 
140658600ac3SJames Wright     // -- Input
140758600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
140858600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
140958600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
141050f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
14114c17272bSJames Wright     if (X_loc) {
14124c17272bSJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
14134c17272bSJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14144c17272bSJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
14154c17272bSJames Wright     }
14164c17272bSJames 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",
14174c17272bSJames Wright                x_loc_len, dm_x_loc_len);
14184c17272bSJames 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 ")",
14194c17272bSJames Wright                x_loc_len, ctx_x_loc_len);
142058600ac3SJames Wright 
142158600ac3SJames Wright     // -- Output
142258600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
142358600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
142458600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
142550f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
14264c17272bSJames 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",
14274c17272bSJames Wright                ctx_y_loc_len, dm_y_loc_len);
142858600ac3SJames Wright 
142958600ac3SJames Wright     // -- Transpose
143058600ac3SJames Wright     if (Y_loc_transpose) {
143158600ac3SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
14324c17272bSJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14334c17272bSJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
143458600ac3SJames Wright     }
143558600ac3SJames Wright   }
143658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
143758600ac3SJames Wright }
143858600ac3SJames Wright 
143958600ac3SJames Wright /**
144058600ac3SJames Wright   @brief Increment reference counter for `MATCEED` context.
144158600ac3SJames Wright 
144258600ac3SJames Wright   Not collective across MPI processes.
144358600ac3SJames Wright 
144458600ac3SJames Wright   @param[in,out]  ctx  Context data
144558600ac3SJames Wright 
144658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
144758600ac3SJames Wright **/
144858600ac3SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
144958600ac3SJames Wright   PetscFunctionBeginUser;
145058600ac3SJames Wright   ctx->ref_count++;
145158600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
145258600ac3SJames Wright }
145358600ac3SJames Wright 
145458600ac3SJames Wright /**
145558600ac3SJames Wright   @brief Copy reference for `MATCEED`.
145658600ac3SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
145758600ac3SJames Wright 
145858600ac3SJames Wright   Not collective across MPI processes.
145958600ac3SJames Wright 
146058600ac3SJames Wright   @param[in]   ctx       Context data
146158600ac3SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
146258600ac3SJames Wright 
146358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
146458600ac3SJames Wright **/
146558600ac3SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
146658600ac3SJames Wright   PetscFunctionBeginUser;
146758600ac3SJames Wright   PetscCall(MatCeedContextReference(ctx));
146858600ac3SJames Wright   PetscCall(MatCeedContextDestroy(*ctx_copy));
146958600ac3SJames Wright   *ctx_copy = ctx;
147058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
147158600ac3SJames Wright }
147258600ac3SJames Wright 
147358600ac3SJames Wright /**
147458600ac3SJames Wright   @brief Destroy context data for operator application.
147558600ac3SJames Wright 
147658600ac3SJames Wright   Collective across MPI processes.
147758600ac3SJames Wright 
147858600ac3SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
147958600ac3SJames Wright 
148058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
148158600ac3SJames Wright **/
148258600ac3SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext ctx) {
148358600ac3SJames Wright   PetscFunctionBeginUser;
148458600ac3SJames Wright   if (!ctx || --ctx->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
148558600ac3SJames Wright 
148658600ac3SJames Wright   // PETSc objects
148758600ac3SJames Wright   PetscCall(DMDestroy(&ctx->dm_x));
148858600ac3SJames Wright   PetscCall(DMDestroy(&ctx->dm_y));
148958600ac3SJames Wright   PetscCall(VecDestroy(&ctx->X_loc));
149058600ac3SJames Wright   PetscCall(VecDestroy(&ctx->Y_loc_transpose));
149158600ac3SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
149258600ac3SJames Wright   PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
149340d80af1SJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
149458600ac3SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_full));
149558600ac3SJames Wright   PetscCall(PetscFree(ctx->mats_assembled_pbd));
149658600ac3SJames Wright 
149758600ac3SJames Wright   // libCEED objects
149850f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->x_loc));
149950f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->y_loc));
150050f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_full));
150150f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedVectorDestroy(&ctx->coo_values_pbd));
150250f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult));
150350f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorDestroy(&ctx->op_mult_transpose));
150458600ac3SJames Wright   PetscCheck(CeedDestroy(&ctx->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
150558600ac3SJames Wright 
150658600ac3SJames Wright   // Deallocate
150758600ac3SJames Wright   ctx->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
150858600ac3SJames Wright   PetscCall(PetscFree(ctx));
150958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
151058600ac3SJames Wright }
151158600ac3SJames Wright 
151258600ac3SJames Wright /**
151358600ac3SJames Wright   @brief Compute the diagonal of an operator via libCEED.
151458600ac3SJames Wright 
151558600ac3SJames Wright   Collective across MPI processes.
151658600ac3SJames Wright 
151758600ac3SJames Wright   @param[in]   A  `MATCEED`
151858600ac3SJames Wright   @param[out]  D  Vector holding operator diagonal
151958600ac3SJames Wright 
152058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
152158600ac3SJames Wright **/
152258600ac3SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
152358600ac3SJames Wright   PetscMemType   mem_type;
152458600ac3SJames Wright   Vec            D_loc;
152558600ac3SJames Wright   MatCeedContext ctx;
152658600ac3SJames Wright 
152758600ac3SJames Wright   PetscFunctionBeginUser;
152858600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
152958600ac3SJames Wright 
153058600ac3SJames Wright   // Place PETSc vector in libCEED vector
1531c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
153258600ac3SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1533a7dac1d5SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
153458600ac3SJames Wright 
153558600ac3SJames Wright   // Compute Diagonal
1536c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
153750f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1538c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
153958600ac3SJames Wright 
154058600ac3SJames Wright   // Restore PETSc vector
1541a7dac1d5SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
154258600ac3SJames Wright 
154358600ac3SJames Wright   // Local-to-Global
154458600ac3SJames Wright   PetscCall(VecZeroEntries(D));
154558600ac3SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
154658600ac3SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1547c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
154858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
154958600ac3SJames Wright }
155058600ac3SJames Wright 
155158600ac3SJames Wright /**
155258600ac3SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
155358600ac3SJames Wright 
155458600ac3SJames Wright   Collective across MPI processes.
155558600ac3SJames Wright 
155658600ac3SJames Wright   @param[in]   A  `MATCEED`
155758600ac3SJames Wright   @param[in]   X  Input PETSc vector
155858600ac3SJames Wright   @param[out]  Y  Output PETSc vector
155958600ac3SJames Wright 
156058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
156158600ac3SJames Wright **/
156258600ac3SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
156358600ac3SJames Wright   MatCeedContext ctx;
156458600ac3SJames Wright 
156558600ac3SJames Wright   PetscFunctionBeginUser;
156658600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1567c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, NULL));
156858600ac3SJames Wright 
156958600ac3SJames Wright   {
157058600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
157158600ac3SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
157258600ac3SJames Wright 
157358600ac3SJames Wright     // Get local vectors
157458600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
157558600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
157658600ac3SJames Wright 
157758600ac3SJames Wright     // Global-to-local
157858600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
157958600ac3SJames Wright 
158058600ac3SJames Wright     // Setup libCEED vectors
1581a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
158258600ac3SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1583a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
158458600ac3SJames Wright 
158558600ac3SJames Wright     // Apply libCEED operator
1586c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult, A, X, Y, NULL));
1587537ec908SJames Wright     PetscCall(PetscLogGpuTimeBegin());
158850f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
158958600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1590537ec908SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult, A, X, Y, NULL));
159158600ac3SJames Wright 
159258600ac3SJames Wright     // Restore PETSc vectors
1593a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1594a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
159558600ac3SJames Wright 
159658600ac3SJames Wright     // Local-to-global
159758600ac3SJames Wright     PetscCall(VecZeroEntries(Y));
159858600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
159958600ac3SJames Wright 
160058600ac3SJames Wright     // Restore local vectors, as needed
160158600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
160258600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
160358600ac3SJames Wright   }
160458600ac3SJames Wright 
160558600ac3SJames Wright   // Log flops
160658600ac3SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
160758600ac3SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult));
1608c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, NULL));
160958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
161058600ac3SJames Wright }
161158600ac3SJames Wright 
161258600ac3SJames Wright /**
161358600ac3SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
161458600ac3SJames Wright 
161558600ac3SJames Wright   Collective across MPI processes.
161658600ac3SJames Wright 
161758600ac3SJames Wright   @param[in]   A  `MATCEED`
161858600ac3SJames Wright   @param[in]   Y  Input PETSc vector
161958600ac3SJames Wright   @param[out]  X  Output PETSc vector
162058600ac3SJames Wright 
162158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
162258600ac3SJames Wright **/
162358600ac3SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
162458600ac3SJames Wright   MatCeedContext ctx;
162558600ac3SJames Wright 
162658600ac3SJames Wright   PetscFunctionBeginUser;
162758600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1628c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, NULL));
162958600ac3SJames Wright 
163058600ac3SJames Wright   {
163158600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
163258600ac3SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
163358600ac3SJames Wright 
163458600ac3SJames Wright     // Get local vectors
163558600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
163658600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
163758600ac3SJames Wright 
163858600ac3SJames Wright     // Global-to-local
163958600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
164058600ac3SJames Wright 
164158600ac3SJames Wright     // Setup libCEED vectors
1642a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
164358600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
1644a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
164558600ac3SJames Wright 
164658600ac3SJames Wright     // Apply libCEED operator
1647c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
1648537ec908SJames Wright     PetscCall(PetscLogGpuTimeBegin());
164950f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
165058600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1651537ec908SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
165258600ac3SJames Wright 
165358600ac3SJames Wright     // Restore PETSc vectors
1654a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1655a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
165658600ac3SJames Wright 
165758600ac3SJames Wright     // Local-to-global
165858600ac3SJames Wright     PetscCall(VecZeroEntries(X));
165958600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
166058600ac3SJames Wright 
166158600ac3SJames Wright     // Restore local vectors, as needed
166258600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
166358600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
166458600ac3SJames Wright   }
166558600ac3SJames Wright 
166658600ac3SJames Wright   // Log flops
166758600ac3SJames Wright   if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
166858600ac3SJames Wright   else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
1669c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, NULL));
167058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
167158600ac3SJames Wright }
1672