13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 33d8e8822SJeremy L Thompson // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 53d8e8822SJeremy L Thompson // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 73d8e8822SJeremy L Thompson 8ccaff030SJeremy L Thompson /// @file 9ccaff030SJeremy L Thompson /// Matrix shell operations for solid mechanics example using PETSc 10ccaff030SJeremy L Thompson 115754ecacSJeremy L Thompson #include "../include/matops.h" 12*2b730f8bSJeremy L Thompson 135754ecacSJeremy L Thompson #include "../include/structs.h" 145754ecacSJeremy L Thompson #include "../include/utils.h" 15ccaff030SJeremy L Thompson 16ccaff030SJeremy L Thompson // ----------------------------------------------------------------------------- 17ccaff030SJeremy L Thompson // libCEED Operators for MatShell 18ccaff030SJeremy L Thompson // ----------------------------------------------------------------------------- 19ccaff030SJeremy L Thompson // This function uses libCEED to compute the local action of an operator 20ccaff030SJeremy L Thompson PetscErrorCode ApplyLocalCeedOp(Vec X, Vec Y, UserMult user) { 21ccaff030SJeremy L Thompson PetscScalar *x, *y; 22d1d35e2fSjeremylt PetscMemType x_mem_type, y_mem_type; 23ccaff030SJeremy L Thompson 24ccaff030SJeremy L Thompson PetscFunctionBeginUser; 25ccaff030SJeremy L Thompson 26ccaff030SJeremy L Thompson // Global-to-local 27*2b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(user->dm, X, INSERT_VALUES, user->X_loc)); 28*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->Y_loc)); 29ccaff030SJeremy L Thompson 30ccaff030SJeremy L Thompson // Setup CEED vectors 31*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x, &x_mem_type)); 32*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(user->Y_loc, &y, &y_mem_type)); 33d1d35e2fSjeremylt CeedVectorSetArray(user->x_ceed, MemTypeP2C(x_mem_type), CEED_USE_POINTER, x); 34d1d35e2fSjeremylt CeedVectorSetArray(user->y_ceed, MemTypeP2C(y_mem_type), CEED_USE_POINTER, y); 35ccaff030SJeremy L Thompson 36ccaff030SJeremy L Thompson // Apply CEED operator 37d1d35e2fSjeremylt CeedOperatorApply(user->op, user->x_ceed, user->y_ceed, CEED_REQUEST_IMMEDIATE); 38ccaff030SJeremy L Thompson 39ccaff030SJeremy L Thompson // Restore PETSc vectors 40d1d35e2fSjeremylt CeedVectorTakeArray(user->x_ceed, MemTypeP2C(x_mem_type), NULL); 41d1d35e2fSjeremylt CeedVectorTakeArray(user->y_ceed, MemTypeP2C(y_mem_type), NULL); 42*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x)); 43*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayAndMemType(user->Y_loc, &y)); 44ccaff030SJeremy L Thompson 45ccaff030SJeremy L Thompson // Local-to-global 46*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Y)); 47*2b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(user->dm, user->Y_loc, ADD_VALUES, Y)); 48ccaff030SJeremy L Thompson 49ccaff030SJeremy L Thompson PetscFunctionReturn(0); 50ccaff030SJeremy L Thompson }; 51ccaff030SJeremy L Thompson 52ccaff030SJeremy L Thompson // This function uses libCEED to compute the non-linear residual 53ccaff030SJeremy L Thompson PetscErrorCode FormResidual_Ceed(SNES snes, Vec X, Vec Y, void *ctx) { 54ccaff030SJeremy L Thompson UserMult user = (UserMult)ctx; 55ccaff030SJeremy L Thompson 56ccaff030SJeremy L Thompson PetscFunctionBeginUser; 57ccaff030SJeremy L Thompson 58ccaff030SJeremy L Thompson // Use computed BCs 59*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->X_loc)); 60*2b730f8bSJeremy L Thompson PetscCall(DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, user->X_loc, user->load_increment, NULL, NULL, NULL)); 61ccaff030SJeremy L Thompson 62ccaff030SJeremy L Thompson // libCEED for local action of residual evaluator 63*2b730f8bSJeremy L Thompson PetscCall(ApplyLocalCeedOp(X, Y, user)); 64ccaff030SJeremy L Thompson 65fe394131Sjeremylt // Neumann BCs 66d1d35e2fSjeremylt if (user->neumann_bcs) { 67*2b730f8bSJeremy L Thompson PetscCall(VecAXPY(Y, -user->load_increment, user->neumann_bcs)); 68fe394131Sjeremylt } 69fe394131Sjeremylt 70ccaff030SJeremy L Thompson PetscFunctionReturn(0); 71ccaff030SJeremy L Thompson }; 72ccaff030SJeremy L Thompson 73ccaff030SJeremy L Thompson // This function uses libCEED to apply the Jacobian for assembly via a SNES 74ccaff030SJeremy L Thompson PetscErrorCode ApplyJacobianCoarse_Ceed(SNES snes, Vec X, Vec Y, void *ctx) { 75ccaff030SJeremy L Thompson UserMult user = (UserMult)ctx; 76ccaff030SJeremy L Thompson 77ccaff030SJeremy L Thompson PetscFunctionBeginUser; 78ccaff030SJeremy L Thompson 7962e9c006SJeremy L Thompson // Zero boundary values 80*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->X_loc)); 81ccaff030SJeremy L Thompson 82ccaff030SJeremy L Thompson // libCEED for local action of residual evaluator 83*2b730f8bSJeremy L Thompson PetscCall(ApplyLocalCeedOp(X, Y, user)); 84ccaff030SJeremy L Thompson 85ccaff030SJeremy L Thompson PetscFunctionReturn(0); 86ccaff030SJeremy L Thompson }; 87ccaff030SJeremy L Thompson 88ccaff030SJeremy L Thompson // This function uses libCEED to compute the action of the Jacobian 89ccaff030SJeremy L Thompson PetscErrorCode ApplyJacobian_Ceed(Mat A, Vec X, Vec Y) { 90ccaff030SJeremy L Thompson UserMult user; 91ccaff030SJeremy L Thompson 92ccaff030SJeremy L Thompson PetscFunctionBeginUser; 93ccaff030SJeremy L Thompson 94ccaff030SJeremy L Thompson // Zero boundary values 95*2b730f8bSJeremy L Thompson PetscCall(MatShellGetContext(A, &user)); 96*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->X_loc)); 97ccaff030SJeremy L Thompson 98ccaff030SJeremy L Thompson // libCEED for local action of Jacobian 99*2b730f8bSJeremy L Thompson PetscCall(ApplyLocalCeedOp(X, Y, user)); 100ccaff030SJeremy L Thompson 101ccaff030SJeremy L Thompson PetscFunctionReturn(0); 102ccaff030SJeremy L Thompson }; 103ccaff030SJeremy L Thompson 104ccaff030SJeremy L Thompson // This function uses libCEED to compute the action of the prolongation operator 105ccaff030SJeremy L Thompson PetscErrorCode Prolong_Ceed(Mat A, Vec X, Vec Y) { 106ccaff030SJeremy L Thompson UserMultProlongRestr user; 107ccaff030SJeremy L Thompson PetscScalar *c, *f; 108d1d35e2fSjeremylt PetscMemType c_mem_type, f_mem_type; 109ccaff030SJeremy L Thompson 110ccaff030SJeremy L Thompson PetscFunctionBeginUser; 111ccaff030SJeremy L Thompson 112*2b730f8bSJeremy L Thompson PetscCall(MatShellGetContext(A, &user)); 113ccaff030SJeremy L Thompson 114ccaff030SJeremy L Thompson // Global-to-local 115*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->loc_vec_c)); 116*2b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(user->dm_c, X, INSERT_VALUES, user->loc_vec_c)); 117*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->loc_vec_f)); 118ccaff030SJeremy L Thompson 119ccaff030SJeremy L Thompson // Setup CEED vectors 120*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayReadAndMemType(user->loc_vec_c, (const PetscScalar **)&c, &c_mem_type)); 121*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(user->loc_vec_f, &f, &f_mem_type)); 122*2b730f8bSJeremy L Thompson CeedVectorSetArray(user->ceed_vec_c, MemTypeP2C(c_mem_type), CEED_USE_POINTER, c); 123*2b730f8bSJeremy L Thompson CeedVectorSetArray(user->ceed_vec_f, MemTypeP2C(f_mem_type), CEED_USE_POINTER, f); 124ccaff030SJeremy L Thompson 125ccaff030SJeremy L Thompson // Apply CEED operator 126*2b730f8bSJeremy L Thompson CeedOperatorApply(user->op_prolong, user->ceed_vec_c, user->ceed_vec_f, CEED_REQUEST_IMMEDIATE); 127ccaff030SJeremy L Thompson 128ccaff030SJeremy L Thompson // Restore PETSc vectors 129d1d35e2fSjeremylt CeedVectorTakeArray(user->ceed_vec_c, MemTypeP2C(c_mem_type), NULL); 130d1d35e2fSjeremylt CeedVectorTakeArray(user->ceed_vec_f, MemTypeP2C(f_mem_type), NULL); 131*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayReadAndMemType(user->loc_vec_c, (const PetscScalar **)&c)); 132*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayAndMemType(user->loc_vec_f, &f)); 133ccaff030SJeremy L Thompson 134ccaff030SJeremy L Thompson // Local-to-global 135*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Y)); 136*2b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(user->dm_f, user->loc_vec_f, ADD_VALUES, Y)); 137ccaff030SJeremy L Thompson 138ccaff030SJeremy L Thompson PetscFunctionReturn(0); 139ccaff030SJeremy L Thompson } 140ccaff030SJeremy L Thompson 141ccaff030SJeremy L Thompson // This function uses libCEED to compute the action of the restriction operator 142ccaff030SJeremy L Thompson PetscErrorCode Restrict_Ceed(Mat A, Vec X, Vec Y) { 143ccaff030SJeremy L Thompson UserMultProlongRestr user; 144ccaff030SJeremy L Thompson PetscScalar *c, *f; 145d1d35e2fSjeremylt PetscMemType c_mem_type, f_mem_type; 146ccaff030SJeremy L Thompson 147ccaff030SJeremy L Thompson PetscFunctionBeginUser; 148ccaff030SJeremy L Thompson 149*2b730f8bSJeremy L Thompson PetscCall(MatShellGetContext(A, &user)); 150ccaff030SJeremy L Thompson 151ccaff030SJeremy L Thompson // Global-to-local 152*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->loc_vec_f)); 153*2b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(user->dm_f, X, INSERT_VALUES, user->loc_vec_f)); 154*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->loc_vec_c)); 155ccaff030SJeremy L Thompson 156ccaff030SJeremy L Thompson // Setup CEED vectors 157*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayReadAndMemType(user->loc_vec_f, (const PetscScalar **)&f, &f_mem_type)); 158*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(user->loc_vec_c, &c, &c_mem_type)); 159*2b730f8bSJeremy L Thompson CeedVectorSetArray(user->ceed_vec_f, MemTypeP2C(f_mem_type), CEED_USE_POINTER, f); 160*2b730f8bSJeremy L Thompson CeedVectorSetArray(user->ceed_vec_c, MemTypeP2C(c_mem_type), CEED_USE_POINTER, c); 161ccaff030SJeremy L Thompson 162ccaff030SJeremy L Thompson // Apply CEED operator 163*2b730f8bSJeremy L Thompson CeedOperatorApply(user->op_restrict, user->ceed_vec_f, user->ceed_vec_c, CEED_REQUEST_IMMEDIATE); 164ccaff030SJeremy L Thompson 165ccaff030SJeremy L Thompson // Restore PETSc vectors 166d1d35e2fSjeremylt CeedVectorTakeArray(user->ceed_vec_f, MemTypeP2C(f_mem_type), NULL); 167d1d35e2fSjeremylt CeedVectorTakeArray(user->ceed_vec_c, MemTypeP2C(c_mem_type), NULL); 168*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayReadAndMemType(user->loc_vec_f, (const PetscScalar **)&f)); 169*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayAndMemType(user->loc_vec_c, &c)); 170ccaff030SJeremy L Thompson 171ccaff030SJeremy L Thompson // Local-to-global 172*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Y)); 173*2b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(user->dm_c, user->loc_vec_c, ADD_VALUES, Y)); 174ccaff030SJeremy L Thompson 175ccaff030SJeremy L Thompson PetscFunctionReturn(0); 176ccaff030SJeremy L Thompson }; 1772d93065eSjeremylt 178ccaff030SJeremy L Thompson // This function returns the computed diagonal of the operator 179ccaff030SJeremy L Thompson PetscErrorCode GetDiag_Ceed(Mat A, Vec D) { 180ccaff030SJeremy L Thompson UserMult user; 181ccaff030SJeremy L Thompson 182ccaff030SJeremy L Thompson PetscFunctionBeginUser; 183ccaff030SJeremy L Thompson 184*2b730f8bSJeremy L Thompson PetscCall(MatShellGetContext(A, &user)); 185ccaff030SJeremy L Thompson 186f7b4142eSJeremy L Thompson // -- Set physics context 187*2b730f8bSJeremy L Thompson if (user->ctx_phys_smoother) CeedQFunctionSetContext(user->qf, user->ctx_phys_smoother); 188f7b4142eSJeremy L Thompson 1892bba3ffaSJeremy L Thompson // Compute Diagonal via libCEED 1902bba3ffaSJeremy L Thompson PetscScalar *x; 191d1d35e2fSjeremylt PetscMemType x_mem_type; 1922bba3ffaSJeremy L Thompson 1932bba3ffaSJeremy L Thompson // -- Place PETSc vector in libCEED vector 194*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(user->X_loc, &x, &x_mem_type)); 195d1d35e2fSjeremylt CeedVectorSetArray(user->x_ceed, MemTypeP2C(x_mem_type), CEED_USE_POINTER, x); 1962bba3ffaSJeremy L Thompson 1972bba3ffaSJeremy L Thompson // -- Compute Diagonal 198*2b730f8bSJeremy L Thompson CeedOperatorLinearAssembleDiagonal(user->op, user->x_ceed, CEED_REQUEST_IMMEDIATE); 199ccaff030SJeremy L Thompson 200f7b4142eSJeremy L Thompson // -- Reset physics context 201*2b730f8bSJeremy L Thompson if (user->ctx_phys_smoother) CeedQFunctionSetContext(user->qf, user->ctx_phys); 202f7b4142eSJeremy L Thompson 203ccaff030SJeremy L Thompson // -- Local-to-Global 204d1d35e2fSjeremylt CeedVectorTakeArray(user->x_ceed, MemTypeP2C(x_mem_type), NULL); 205*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayAndMemType(user->X_loc, &x)); 206*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(D)); 207*2b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(user->dm, user->X_loc, ADD_VALUES, D)); 208ccaff030SJeremy L Thompson 2092bba3ffaSJeremy L Thompson // Cleanup 210*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->X_loc)); 211ccaff030SJeremy L Thompson 212ccaff030SJeremy L Thompson PetscFunctionReturn(0); 213ccaff030SJeremy L Thompson }; 2142d93065eSjeremylt 2152d93065eSjeremylt // This function calculates the strain energy in the final solution 216*2b730f8bSJeremy L Thompson PetscErrorCode ComputeStrainEnergy(DM dmEnergy, UserMult user, CeedOperator op_energy, Vec X, PetscReal *energy) { 2172d93065eSjeremylt PetscScalar *x; 218d1d35e2fSjeremylt PetscMemType x_mem_type; 2192d93065eSjeremylt CeedInt length; 2202d93065eSjeremylt 2212d93065eSjeremylt PetscFunctionBeginUser; 2222d93065eSjeremylt 2232d93065eSjeremylt // Global-to-local 224*2b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(user->X_loc)); 225*2b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(user->dm, X, INSERT_VALUES, user->X_loc)); 226*2b730f8bSJeremy L Thompson PetscCall(DMPlexInsertBoundaryValues(user->dm, PETSC_TRUE, user->X_loc, user->load_increment, NULL, NULL, NULL)); 2272d93065eSjeremylt 228a3c02c40SJeremy L Thompson // Setup libCEED input vector 229*2b730f8bSJeremy L Thompson PetscCall(VecGetArrayReadAndMemType(user->X_loc, (const PetscScalar **)&x, &x_mem_type)); 230d1d35e2fSjeremylt CeedVectorSetArray(user->x_ceed, MemTypeP2C(x_mem_type), CEED_USE_POINTER, x); 2312d93065eSjeremylt 232a3c02c40SJeremy L Thompson // Setup libCEED output vector 233d1d35e2fSjeremylt Vec E_loc; 234d1d35e2fSjeremylt CeedVector e_loc; 235*2b730f8bSJeremy L Thompson PetscCall(DMCreateLocalVector(dmEnergy, &E_loc)); 236*2b730f8bSJeremy L Thompson PetscCall(VecGetSize(E_loc, &length)); 237*2b730f8bSJeremy L Thompson PetscCall(VecDestroy(&E_loc)); 238d1d35e2fSjeremylt CeedVectorCreate(user->ceed, length, &e_loc); 239a3c02c40SJeremy L Thompson 2402d93065eSjeremylt // Apply libCEED operator 241d1d35e2fSjeremylt CeedOperatorApply(op_energy, user->x_ceed, e_loc, CEED_REQUEST_IMMEDIATE); 2422d93065eSjeremylt 2432d93065eSjeremylt // Restore PETSc vector 244d1d35e2fSjeremylt CeedVectorTakeArray(user->x_ceed, MemTypeP2C(x_mem_type), NULL); 245*2b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayRead(user->X_loc, (const PetscScalar **)&x)); 2462d93065eSjeremylt 2472d93065eSjeremylt // Reduce max error 2482d93065eSjeremylt const CeedScalar *e; 249d1d35e2fSjeremylt CeedVectorGetArrayRead(e_loc, CEED_MEM_HOST, &e); 2502d93065eSjeremylt (*energy) = 0; 251*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < length; i++) (*energy) += e[i]; 252d1d35e2fSjeremylt CeedVectorRestoreArrayRead(e_loc, &e); 253d1d35e2fSjeremylt CeedVectorDestroy(&e_loc); 2542d93065eSjeremylt 255*2b730f8bSJeremy L Thompson PetscCall(MPI_Allreduce(MPI_IN_PLACE, energy, 1, MPIU_REAL, MPIU_SUM, user->comm)); 2562d93065eSjeremylt 2572d93065eSjeremylt PetscFunctionReturn(0); 2582d93065eSjeremylt }; 259