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