xref: /libCEED/examples/fluids/src/petsc_ops.c (revision 4021610ddd54d2077dba1164ccecc5411a2898fa)
1*4021610dSJames Wright // Copyright (c) 2017-2023, Lawrence Livermore National Security, LLC and other CEED contributors.
2*4021610dSJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3*4021610dSJames Wright //
4*4021610dSJames Wright // SPDX-License-Identifier: BSD-2-Clause
5*4021610dSJames Wright //
6*4021610dSJames Wright // This file is part of CEED:  http://github.com/ceed
7*4021610dSJames Wright 
8*4021610dSJames Wright #include "../include/petsc_ops.h"
9*4021610dSJames Wright 
10*4021610dSJames Wright #include <ceed.h>
11*4021610dSJames Wright #include <petscdm.h>
12*4021610dSJames Wright 
13*4021610dSJames Wright #include "../navierstokes.h"
14*4021610dSJames Wright 
15*4021610dSJames Wright // -----------------------------------------------------------------------------
16*4021610dSJames Wright // Setup apply operator context data
17*4021610dSJames Wright // -----------------------------------------------------------------------------
18*4021610dSJames Wright PetscErrorCode OperatorApplyContextCreate(DM dm_x, DM dm_y, Ceed ceed, CeedOperator op_apply, CeedVector x_ceed, CeedVector y_ceed, Vec X_loc,
19*4021610dSJames Wright                                           Vec Y_loc, OperatorApplyContext *op_apply_ctx) {
20*4021610dSJames Wright   PetscFunctionBeginUser;
21*4021610dSJames Wright 
22*4021610dSJames Wright   {  // Verify sizes
23*4021610dSJames Wright     CeedSize x_size, y_size;
24*4021610dSJames Wright     PetscInt X_size, Y_size;
25*4021610dSJames Wright     CeedOperatorGetActiveVectorLengths(op_apply, &x_size, &y_size);
26*4021610dSJames Wright     if (X_loc) {
27*4021610dSJames Wright       PetscCall(VecGetLocalSize(X_loc, &X_size));
28*4021610dSJames Wright       PetscCheck(X_size == x_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ,
29*4021610dSJames Wright                  "X_loc (%" PetscInt_FMT ") not correct size for CeedOperator active input size (%" CeedSize_FMT ")", X_size, x_size);
30*4021610dSJames Wright     }
31*4021610dSJames Wright     if (Y_loc) {
32*4021610dSJames Wright       PetscCall(VecGetLocalSize(Y_loc, &Y_size));
33*4021610dSJames Wright       PetscCheck(Y_size == y_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ,
34*4021610dSJames Wright                  "Y_loc (%" PetscInt_FMT ") not correct size for CeedOperator active output size (%" CeedSize_FMT ")", Y_size, y_size);
35*4021610dSJames Wright     }
36*4021610dSJames Wright   }
37*4021610dSJames Wright 
38*4021610dSJames Wright   PetscCall(PetscNew(op_apply_ctx));
39*4021610dSJames Wright 
40*4021610dSJames Wright   // Copy PETSc Objects
41*4021610dSJames Wright   if (dm_x) PetscCall(PetscObjectReference((PetscObject)dm_x));
42*4021610dSJames Wright   (*op_apply_ctx)->dm_x = dm_x;
43*4021610dSJames Wright   if (dm_y) PetscCall(PetscObjectReference((PetscObject)dm_y));
44*4021610dSJames Wright   (*op_apply_ctx)->dm_y = dm_y;
45*4021610dSJames Wright 
46*4021610dSJames Wright   if (X_loc) PetscCall(PetscObjectReference((PetscObject)X_loc));
47*4021610dSJames Wright   (*op_apply_ctx)->X_loc = X_loc;
48*4021610dSJames Wright   if (Y_loc) PetscCall(PetscObjectReference((PetscObject)Y_loc));
49*4021610dSJames Wright   (*op_apply_ctx)->Y_loc = Y_loc;
50*4021610dSJames Wright 
51*4021610dSJames Wright   // Copy libCEED objects
52*4021610dSJames Wright   if (x_ceed) CeedVectorReferenceCopy(x_ceed, &(*op_apply_ctx)->x_ceed);
53*4021610dSJames Wright   if (y_ceed) CeedVectorReferenceCopy(y_ceed, &(*op_apply_ctx)->y_ceed);
54*4021610dSJames Wright   CeedOperatorReferenceCopy(op_apply, &(*op_apply_ctx)->op);
55*4021610dSJames Wright   CeedReferenceCopy(ceed, &(*op_apply_ctx)->ceed);
56*4021610dSJames Wright 
57*4021610dSJames Wright   PetscFunctionReturn(0);
58*4021610dSJames Wright }
59*4021610dSJames Wright 
60*4021610dSJames Wright // -----------------------------------------------------------------------------
61*4021610dSJames Wright // Destroy apply operator context data
62*4021610dSJames Wright // -----------------------------------------------------------------------------
63*4021610dSJames Wright PetscErrorCode OperatorApplyContextDestroy(OperatorApplyContext op_apply_ctx) {
64*4021610dSJames Wright   PetscFunctionBeginUser;
65*4021610dSJames Wright 
66*4021610dSJames Wright   if (!op_apply_ctx) PetscFunctionReturn(0);
67*4021610dSJames Wright 
68*4021610dSJames Wright   // Destroy PETSc Objects
69*4021610dSJames Wright   PetscCall(DMDestroy(&op_apply_ctx->dm_x));
70*4021610dSJames Wright   PetscCall(DMDestroy(&op_apply_ctx->dm_y));
71*4021610dSJames Wright   PetscCall(VecDestroy(&op_apply_ctx->X_loc));
72*4021610dSJames Wright   PetscCall(VecDestroy(&op_apply_ctx->Y_loc));
73*4021610dSJames Wright 
74*4021610dSJames Wright   // Destroy libCEED Objects
75*4021610dSJames Wright   CeedVectorDestroy(&op_apply_ctx->x_ceed);
76*4021610dSJames Wright   CeedVectorDestroy(&op_apply_ctx->y_ceed);
77*4021610dSJames Wright   CeedOperatorDestroy(&op_apply_ctx->op);
78*4021610dSJames Wright   CeedDestroy(&op_apply_ctx->ceed);
79*4021610dSJames Wright 
80*4021610dSJames Wright   PetscCall(PetscFree(op_apply_ctx));
81*4021610dSJames Wright 
82*4021610dSJames Wright   PetscFunctionReturn(0);
83*4021610dSJames Wright }
84*4021610dSJames Wright 
85*4021610dSJames Wright /**
86*4021610dSJames Wright   @brief Transfer array from PETSc Vec to CeedVector
87*4021610dSJames Wright 
88*4021610dSJames Wright   @param[in]   X_petsc   PETSc Vec
89*4021610dSJames Wright   @param[out]  mem_type  PETSc MemType
90*4021610dSJames Wright   @param[out]  x_ceed    CeedVector
91*4021610dSJames Wright 
92*4021610dSJames Wright   @return An error code: 0 - success, otherwise - failure
93*4021610dSJames Wright **/
94*4021610dSJames Wright PetscErrorCode VecP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed) {
95*4021610dSJames Wright   PetscScalar *x;
96*4021610dSJames Wright   PetscInt     X_size;
97*4021610dSJames Wright   CeedSize     x_size;
98*4021610dSJames Wright 
99*4021610dSJames Wright   PetscFunctionBeginUser;
100*4021610dSJames Wright   PetscCall(VecGetLocalSize(X_petsc, &X_size));
101*4021610dSJames Wright   CeedVectorGetLength(x_ceed, &x_size);
102*4021610dSJames Wright   PetscCheck(X_size == x_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "X_petsc (%" PetscInt_FMT ") and x_ceed (%" CeedSize_FMT ") must be same size",
103*4021610dSJames Wright              X_size, x_size);
104*4021610dSJames Wright 
105*4021610dSJames Wright   PetscCall(VecGetArrayAndMemType(X_petsc, &x, mem_type));
106*4021610dSJames Wright   CeedVectorSetArray(x_ceed, MemTypeP2C(*mem_type), CEED_USE_POINTER, x);
107*4021610dSJames Wright 
108*4021610dSJames Wright   PetscFunctionReturn(0);
109*4021610dSJames Wright }
110*4021610dSJames Wright 
111*4021610dSJames Wright /**
112*4021610dSJames Wright   @brief Transfer array from CeedVector to PETSc Vec
113*4021610dSJames Wright 
114*4021610dSJames Wright   @param[in]   x_ceed    CeedVector
115*4021610dSJames Wright   @param[in]   mem_type  PETSc MemType
116*4021610dSJames Wright   @param[out]  X_petsc   PETSc Vec
117*4021610dSJames Wright 
118*4021610dSJames Wright   @return An error code: 0 - success, otherwise - failure
119*4021610dSJames Wright **/
120*4021610dSJames Wright PetscErrorCode VecC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc) {
121*4021610dSJames Wright   PetscScalar *x;
122*4021610dSJames Wright   PetscInt     X_size;
123*4021610dSJames Wright   CeedSize     x_size;
124*4021610dSJames Wright 
125*4021610dSJames Wright   PetscFunctionBeginUser;
126*4021610dSJames Wright   PetscCall(VecGetLocalSize(X_petsc, &X_size));
127*4021610dSJames Wright   CeedVectorGetLength(x_ceed, &x_size);
128*4021610dSJames Wright   PetscCheck(X_size == x_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "X_petsc (%" PetscInt_FMT ") and x_ceed (%" CeedSize_FMT ") must be same size",
129*4021610dSJames Wright              X_size, x_size);
130*4021610dSJames Wright 
131*4021610dSJames Wright   CeedVectorTakeArray(x_ceed, MemTypeP2C(mem_type), &x);
132*4021610dSJames Wright   PetscCall(VecRestoreArrayAndMemType(X_petsc, &x));
133*4021610dSJames Wright 
134*4021610dSJames Wright   PetscFunctionReturn(0);
135*4021610dSJames Wright }
136*4021610dSJames Wright 
137*4021610dSJames Wright /**
138*4021610dSJames Wright   @brief Transfer read-only array from PETSc Vec to CeedVector
139*4021610dSJames Wright 
140*4021610dSJames Wright   @param[in]   X_petsc   PETSc Vec
141*4021610dSJames Wright   @param[out]  mem_type  PETSc MemType
142*4021610dSJames Wright   @param[out]  x_ceed    CeedVector
143*4021610dSJames Wright 
144*4021610dSJames Wright   @return An error code: 0 - success, otherwise - failure
145*4021610dSJames Wright **/
146*4021610dSJames Wright PetscErrorCode VecReadP2C(Vec X_petsc, PetscMemType *mem_type, CeedVector x_ceed) {
147*4021610dSJames Wright   PetscScalar *x;
148*4021610dSJames Wright   PetscInt     X_size;
149*4021610dSJames Wright   CeedSize     x_size;
150*4021610dSJames Wright 
151*4021610dSJames Wright   PetscFunctionBeginUser;
152*4021610dSJames Wright   PetscCall(VecGetLocalSize(X_petsc, &X_size));
153*4021610dSJames Wright   CeedVectorGetLength(x_ceed, &x_size);
154*4021610dSJames Wright   PetscCheck(X_size == x_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "X_petsc (%" PetscInt_FMT ") and x_ceed (%" CeedSize_FMT ") must be same size",
155*4021610dSJames Wright              X_size, x_size);
156*4021610dSJames Wright 
157*4021610dSJames Wright   PetscCall(VecGetArrayReadAndMemType(X_petsc, (const PetscScalar **)&x, mem_type));
158*4021610dSJames Wright   CeedVectorSetArray(x_ceed, MemTypeP2C(*mem_type), CEED_USE_POINTER, x);
159*4021610dSJames Wright 
160*4021610dSJames Wright   PetscFunctionReturn(0);
161*4021610dSJames Wright }
162*4021610dSJames Wright 
163*4021610dSJames Wright /**
164*4021610dSJames Wright   @brief Transfer read-only array from CeedVector to PETSc Vec
165*4021610dSJames Wright 
166*4021610dSJames Wright   @param[in]   x_ceed    CeedVector
167*4021610dSJames Wright   @param[in]   mem_type  PETSc MemType
168*4021610dSJames Wright   @param[out]  X_petsc   PETSc Vec
169*4021610dSJames Wright 
170*4021610dSJames Wright   @return An error code: 0 - success, otherwise - failure
171*4021610dSJames Wright **/
172*4021610dSJames Wright PetscErrorCode VecReadC2P(CeedVector x_ceed, PetscMemType mem_type, Vec X_petsc) {
173*4021610dSJames Wright   PetscScalar *x;
174*4021610dSJames Wright   PetscInt     X_size;
175*4021610dSJames Wright   CeedSize     x_size;
176*4021610dSJames Wright 
177*4021610dSJames Wright   PetscFunctionBeginUser;
178*4021610dSJames Wright   PetscCall(VecGetLocalSize(X_petsc, &X_size));
179*4021610dSJames Wright   CeedVectorGetLength(x_ceed, &x_size);
180*4021610dSJames Wright   PetscCheck(X_size == x_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "X_petsc (%" PetscInt_FMT ") and x_ceed (%" CeedSize_FMT ") must be same size",
181*4021610dSJames Wright              X_size, x_size);
182*4021610dSJames Wright 
183*4021610dSJames Wright   CeedVectorTakeArray(x_ceed, MemTypeP2C(mem_type), &x);
184*4021610dSJames Wright   PetscCall(VecRestoreArrayReadAndMemType(X_petsc, (const PetscScalar **)&x));
185*4021610dSJames Wright 
186*4021610dSJames Wright   PetscFunctionReturn(0);
187*4021610dSJames Wright }
188*4021610dSJames Wright 
189*4021610dSJames Wright /**
190*4021610dSJames Wright   @brief Copy PETSc Vec data into CeedVector
191*4021610dSJames Wright 
192*4021610dSJames Wright   @param[in]   X_petsc PETSc Vec
193*4021610dSJames Wright   @param[out]  x_ceed  CeedVector
194*4021610dSJames Wright 
195*4021610dSJames Wright   @return An error code: 0 - success, otherwise - failure
196*4021610dSJames Wright **/
197*4021610dSJames Wright PetscErrorCode VecCopyP2C(Vec X_petsc, CeedVector x_ceed) {
198*4021610dSJames Wright   PetscScalar *x;
199*4021610dSJames Wright   PetscMemType mem_type;
200*4021610dSJames Wright   PetscInt     X_size;
201*4021610dSJames Wright   CeedSize     x_size;
202*4021610dSJames Wright 
203*4021610dSJames Wright   PetscFunctionBeginUser;
204*4021610dSJames Wright   PetscCall(VecGetLocalSize(X_petsc, &X_size));
205*4021610dSJames Wright   CeedVectorGetLength(x_ceed, &x_size);
206*4021610dSJames Wright   PetscCheck(X_size == x_size, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "X_petsc (%" PetscInt_FMT ") and x_ceed (%" CeedSize_FMT ") must be same size",
207*4021610dSJames Wright              X_size, x_size);
208*4021610dSJames Wright 
209*4021610dSJames Wright   PetscCall(VecGetArrayReadAndMemType(X_petsc, (const PetscScalar **)&x, &mem_type));
210*4021610dSJames Wright   CeedVectorSetArray(x_ceed, MemTypeP2C(mem_type), CEED_COPY_VALUES, x);
211*4021610dSJames Wright   PetscCall(VecRestoreArrayReadAndMemType(X_petsc, (const PetscScalar **)&x));
212*4021610dSJames Wright 
213*4021610dSJames Wright   PetscFunctionReturn(0);
214*4021610dSJames Wright }
215*4021610dSJames Wright 
216*4021610dSJames Wright /**
217*4021610dSJames Wright  * @brief Apply FEM Operator defined by `OperatorApplyContext` to various input and output vectors
218*4021610dSJames Wright  *
219*4021610dSJames Wright  * @param X             Input global `Vec`, maybe `NULL`
220*4021610dSJames Wright  * @param X_loc         Input local `Vec`, maybe `NULL`
221*4021610dSJames Wright  * @param x_ceed        Input `CeedVector`, maybe `CEED_VECTOR_NONE`
222*4021610dSJames Wright  * @param y_ceed        Output `CeedVector`, maybe `CEED_VECTOR_NONE`
223*4021610dSJames Wright  * @param Y_loc         Output local `Vec`, maybe `NULL`
224*4021610dSJames Wright  * @param Y             Output global `Vec`, maybe `NULL`
225*4021610dSJames Wright  * @param ctx           Context for the operator apply
226*4021610dSJames Wright  * @param use_apply_add Whether to use `CeedOperatorApply` or `CeedOperatorApplyAdd`
227*4021610dSJames Wright  */
228*4021610dSJames Wright PetscErrorCode ApplyCeedOperator_Core(Vec X, Vec X_loc, CeedVector x_ceed, CeedVector y_ceed, Vec Y_loc, Vec Y, OperatorApplyContext ctx,
229*4021610dSJames Wright                                       bool use_apply_add) {
230*4021610dSJames Wright   PetscMemType x_mem_type, y_mem_type;
231*4021610dSJames Wright 
232*4021610dSJames Wright   PetscFunctionBeginUser;
233*4021610dSJames Wright   if (X) PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc));
234*4021610dSJames Wright   if (X_loc) PetscCall(VecReadP2C(X_loc, &x_mem_type, x_ceed));
235*4021610dSJames Wright 
236*4021610dSJames Wright   if (Y_loc) PetscCall(VecP2C(Y_loc, &y_mem_type, y_ceed));
237*4021610dSJames Wright 
238*4021610dSJames Wright   if (use_apply_add) CeedOperatorApplyAdd(ctx->op, x_ceed, y_ceed, CEED_REQUEST_IMMEDIATE);
239*4021610dSJames Wright   else CeedOperatorApply(ctx->op, x_ceed, y_ceed, CEED_REQUEST_IMMEDIATE);
240*4021610dSJames Wright 
241*4021610dSJames Wright   if (X_loc) PetscCall(VecReadC2P(ctx->x_ceed, x_mem_type, X_loc));
242*4021610dSJames Wright 
243*4021610dSJames Wright   if (Y_loc) PetscCall(VecC2P(ctx->y_ceed, y_mem_type, Y_loc));
244*4021610dSJames Wright   if (Y) PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y));
245*4021610dSJames Wright 
246*4021610dSJames Wright   PetscFunctionReturn(0);
247*4021610dSJames Wright };
248*4021610dSJames Wright 
249*4021610dSJames Wright PetscErrorCode ApplyCeedOperatorGlobalToGlobal(Vec X, Vec Y, OperatorApplyContext ctx) {
250*4021610dSJames Wright   Vec X_loc = ctx->X_loc, Y_loc = ctx->Y_loc;
251*4021610dSJames Wright 
252*4021610dSJames Wright   PetscFunctionBeginUser;
253*4021610dSJames Wright   PetscCall(VecZeroEntries(Y));
254*4021610dSJames Wright 
255*4021610dSJames Wright   // Get local vectors (if needed)
256*4021610dSJames Wright   if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
257*4021610dSJames Wright   if (!ctx->Y_loc) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
258*4021610dSJames Wright 
259*4021610dSJames Wright   PetscCall(ApplyCeedOperator_Core(X, X_loc, ctx->x_ceed, ctx->y_ceed, Y_loc, Y, ctx, false));
260*4021610dSJames Wright 
261*4021610dSJames Wright   // Restore local vector (if needed)
262*4021610dSJames Wright   if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
263*4021610dSJames Wright   if (!ctx->Y_loc) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
264*4021610dSJames Wright 
265*4021610dSJames Wright   PetscFunctionReturn(0);
266*4021610dSJames Wright }
267*4021610dSJames Wright 
268*4021610dSJames Wright PetscErrorCode ApplyCeedOperatorLocalToGlobal(Vec X_loc, Vec Y, OperatorApplyContext ctx) {
269*4021610dSJames Wright   Vec Y_loc = ctx->Y_loc;
270*4021610dSJames Wright 
271*4021610dSJames Wright   PetscFunctionBeginUser;
272*4021610dSJames Wright   PetscCall(VecZeroEntries(Y));
273*4021610dSJames Wright 
274*4021610dSJames Wright   // Get local vectors (if needed)
275*4021610dSJames Wright   if (!ctx->Y_loc) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
276*4021610dSJames Wright 
277*4021610dSJames Wright   PetscCall(ApplyCeedOperator_Core(NULL, X_loc, ctx->x_ceed, ctx->y_ceed, Y_loc, Y, ctx, false));
278*4021610dSJames Wright 
279*4021610dSJames Wright   // Restore local vectors (if needed)
280*4021610dSJames Wright   if (!ctx->Y_loc) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
281*4021610dSJames Wright 
282*4021610dSJames Wright   PetscFunctionReturn(0);
283*4021610dSJames Wright }
284*4021610dSJames Wright 
285*4021610dSJames Wright PetscErrorCode ApplyCeedOperatorGlobalToLocal(Vec X, Vec Y_loc, OperatorApplyContext ctx) {
286*4021610dSJames Wright   Vec X_loc = ctx->X_loc;
287*4021610dSJames Wright 
288*4021610dSJames Wright   PetscFunctionBeginUser;
289*4021610dSJames Wright   // Get local vectors (if needed)
290*4021610dSJames Wright   if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc));
291*4021610dSJames Wright 
292*4021610dSJames Wright   PetscCall(ApplyCeedOperator_Core(X, X_loc, ctx->x_ceed, ctx->y_ceed, Y_loc, NULL, ctx, false));
293*4021610dSJames Wright 
294*4021610dSJames Wright   // Restore local vector (if needed)
295*4021610dSJames Wright   if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc));
296*4021610dSJames Wright 
297*4021610dSJames Wright   PetscFunctionReturn(0);
298*4021610dSJames Wright }
299*4021610dSJames Wright 
300*4021610dSJames Wright PetscErrorCode ApplyAddCeedOperatorLocalToLocal(Vec X_loc, Vec Y_loc, OperatorApplyContext ctx) {
301*4021610dSJames Wright   PetscFunctionBeginUser;
302*4021610dSJames Wright   PetscCall(ApplyCeedOperator_Core(NULL, X_loc, ctx->x_ceed, ctx->y_ceed, Y_loc, NULL, ctx, true));
303*4021610dSJames Wright   PetscFunctionReturn(0);
304*4021610dSJames Wright }
305*4021610dSJames Wright 
306*4021610dSJames Wright // -----------------------------------------------------------------------------
307*4021610dSJames Wright // Wraps the libCEED operator for a MatShell
308*4021610dSJames Wright // -----------------------------------------------------------------------------
309*4021610dSJames Wright PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
310*4021610dSJames Wright   OperatorApplyContext ctx;
311*4021610dSJames Wright   PetscFunctionBeginUser;
312*4021610dSJames Wright 
313*4021610dSJames Wright   PetscCall(MatShellGetContext(A, &ctx));
314*4021610dSJames Wright   PetscCall(ApplyCeedOperatorGlobalToGlobal(X, Y, ctx));
315*4021610dSJames Wright 
316*4021610dSJames Wright   PetscFunctionReturn(0);
317*4021610dSJames Wright };
318*4021610dSJames Wright 
319*4021610dSJames Wright // -----------------------------------------------------------------------------
320*4021610dSJames Wright // Returns the computed diagonal of the operator
321*4021610dSJames Wright // -----------------------------------------------------------------------------
322*4021610dSJames Wright PetscErrorCode MatGetDiag_Ceed(Mat A, Vec D) {
323*4021610dSJames Wright   OperatorApplyContext ctx;
324*4021610dSJames Wright   Vec                  Y_loc;
325*4021610dSJames Wright   PetscMemType         mem_type;
326*4021610dSJames Wright   PetscFunctionBeginUser;
327*4021610dSJames Wright 
328*4021610dSJames Wright   PetscCall(MatShellGetContext(A, &ctx));
329*4021610dSJames Wright   if (ctx->Y_loc) Y_loc = ctx->Y_loc;
330*4021610dSJames Wright   else PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc));
331*4021610dSJames Wright 
332*4021610dSJames Wright   // -- Place PETSc vector in libCEED vector
333*4021610dSJames Wright   PetscCall(VecP2C(Y_loc, &mem_type, ctx->y_ceed));
334*4021610dSJames Wright 
335*4021610dSJames Wright   // -- Compute Diagonal
336*4021610dSJames Wright   CeedOperatorLinearAssembleDiagonal(ctx->op, ctx->y_ceed, CEED_REQUEST_IMMEDIATE);
337*4021610dSJames Wright 
338*4021610dSJames Wright   // -- Local-to-Global
339*4021610dSJames Wright   PetscCall(VecC2P(ctx->y_ceed, mem_type, Y_loc));
340*4021610dSJames Wright   PetscCall(VecZeroEntries(D));
341*4021610dSJames Wright   PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, D));
342*4021610dSJames Wright 
343*4021610dSJames Wright   if (!ctx->Y_loc) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc));
344*4021610dSJames Wright   PetscFunctionReturn(0);
345*4021610dSJames Wright };
346*4021610dSJames Wright 
347*4021610dSJames Wright // -----------------------------------------------------------------------------
348