xref: /honee/src/mat-ceed.c (revision 4cb1f0ec1e14de19a3838afb52ff4117b811185e)
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 
19b846ad1aSJames Wright #if PETSC_VERSION_LT(3, 24, 0)
20b846ad1aSJames Wright typedef void (*MatSetOpFn)(void);
21b846ad1aSJames Wright #else
22b846ad1aSJames Wright typedef PetscErrorCodeFn *MatSetOpFn;
23b846ad1aSJames Wright #endif
24b846ad1aSJames Wright 
2558600ac3SJames Wright PetscClassId  MATCEED_CLASSID;
26c63b910fSJames Wright PetscLogEvent MATCEED_MULT, MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE, MATCEED_MULT_TRANSPOSE_CEEDOP, MATCEED_ASSEMBLE_DIAGONAL,
27c63b910fSJames Wright     MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, MATCEED_SETUP_PBDIAGONAL, MATCEED_SETUP_PBDIAGONAL_CEEDOP, MATCEED_ASSEMBLE_PBDIAGONAL,
28c63b910fSJames Wright     MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, MATCEED_SETUP_FULL, MATCEED_SETUP_FULL_CEEDOP, MATCEED_ASSEMBLE_FULL, MATCEED_ASSEMBLE_FULL_CEEDOP;
2958600ac3SJames Wright 
3058600ac3SJames Wright /**
3158600ac3SJames Wright   @brief Register MATCEED log events.
3258600ac3SJames Wright 
3358600ac3SJames Wright   Not collective across MPI processes.
3458600ac3SJames Wright 
3558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
3658600ac3SJames Wright **/
MatCeedRegisterLogEvents()3758600ac3SJames Wright static PetscErrorCode MatCeedRegisterLogEvents() {
3840d80af1SJames Wright   static PetscBool registered = PETSC_FALSE;
3958600ac3SJames Wright 
4058600ac3SJames Wright   PetscFunctionBeginUser;
4158600ac3SJames Wright   if (registered) PetscFunctionReturn(PETSC_SUCCESS);
42c63b910fSJames Wright   PetscCall(PetscClassIdRegister("MatCEED", &MATCEED_CLASSID));
43c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMul", MATCEED_CLASSID, &MATCEED_MULT));
44c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulCeed", MATCEED_CLASSID, &MATCEED_MULT_CEEDOP));
45c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulT", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE));
46c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDMulTCeed", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE_CEEDOP));
47c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmDiag", MATCEED_CLASSID, &MATCEED_ASSEMBLE_DIAGONAL));
48c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSU", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL));
49c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL_CEEDOP));
50c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBD", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL));
51c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmPBDCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP));
52c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSU", MATCEED_CLASSID, &MATCEED_SETUP_FULL));
53c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_FULL_CEEDOP));
54c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsm", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL));
55c63b910fSJames Wright   PetscCall(PetscLogEventRegister("MatCEEDAsmCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL_CEEDOP));
5640d80af1SJames Wright   registered = PETSC_TRUE;
5758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
5858600ac3SJames Wright }
5958600ac3SJames Wright 
6058600ac3SJames Wright /**
6158600ac3SJames Wright   @brief Assemble the point block diagonal of a `MATCEED` into a `MATAIJ` or similar.
6258600ac3SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
6358600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
6458600ac3SJames Wright 
6558600ac3SJames Wright   Collective across MPI processes.
6658600ac3SJames Wright 
6758600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
6858600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
6958600ac3SJames Wright 
7058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
7158600ac3SJames Wright **/
MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed,Mat mat_coo)7258600ac3SJames Wright static PetscErrorCode MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed, Mat mat_coo) {
7358600ac3SJames Wright   MatCeedContext ctx;
7458600ac3SJames Wright 
7558600ac3SJames Wright   PetscFunctionBeginUser;
7658600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
7758600ac3SJames Wright 
7858600ac3SJames Wright   // Check if COO pattern set
7958600ac3SJames Wright   {
8058600ac3SJames Wright     PetscInt index = -1;
8158600ac3SJames Wright 
8258600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
8358600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == mat_coo) index = i;
8458600ac3SJames Wright     }
8558600ac3SJames Wright     if (index == -1) {
8658600ac3SJames Wright       PetscInt     *rows_petsc = NULL, *cols_petsc = NULL;
8758600ac3SJames Wright       CeedInt      *rows_ceed, *cols_ceed;
8858600ac3SJames Wright       PetscCount    num_entries;
8958600ac3SJames Wright       PetscLogStage stage_amg_setup;
9058600ac3SJames Wright 
9158600ac3SJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
92c63b910fSJames Wright       PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
9358600ac3SJames Wright       if (stage_amg_setup == -1) {
94c63b910fSJames Wright         PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
9558600ac3SJames Wright       }
9658600ac3SJames Wright       PetscCall(PetscLogStagePush(stage_amg_setup));
97c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
98c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
9950f50432SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
100c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
101a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
102a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
10358600ac3SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
10458600ac3SJames Wright       free(rows_petsc);
10558600ac3SJames Wright       free(cols_petsc);
10650f50432SJames Wright       if (!ctx->coo_values_pbd) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_pbd));
10758600ac3SJames Wright       PetscCall(PetscRealloc(++ctx->num_mats_assembled_pbd * sizeof(Mat), &ctx->mats_assembled_pbd));
10858600ac3SJames Wright       ctx->mats_assembled_pbd[ctx->num_mats_assembled_pbd - 1] = mat_coo;
109c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
11058600ac3SJames Wright       PetscCall(PetscLogStagePop());
11158600ac3SJames Wright     }
11258600ac3SJames Wright   }
11358600ac3SJames Wright 
11458600ac3SJames Wright   // Assemble mat_ceed
115c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
11658600ac3SJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
11758600ac3SJames Wright   {
11858600ac3SJames Wright     const CeedScalar *values;
119ed5c6999SJames Wright     PetscMemType      mem_type_petsc;
12058600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
12158600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
12258600ac3SJames Wright 
1232da92326SJames Wright     PetscCall(MatGetMemTypeFromVecType(mat_coo, &mem_type_petsc));
124ed5c6999SJames Wright     mem_type = MemTypePetscToCeed(mem_type_petsc);
125c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12650f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonal(ctx->op_mult, ctx->coo_values_pbd, CEED_REQUEST_IMMEDIATE));
127c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
12850f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_pbd, mem_type, &values));
12958600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
13058600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
13158600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
13250f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_pbd, &values));
13358600ac3SJames Wright   }
13458600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
135c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL));
13658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
13758600ac3SJames Wright }
13858600ac3SJames Wright 
13958600ac3SJames Wright /**
14058600ac3SJames Wright   @brief Assemble inner `Mat` for diagonal `PC` operations
14158600ac3SJames Wright 
14258600ac3SJames Wright   Collective across MPI processes.
14358600ac3SJames Wright 
144*e338a12eSJames Wright   @param[in]   mat_ceed      `MATCEED` to assemble block diagonal of
14558600ac3SJames Wright   @param[in]   use_ceed_pbd  Boolean flag to use libCEED PBD assembly
14658600ac3SJames Wright   @param[out]  mat_inner     Inner `Mat` for diagonal operations
14758600ac3SJames Wright 
14858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
14958600ac3SJames Wright **/
MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed,PetscBool use_ceed_pbd,Mat * mat_inner)15058600ac3SJames Wright static PetscErrorCode MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed, PetscBool use_ceed_pbd, Mat *mat_inner) {
15158600ac3SJames Wright   MatCeedContext ctx;
15258600ac3SJames Wright 
15358600ac3SJames Wright   PetscFunctionBeginUser;
15458600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
15558600ac3SJames Wright   if (use_ceed_pbd) {
15658600ac3SJames Wright     // Check if COO pattern set
15740d80af1SJames Wright     if (!ctx->mat_assembled_pbd_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_pbd_internal));
15858600ac3SJames Wright 
15958600ac3SJames Wright     // Assemble mat_assembled_full_internal
16058600ac3SJames Wright     PetscCall(MatCeedAssemblePointBlockDiagonalCOO(mat_ceed, ctx->mat_assembled_pbd_internal));
16158600ac3SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_pbd_internal;
16258600ac3SJames Wright   } else {
16358600ac3SJames Wright     // Check if COO pattern set
16440d80af1SJames Wright     if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
16558600ac3SJames Wright 
16658600ac3SJames Wright     // Assemble mat_assembled_full_internal
16758600ac3SJames Wright     PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
16858600ac3SJames Wright     if (mat_inner) *mat_inner = ctx->mat_assembled_full_internal;
16958600ac3SJames Wright   }
17058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
17158600ac3SJames Wright }
17258600ac3SJames Wright 
17358600ac3SJames Wright /**
174e8ff1987SJames Wright   @brief Get `MATCEED` variable block diagonal for Jacobi.
175e8ff1987SJames Wright 
176e8ff1987SJames Wright   Collective across MPI processes.
177e8ff1987SJames Wright 
178*e338a12eSJames Wright   @param[in]   mat_ceed   `MATCEED` to get variable block diagonal of
179e8ff1987SJames Wright   @param[out]  mat_vblock  The variable diagonal block matrix
180e8ff1987SJames Wright 
181e8ff1987SJames Wright   @return An error code: 0 - success, otherwise - failure
182e8ff1987SJames Wright **/
MatGetVariableBlockDiagonal_Ceed(Mat mat_ceed,Mat * mat_vblock)183e8ff1987SJames Wright static PetscErrorCode MatGetVariableBlockDiagonal_Ceed(Mat mat_ceed, Mat *mat_vblock) {
184e8ff1987SJames Wright   MatCeedContext ctx;
185e8ff1987SJames Wright 
186e8ff1987SJames Wright   PetscFunctionBeginUser;
187e8ff1987SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
188e8ff1987SJames Wright 
189e8ff1987SJames Wright   // Assemble inner mat if needed
190e8ff1987SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, mat_vblock));
191e8ff1987SJames Wright   PetscCall(PetscObjectReference((PetscObject)*mat_vblock));
192e8ff1987SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
193e8ff1987SJames Wright }
194e8ff1987SJames Wright 
195e8ff1987SJames Wright /**
196e8ff1987SJames Wright   @brief Get `MATCEED` block diagonal for Jacobi.
197e8ff1987SJames Wright 
198e8ff1987SJames Wright   Collective across MPI processes.
199e8ff1987SJames Wright 
200*e338a12eSJames Wright   @param[in]   mat_ceed   `MATCEED` to to get block diagonal of
201*e338a12eSJames Wright   @param[out]  mat_block  The diagonal block matrix
202e8ff1987SJames Wright 
203e8ff1987SJames Wright   @return An error code: 0 - success, otherwise - failure
204e8ff1987SJames Wright **/
MatGetBlockDiagonal_Ceed(Mat mat_ceed,Mat * mat_block)205e8ff1987SJames Wright static PetscErrorCode MatGetBlockDiagonal_Ceed(Mat mat_ceed, Mat *mat_block) {
206e8ff1987SJames Wright   MatCeedContext ctx;
207e8ff1987SJames Wright 
208e8ff1987SJames Wright   PetscFunctionBeginUser;
209e8ff1987SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
210e8ff1987SJames Wright 
211e8ff1987SJames Wright   // Assemble inner mat if needed
212e8ff1987SJames Wright   PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, mat_block));
213e8ff1987SJames Wright   PetscCall(PetscObjectReference((PetscObject)*mat_block));
214e8ff1987SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
215e8ff1987SJames Wright }
216e8ff1987SJames Wright 
217e8ff1987SJames Wright /**
218*e338a12eSJames Wright   @brief Get on-process diagonal block of `MATCEED`.
219c1bdbf00SJames Wright 
220c1bdbf00SJames Wright   This is a block per-process of the diagonal of the global matrix.
221c1bdbf00SJames Wright   This is NOT the diagonal blocks associated with the block size of the matrix (i.e. `MatSetBlockSize()` has no effect on this function).
22258600ac3SJames Wright 
22358600ac3SJames Wright   Collective across MPI processes.
22458600ac3SJames Wright 
225*e338a12eSJames Wright   @param[in]   mat_ceed   `MATCEED` to get the block per-proces of
22658600ac3SJames Wright   @param[out]  mat_block  The diagonal block matrix
22758600ac3SJames Wright 
22858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
22958600ac3SJames Wright **/
MatGetDiagonalBlock_Ceed(Mat mat_ceed,Mat * mat_block)23058600ac3SJames Wright static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) {
23158600ac3SJames Wright   MatCeedContext ctx;
23258600ac3SJames Wright 
23358600ac3SJames Wright   PetscFunctionBeginUser;
23458600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
23558600ac3SJames Wright 
236c1bdbf00SJames Wright   // Check if COO pattern set
237c1bdbf00SJames Wright   if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal));
23858600ac3SJames Wright 
239c1bdbf00SJames Wright   // Assemble mat_assembled_full_internal
240c1bdbf00SJames Wright   PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal));
241c1bdbf00SJames Wright 
242c1bdbf00SJames Wright   // Get diagonal block
243c1bdbf00SJames Wright   PetscCall(MatGetDiagonalBlock(ctx->mat_assembled_full_internal, mat_block));
24458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
24558600ac3SJames Wright }
24658600ac3SJames Wright 
24758600ac3SJames Wright /**
248e90c2ceeSJames Wright   @brief View `MATCEED`.
249e90c2ceeSJames Wright 
250e90c2ceeSJames Wright   Collective across MPI processes.
251e90c2ceeSJames Wright 
252e90c2ceeSJames Wright   @param[in]   mat_ceed  `MATCEED` to view
253e90c2ceeSJames Wright   @param[in]   viewer    The visualization context
254e90c2ceeSJames Wright 
255e90c2ceeSJames Wright   @return An error code: 0 - success, otherwise - failure
256e90c2ceeSJames Wright **/
MatView_Ceed(Mat mat_ceed,PetscViewer viewer)257e90c2ceeSJames Wright static PetscErrorCode MatView_Ceed(Mat mat_ceed, PetscViewer viewer) {
258e90c2ceeSJames Wright   PetscBool         is_ascii;
259e90c2ceeSJames Wright   PetscViewerFormat format;
260000d2032SJeremy L Thompson   PetscMPIInt       size, rank;
261e90c2ceeSJames Wright   MatCeedContext    ctx;
262e90c2ceeSJames Wright 
263e90c2ceeSJames Wright   PetscFunctionBeginUser;
264e90c2ceeSJames Wright   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
265e90c2ceeSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
266e90c2ceeSJames Wright   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat_ceed), &viewer));
267e90c2ceeSJames Wright 
268e90c2ceeSJames Wright   PetscCall(PetscViewerGetFormat(viewer, &format));
269e90c2ceeSJames Wright   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat_ceed), &size));
270e90c2ceeSJames Wright   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
271e90c2ceeSJames Wright 
272000d2032SJeremy L Thompson   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat_ceed), &rank));
273000d2032SJeremy L Thompson   if (rank != 0) PetscFunctionReturn(PETSC_SUCCESS);
274000d2032SJeremy L Thompson 
275e90c2ceeSJames Wright   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii));
276e90c2ceeSJames Wright   {
277000d2032SJeremy L Thompson     PetscBool is_detailed     = format == PETSC_VIEWER_ASCII_INFO_DETAIL;
278000d2032SJeremy L Thompson     char      rank_string[16] = {'\0'};
279b846ad1aSJames Wright     PetscInt  num_tabs        = 0;
280*e338a12eSJames Wright     CeedInt   prev_num_tabs;
281e90c2ceeSJames Wright     FILE     *file;
282e90c2ceeSJames Wright 
283dfdd2b92SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n"));
284537ec908SJames Wright     PetscCall(PetscViewerASCIIPushTab(viewer));  // MatCEED
285dfdd2b92SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "Default COO MatType: %s\n", ctx->coo_mat_type));
286000d2032SJeremy L Thompson     PetscCall(PetscSNPrintf(rank_string, 16, "on Rank %d", rank));
287000d2032SJeremy L Thompson     PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary"));
288e8ff1987SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "libCEED PB Diagonal Assembly: %s\n", ctx->is_ceed_pbd_valid ? "True" : "False"));
289e8ff1987SJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "libCEED VPB Diagonal Assembly: %s\n", ctx->is_ceed_vpbd_valid ? "True" : "False"));
290b846ad1aSJames Wright     PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary"));
291537ec908SJames Wright     PetscCall(PetscViewerASCIIGetPointer(viewer, &file));
292537ec908SJames Wright     PetscCall(PetscViewerASCIIPushTab(viewer));  // CeedOperator
293b846ad1aSJames Wright     PetscCall(PetscViewerASCIIGetTab(viewer, &num_tabs));
294b846ad1aSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult, num_tabs));
295000d2032SJeremy L Thompson     if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file));
296000d2032SJeremy L Thompson     else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult, file));
297b846ad1aSJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult, 0));
298537ec908SJames Wright     PetscCall(PetscViewerASCIIPopTab(viewer));  // CeedOperator
299e90c2ceeSJames Wright     if (ctx->op_mult_transpose) {
300000d2032SJeremy L Thompson       PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator ApplyTranspose %s:\n", is_detailed ? rank_string : "Summary"));
301537ec908SJames Wright       PetscCall(PetscViewerASCIIPushTab(viewer));  // CeedOperator
302b846ad1aSJames Wright       PetscCall(PetscViewerASCIIGetTab(viewer, &num_tabs));
303*e338a12eSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetNumViewTabs(ctx->op_mult_transpose, &prev_num_tabs));
304b846ad1aSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult_transpose, num_tabs));
305000d2032SJeremy L Thompson       if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file));
306000d2032SJeremy L Thompson       else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult_transpose, file));
307*e338a12eSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorSetNumViewTabs(ctx->op_mult_transpose, prev_num_tabs));
308537ec908SJames Wright       PetscCall(PetscViewerASCIIPopTab(viewer));  // CeedOperator
309e90c2ceeSJames Wright     }
310537ec908SJames Wright     PetscCall(PetscViewerASCIIPopTab(viewer));  // MatCEED
311e90c2ceeSJames Wright   }
312e90c2ceeSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
313e90c2ceeSJames Wright }
314e90c2ceeSJames Wright 
315b846ad1aSJames Wright /**
316*e338a12eSJames Wright   @brief Set options for MatCeed from command-line interface
317b846ad1aSJames Wright 
318b846ad1aSJames Wright   @note This is a PETSc interface, thus the odd signature
319b846ad1aSJames Wright   @note The name of the second parameter must be `PetscOptionsObject` due to abuse of PETSc macros
320b846ad1aSJames Wright 
321b846ad1aSJames Wright   Collective across MPI processes.
322b846ad1aSJames Wright 
323b846ad1aSJames Wright   @param[in]  mat_ceed            `Mat` object to set up
324b846ad1aSJames Wright   @param[in]  PetscOptionsObject  `PetscOptionItems` object to read options from
325b846ad1aSJames Wright 
326b846ad1aSJames Wright   @return An error code: 0 - success, otherwise - failure
327b846ad1aSJames Wright **/
MatSetFromOptions_Ceed(Mat mat_ceed,PetscOptionItems PetscOptionsObject)328b846ad1aSJames Wright static PetscErrorCode MatSetFromOptions_Ceed(Mat mat_ceed, PetscOptionItems PetscOptionsObject) {
329b846ad1aSJames Wright   MatCeedContext ctx;
330b846ad1aSJames Wright   char           coo_mat_type_cl[PETSC_MAX_OPTION_NAME];
331b846ad1aSJames Wright   PetscBool      is_coo_mat_type_cl;
332b846ad1aSJames Wright 
333b846ad1aSJames Wright   PetscFunctionBegin;
334b846ad1aSJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
335b846ad1aSJames Wright 
336b846ad1aSJames Wright   PetscOptionsHeadBegin(PetscOptionsObject, "MATCEED options");
337b846ad1aSJames Wright   // Check for specific CL coo mat type for this Mat
338b846ad1aSJames Wright   PetscCall(PetscOptionsFList("-mat_ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl,
339b846ad1aSJames Wright                               sizeof(coo_mat_type_cl), &is_coo_mat_type_cl));
340b846ad1aSJames Wright   if (is_coo_mat_type_cl) {
341b846ad1aSJames Wright     PetscCall(PetscFree(ctx->coo_mat_type));
342b846ad1aSJames Wright     PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type));
343b846ad1aSJames Wright   }
344b846ad1aSJames Wright   // Check for COO mat reuse flag
345b846ad1aSJames Wright   PetscCall(PetscOptionsBool("-mat_ceed_coo_reuse_preallocation",
346b846ad1aSJames Wright                              "Flag to allow the MatCeed to reuse existing COO preallocations, even if not set by this MatCeed", NULL,
347b846ad1aSJames Wright                              ctx->coo_reuse_preallocation, &ctx->coo_reuse_preallocation, NULL));
348b846ad1aSJames Wright   PetscOptionsHeadEnd();
349b846ad1aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
350b846ad1aSJames Wright }
351b846ad1aSJames Wright 
35258600ac3SJames Wright // -----------------------------------------------------------------------------
35358600ac3SJames Wright // MatCeed
35458600ac3SJames Wright // -----------------------------------------------------------------------------
35558600ac3SJames Wright 
35658600ac3SJames Wright /**
35758600ac3SJames Wright   @brief Create PETSc `Mat` from libCEED operators.
35858600ac3SJames Wright 
35958600ac3SJames Wright   Collective across MPI processes.
36058600ac3SJames Wright 
36158600ac3SJames Wright   @param[in]   dm_x                      Input `DM`
36258600ac3SJames Wright   @param[in]   dm_y                      Output `DM`
36358600ac3SJames Wright   @param[in]   op_mult                   `CeedOperator` for forward evaluation
36458600ac3SJames Wright   @param[in]   op_mult_transpose         `CeedOperator` for transpose evaluation
36558600ac3SJames Wright   @param[out]  mat                        New MatCeed
36658600ac3SJames Wright 
36758600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
36858600ac3SJames Wright **/
MatCreateCeed(DM dm_x,DM dm_y,CeedOperator op_mult,CeedOperator op_mult_transpose,Mat * mat)369000d2032SJeremy L Thompson PetscErrorCode MatCreateCeed(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) {
37058600ac3SJames Wright   PetscInt       X_l_size, X_g_size, Y_l_size, Y_g_size;
37158600ac3SJames Wright   VecType        vec_type;
37258600ac3SJames Wright   MatCeedContext ctx;
37358600ac3SJames Wright 
37458600ac3SJames Wright   PetscFunctionBeginUser;
37558600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
37658600ac3SJames Wright 
37758600ac3SJames Wright   // Collect context data
37858600ac3SJames Wright   PetscCall(DMGetVecType(dm_x, &vec_type));
37958600ac3SJames Wright   {
38058600ac3SJames Wright     Vec X;
38158600ac3SJames Wright 
38258600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_x, &X));
38358600ac3SJames Wright     PetscCall(VecGetSize(X, &X_g_size));
38458600ac3SJames Wright     PetscCall(VecGetLocalSize(X, &X_l_size));
38558600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_x, &X));
38658600ac3SJames Wright   }
38758600ac3SJames Wright   if (dm_y) {
38858600ac3SJames Wright     Vec Y;
38958600ac3SJames Wright 
39058600ac3SJames Wright     PetscCall(DMGetGlobalVector(dm_y, &Y));
39158600ac3SJames Wright     PetscCall(VecGetSize(Y, &Y_g_size));
39258600ac3SJames Wright     PetscCall(VecGetLocalSize(Y, &Y_l_size));
39358600ac3SJames Wright     PetscCall(DMRestoreGlobalVector(dm_y, &Y));
39458600ac3SJames Wright   } else {
39558600ac3SJames Wright     dm_y     = dm_x;
39658600ac3SJames Wright     Y_g_size = X_g_size;
39758600ac3SJames Wright     Y_l_size = X_l_size;
39858600ac3SJames Wright   }
39940d80af1SJames Wright 
40058600ac3SJames Wright   // Create context
40158600ac3SJames Wright   {
40258600ac3SJames Wright     Vec X_loc, Y_loc_transpose = NULL;
40358600ac3SJames Wright 
40458600ac3SJames Wright     PetscCall(DMCreateLocalVector(dm_x, &X_loc));
40558600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
40658600ac3SJames Wright     if (op_mult_transpose) {
40758600ac3SJames Wright       PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose));
40858600ac3SJames Wright       PetscCall(VecZeroEntries(Y_loc_transpose));
40958600ac3SJames Wright     }
410c63b910fSJames Wright     PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE,
411c63b910fSJames Wright                                    MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE_CEEDOP, &ctx));
41258600ac3SJames Wright     PetscCall(VecDestroy(&X_loc));
41358600ac3SJames Wright     PetscCall(VecDestroy(&Y_loc_transpose));
41458600ac3SJames Wright   }
41558600ac3SJames Wright 
41658600ac3SJames Wright   // Create mat
41758600ac3SJames Wright   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat));
41858600ac3SJames Wright   PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED));
41958600ac3SJames Wright   // -- Set block and variable block sizes
42058600ac3SJames Wright   if (dm_x == dm_y) {
42158600ac3SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
42258600ac3SJames Wright     Mat     temp_mat;
42358600ac3SJames Wright 
42458600ac3SJames Wright     PetscCall(DMGetMatType(dm_x, &dm_mat_type));
42558600ac3SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
42658600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, MATAIJ));
42758600ac3SJames Wright     PetscCall(DMCreateMatrix(dm_x, &temp_mat));
42858600ac3SJames Wright     PetscCall(DMSetMatType(dm_x, dm_mat_type_copy));
42958600ac3SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
43058600ac3SJames Wright 
43158600ac3SJames Wright     {
43258600ac3SJames Wright       PetscInt        block_size, num_blocks, max_vblock_size = PETSC_INT_MAX;
43358600ac3SJames Wright       const PetscInt *vblock_sizes;
43458600ac3SJames Wright 
43558600ac3SJames Wright       // -- Get block sizes
43658600ac3SJames Wright       PetscCall(MatGetBlockSize(temp_mat, &block_size));
43758600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes));
43858600ac3SJames Wright       {
43958600ac3SJames Wright         PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX};
44058600ac3SJames Wright 
44158600ac3SJames Wright         for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]);
44258600ac3SJames Wright         PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max));
44358600ac3SJames Wright         max_vblock_size = global_min_max[1];
44458600ac3SJames Wright       }
44558600ac3SJames Wright 
44658600ac3SJames Wright       // -- Copy block sizes
44758600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size));
44858600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes));
44958600ac3SJames Wright 
45058600ac3SJames Wright       // -- Check libCEED compatibility
45158600ac3SJames Wright       {
45258600ac3SJames Wright         bool is_composite;
45358600ac3SJames Wright 
45458600ac3SJames Wright         ctx->is_ceed_pbd_valid  = PETSC_TRUE;
45558600ac3SJames Wright         ctx->is_ceed_vpbd_valid = PETSC_TRUE;
45650f50432SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite));
45758600ac3SJames Wright         if (is_composite) {
45858600ac3SJames Wright           CeedInt       num_sub_operators;
45958600ac3SJames Wright           CeedOperator *sub_operators;
46058600ac3SJames Wright 
461da7f3a07SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorCompositeGetNumSub(op_mult, &num_sub_operators));
462da7f3a07SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorCompositeGetSubList(op_mult, &sub_operators));
46358600ac3SJames Wright           for (CeedInt i = 0; i < num_sub_operators; i++) {
46458600ac3SJames Wright             CeedInt                  num_bases, num_comp;
46558600ac3SJames Wright             CeedBasis               *active_bases;
46658600ac3SJames Wright             CeedOperatorAssemblyData assembly_data;
46758600ac3SJames Wright 
46850f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data));
46950f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
47050f50432SJames Wright             PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
47158600ac3SJames Wright             if (num_bases > 1) {
47258600ac3SJames Wright               ctx->is_ceed_pbd_valid  = PETSC_FALSE;
47358600ac3SJames Wright               ctx->is_ceed_vpbd_valid = PETSC_FALSE;
47458600ac3SJames Wright             }
47558600ac3SJames Wright             if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
47658600ac3SJames Wright             if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
47758600ac3SJames Wright           }
47858600ac3SJames Wright         } else {
47958600ac3SJames Wright           // LCOV_EXCL_START
48058600ac3SJames Wright           CeedInt                  num_bases, num_comp;
48158600ac3SJames Wright           CeedBasis               *active_bases;
48258600ac3SJames Wright           CeedOperatorAssemblyData assembly_data;
48358600ac3SJames Wright 
48450f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data));
48550f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL));
48650f50432SJames Wright           PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp));
48758600ac3SJames Wright           if (num_bases > 1) {
48858600ac3SJames Wright             ctx->is_ceed_pbd_valid  = PETSC_FALSE;
48958600ac3SJames Wright             ctx->is_ceed_vpbd_valid = PETSC_FALSE;
49058600ac3SJames Wright           }
49158600ac3SJames Wright           if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE;
49258600ac3SJames Wright           if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE;
49358600ac3SJames Wright           // LCOV_EXCL_STOP
49458600ac3SJames Wright         }
49558600ac3SJames Wright         {
49658600ac3SJames Wright           PetscInt local_is_valid[2], global_is_valid[2];
49758600ac3SJames Wright 
49858600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid;
49958600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
50058600ac3SJames Wright           ctx->is_ceed_pbd_valid = global_is_valid[0];
50158600ac3SJames Wright           local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid;
50258600ac3SJames Wright           PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid));
50358600ac3SJames Wright           ctx->is_ceed_vpbd_valid = global_is_valid[0];
50458600ac3SJames Wright         }
50558600ac3SJames Wright       }
50658600ac3SJames Wright     }
50758600ac3SJames Wright     PetscCall(MatDestroy(&temp_mat));
50858600ac3SJames Wright   }
50958600ac3SJames Wright   // -- Set internal mat type
51058600ac3SJames Wright   {
51158600ac3SJames Wright     VecType vec_type;
51240d80af1SJames Wright     MatType coo_mat_type;
51358600ac3SJames Wright 
51458600ac3SJames Wright     PetscCall(VecGetType(ctx->X_loc, &vec_type));
515ed5c6999SJames Wright     PetscCall(DefaultMatTypeFromVecType(vec_type, &coo_mat_type));
51640d80af1SJames Wright     PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type));
51758600ac3SJames Wright   }
51858600ac3SJames Wright   // -- Set mat operations
51967aa9f91SJames Wright   PetscCall(MatShellSetContextDestroy(*mat, (PetscCtxDestroyFn *)MatCeedContextDestroy));
520b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (MatSetOpFn)MatView_Ceed));
521b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (MatSetOpFn)MatMult_Ceed));
522b846ad1aSJames Wright   if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (MatSetOpFn)MatMultTranspose_Ceed));
523b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (MatSetOpFn)MatGetDiagonal_Ceed));
524b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (MatSetOpFn)MatGetDiagonalBlock_Ceed));
525b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_BLOCK_DIAGONAL, (MatSetOpFn)MatGetBlockDiagonal_Ceed));
526b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_GET_VBLOCK_DIAGONAL, (MatSetOpFn)MatGetVariableBlockDiagonal_Ceed));
527b846ad1aSJames Wright   PetscCall(MatShellSetOperation(*mat, MATOP_SET_FROM_OPTIONS, (MatSetOpFn)MatSetFromOptions_Ceed));
52858600ac3SJames Wright   PetscCall(MatShellSetVecType(*mat, vec_type));
52958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
53058600ac3SJames Wright }
53158600ac3SJames Wright 
53258600ac3SJames Wright /**
53358600ac3SJames Wright   @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`.
53458600ac3SJames Wright 
53558600ac3SJames Wright   Collective across MPI processes.
53658600ac3SJames Wright 
53758600ac3SJames Wright   @param[in]   mat_ceed   `MATCEED` to copy from
53858600ac3SJames Wright   @param[out]  mat_other  `MatShell` or `MATCEED` to copy into
53958600ac3SJames Wright 
54058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
54158600ac3SJames Wright **/
MatCeedCopy(Mat mat_ceed,Mat mat_other)54258600ac3SJames Wright PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) {
54358600ac3SJames Wright   PetscFunctionBeginUser;
54458600ac3SJames Wright   PetscCall(MatCeedRegisterLogEvents());
54558600ac3SJames Wright 
54658600ac3SJames Wright   // Check type compatibility
54758600ac3SJames Wright   {
54840d80af1SJames Wright     PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE;
54958600ac3SJames Wright     MatType   mat_type_ceed, mat_type_other;
55058600ac3SJames Wright 
55158600ac3SJames Wright     PetscCall(MatGetType(mat_ceed, &mat_type_ceed));
55240d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed));
55340d80af1SJames Wright     PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED);
55440d80af1SJames Wright     PetscCall(MatGetType(mat_other, &mat_type_other));
55540d80af1SJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed));
556b846ad1aSJames Wright     PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matshell));
55740d80af1SJames Wright     PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL);
55858600ac3SJames Wright   }
55958600ac3SJames Wright 
56058600ac3SJames Wright   // Check dimension compatibility
56158600ac3SJames Wright   {
56258600ac3SJames 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;
56358600ac3SJames Wright 
56458600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size));
56558600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size));
56658600ac3SJames Wright     PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size));
56758600ac3SJames Wright     PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size));
56858600ac3SJames 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) &&
56958600ac3SJames Wright                    (X_l_ceed_size == X_l_other_size),
57058600ac3SJames Wright                PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
57158600ac3SJames Wright                "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT
57258600ac3SJames Wright                "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT
57358600ac3SJames Wright                ", %" PetscInt_FMT ")",
57458600ac3SJames 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);
57558600ac3SJames Wright   }
57658600ac3SJames Wright 
57758600ac3SJames Wright   // Convert
57858600ac3SJames Wright   {
57958600ac3SJames Wright     VecType        vec_type;
58058600ac3SJames Wright     MatCeedContext ctx;
58158600ac3SJames Wright 
58258600ac3SJames Wright     PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED));
58358600ac3SJames Wright     PetscCall(MatShellGetContext(mat_ceed, &ctx));
58458600ac3SJames Wright     PetscCall(MatCeedContextReference(ctx));
58558600ac3SJames Wright     PetscCall(MatShellSetContext(mat_other, ctx));
58667aa9f91SJames Wright     PetscCall(MatShellSetContextDestroy(mat_other, (PetscCtxDestroyFn *)MatCeedContextDestroy));
587b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (MatSetOpFn)MatView_Ceed));
588b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (MatSetOpFn)MatMult_Ceed));
589b846ad1aSJames Wright     if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (MatSetOpFn)MatMultTranspose_Ceed));
590b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (MatSetOpFn)MatGetDiagonal_Ceed));
591b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (MatSetOpFn)MatGetDiagonalBlock_Ceed));
592b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_BLOCK_DIAGONAL, (MatSetOpFn)MatGetBlockDiagonal_Ceed));
593b846ad1aSJames Wright     PetscCall(MatShellSetOperation(mat_other, MATOP_GET_VBLOCK_DIAGONAL, (MatSetOpFn)MatGetVariableBlockDiagonal_Ceed));
59458600ac3SJames Wright     {
59558600ac3SJames Wright       PetscInt block_size;
59658600ac3SJames Wright 
59758600ac3SJames Wright       PetscCall(MatGetBlockSize(mat_ceed, &block_size));
59858600ac3SJames Wright       if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size));
59958600ac3SJames Wright     }
60058600ac3SJames Wright     {
60158600ac3SJames Wright       PetscInt        num_blocks;
60258600ac3SJames Wright       const PetscInt *block_sizes;
60358600ac3SJames Wright 
60458600ac3SJames Wright       PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes));
60558600ac3SJames Wright       if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes));
60658600ac3SJames Wright     }
60758600ac3SJames Wright     PetscCall(DMGetVecType(ctx->dm_x, &vec_type));
60858600ac3SJames Wright     PetscCall(MatShellSetVecType(mat_other, vec_type));
60958600ac3SJames Wright   }
61058600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
61158600ac3SJames Wright }
61258600ac3SJames Wright 
61358600ac3SJames Wright /**
614ba95ebb4SJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly for a `MatCEED`.
615000d2032SJeremy L Thompson 
616000d2032SJeremy L Thompson   Collective across MPI processes.
617000d2032SJeremy L Thompson 
618000d2032SJeremy L Thompson   @param[in]   mat_ceed       `MATCEED`
619000d2032SJeremy L Thompson   @param[out]  update_needed  Boolean flag indicating `CeedQFunction` update needed
620000d2032SJeremy L Thompson 
621000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
622000d2032SJeremy L Thompson **/
MatCeedSetAssemblyDataUpdateNeeded(Mat mat_ceed,PetscBool update_needed)623000d2032SJeremy L Thompson PetscErrorCode MatCeedSetAssemblyDataUpdateNeeded(Mat mat_ceed, PetscBool update_needed) {
624000d2032SJeremy L Thompson   MatCeedContext ctx;
625000d2032SJeremy L Thompson 
626000d2032SJeremy L Thompson   PetscFunctionBeginUser;
627000d2032SJeremy L Thompson   PetscCall(MatShellGetContext(mat_ceed, &ctx));
628000d2032SJeremy L Thompson   PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult, update_needed));
629000d2032SJeremy L Thompson   if (ctx->op_mult_transpose) {
630000d2032SJeremy L Thompson     PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult_transpose, update_needed));
631000d2032SJeremy L Thompson   }
632397c0187SJeremy L Thompson   if (update_needed) {
633397c0187SJeremy L Thompson     PetscCall(MatAssemblyBegin(mat_ceed, MAT_FINAL_ASSEMBLY));
634397c0187SJeremy L Thompson     PetscCall(MatAssemblyEnd(mat_ceed, MAT_FINAL_ASSEMBLY));
635397c0187SJeremy L Thompson   }
636000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
637000d2032SJeremy L Thompson }
638000d2032SJeremy L Thompson 
639000d2032SJeremy L Thompson /**
64040d80af1SJames Wright   @brief Setup a `Mat` with the same COO pattern as a `MatCEED`.
64140d80af1SJames Wright 
64240d80af1SJames Wright   Collective across MPI processes.
64340d80af1SJames Wright 
64440d80af1SJames Wright   @param[in]   mat_ceed  `MATCEED`
64540d80af1SJames Wright   @param[out]  mat_coo   Sparse `Mat` with same COO pattern
64640d80af1SJames Wright 
64740d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
64840d80af1SJames Wright **/
MatCeedCreateMatCOO(Mat mat_ceed,Mat * mat_coo)64940d80af1SJames Wright PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) {
65040d80af1SJames Wright   MatCeedContext ctx;
65140d80af1SJames Wright 
65240d80af1SJames Wright   PetscFunctionBeginUser;
65340d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
65440d80af1SJames Wright 
65540d80af1SJames 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");
65640d80af1SJames Wright 
65740d80af1SJames Wright   // Create sparse matrix
65840d80af1SJames Wright   {
65940d80af1SJames Wright     MatType dm_mat_type, dm_mat_type_copy;
66040d80af1SJames Wright 
66140d80af1SJames Wright     PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type));
66240d80af1SJames Wright     PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy));
66340d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type));
66440d80af1SJames Wright     PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo));
66540d80af1SJames Wright     PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy));
66640d80af1SJames Wright     PetscCall(PetscFree(dm_mat_type_copy));
66740d80af1SJames Wright   }
66840d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
66940d80af1SJames Wright }
67040d80af1SJames Wright 
67140d80af1SJames Wright /**
67240d80af1SJames Wright   @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar.
67358600ac3SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
67458600ac3SJames Wright 
67558600ac3SJames Wright   Collective across MPI processes.
67658600ac3SJames Wright 
67758600ac3SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
67858600ac3SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
67958600ac3SJames Wright 
68058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
68158600ac3SJames Wright **/
MatCeedSetPreallocationCOO(Mat mat_ceed,Mat mat_coo)68240d80af1SJames Wright PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) {
68358600ac3SJames Wright   MatCeedContext ctx;
68458600ac3SJames Wright 
68558600ac3SJames Wright   PetscFunctionBeginUser;
68658600ac3SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
68758600ac3SJames Wright 
68858600ac3SJames Wright   {
68958600ac3SJames Wright     PetscCount    num_entries;
69058600ac3SJames Wright     PetscLogStage stage_amg_setup;
691b846ad1aSJames Wright     PetscObject   coo_struct;
69258600ac3SJames Wright 
693c63b910fSJames Wright     PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup));
69458600ac3SJames Wright     if (stage_amg_setup == -1) {
695c63b910fSJames Wright       PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup));
69658600ac3SJames Wright     }
69758600ac3SJames Wright     PetscCall(PetscLogStagePush(stage_amg_setup));
698c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
699b846ad1aSJames Wright     PetscCall(PetscObjectQuery((PetscObject)mat_coo, "__PETSc_MatCOOStruct_Host", (PetscObject *)&coo_struct));
700b846ad1aSJames Wright     // -- Check for existing assembly data
701b846ad1aSJames Wright     if (!ctx->coo_reuse_preallocation || !coo_struct) {
702b846ad1aSJames Wright       PetscInt *rows_petsc = NULL, *cols_petsc = NULL;
703b846ad1aSJames Wright       CeedInt  *rows_ceed, *cols_ceed;
704b846ad1aSJames Wright 
705b846ad1aSJames Wright       // -- Assemble sparsity pattern if mat hasn't been assembled before
706c63b910fSJames Wright       PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
70750f50432SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed));
708c63b910fSJames Wright       PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
709a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc));
710a7dac1d5SJames Wright       PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc));
71158600ac3SJames Wright       PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc));
71258600ac3SJames Wright       free(rows_petsc);
71358600ac3SJames Wright       free(cols_petsc);
714b846ad1aSJames Wright     } else {
715b846ad1aSJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleGetNumEntries(ctx->op_mult, &num_entries));
716b846ad1aSJames Wright     }
717b846ad1aSJames Wright 
71850f50432SJames Wright     if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full));
71958600ac3SJames Wright     PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full));
72058600ac3SJames Wright     ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo;
721c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL));
72258600ac3SJames Wright     PetscCall(PetscLogStagePop());
72358600ac3SJames Wright   }
72440d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
72540d80af1SJames Wright }
72640d80af1SJames Wright 
72740d80af1SJames Wright /**
72840d80af1SJames Wright   @brief Assemble a `MATCEED` into a `MATAIJ` or similar.
72940d80af1SJames Wright          The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`.
73040d80af1SJames Wright          The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail.
73140d80af1SJames Wright 
73240d80af1SJames Wright   Collective across MPI processes.
73340d80af1SJames Wright 
73440d80af1SJames Wright   @param[in]      mat_ceed  `MATCEED` to assemble
73540d80af1SJames Wright   @param[in,out]  mat_coo   `MATAIJ` or similar to assemble into
73640d80af1SJames Wright 
73740d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
73840d80af1SJames Wright **/
MatCeedAssembleCOO(Mat mat_ceed,Mat mat_coo)73940d80af1SJames Wright PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) {
74040d80af1SJames Wright   MatCeedContext ctx;
74140d80af1SJames Wright 
74240d80af1SJames Wright   PetscFunctionBeginUser;
74340d80af1SJames Wright   PetscCall(MatShellGetContext(mat_ceed, &ctx));
74440d80af1SJames Wright 
74540d80af1SJames Wright   // Set COO pattern if needed
74640d80af1SJames Wright   {
74740d80af1SJames Wright     CeedInt index = -1;
74840d80af1SJames Wright 
74940d80af1SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
75040d80af1SJames Wright       if (ctx->mats_assembled_full[i] == mat_coo) index = i;
75140d80af1SJames Wright     }
75240d80af1SJames Wright     if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo));
75358600ac3SJames Wright   }
75458600ac3SJames Wright 
75558600ac3SJames Wright   // Assemble mat_ceed
756c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
75758600ac3SJames Wright   {
75858600ac3SJames Wright     const CeedScalar *values;
75958600ac3SJames Wright     CeedMemType       mem_type = CEED_MEM_HOST;
76058600ac3SJames Wright     PetscBool         is_spd, is_spd_known;
761ed5c6999SJames Wright     PetscMemType      mem_type_petsc;
76258600ac3SJames Wright 
7632da92326SJames Wright     PetscCall(MatGetMemTypeFromVecType(mat_coo, &mem_type_petsc));
764ed5c6999SJames Wright     mem_type = MemTypePetscToCeed(mem_type_petsc);
765c63b910fSJames Wright     PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
76650f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full));
767c63b910fSJames Wright     PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL));
76850f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values));
76958600ac3SJames Wright     PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES));
77058600ac3SJames Wright     PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd));
77158600ac3SJames Wright     if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd));
77250f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values));
77358600ac3SJames Wright   }
774b846ad1aSJames Wright   PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY));
77558600ac3SJames Wright   PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY));
776c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL));
77758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
77858600ac3SJames Wright }
77958600ac3SJames Wright 
78058600ac3SJames Wright /**
78140d80af1SJames Wright   @brief Set the current value of a context field for a `MatCEED`.
78240d80af1SJames Wright 
78340d80af1SJames Wright   Not collective across MPI processes.
78440d80af1SJames Wright 
78540d80af1SJames Wright   @param[in,out]  mat    `MatCEED`
78640d80af1SJames Wright   @param[in]      name   Name of the context field
78740d80af1SJames Wright   @param[in]      value  New context field value
78840d80af1SJames Wright 
78940d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
79040d80af1SJames Wright **/
MatCeedSetContextDouble(Mat mat,const char * name,double value)79140d80af1SJames Wright PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) {
79240d80af1SJames Wright   PetscBool      was_updated = PETSC_FALSE;
79340d80af1SJames Wright   MatCeedContext ctx;
79440d80af1SJames Wright 
79540d80af1SJames Wright   PetscFunctionBeginUser;
79640d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
79740d80af1SJames Wright   {
79840d80af1SJames Wright     CeedContextFieldLabel label = NULL;
79940d80af1SJames Wright 
80040d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label));
80140d80af1SJames Wright     if (label) {
802000d2032SJeremy L Thompson       double set_value = 2 * value + 1.0;
803000d2032SJeremy L Thompson 
804000d2032SJeremy L Thompson       PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
805000d2032SJeremy L Thompson       if (set_value != value) {
80640d80af1SJames Wright         PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value));
80740d80af1SJames Wright         was_updated = PETSC_TRUE;
80840d80af1SJames Wright       }
809000d2032SJeremy L Thompson     }
81040d80af1SJames Wright     if (ctx->op_mult_transpose) {
81140d80af1SJames Wright       label = NULL;
81240d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label));
81340d80af1SJames Wright       if (label) {
814000d2032SJeremy L Thompson         double set_value = 2 * value + 1.0;
815000d2032SJeremy L Thompson 
816000d2032SJeremy L Thompson         PetscCall(MatCeedGetContextDouble(mat, name, &set_value));
817000d2032SJeremy L Thompson         if (set_value != value) {
81840d80af1SJames Wright           PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value));
81940d80af1SJames Wright           was_updated = PETSC_TRUE;
82040d80af1SJames Wright         }
82140d80af1SJames Wright       }
82240d80af1SJames Wright     }
823000d2032SJeremy L Thompson   }
82440d80af1SJames Wright   if (was_updated) {
82540d80af1SJames Wright     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
82640d80af1SJames Wright     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
82740d80af1SJames Wright   }
82840d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
82940d80af1SJames Wright }
83040d80af1SJames Wright 
83140d80af1SJames Wright /**
83240d80af1SJames Wright   @brief Get the current value of a context field for a `MatCEED`.
83340d80af1SJames Wright 
83440d80af1SJames Wright   Not collective across MPI processes.
83540d80af1SJames Wright 
83640d80af1SJames Wright   @param[in]   mat    `MatCEED`
83740d80af1SJames Wright   @param[in]   name   Name of the context field
83840d80af1SJames Wright   @param[out]  value  Current context field value
83940d80af1SJames Wright 
84040d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
84140d80af1SJames Wright **/
MatCeedGetContextDouble(Mat mat,const char * name,double * value)84240d80af1SJames Wright PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) {
84340d80af1SJames Wright   MatCeedContext ctx;
84440d80af1SJames Wright 
84540d80af1SJames Wright   PetscFunctionBeginUser;
84640d80af1SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
84740d80af1SJames Wright   {
84840d80af1SJames Wright     CeedContextFieldLabel label = NULL;
84940d80af1SJames Wright     CeedOperator          op    = ctx->op_mult;
85040d80af1SJames Wright 
85140d80af1SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
85240d80af1SJames Wright     if (!label && ctx->op_mult_transpose) {
85340d80af1SJames Wright       op = ctx->op_mult_transpose;
85440d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label));
85540d80af1SJames Wright     }
85640d80af1SJames Wright     if (label) {
85740d80af1SJames Wright       PetscSizeT    num_values;
85840d80af1SJames Wright       const double *values_ceed;
85940d80af1SJames Wright 
86040d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed));
86140d80af1SJames Wright       *value = values_ceed[0];
86240d80af1SJames Wright       PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed));
86340d80af1SJames Wright     }
86440d80af1SJames Wright   }
86540d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
86640d80af1SJames Wright }
86740d80af1SJames Wright 
86840d80af1SJames Wright /**
869000d2032SJeremy L Thompson   @brief Set the current `PetscReal` value of a context field for a `MatCEED`.
870000d2032SJeremy L Thompson 
871000d2032SJeremy L Thompson   Not collective across MPI processes.
872000d2032SJeremy L Thompson 
873000d2032SJeremy L Thompson   @param[in,out]  mat    `MatCEED`
874000d2032SJeremy L Thompson   @param[in]      name   Name of the context field
875000d2032SJeremy L Thompson   @param[in]      value  New context field value
876000d2032SJeremy L Thompson 
877000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
878000d2032SJeremy L Thompson **/
MatCeedSetContextReal(Mat mat,const char * name,PetscReal value)879000d2032SJeremy L Thompson PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) {
880000d2032SJeremy L Thompson   double value_double = value;
881000d2032SJeremy L Thompson 
882000d2032SJeremy L Thompson   PetscFunctionBeginUser;
883000d2032SJeremy L Thompson   PetscCall(MatCeedSetContextDouble(mat, name, value_double));
884000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
885000d2032SJeremy L Thompson }
886000d2032SJeremy L Thompson 
887000d2032SJeremy L Thompson /**
88851bb547fSJames Wright   @brief Get the current `PetscReal` value of a context field for a `MatCEED`.
88951bb547fSJames Wright 
89051bb547fSJames Wright   Not collective across MPI processes.
89151bb547fSJames Wright 
89251bb547fSJames Wright   @param[in]   mat    `MatCEED`
89351bb547fSJames Wright   @param[in]   name   Name of the context field
89451bb547fSJames Wright   @param[out]  value  Current context field value
89551bb547fSJames Wright 
89651bb547fSJames Wright   @return An error code: 0 - success, otherwise - failure
89751bb547fSJames Wright **/
MatCeedGetContextReal(Mat mat,const char * name,PetscReal * value)89851bb547fSJames Wright PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) {
89987d3884fSJeremy L Thompson   double value_double = 0.0;
90051bb547fSJames Wright 
90151bb547fSJames Wright   PetscFunctionBeginUser;
90251bb547fSJames Wright   PetscCall(MatCeedGetContextDouble(mat, name, &value_double));
90351bb547fSJames Wright   *value = value_double;
90451bb547fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
90551bb547fSJames Wright }
90651bb547fSJames Wright 
90751bb547fSJames Wright /**
908000d2032SJeremy L Thompson   @brief Set the current time for a `MatCEED`.
909000d2032SJeremy L Thompson 
910000d2032SJeremy L Thompson   Not collective across MPI processes.
911000d2032SJeremy L Thompson 
912000d2032SJeremy L Thompson   @param[in,out]  mat   `MatCEED`
913000d2032SJeremy L Thompson   @param[in]      time  Current time
914000d2032SJeremy L Thompson 
915000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
916000d2032SJeremy L Thompson **/
MatCeedSetTime(Mat mat,PetscReal time)917000d2032SJeremy L Thompson PetscErrorCode MatCeedSetTime(Mat mat, PetscReal time) {
918000d2032SJeremy L Thompson   PetscFunctionBeginUser;
919000d2032SJeremy L Thompson   {
920000d2032SJeremy L Thompson     double time_ceed = time;
921000d2032SJeremy L Thompson 
922000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "time", time_ceed));
923000d2032SJeremy L Thompson   }
924000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
925000d2032SJeremy L Thompson }
926000d2032SJeremy L Thompson 
927000d2032SJeremy L Thompson /**
928000d2032SJeremy L Thompson   @brief Get the current time for a `MatCEED`.
929000d2032SJeremy L Thompson 
930000d2032SJeremy L Thompson   Not collective across MPI processes.
931000d2032SJeremy L Thompson 
932000d2032SJeremy L Thompson   @param[in]   mat   `MatCEED`
933000d2032SJeremy L Thompson   @param[out]  time  Current time, or -1.0 if the boundary evaluator has no time field
934000d2032SJeremy L Thompson 
935000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
936000d2032SJeremy L Thompson **/
MatCeedGetTime(Mat mat,PetscReal * time)937000d2032SJeremy L Thompson PetscErrorCode MatCeedGetTime(Mat mat, PetscReal *time) {
938000d2032SJeremy L Thompson   PetscFunctionBeginUser;
939000d2032SJeremy L Thompson   *time = -1.0;
940000d2032SJeremy L Thompson   {
941000d2032SJeremy L Thompson     double time_ceed = -1.0;
942000d2032SJeremy L Thompson 
943000d2032SJeremy L Thompson     PetscCall(MatCeedGetContextDouble(mat, "time", &time_ceed));
944000d2032SJeremy L Thompson     *time = time_ceed;
945000d2032SJeremy L Thompson   }
946000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
947000d2032SJeremy L Thompson }
948000d2032SJeremy L Thompson 
949000d2032SJeremy L Thompson /**
950000d2032SJeremy L Thompson   @brief Set the current time step for a `MatCEED`.
951000d2032SJeremy L Thompson 
952000d2032SJeremy L Thompson   Not collective across MPI processes.
953000d2032SJeremy L Thompson 
954000d2032SJeremy L Thompson   @param[in,out]  mat  `MatCEED`
955000d2032SJeremy L Thompson   @param[in]      dt   Current time step
956000d2032SJeremy L Thompson 
957000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
958000d2032SJeremy L Thompson **/
MatCeedSetDt(Mat mat,PetscReal dt)959000d2032SJeremy L Thompson PetscErrorCode MatCeedSetDt(Mat mat, PetscReal dt) {
960000d2032SJeremy L Thompson   PetscFunctionBeginUser;
961000d2032SJeremy L Thompson   {
962000d2032SJeremy L Thompson     double dt_ceed = dt;
963000d2032SJeremy L Thompson 
964000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "dt", dt_ceed));
965000d2032SJeremy L Thompson   }
966000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
967000d2032SJeremy L Thompson }
968000d2032SJeremy L Thompson 
969000d2032SJeremy L Thompson /**
970000d2032SJeremy L Thompson   @brief Set the Jacobian shifts for a `MatCEED`.
971000d2032SJeremy L Thompson 
972000d2032SJeremy L Thompson   Not collective across MPI processes.
973000d2032SJeremy L Thompson 
974000d2032SJeremy L Thompson   @param[in,out]  mat      `MatCEED`
975000d2032SJeremy L Thompson   @param[in]      shift_v  Velocity shift
976000d2032SJeremy L Thompson   @param[in]      shift_a  Acceleration shift
977000d2032SJeremy L Thompson 
978000d2032SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
979000d2032SJeremy L Thompson **/
MatCeedSetShifts(Mat mat,PetscReal shift_v,PetscReal shift_a)980000d2032SJeremy L Thompson PetscErrorCode MatCeedSetShifts(Mat mat, PetscReal shift_v, PetscReal shift_a) {
981000d2032SJeremy L Thompson   PetscFunctionBeginUser;
982000d2032SJeremy L Thompson   {
983000d2032SJeremy L Thompson     double shift_v_ceed = shift_v;
984000d2032SJeremy L Thompson 
985000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift v", shift_v_ceed));
986000d2032SJeremy L Thompson   }
987000d2032SJeremy L Thompson   if (shift_a) {
988000d2032SJeremy L Thompson     double shift_a_ceed = shift_a;
989000d2032SJeremy L Thompson 
990000d2032SJeremy L Thompson     PetscCall(MatCeedSetContextDouble(mat, "shift a", shift_a_ceed));
991000d2032SJeremy L Thompson   }
992000d2032SJeremy L Thompson   PetscFunctionReturn(PETSC_SUCCESS);
993000d2032SJeremy L Thompson }
994000d2032SJeremy L Thompson 
995000d2032SJeremy L Thompson /**
99658600ac3SJames Wright   @brief Set user context for a `MATCEED`.
99758600ac3SJames Wright 
99858600ac3SJames Wright   Collective across MPI processes.
99958600ac3SJames Wright 
100058600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
100158600ac3SJames Wright   @param[in]      f    The context destroy function, or NULL
100258600ac3SJames Wright   @param[in]      ctx  User context, or NULL to unset
100358600ac3SJames Wright 
100458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
100558600ac3SJames Wright **/
MatCeedSetContext(Mat mat,PetscCtxDestroyFn f,void * ctx)100667aa9f91SJames Wright PetscErrorCode MatCeedSetContext(Mat mat, PetscCtxDestroyFn f, void *ctx) {
100758600ac3SJames Wright   PetscContainer user_ctx = NULL;
100858600ac3SJames Wright 
100958600ac3SJames Wright   PetscFunctionBeginUser;
101058600ac3SJames Wright   if (ctx) {
101158600ac3SJames Wright     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx));
101258600ac3SJames Wright     PetscCall(PetscContainerSetPointer(user_ctx, ctx));
101367aa9f91SJames Wright     PetscCall(PetscContainerSetCtxDestroy(user_ctx, f));
101458600ac3SJames Wright   }
101558600ac3SJames Wright   PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx));
101658600ac3SJames Wright   PetscCall(PetscContainerDestroy(&user_ctx));
101758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
101858600ac3SJames Wright }
101958600ac3SJames Wright 
102058600ac3SJames Wright /**
102158600ac3SJames Wright   @brief Retrieve the user context for a `MATCEED`.
102258600ac3SJames Wright 
102358600ac3SJames Wright   Collective across MPI processes.
102458600ac3SJames Wright 
102558600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
102658600ac3SJames Wright   @param[in]      ctx  User context
102758600ac3SJames Wright 
102858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
102958600ac3SJames Wright **/
MatCeedGetContext(Mat mat,void * ctx)103058600ac3SJames Wright PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) {
103158600ac3SJames Wright   PetscContainer user_ctx;
103258600ac3SJames Wright 
103358600ac3SJames Wright   PetscFunctionBeginUser;
103458600ac3SJames Wright   PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx));
103558600ac3SJames Wright   if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx));
103658600ac3SJames Wright   else *(void **)ctx = NULL;
103758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
103858600ac3SJames Wright }
103958600ac3SJames Wright /**
104040d80af1SJames Wright   @brief Set a user defined matrix operation for a `MATCEED` matrix.
104140d80af1SJames Wright 
104240d80af1SJames Wright   Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by
104340d80af1SJames Wright `MatCeedSetContext()`.
104458600ac3SJames Wright 
104558600ac3SJames Wright   Collective across MPI processes.
104658600ac3SJames Wright 
104758600ac3SJames Wright   @param[in,out]  mat  `MATCEED`
104840d80af1SJames Wright   @param[in]      op   Name of the `MatOperation`
104940d80af1SJames Wright   @param[in]      g    Function that provides the operation
105058600ac3SJames Wright 
105158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
105258600ac3SJames Wright **/
MatCeedSetOperation(Mat mat,MatOperation op,void (* g)(void))1053b846ad1aSJames Wright PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) {
105440d80af1SJames Wright   PetscFunctionBeginUser;
1055b846ad1aSJames Wright   PetscCall(MatShellSetOperation(mat, op, (MatSetOpFn)g));
1056b846ad1aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1057b846ad1aSJames Wright }
1058b846ad1aSJames Wright 
1059b846ad1aSJames Wright /**
1060b846ad1aSJames Wright   @brief Set the flag for whether the `MATCEED` should reuse a COO matrix, even if not created by this `MATCEED`.
1061b846ad1aSJames Wright 
1062b846ad1aSJames Wright   @note Only set this flag if you are certain that the COO layout is properly set on incoming matrices.
1063b846ad1aSJames Wright 
1064b846ad1aSJames Wright   Collective across MPI processes.
1065b846ad1aSJames Wright 
1066b846ad1aSJames Wright   @param[in,out]  mat                      `MATCEED`
1067b846ad1aSJames Wright   @param[in]      coo_reuse_preallocation  Flag value to set
1068b846ad1aSJames Wright 
1069b846ad1aSJames Wright   @return An error code: 0 - success, otherwise - failure
1070b846ad1aSJames Wright **/
MatCeedSetReusePreallocationCOO(Mat mat,PetscBool coo_reuse_preallocation)1071b846ad1aSJames Wright PetscErrorCode MatCeedSetReusePreallocationCOO(Mat mat, PetscBool coo_reuse_preallocation) {
1072b846ad1aSJames Wright   MatCeedContext ctx;
1073b846ad1aSJames Wright 
1074b846ad1aSJames Wright   PetscFunctionBeginUser;
1075b846ad1aSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1076b846ad1aSJames Wright   ctx->coo_reuse_preallocation = coo_reuse_preallocation;
1077b846ad1aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1078b846ad1aSJames Wright }
1079b846ad1aSJames Wright 
1080b846ad1aSJames Wright /**
1081b846ad1aSJames Wright   @brief Gets the flag for whether the `MATCEED` should reuse a COO matrix, even if not created by this `MATCEED`.
1082b846ad1aSJames Wright 
1083b846ad1aSJames Wright   Collective across MPI processes.
1084b846ad1aSJames Wright 
1085b846ad1aSJames Wright   @param[in]  mat                      `MATCEED`
1086b846ad1aSJames Wright   @param[in]  coo_reuse_preallocation  Address to store current flag value
1087b846ad1aSJames Wright 
1088b846ad1aSJames Wright   @return An error code: 0 - success, otherwise - failure
1089b846ad1aSJames Wright **/
MatCeedGetReusePreallocationCOO(Mat mat,PetscBool * coo_reuse_preallocation)1090b846ad1aSJames Wright PetscErrorCode MatCeedGetReusePreallocationCOO(Mat mat, PetscBool *coo_reuse_preallocation) {
1091b846ad1aSJames Wright   MatCeedContext ctx;
1092b846ad1aSJames Wright 
1093b846ad1aSJames Wright   PetscFunctionBeginUser;
1094b846ad1aSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1095b846ad1aSJames Wright   *coo_reuse_preallocation = ctx->coo_reuse_preallocation;
109640d80af1SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
109740d80af1SJames Wright }
109840d80af1SJames Wright 
109940d80af1SJames Wright /**
110040d80af1SJames Wright   @brief Sets the default COO matrix type as a string from the `MATCEED`.
110140d80af1SJames Wright 
110240d80af1SJames Wright   Collective across MPI processes.
110340d80af1SJames Wright 
110440d80af1SJames Wright   @param[in,out]  mat   `MATCEED`
110540d80af1SJames Wright   @param[in]      type  COO `MatType` to set
110640d80af1SJames Wright 
110740d80af1SJames Wright   @return An error code: 0 - success, otherwise - failure
110840d80af1SJames Wright **/
MatCeedSetCOOMatType(Mat mat,MatType type)110940d80af1SJames Wright PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) {
111058600ac3SJames Wright   MatCeedContext ctx;
111158600ac3SJames Wright 
111258600ac3SJames Wright   PetscFunctionBeginUser;
111358600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
111458600ac3SJames Wright   // Check if same
111558600ac3SJames Wright   {
111658600ac3SJames Wright     size_t    len_old, len_new;
111758600ac3SJames Wright     PetscBool is_same = PETSC_FALSE;
111858600ac3SJames Wright 
111940d80af1SJames Wright     PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old));
112058600ac3SJames Wright     PetscCall(PetscStrlen(type, &len_new));
112140d80af1SJames Wright     if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same));
112258600ac3SJames Wright     if (is_same) PetscFunctionReturn(PETSC_SUCCESS);
112358600ac3SJames Wright   }
112458600ac3SJames Wright   // Clean up old mats in different format
112558600ac3SJames Wright   // LCOV_EXCL_START
112658600ac3SJames Wright   if (ctx->mat_assembled_full_internal) {
112758600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) {
112858600ac3SJames Wright       if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) {
112958600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) {
113058600ac3SJames Wright           ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j];
113158600ac3SJames Wright         }
113258600ac3SJames Wright         ctx->num_mats_assembled_full--;
113358600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
113458600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_full_internal));
113558600ac3SJames Wright       }
113658600ac3SJames Wright     }
113758600ac3SJames Wright   }
113858600ac3SJames Wright   if (ctx->mat_assembled_pbd_internal) {
113958600ac3SJames Wright     for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) {
114058600ac3SJames Wright       if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) {
114158600ac3SJames Wright         for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) {
114258600ac3SJames Wright           ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j];
114358600ac3SJames Wright         }
114458600ac3SJames Wright         // Note: we'll realloc this array again, so no need to shrink the allocation
114558600ac3SJames Wright         ctx->num_mats_assembled_pbd--;
114658600ac3SJames Wright         PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal));
114758600ac3SJames Wright       }
114858600ac3SJames Wright     }
114958600ac3SJames Wright   }
115040d80af1SJames Wright   PetscCall(PetscFree(ctx->coo_mat_type));
115140d80af1SJames Wright   PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type));
115258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
115358600ac3SJames Wright   // LCOV_EXCL_STOP
115458600ac3SJames Wright }
115558600ac3SJames Wright 
115658600ac3SJames Wright /**
115740d80af1SJames Wright   @brief Gets the default COO matrix type as a string from the `MATCEED`.
115858600ac3SJames Wright 
115958600ac3SJames Wright   Collective across MPI processes.
116058600ac3SJames Wright 
116158600ac3SJames Wright   @param[in,out]  mat   `MATCEED`
116240d80af1SJames Wright   @param[in]      type  COO `MatType`
116358600ac3SJames Wright 
116458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
116558600ac3SJames Wright **/
MatCeedGetCOOMatType(Mat mat,MatType * type)116640d80af1SJames Wright PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) {
116758600ac3SJames Wright   MatCeedContext ctx;
116858600ac3SJames Wright 
116958600ac3SJames Wright   PetscFunctionBeginUser;
117058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
117140d80af1SJames Wright   *type = ctx->coo_mat_type;
117258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
117358600ac3SJames Wright }
117458600ac3SJames Wright 
117558600ac3SJames Wright /**
117658600ac3SJames Wright   @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
117758600ac3SJames Wright 
117858600ac3SJames Wright   Not collective across MPI processes.
117958600ac3SJames Wright 
118058600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
118158600ac3SJames Wright   @param[in]      X_loc            Input PETSc local vector, or NULL
118258600ac3SJames Wright   @param[in]      Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
118358600ac3SJames Wright 
118458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
118558600ac3SJames Wright **/
MatCeedSetLocalVectors(Mat mat,Vec X_loc,Vec Y_loc_transpose)118658600ac3SJames Wright PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) {
118758600ac3SJames Wright   MatCeedContext ctx;
118858600ac3SJames Wright 
118958600ac3SJames Wright   PetscFunctionBeginUser;
119058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
119158600ac3SJames Wright   if (X_loc) {
119258600ac3SJames Wright     PetscInt len_old, len_new;
119358600ac3SJames Wright 
119458600ac3SJames Wright     PetscCall(VecGetSize(ctx->X_loc, &len_old));
119558600ac3SJames Wright     PetscCall(VecGetSize(X_loc, &len_new));
119658600ac3SJames 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,
119758600ac3SJames Wright                len_new, len_old);
119840d80af1SJames Wright     PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc));
119958600ac3SJames Wright   }
120058600ac3SJames Wright   if (Y_loc_transpose) {
120158600ac3SJames Wright     PetscInt len_old, len_new;
120258600ac3SJames Wright 
120358600ac3SJames Wright     PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old));
120458600ac3SJames Wright     PetscCall(VecGetSize(Y_loc_transpose, &len_new));
120558600ac3SJames Wright     PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB,
120658600ac3SJames Wright                "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old);
120740d80af1SJames Wright     PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose));
120858600ac3SJames Wright   }
120958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
121058600ac3SJames Wright }
121158600ac3SJames Wright 
121258600ac3SJames Wright /**
121358600ac3SJames Wright   @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
121458600ac3SJames Wright 
121558600ac3SJames Wright   Not collective across MPI processes.
121658600ac3SJames Wright 
121758600ac3SJames Wright   @param[in,out]  mat              `MATCEED`
121858600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
121958600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
122058600ac3SJames Wright 
122158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
122258600ac3SJames Wright **/
MatCeedGetLocalVectors(Mat mat,Vec * X_loc,Vec * Y_loc_transpose)122358600ac3SJames Wright PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
122458600ac3SJames Wright   MatCeedContext ctx;
122558600ac3SJames Wright 
122658600ac3SJames Wright   PetscFunctionBeginUser;
122758600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
122858600ac3SJames Wright   if (X_loc) {
122940d80af1SJames Wright     *X_loc = NULL;
123040d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->X_loc, X_loc));
123158600ac3SJames Wright   }
123258600ac3SJames Wright   if (Y_loc_transpose) {
123340d80af1SJames Wright     *Y_loc_transpose = NULL;
123440d80af1SJames Wright     PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose));
123558600ac3SJames Wright   }
123658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
123758600ac3SJames Wright }
123858600ac3SJames Wright 
123958600ac3SJames Wright /**
124058600ac3SJames Wright   @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
124158600ac3SJames Wright 
124258600ac3SJames Wright   Not collective across MPI processes.
124358600ac3SJames Wright 
124458600ac3SJames Wright   @param[in,out]  mat              MatCeed
124558600ac3SJames Wright   @param[out]     X_loc            Input PETSc local vector, or NULL
124658600ac3SJames Wright   @param[out]     Y_loc_transpose  Input PETSc local vector for transpose operation, or NULL
124758600ac3SJames Wright 
124858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
124958600ac3SJames Wright **/
MatCeedRestoreLocalVectors(Mat mat,Vec * X_loc,Vec * Y_loc_transpose)125058600ac3SJames Wright PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) {
125158600ac3SJames Wright   PetscFunctionBeginUser;
125258600ac3SJames Wright   if (X_loc) PetscCall(VecDestroy(X_loc));
125358600ac3SJames Wright   if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose));
125458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
125558600ac3SJames Wright }
125658600ac3SJames Wright 
125758600ac3SJames Wright /**
125858600ac3SJames Wright   @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
125958600ac3SJames Wright 
126058600ac3SJames Wright   Not collective across MPI processes.
126158600ac3SJames Wright 
126258600ac3SJames Wright   @param[in,out]  mat                MatCeed
126358600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
126458600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
126558600ac3SJames Wright 
126658600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
126758600ac3SJames Wright **/
MatCeedGetCeedOperators(Mat mat,CeedOperator * op_mult,CeedOperator * op_mult_transpose)126858600ac3SJames Wright PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
126958600ac3SJames Wright   MatCeedContext ctx;
127058600ac3SJames Wright 
127158600ac3SJames Wright   PetscFunctionBeginUser;
127258600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
127358600ac3SJames Wright   if (op_mult) {
127458600ac3SJames Wright     *op_mult = NULL;
127550f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult));
127658600ac3SJames Wright   }
127758600ac3SJames Wright   if (op_mult_transpose) {
127858600ac3SJames Wright     *op_mult_transpose = NULL;
127950f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose));
128058600ac3SJames Wright   }
128158600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
128258600ac3SJames Wright }
128358600ac3SJames Wright 
128458600ac3SJames Wright /**
128558600ac3SJames Wright   @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations.
128658600ac3SJames Wright 
128758600ac3SJames Wright   Not collective across MPI processes.
128858600ac3SJames Wright 
128958600ac3SJames Wright   @param[in,out]  mat                MatCeed
129058600ac3SJames Wright   @param[out]     op_mult            libCEED `CeedOperator` for `MatMult()`, or NULL
129158600ac3SJames Wright   @param[out]     op_mult_transpose  libCEED `CeedOperator` for `MatMultTranspose()`, or NULL
129258600ac3SJames Wright 
129358600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
129458600ac3SJames Wright **/
MatCeedRestoreCeedOperators(Mat mat,CeedOperator * op_mult,CeedOperator * op_mult_transpose)129558600ac3SJames Wright PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) {
129658600ac3SJames Wright   MatCeedContext ctx;
129758600ac3SJames Wright 
129858600ac3SJames Wright   PetscFunctionBeginUser;
129958600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
130050f50432SJames Wright   if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult));
130150f50432SJames Wright   if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose));
130258600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
130358600ac3SJames Wright }
130458600ac3SJames Wright 
130558600ac3SJames Wright /**
130658600ac3SJames Wright   @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
130758600ac3SJames Wright 
130858600ac3SJames Wright   Not collective across MPI processes.
130958600ac3SJames Wright 
131058600ac3SJames Wright   @param[in,out]  mat                       MatCeed
131158600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
131258600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
131358600ac3SJames Wright 
131458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
131558600ac3SJames Wright **/
MatCeedSetLogEvents(Mat mat,PetscLogEvent log_event_mult,PetscLogEvent log_event_mult_transpose)131658600ac3SJames Wright PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
131758600ac3SJames Wright   MatCeedContext ctx;
131858600ac3SJames Wright 
131958600ac3SJames Wright   PetscFunctionBeginUser;
132058600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
132158600ac3SJames Wright   if (log_event_mult) ctx->log_event_mult = log_event_mult;
132258600ac3SJames Wright   if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose;
132358600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
132458600ac3SJames Wright }
132558600ac3SJames Wright 
132658600ac3SJames Wright /**
132758600ac3SJames Wright   @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
132858600ac3SJames Wright 
132958600ac3SJames Wright   Not collective across MPI processes.
133058600ac3SJames Wright 
133158600ac3SJames Wright   @param[in,out]  mat                       MatCeed
133258600ac3SJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward evaluation, or NULL
133358600ac3SJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose evaluation, or NULL
133458600ac3SJames Wright 
133558600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
133658600ac3SJames Wright **/
MatCeedGetLogEvents(Mat mat,PetscLogEvent * log_event_mult,PetscLogEvent * log_event_mult_transpose)133758600ac3SJames Wright PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
133858600ac3SJames Wright   MatCeedContext ctx;
133958600ac3SJames Wright 
134058600ac3SJames Wright   PetscFunctionBeginUser;
134158600ac3SJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
134258600ac3SJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_mult;
134358600ac3SJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose;
134458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
134558600ac3SJames Wright }
134658600ac3SJames Wright 
1347c63b910fSJames Wright /**
1348c63b910fSJames Wright   @brief Set `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1349c63b910fSJames Wright 
1350c63b910fSJames Wright   Not collective across MPI processes.
1351c63b910fSJames Wright 
1352c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1353c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1354c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1355c63b910fSJames Wright 
1356c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1357c63b910fSJames Wright **/
MatCeedSetCeedOperatorLogEvents(Mat mat,PetscLogEvent log_event_mult,PetscLogEvent log_event_mult_transpose)1358c63b910fSJames Wright PetscErrorCode MatCeedSetCeedOperatorLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) {
1359c63b910fSJames Wright   MatCeedContext ctx;
1360c63b910fSJames Wright 
1361c63b910fSJames Wright   PetscFunctionBeginUser;
1362c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1363c63b910fSJames Wright   if (log_event_mult) ctx->log_event_ceed_mult = log_event_mult;
1364c63b910fSJames Wright   if (log_event_mult_transpose) ctx->log_event_ceed_mult_transpose = log_event_mult_transpose;
1365c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1366c63b910fSJames Wright }
1367c63b910fSJames Wright 
1368c63b910fSJames Wright /**
1369c63b910fSJames Wright   @brief Get `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators.
1370c63b910fSJames Wright 
1371c63b910fSJames Wright   Not collective across MPI processes.
1372c63b910fSJames Wright 
1373c63b910fSJames Wright   @param[in,out]  mat                       MatCeed
1374c63b910fSJames Wright   @param[out]     log_event_mult            `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL
1375c63b910fSJames Wright   @param[out]     log_event_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL
1376c63b910fSJames Wright 
1377c63b910fSJames Wright   @return An error code: 0 - success, otherwise - failure
1378c63b910fSJames Wright **/
MatCeedGetCeedOperatorLogEvents(Mat mat,PetscLogEvent * log_event_mult,PetscLogEvent * log_event_mult_transpose)1379c63b910fSJames Wright PetscErrorCode MatCeedGetCeedOperatorLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) {
1380c63b910fSJames Wright   MatCeedContext ctx;
1381c63b910fSJames Wright 
1382c63b910fSJames Wright   PetscFunctionBeginUser;
1383c63b910fSJames Wright   PetscCall(MatShellGetContext(mat, &ctx));
1384c63b910fSJames Wright   if (log_event_mult) *log_event_mult = ctx->log_event_ceed_mult;
1385c63b910fSJames Wright   if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_ceed_mult_transpose;
1386c63b910fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1387c63b910fSJames Wright }
1388c63b910fSJames Wright 
138958600ac3SJames Wright // -----------------------------------------------------------------------------
139058600ac3SJames Wright // Operator context data
139158600ac3SJames Wright // -----------------------------------------------------------------------------
139258600ac3SJames Wright 
139358600ac3SJames Wright /**
139458600ac3SJames Wright   @brief Setup context data for operator application.
139558600ac3SJames Wright 
139658600ac3SJames Wright   Collective across MPI processes.
139758600ac3SJames Wright 
139858600ac3SJames Wright   @param[in]   dm_x                           Input `DM`
139958600ac3SJames Wright   @param[in]   dm_y                           Output `DM`
140058600ac3SJames Wright   @param[in]   X_loc                          Input PETSc local vector, or NULL
140158600ac3SJames Wright   @param[in]   Y_loc_transpose                Input PETSc local vector for transpose operation, or NULL
140258600ac3SJames Wright   @param[in]   op_mult                        `CeedOperator` for forward evaluation
140358600ac3SJames Wright   @param[in]   op_mult_transpose              `CeedOperator` for transpose evaluation
140458600ac3SJames Wright   @param[in]   log_event_mult                 `PetscLogEvent` for forward evaluation
140558600ac3SJames Wright   @param[in]   log_event_mult_transpose       `PetscLogEvent` for transpose evaluation
1406c63b910fSJames Wright   @param[in]   log_event_ceed_mult            `PetscLogEvent` for forward `CeedOperator` evaluation
1407c63b910fSJames Wright   @param[in]   log_event_ceed_mult_transpose  `PetscLogEvent` for transpose `CeedOperator` evaluation
140858600ac3SJames Wright   @param[out]  ctx                            Context data for operator evaluation
140958600ac3SJames Wright 
141058600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
141158600ac3SJames Wright **/
MatCeedContextCreate(DM dm_x,DM dm_y,Vec X_loc,Vec Y_loc_transpose,CeedOperator op_mult,CeedOperator op_mult_transpose,PetscLogEvent log_event_mult,PetscLogEvent log_event_mult_transpose,PetscLogEvent log_event_ceed_mult,PetscLogEvent log_event_ceed_mult_transpose,MatCeedContext * ctx)141258600ac3SJames Wright PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose,
1413c63b910fSJames Wright                                     PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, PetscLogEvent log_event_ceed_mult,
1414c63b910fSJames Wright                                     PetscLogEvent log_event_ceed_mult_transpose, MatCeedContext *ctx) {
141558600ac3SJames Wright   CeedSize x_loc_len, y_loc_len;
141658600ac3SJames Wright 
141758600ac3SJames Wright   PetscFunctionBeginUser;
141858600ac3SJames Wright   // Allocate
141958600ac3SJames Wright   PetscCall(PetscNew(ctx));
142058600ac3SJames Wright   (*ctx)->ref_count = 1;
142158600ac3SJames Wright 
142258600ac3SJames Wright   // Logging
142358600ac3SJames Wright   (*ctx)->log_event_mult                = log_event_mult;
142458600ac3SJames Wright   (*ctx)->log_event_mult_transpose      = log_event_mult_transpose;
1425c63b910fSJames Wright   (*ctx)->log_event_ceed_mult           = log_event_ceed_mult;
1426c63b910fSJames Wright   (*ctx)->log_event_ceed_mult_transpose = log_event_ceed_mult_transpose;
142758600ac3SJames Wright 
142858600ac3SJames Wright   // PETSc objects
142940d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x));
143040d80af1SJames Wright   PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y));
143140d80af1SJames Wright   if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc));
143240d80af1SJames Wright   if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose));
143358600ac3SJames Wright 
143458600ac3SJames Wright   // Memtype
143558600ac3SJames Wright   {
143658600ac3SJames Wright     const PetscScalar *x;
143758600ac3SJames Wright     Vec                X;
143858600ac3SJames Wright 
143958600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &X));
144058600ac3SJames Wright     PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type));
144158600ac3SJames Wright     PetscCall(VecRestoreArrayReadAndMemType(X, &x));
144258600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &X));
144358600ac3SJames Wright   }
144458600ac3SJames Wright 
144558600ac3SJames Wright   // libCEED objects
144658600ac3SJames Wright   PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB,
144758600ac3SJames Wright              "retrieving Ceed context object failed");
144850f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len));
144950f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult));
145050f50432SJames Wright   if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose));
1451b846ad1aSJames Wright   if (x_loc_len == -1) x_loc_len = 0;
145250f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc));
1453b846ad1aSJames Wright   if (y_loc_len == -1) y_loc_len = 0;
145450f50432SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc));
145558600ac3SJames Wright 
145658600ac3SJames Wright   // Flop counting
145758600ac3SJames Wright   {
145858600ac3SJames Wright     CeedSize ceed_flops_estimate = 0;
145958600ac3SJames Wright 
146050f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate));
146158600ac3SJames Wright     (*ctx)->flops_mult = ceed_flops_estimate;
146258600ac3SJames Wright     if (op_mult_transpose) {
146350f50432SJames Wright       PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate));
146458600ac3SJames Wright       (*ctx)->flops_mult_transpose = ceed_flops_estimate;
146558600ac3SJames Wright     }
146658600ac3SJames Wright   }
146758600ac3SJames Wright 
146858600ac3SJames Wright   // Check sizes
146958600ac3SJames Wright   if (x_loc_len > 0 || y_loc_len > 0) {
147058600ac3SJames Wright     CeedSize ctx_x_loc_len, ctx_y_loc_len;
147158600ac3SJames Wright     PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len;
147258600ac3SJames Wright     Vec      dm_X_loc, dm_Y_loc;
147358600ac3SJames Wright 
147458600ac3SJames Wright     // -- Input
147558600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_x, &dm_X_loc));
147658600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len));
147758600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc));
147850f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len));
14794c17272bSJames Wright     if (X_loc) {
14804c17272bSJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_loc_len));
14814c17272bSJames Wright       PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
14824c17272bSJames Wright                  "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len);
14834c17272bSJames Wright     }
14844c17272bSJames 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",
14854c17272bSJames Wright                x_loc_len, dm_x_loc_len);
14864c17272bSJames 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 ")",
14874c17272bSJames Wright                x_loc_len, ctx_x_loc_len);
148858600ac3SJames Wright 
148958600ac3SJames Wright     // -- Output
149058600ac3SJames Wright     PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc));
149158600ac3SJames Wright     PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len));
149258600ac3SJames Wright     PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc));
149350f50432SJames Wright     PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len));
14944c17272bSJames 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",
14954c17272bSJames Wright                ctx_y_loc_len, dm_y_loc_len);
149658600ac3SJames Wright 
149758600ac3SJames Wright     // -- Transpose
149858600ac3SJames Wright     if (Y_loc_transpose) {
149958600ac3SJames Wright       PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len));
15004c17272bSJames Wright       PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB,
15014c17272bSJames Wright                  "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len);
150258600ac3SJames Wright     }
150358600ac3SJames Wright   }
150458600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
150558600ac3SJames Wright }
150658600ac3SJames Wright 
150758600ac3SJames Wright /**
150858600ac3SJames Wright   @brief Increment reference counter for `MATCEED` context.
150958600ac3SJames Wright 
151058600ac3SJames Wright   Not collective across MPI processes.
151158600ac3SJames Wright 
151258600ac3SJames Wright   @param[in,out]  ctx  Context data
151358600ac3SJames Wright 
151458600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
151558600ac3SJames Wright **/
MatCeedContextReference(MatCeedContext ctx)151658600ac3SJames Wright PetscErrorCode MatCeedContextReference(MatCeedContext ctx) {
151758600ac3SJames Wright   PetscFunctionBeginUser;
151858600ac3SJames Wright   ctx->ref_count++;
151958600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
152058600ac3SJames Wright }
152158600ac3SJames Wright 
152258600ac3SJames Wright /**
152358600ac3SJames Wright   @brief Copy reference for `MATCEED`.
152458600ac3SJames Wright          Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`.
152558600ac3SJames Wright 
152658600ac3SJames Wright   Not collective across MPI processes.
152758600ac3SJames Wright 
152858600ac3SJames Wright   @param[in]   ctx       Context data
152958600ac3SJames Wright   @param[out]  ctx_copy  Copy of pointer to context data
153058600ac3SJames Wright 
153158600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
153258600ac3SJames Wright **/
MatCeedContextReferenceCopy(MatCeedContext ctx,MatCeedContext * ctx_copy)153358600ac3SJames Wright PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) {
153458600ac3SJames Wright   PetscFunctionBeginUser;
153558600ac3SJames Wright   PetscCall(MatCeedContextReference(ctx));
153667aa9f91SJames Wright   PetscCall(MatCeedContextDestroy(ctx_copy));
153758600ac3SJames Wright   *ctx_copy = ctx;
153858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
153958600ac3SJames Wright }
154058600ac3SJames Wright 
154158600ac3SJames Wright /**
154258600ac3SJames Wright   @brief Destroy context data for operator application.
154358600ac3SJames Wright 
154458600ac3SJames Wright   Collective across MPI processes.
154558600ac3SJames Wright 
154658600ac3SJames Wright   @param[in,out]  ctx  Context data for operator evaluation
154758600ac3SJames Wright 
154858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
154958600ac3SJames Wright **/
MatCeedContextDestroy(MatCeedContext * ctx)155067aa9f91SJames Wright PetscErrorCode MatCeedContextDestroy(MatCeedContext *ctx) {
155158600ac3SJames Wright   PetscFunctionBeginUser;
155267aa9f91SJames Wright   if (!ctx || --(*ctx)->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS);
155358600ac3SJames Wright 
155458600ac3SJames Wright   // PETSc objects
155567aa9f91SJames Wright   PetscCall(DMDestroy(&(*ctx)->dm_x));
155667aa9f91SJames Wright   PetscCall(DMDestroy(&(*ctx)->dm_y));
155767aa9f91SJames Wright   PetscCall(VecDestroy(&(*ctx)->X_loc));
155867aa9f91SJames Wright   PetscCall(VecDestroy(&(*ctx)->Y_loc_transpose));
155967aa9f91SJames Wright   PetscCall(MatDestroy(&(*ctx)->mat_assembled_full_internal));
156067aa9f91SJames Wright   PetscCall(MatDestroy(&(*ctx)->mat_assembled_pbd_internal));
156167aa9f91SJames Wright   PetscCall(PetscFree((*ctx)->coo_mat_type));
156267aa9f91SJames Wright   PetscCall(PetscFree((*ctx)->mats_assembled_full));
156367aa9f91SJames Wright   PetscCall(PetscFree((*ctx)->mats_assembled_pbd));
156458600ac3SJames Wright 
156558600ac3SJames Wright   // libCEED objects
156667aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->x_loc));
156767aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->y_loc));
156867aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->coo_values_full));
156967aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->coo_values_pbd));
157067aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorDestroy(&(*ctx)->op_mult));
157167aa9f91SJames Wright   PetscCallCeed((*ctx)->ceed, CeedOperatorDestroy(&(*ctx)->op_mult_transpose));
157267aa9f91SJames Wright   PetscCheck(CeedDestroy(&(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed");
157358600ac3SJames Wright 
157458600ac3SJames Wright   // Deallocate
157567aa9f91SJames Wright   (*ctx)->is_destroyed = PETSC_TRUE;  // Flag as destroyed in case someone has stale ref
157667aa9f91SJames Wright   PetscCall(PetscFree(*ctx));
157758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
157858600ac3SJames Wright }
157958600ac3SJames Wright 
158058600ac3SJames Wright /**
158158600ac3SJames Wright   @brief Compute the diagonal of an operator via libCEED.
158258600ac3SJames Wright 
158358600ac3SJames Wright   Collective across MPI processes.
158458600ac3SJames Wright 
158558600ac3SJames Wright   @param[in]   A  `MATCEED`
158658600ac3SJames Wright   @param[out]  D  Vector holding operator diagonal
158758600ac3SJames Wright 
158858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
158958600ac3SJames Wright **/
MatGetDiagonal_Ceed(Mat A,Vec D)159058600ac3SJames Wright PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) {
159158600ac3SJames Wright   PetscMemType   mem_type;
159258600ac3SJames Wright   Vec            D_loc;
159358600ac3SJames Wright   MatCeedContext ctx;
159458600ac3SJames Wright 
159558600ac3SJames Wright   PetscFunctionBeginUser;
159658600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
159758600ac3SJames Wright 
159858600ac3SJames Wright   // Place PETSc vector in libCEED vector
1599c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
160058600ac3SJames Wright   PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc));
1601a7dac1d5SJames Wright   PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc));
160258600ac3SJames Wright 
160358600ac3SJames Wright   // Compute Diagonal
1604c63b910fSJames Wright   PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
160550f50432SJames Wright   PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1606c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL));
160758600ac3SJames Wright 
160858600ac3SJames Wright   // Restore PETSc vector
1609a7dac1d5SJames Wright   PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc));
161058600ac3SJames Wright 
161158600ac3SJames Wright   // Local-to-Global
161258600ac3SJames Wright   PetscCall(VecZeroEntries(D));
161358600ac3SJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D));
161458600ac3SJames Wright   PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc));
1615c63b910fSJames Wright   PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL));
161658600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
161758600ac3SJames Wright }
161858600ac3SJames Wright 
161958600ac3SJames Wright /**
162058600ac3SJames Wright   @brief Compute `A X = Y` for a `MATCEED`.
162158600ac3SJames Wright 
162258600ac3SJames Wright   Collective across MPI processes.
162358600ac3SJames Wright 
162458600ac3SJames Wright   @param[in]   A  `MATCEED`
162558600ac3SJames Wright   @param[in]   X  Input PETSc vector
162658600ac3SJames Wright   @param[out]  Y  Output PETSc vector
162758600ac3SJames Wright 
162858600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
162958600ac3SJames Wright **/
MatMult_Ceed(Mat A,Vec X,Vec Y)163058600ac3SJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
163158600ac3SJames Wright   MatCeedContext ctx;
163258600ac3SJames Wright 
163358600ac3SJames Wright   PetscFunctionBeginUser;
163458600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1635c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, NULL));
163658600ac3SJames Wright 
163758600ac3SJames Wright   {
163858600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
163958600ac3SJames Wright     Vec          X_loc = ctx->X_loc, Y_loc;
164058600ac3SJames Wright 
164158600ac3SJames Wright     // Get local vectors
164258600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
164358600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
164458600ac3SJames Wright 
164558600ac3SJames Wright     // Global-to-local
164658600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
164758600ac3SJames Wright 
164858600ac3SJames Wright     // Setup libCEED vectors
1649a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
165058600ac3SJames Wright     PetscCall(VecZeroEntries(Y_loc));
1651a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
165258600ac3SJames Wright 
165358600ac3SJames Wright     // Apply libCEED operator
1654c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult, A, X, Y, NULL));
1655537ec908SJames Wright     PetscCall(PetscLogGpuTimeBegin());
165650f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE));
1657ed5c6999SJames Wright     // Log flops
1658ed5c6999SJames Wright     if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult));
1659ed5c6999SJames Wright     else PetscCall(PetscLogFlops(ctx->flops_mult));
166058600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1661537ec908SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult, A, X, Y, NULL));
166258600ac3SJames Wright 
166358600ac3SJames Wright     // Restore PETSc vectors
1664a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
1665a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
166658600ac3SJames Wright 
166758600ac3SJames Wright     // Local-to-global
166858600ac3SJames Wright     PetscCall(VecZeroEntries(Y));
166958600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
167058600ac3SJames Wright 
167158600ac3SJames Wright     // Restore local vectors, as needed
167258600ac3SJames Wright     if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
167358600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
167458600ac3SJames Wright   }
167558600ac3SJames Wright 
1676c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, NULL));
167758600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
167858600ac3SJames Wright }
167958600ac3SJames Wright 
168058600ac3SJames Wright /**
168158600ac3SJames Wright   @brief Compute `A^T Y = X` for a `MATCEED`.
168258600ac3SJames Wright 
168358600ac3SJames Wright   Collective across MPI processes.
168458600ac3SJames Wright 
168558600ac3SJames Wright   @param[in]   A  `MATCEED`
168658600ac3SJames Wright   @param[in]   Y  Input PETSc vector
168758600ac3SJames Wright   @param[out]  X  Output PETSc vector
168858600ac3SJames Wright 
168958600ac3SJames Wright   @return An error code: 0 - success, otherwise - failure
169058600ac3SJames Wright **/
MatMultTranspose_Ceed(Mat A,Vec Y,Vec X)169158600ac3SJames Wright PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) {
169258600ac3SJames Wright   MatCeedContext ctx;
169358600ac3SJames Wright 
169458600ac3SJames Wright   PetscFunctionBeginUser;
169558600ac3SJames Wright   PetscCall(MatShellGetContext(A, &ctx));
1696c63b910fSJames Wright   PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, NULL));
169758600ac3SJames Wright 
169858600ac3SJames Wright   {
169958600ac3SJames Wright     PetscMemType x_mem_type, y_mem_type;
170058600ac3SJames Wright     Vec          X_loc, Y_loc = ctx->Y_loc_transpose;
170158600ac3SJames Wright 
170258600ac3SJames Wright     // Get local vectors
170358600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
170458600ac3SJames Wright     PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
170558600ac3SJames Wright 
170658600ac3SJames Wright     // Global-to-local
170758600ac3SJames Wright     PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc));
170858600ac3SJames Wright 
170958600ac3SJames Wright     // Setup libCEED vectors
1710a7dac1d5SJames Wright     PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc));
171158600ac3SJames Wright     PetscCall(VecZeroEntries(X_loc));
1712a7dac1d5SJames Wright     PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc));
171358600ac3SJames Wright 
171458600ac3SJames Wright     // Apply libCEED operator
1715c63b910fSJames Wright     PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
1716537ec908SJames Wright     PetscCall(PetscLogGpuTimeBegin());
171750f50432SJames Wright     PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE));
1718ed5c6999SJames Wright     // Log flops
1719ed5c6999SJames Wright     if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose));
1720ed5c6999SJames Wright     else PetscCall(PetscLogFlops(ctx->flops_mult_transpose));
172158600ac3SJames Wright     PetscCall(PetscLogGpuTimeEnd());
1722537ec908SJames Wright     PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL));
172358600ac3SJames Wright 
172458600ac3SJames Wright     // Restore PETSc vectors
1725a7dac1d5SJames Wright     PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc));
1726a7dac1d5SJames Wright     PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc));
172758600ac3SJames Wright 
172858600ac3SJames Wright     // Local-to-global
172958600ac3SJames Wright     PetscCall(VecZeroEntries(X));
173058600ac3SJames Wright     PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X));
173158600ac3SJames Wright 
173258600ac3SJames Wright     // Restore local vectors, as needed
173358600ac3SJames Wright     if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
173458600ac3SJames Wright     PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
173558600ac3SJames Wright   }
173658600ac3SJames Wright 
1737c63b910fSJames Wright   PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, NULL));
173858600ac3SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
173958600ac3SJames Wright }
1740