1e83e87a5Sjeremylt #include "../include/matops.h" 2e83e87a5Sjeremylt #include "../include/petscutils.h" 3e83e87a5Sjeremylt 4e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 5*6c88e6a2Srezgarshakeri // Setup apply operator context data 6*6c88e6a2Srezgarshakeri // ----------------------------------------------------------------------------- 7*6c88e6a2Srezgarshakeri PetscErrorCode SetupApplyOperatorCtx(MPI_Comm comm, DM dm, Ceed ceed, 8*6c88e6a2Srezgarshakeri CeedData ceed_data, Vec X_loc, 9*6c88e6a2Srezgarshakeri OperatorApplyContext op_apply_ctx) { 10*6c88e6a2Srezgarshakeri PetscErrorCode ierr; 11*6c88e6a2Srezgarshakeri PetscFunctionBeginUser; 12*6c88e6a2Srezgarshakeri 13*6c88e6a2Srezgarshakeri op_apply_ctx->comm = comm; 14*6c88e6a2Srezgarshakeri op_apply_ctx->dm = dm; 15*6c88e6a2Srezgarshakeri op_apply_ctx->X_loc = X_loc; 16*6c88e6a2Srezgarshakeri ierr = VecDuplicate(X_loc, &op_apply_ctx->Y_loc); CHKERRQ(ierr); 17*6c88e6a2Srezgarshakeri op_apply_ctx->x_ceed = ceed_data->x_ceed; 18*6c88e6a2Srezgarshakeri op_apply_ctx->y_ceed = ceed_data->y_ceed; 19*6c88e6a2Srezgarshakeri op_apply_ctx->op = ceed_data->op_apply; 20*6c88e6a2Srezgarshakeri op_apply_ctx->ceed = ceed; 21*6c88e6a2Srezgarshakeri PetscFunctionReturn(0); 22*6c88e6a2Srezgarshakeri } 23*6c88e6a2Srezgarshakeri 24*6c88e6a2Srezgarshakeri // ----------------------------------------------------------------------------- 25*6c88e6a2Srezgarshakeri // Setup error operator context data 26*6c88e6a2Srezgarshakeri // ----------------------------------------------------------------------------- 27*6c88e6a2Srezgarshakeri PetscErrorCode SetupErrorOperatorCtx(MPI_Comm comm, DM dm, Ceed ceed, 28*6c88e6a2Srezgarshakeri CeedData ceed_data, Vec X_loc, CeedOperator op_error, 29*6c88e6a2Srezgarshakeri OperatorApplyContext op_error_ctx) { 30*6c88e6a2Srezgarshakeri PetscErrorCode ierr; 31*6c88e6a2Srezgarshakeri PetscFunctionBeginUser; 32*6c88e6a2Srezgarshakeri 33*6c88e6a2Srezgarshakeri op_error_ctx->comm = comm; 34*6c88e6a2Srezgarshakeri op_error_ctx->dm = dm; 35*6c88e6a2Srezgarshakeri op_error_ctx->X_loc = X_loc; 36*6c88e6a2Srezgarshakeri ierr = VecDuplicate(X_loc, &op_error_ctx->Y_loc); CHKERRQ(ierr); 37*6c88e6a2Srezgarshakeri op_error_ctx->x_ceed = ceed_data->x_ceed; 38*6c88e6a2Srezgarshakeri op_error_ctx->y_ceed = ceed_data->y_ceed; 39*6c88e6a2Srezgarshakeri op_error_ctx->op = op_error; 40*6c88e6a2Srezgarshakeri op_error_ctx->ceed = ceed; 41*6c88e6a2Srezgarshakeri PetscFunctionReturn(0); 42*6c88e6a2Srezgarshakeri } 43*6c88e6a2Srezgarshakeri 44*6c88e6a2Srezgarshakeri // ----------------------------------------------------------------------------- 45e83e87a5Sjeremylt // This function returns the computed diagonal of the operator 46e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 47e83e87a5Sjeremylt PetscErrorCode MatGetDiag(Mat A, Vec D) { 48e83e87a5Sjeremylt PetscErrorCode ierr; 49d4d45553Srezgarshakeri OperatorApplyContext op_apply_ctx; 50e83e87a5Sjeremylt 51e83e87a5Sjeremylt PetscFunctionBeginUser; 52e83e87a5Sjeremylt 53d4d45553Srezgarshakeri ierr = MatShellGetContext(A, &op_apply_ctx); CHKERRQ(ierr); 54e83e87a5Sjeremylt 55e83e87a5Sjeremylt // Compute Diagonal via libCEED 56f1c40530SJeremy L Thompson PetscScalar *y; 579b072555Sjeremylt PetscMemType mem_type; 58e83e87a5Sjeremylt 59e83e87a5Sjeremylt // -- Place PETSc vector in libCEED vector 60d4d45553Srezgarshakeri ierr = VecGetArrayAndMemType(op_apply_ctx->Y_loc, &y, &mem_type); CHKERRQ(ierr); 61d4d45553Srezgarshakeri CeedVectorSetArray(op_apply_ctx->y_ceed, MemTypeP2C(mem_type), 62d4d45553Srezgarshakeri CEED_USE_POINTER, y); 63e83e87a5Sjeremylt 64e83e87a5Sjeremylt // -- Compute Diagonal 65d4d45553Srezgarshakeri CeedOperatorLinearAssembleDiagonal(op_apply_ctx->op, op_apply_ctx->y_ceed, 66e83e87a5Sjeremylt CEED_REQUEST_IMMEDIATE); 67e83e87a5Sjeremylt 68e83e87a5Sjeremylt // -- Local-to-Global 69d4d45553Srezgarshakeri CeedVectorTakeArray(op_apply_ctx->y_ceed, MemTypeP2C(mem_type), NULL); 70d4d45553Srezgarshakeri ierr = VecRestoreArrayAndMemType(op_apply_ctx->Y_loc, &y); CHKERRQ(ierr); 71e83e87a5Sjeremylt ierr = VecZeroEntries(D); CHKERRQ(ierr); 72d4d45553Srezgarshakeri ierr = DMLocalToGlobal(op_apply_ctx->dm, op_apply_ctx->Y_loc, ADD_VALUES, D); 73d4d45553Srezgarshakeri CHKERRQ(ierr); 74e83e87a5Sjeremylt 75e83e87a5Sjeremylt PetscFunctionReturn(0); 76e83e87a5Sjeremylt }; 77e83e87a5Sjeremylt 78e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 79e83e87a5Sjeremylt // This function uses libCEED to compute the action of the Laplacian with 80e83e87a5Sjeremylt // Dirichlet boundary conditions 81e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 82d4d45553Srezgarshakeri PetscErrorCode ApplyLocal_Ceed(Vec X, Vec Y, 83d4d45553Srezgarshakeri OperatorApplyContext op_apply_ctx) { 84e83e87a5Sjeremylt PetscErrorCode ierr; 85e83e87a5Sjeremylt PetscScalar *x, *y; 869b072555Sjeremylt PetscMemType x_mem_type, y_mem_type; 87e83e87a5Sjeremylt 88e83e87a5Sjeremylt PetscFunctionBeginUser; 89e83e87a5Sjeremylt 90e83e87a5Sjeremylt // Global-to-local 91d4d45553Srezgarshakeri ierr = DMGlobalToLocal(op_apply_ctx->dm, X, INSERT_VALUES, op_apply_ctx->X_loc); 92d4d45553Srezgarshakeri CHKERRQ(ierr); 93e83e87a5Sjeremylt 94e83e87a5Sjeremylt // Setup libCEED vectors 95d4d45553Srezgarshakeri ierr = VecGetArrayReadAndMemType(op_apply_ctx->X_loc, (const PetscScalar **)&x, 969b072555Sjeremylt &x_mem_type); CHKERRQ(ierr); 97d4d45553Srezgarshakeri ierr = VecGetArrayAndMemType(op_apply_ctx->Y_loc, &y, &y_mem_type); 98d4d45553Srezgarshakeri CHKERRQ(ierr); 99d4d45553Srezgarshakeri CeedVectorSetArray(op_apply_ctx->x_ceed, MemTypeP2C(x_mem_type), 100d4d45553Srezgarshakeri CEED_USE_POINTER, x); 101d4d45553Srezgarshakeri CeedVectorSetArray(op_apply_ctx->y_ceed, MemTypeP2C(y_mem_type), 102d4d45553Srezgarshakeri CEED_USE_POINTER, y); 103e83e87a5Sjeremylt 104e83e87a5Sjeremylt // Apply libCEED operator 105d4d45553Srezgarshakeri CeedOperatorApply(op_apply_ctx->op, op_apply_ctx->x_ceed, op_apply_ctx->y_ceed, 106d4d45553Srezgarshakeri CEED_REQUEST_IMMEDIATE); 107e83e87a5Sjeremylt 108e83e87a5Sjeremylt // Restore PETSc vectors 109d4d45553Srezgarshakeri CeedVectorTakeArray(op_apply_ctx->x_ceed, MemTypeP2C(x_mem_type), NULL); 110d4d45553Srezgarshakeri CeedVectorTakeArray(op_apply_ctx->y_ceed, MemTypeP2C(y_mem_type), NULL); 111d4d45553Srezgarshakeri ierr = VecRestoreArrayReadAndMemType(op_apply_ctx->X_loc, 112d4d45553Srezgarshakeri (const PetscScalar **)&x); 113e83e87a5Sjeremylt CHKERRQ(ierr); 114d4d45553Srezgarshakeri ierr = VecRestoreArrayAndMemType(op_apply_ctx->Y_loc, &y); CHKERRQ(ierr); 115e83e87a5Sjeremylt 116e83e87a5Sjeremylt // Local-to-global 117e83e87a5Sjeremylt ierr = VecZeroEntries(Y); CHKERRQ(ierr); 118d4d45553Srezgarshakeri ierr = DMLocalToGlobal(op_apply_ctx->dm, op_apply_ctx->Y_loc, ADD_VALUES, Y); 119d4d45553Srezgarshakeri CHKERRQ(ierr); 120e83e87a5Sjeremylt 121e83e87a5Sjeremylt PetscFunctionReturn(0); 122e83e87a5Sjeremylt }; 123e83e87a5Sjeremylt 124e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 125e83e87a5Sjeremylt // This function wraps the libCEED operator for a MatShell 126e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 127e83e87a5Sjeremylt PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) { 128e83e87a5Sjeremylt PetscErrorCode ierr; 129d4d45553Srezgarshakeri OperatorApplyContext op_apply_ctx; 130e83e87a5Sjeremylt 131e83e87a5Sjeremylt PetscFunctionBeginUser; 132e83e87a5Sjeremylt 133d4d45553Srezgarshakeri ierr = MatShellGetContext(A, &op_apply_ctx); CHKERRQ(ierr); 134e83e87a5Sjeremylt 135e83e87a5Sjeremylt // libCEED for local action of residual evaluator 136d4d45553Srezgarshakeri ierr = ApplyLocal_Ceed(X, Y, op_apply_ctx); CHKERRQ(ierr); 137e83e87a5Sjeremylt 138e83e87a5Sjeremylt PetscFunctionReturn(0); 139e83e87a5Sjeremylt }; 140e83e87a5Sjeremylt 141e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 142e83e87a5Sjeremylt // This function wraps the libCEED operator for a SNES residual evaluation 143e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 144e83e87a5Sjeremylt PetscErrorCode FormResidual_Ceed(SNES snes, Vec X, Vec Y, void *ctx) { 145e83e87a5Sjeremylt PetscErrorCode ierr; 146d4d45553Srezgarshakeri OperatorApplyContext op_apply_ctx = (OperatorApplyContext)ctx; 147e83e87a5Sjeremylt 148e83e87a5Sjeremylt PetscFunctionBeginUser; 149e83e87a5Sjeremylt 150e83e87a5Sjeremylt // libCEED for local action of residual evaluator 151d4d45553Srezgarshakeri ierr = ApplyLocal_Ceed(X, Y, op_apply_ctx); CHKERRQ(ierr); 152e83e87a5Sjeremylt 153e83e87a5Sjeremylt PetscFunctionReturn(0); 154e83e87a5Sjeremylt }; 155e83e87a5Sjeremylt 156e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 157e83e87a5Sjeremylt // This function uses libCEED to compute the action of the prolongation operator 158e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 159e83e87a5Sjeremylt PetscErrorCode MatMult_Prolong(Mat A, Vec X, Vec Y) { 160e83e87a5Sjeremylt PetscErrorCode ierr; 161d4d45553Srezgarshakeri ProlongRestrContext pr_restr_ctx; 162e83e87a5Sjeremylt PetscScalar *c, *f; 1639b072555Sjeremylt PetscMemType c_mem_type, f_mem_type; 164e83e87a5Sjeremylt 165e83e87a5Sjeremylt PetscFunctionBeginUser; 166e83e87a5Sjeremylt 167d4d45553Srezgarshakeri ierr = MatShellGetContext(A, &pr_restr_ctx); CHKERRQ(ierr); 168e83e87a5Sjeremylt 169e83e87a5Sjeremylt // Global-to-local 170d4d45553Srezgarshakeri ierr = VecZeroEntries(pr_restr_ctx->loc_vec_c); CHKERRQ(ierr); 171d4d45553Srezgarshakeri ierr = DMGlobalToLocal(pr_restr_ctx->dmc, X, INSERT_VALUES, 172d4d45553Srezgarshakeri pr_restr_ctx->loc_vec_c); 173e83e87a5Sjeremylt CHKERRQ(ierr); 174e83e87a5Sjeremylt 175e83e87a5Sjeremylt // Setup libCEED vectors 176d4d45553Srezgarshakeri ierr = VecGetArrayReadAndMemType(pr_restr_ctx->loc_vec_c, 177d4d45553Srezgarshakeri (const PetscScalar **)&c, 1789b072555Sjeremylt &c_mem_type); CHKERRQ(ierr); 179d4d45553Srezgarshakeri ierr = VecGetArrayAndMemType(pr_restr_ctx->loc_vec_f, &f, &f_mem_type); 180d4d45553Srezgarshakeri CHKERRQ(ierr); 181d4d45553Srezgarshakeri CeedVectorSetArray(pr_restr_ctx->ceed_vec_c, MemTypeP2C(c_mem_type), 182d4d45553Srezgarshakeri CEED_USE_POINTER, c); 183d4d45553Srezgarshakeri CeedVectorSetArray(pr_restr_ctx->ceed_vec_f, MemTypeP2C(f_mem_type), 184d4d45553Srezgarshakeri CEED_USE_POINTER, f); 185e83e87a5Sjeremylt 186e83e87a5Sjeremylt // Apply libCEED operator 187d4d45553Srezgarshakeri CeedOperatorApply(pr_restr_ctx->op_prolong, pr_restr_ctx->ceed_vec_c, 188d4d45553Srezgarshakeri pr_restr_ctx->ceed_vec_f, CEED_REQUEST_IMMEDIATE); 189e83e87a5Sjeremylt 190e83e87a5Sjeremylt // Restore PETSc vectors 191d4d45553Srezgarshakeri CeedVectorTakeArray(pr_restr_ctx->ceed_vec_c, MemTypeP2C(c_mem_type), NULL); 192d4d45553Srezgarshakeri CeedVectorTakeArray(pr_restr_ctx->ceed_vec_f, MemTypeP2C(f_mem_type), NULL); 193d4d45553Srezgarshakeri ierr = VecRestoreArrayReadAndMemType(pr_restr_ctx->loc_vec_c, 194d4d45553Srezgarshakeri (const PetscScalar **)&c); 195e83e87a5Sjeremylt CHKERRQ(ierr); 196d4d45553Srezgarshakeri ierr = VecRestoreArrayAndMemType(pr_restr_ctx->loc_vec_f, &f); CHKERRQ(ierr); 197e83e87a5Sjeremylt 198e83e87a5Sjeremylt // Multiplicity 199d4d45553Srezgarshakeri ierr = VecPointwiseMult(pr_restr_ctx->loc_vec_f, pr_restr_ctx->loc_vec_f, 200d4d45553Srezgarshakeri pr_restr_ctx->mult_vec); 201e83e87a5Sjeremylt 202e83e87a5Sjeremylt // Local-to-global 203e83e87a5Sjeremylt ierr = VecZeroEntries(Y); CHKERRQ(ierr); 204d4d45553Srezgarshakeri ierr = DMLocalToGlobal(pr_restr_ctx->dmf, pr_restr_ctx->loc_vec_f, ADD_VALUES, 205d4d45553Srezgarshakeri Y); CHKERRQ(ierr); 206e83e87a5Sjeremylt 207e83e87a5Sjeremylt PetscFunctionReturn(0); 208e83e87a5Sjeremylt }; 209e83e87a5Sjeremylt 210e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 211e83e87a5Sjeremylt // This function uses libCEED to compute the action of the restriction operator 212e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 213e83e87a5Sjeremylt PetscErrorCode MatMult_Restrict(Mat A, Vec X, Vec Y) { 214e83e87a5Sjeremylt PetscErrorCode ierr; 215d4d45553Srezgarshakeri ProlongRestrContext pr_restr_ctx; 216e83e87a5Sjeremylt PetscScalar *c, *f; 2179b072555Sjeremylt PetscMemType c_mem_type, f_mem_type; 218e83e87a5Sjeremylt 219e83e87a5Sjeremylt PetscFunctionBeginUser; 220e83e87a5Sjeremylt 221d4d45553Srezgarshakeri ierr = MatShellGetContext(A, &pr_restr_ctx); CHKERRQ(ierr); 222e83e87a5Sjeremylt 223e83e87a5Sjeremylt // Global-to-local 224d4d45553Srezgarshakeri ierr = VecZeroEntries(pr_restr_ctx->loc_vec_f); CHKERRQ(ierr); 225d4d45553Srezgarshakeri ierr = DMGlobalToLocal(pr_restr_ctx->dmf, X, INSERT_VALUES, 226d4d45553Srezgarshakeri pr_restr_ctx->loc_vec_f); 227e83e87a5Sjeremylt CHKERRQ(ierr); 228e83e87a5Sjeremylt 229e83e87a5Sjeremylt // Multiplicity 230d4d45553Srezgarshakeri ierr = VecPointwiseMult(pr_restr_ctx->loc_vec_f, pr_restr_ctx->loc_vec_f, 231d4d45553Srezgarshakeri pr_restr_ctx->mult_vec); 232e83e87a5Sjeremylt CHKERRQ(ierr); 233e83e87a5Sjeremylt 234e83e87a5Sjeremylt // Setup libCEED vectors 235d4d45553Srezgarshakeri ierr = VecGetArrayReadAndMemType(pr_restr_ctx->loc_vec_f, 236d4d45553Srezgarshakeri (const PetscScalar **)&f, 2379b072555Sjeremylt &f_mem_type); CHKERRQ(ierr); 238d4d45553Srezgarshakeri ierr = VecGetArrayAndMemType(pr_restr_ctx->loc_vec_c, &c, &c_mem_type); 239d4d45553Srezgarshakeri CHKERRQ(ierr); 240d4d45553Srezgarshakeri CeedVectorSetArray(pr_restr_ctx->ceed_vec_f, MemTypeP2C(f_mem_type), 241d4d45553Srezgarshakeri CEED_USE_POINTER, f); 242d4d45553Srezgarshakeri CeedVectorSetArray(pr_restr_ctx->ceed_vec_c, MemTypeP2C(c_mem_type), 243d4d45553Srezgarshakeri CEED_USE_POINTER, c); 244e83e87a5Sjeremylt 245e83e87a5Sjeremylt // Apply CEED operator 246d4d45553Srezgarshakeri CeedOperatorApply(pr_restr_ctx->op_restrict, pr_restr_ctx->ceed_vec_f, 247d4d45553Srezgarshakeri pr_restr_ctx->ceed_vec_c, CEED_REQUEST_IMMEDIATE); 248e83e87a5Sjeremylt 249e83e87a5Sjeremylt // Restore PETSc vectors 250d4d45553Srezgarshakeri CeedVectorTakeArray(pr_restr_ctx->ceed_vec_c, MemTypeP2C(c_mem_type), NULL); 251d4d45553Srezgarshakeri CeedVectorTakeArray(pr_restr_ctx->ceed_vec_f, MemTypeP2C(f_mem_type), NULL); 252d4d45553Srezgarshakeri ierr = VecRestoreArrayReadAndMemType(pr_restr_ctx->loc_vec_f, 253d4d45553Srezgarshakeri (const PetscScalar **)&f); CHKERRQ(ierr); 254d4d45553Srezgarshakeri ierr = VecRestoreArrayAndMemType(pr_restr_ctx->loc_vec_c, &c); CHKERRQ(ierr); 255e83e87a5Sjeremylt 256e83e87a5Sjeremylt // Local-to-global 257e83e87a5Sjeremylt ierr = VecZeroEntries(Y); CHKERRQ(ierr); 258d4d45553Srezgarshakeri ierr = DMLocalToGlobal(pr_restr_ctx->dmc, pr_restr_ctx->loc_vec_c, ADD_VALUES, 259d4d45553Srezgarshakeri Y); 260e83e87a5Sjeremylt CHKERRQ(ierr); 261e83e87a5Sjeremylt 262e83e87a5Sjeremylt PetscFunctionReturn(0); 263e83e87a5Sjeremylt }; 264e83e87a5Sjeremylt 265e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 266e83e87a5Sjeremylt // This function calculates the error in the final solution 267e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 268*6c88e6a2Srezgarshakeri PetscErrorCode ComputeErrorMax(OperatorApplyContext op_error_ctx, 269e83e87a5Sjeremylt Vec X, CeedVector target, 2709b072555Sjeremylt PetscScalar *max_error) { 271e83e87a5Sjeremylt PetscErrorCode ierr; 272e83e87a5Sjeremylt PetscScalar *x; 2739b072555Sjeremylt PetscMemType mem_type; 274e83e87a5Sjeremylt CeedVector collocated_error; 2751f9221feSJeremy L Thompson CeedSize length; 276e83e87a5Sjeremylt 277e83e87a5Sjeremylt PetscFunctionBeginUser; 278e83e87a5Sjeremylt CeedVectorGetLength(target, &length); 279*6c88e6a2Srezgarshakeri CeedVectorCreate(op_error_ctx->ceed, length, &collocated_error); 280e83e87a5Sjeremylt 281e83e87a5Sjeremylt // Global-to-local 282*6c88e6a2Srezgarshakeri ierr = DMGlobalToLocal(op_error_ctx->dm, X, INSERT_VALUES, op_error_ctx->X_loc); 283d4d45553Srezgarshakeri CHKERRQ(ierr); 284e83e87a5Sjeremylt 285e83e87a5Sjeremylt // Setup CEED vector 286*6c88e6a2Srezgarshakeri ierr = VecGetArrayAndMemType(op_error_ctx->X_loc, &x, &mem_type); CHKERRQ(ierr); 287*6c88e6a2Srezgarshakeri CeedVectorSetArray(op_error_ctx->x_ceed, MemTypeP2C(mem_type), 288d4d45553Srezgarshakeri CEED_USE_POINTER, x); 289e83e87a5Sjeremylt 290e83e87a5Sjeremylt // Apply CEED operator 291*6c88e6a2Srezgarshakeri CeedOperatorApply(op_error_ctx->op, op_error_ctx->x_ceed, collocated_error, 292e83e87a5Sjeremylt CEED_REQUEST_IMMEDIATE); 293e83e87a5Sjeremylt 294e83e87a5Sjeremylt // Restore PETSc vector 295*6c88e6a2Srezgarshakeri CeedVectorTakeArray(op_error_ctx->x_ceed, MemTypeP2C(mem_type), NULL); 296*6c88e6a2Srezgarshakeri ierr = VecRestoreArrayReadAndMemType(op_error_ctx->X_loc, 297d4d45553Srezgarshakeri (const PetscScalar **)&x); 298e83e87a5Sjeremylt CHKERRQ(ierr); 299e83e87a5Sjeremylt 300e83e87a5Sjeremylt // Reduce max error 3019b072555Sjeremylt *max_error = 0; 302e83e87a5Sjeremylt const CeedScalar *e; 303e83e87a5Sjeremylt CeedVectorGetArrayRead(collocated_error, CEED_MEM_HOST, &e); 304e83e87a5Sjeremylt for (CeedInt i=0; i<length; i++) { 3059b072555Sjeremylt *max_error = PetscMax(*max_error, PetscAbsScalar(e[i])); 306e83e87a5Sjeremylt } 307e83e87a5Sjeremylt CeedVectorRestoreArrayRead(collocated_error, &e); 3089b072555Sjeremylt ierr = MPI_Allreduce(MPI_IN_PLACE, max_error, 1, MPIU_REAL, MPIU_MAX, 309*6c88e6a2Srezgarshakeri op_error_ctx->comm); 310e83e87a5Sjeremylt CHKERRQ(ierr); 311e83e87a5Sjeremylt 312e83e87a5Sjeremylt // Cleanup 313e83e87a5Sjeremylt CeedVectorDestroy(&collocated_error); 314e83e87a5Sjeremylt 315e83e87a5Sjeremylt PetscFunctionReturn(0); 316e83e87a5Sjeremylt }; 317e83e87a5Sjeremylt 318e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 319