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