xref: /libCEED/examples/solids/src/matops.c (revision 2b730f8b5a9c809740a0b3b302db43a719c636b1)
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