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