xref: /libCEED/examples/petsc/src/matops.c (revision e83e87a50f1b2e8810b376a735430565127e4d25)
1*e83e87a5Sjeremylt #include "../include/matops.h"
2*e83e87a5Sjeremylt #include "../include/petscutils.h"
3*e83e87a5Sjeremylt 
4*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
5*e83e87a5Sjeremylt // This function returns the computed diagonal of the operator
6*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
7*e83e87a5Sjeremylt PetscErrorCode MatGetDiag(Mat A, Vec D) {
8*e83e87a5Sjeremylt   PetscErrorCode ierr;
9*e83e87a5Sjeremylt   UserO user;
10*e83e87a5Sjeremylt 
11*e83e87a5Sjeremylt   PetscFunctionBeginUser;
12*e83e87a5Sjeremylt 
13*e83e87a5Sjeremylt   ierr = MatShellGetContext(A, &user); CHKERRQ(ierr);
14*e83e87a5Sjeremylt 
15*e83e87a5Sjeremylt   // Compute Diagonal via libCEED
16*e83e87a5Sjeremylt   PetscScalar *x;
17*e83e87a5Sjeremylt   PetscMemType memtype;
18*e83e87a5Sjeremylt 
19*e83e87a5Sjeremylt   // -- Place PETSc vector in libCEED vector
20*e83e87a5Sjeremylt   ierr = VecGetArrayAndMemType(user->Xloc, &x, &memtype); CHKERRQ(ierr);
21*e83e87a5Sjeremylt   CeedVectorSetArray(user->Xceed, MemTypeP2C(memtype), CEED_USE_POINTER, x);
22*e83e87a5Sjeremylt 
23*e83e87a5Sjeremylt   // -- Compute Diagonal
24*e83e87a5Sjeremylt   CeedOperatorLinearAssembleDiagonal(user->op, user->Xceed,
25*e83e87a5Sjeremylt                                      CEED_REQUEST_IMMEDIATE);
26*e83e87a5Sjeremylt 
27*e83e87a5Sjeremylt   // -- Local-to-Global
28*e83e87a5Sjeremylt   CeedVectorTakeArray(user->Xceed, MemTypeP2C(memtype), NULL);
29*e83e87a5Sjeremylt   ierr = VecRestoreArrayAndMemType(user->Xloc, &x); CHKERRQ(ierr);
30*e83e87a5Sjeremylt   ierr = VecZeroEntries(D); CHKERRQ(ierr);
31*e83e87a5Sjeremylt   ierr = DMLocalToGlobal(user->dm, user->Xloc, ADD_VALUES, D); CHKERRQ(ierr);
32*e83e87a5Sjeremylt 
33*e83e87a5Sjeremylt   // Cleanup
34*e83e87a5Sjeremylt   ierr = VecZeroEntries(user->Xloc); CHKERRQ(ierr);
35*e83e87a5Sjeremylt 
36*e83e87a5Sjeremylt   PetscFunctionReturn(0);
37*e83e87a5Sjeremylt };
38*e83e87a5Sjeremylt 
39*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
40*e83e87a5Sjeremylt // This function uses libCEED to compute the action of the Laplacian with
41*e83e87a5Sjeremylt // Dirichlet boundary conditions
42*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
43*e83e87a5Sjeremylt PetscErrorCode ApplyLocal_Ceed(Vec X, Vec Y, UserO user) {
44*e83e87a5Sjeremylt   PetscErrorCode ierr;
45*e83e87a5Sjeremylt   PetscScalar *x, *y;
46*e83e87a5Sjeremylt   PetscMemType xmemtype, ymemtype;
47*e83e87a5Sjeremylt 
48*e83e87a5Sjeremylt   PetscFunctionBeginUser;
49*e83e87a5Sjeremylt 
50*e83e87a5Sjeremylt   // Global-to-local
51*e83e87a5Sjeremylt   ierr = DMGlobalToLocal(user->dm, X, INSERT_VALUES, user->Xloc); CHKERRQ(ierr);
52*e83e87a5Sjeremylt 
53*e83e87a5Sjeremylt   // Setup libCEED vectors
54*e83e87a5Sjeremylt   ierr = VecGetArrayReadAndMemType(user->Xloc, (const PetscScalar **)&x,
55*e83e87a5Sjeremylt                                    &xmemtype); CHKERRQ(ierr);
56*e83e87a5Sjeremylt   ierr = VecGetArrayAndMemType(user->Yloc, &y, &ymemtype); CHKERRQ(ierr);
57*e83e87a5Sjeremylt   CeedVectorSetArray(user->Xceed, MemTypeP2C(xmemtype), CEED_USE_POINTER, x);
58*e83e87a5Sjeremylt   CeedVectorSetArray(user->Yceed, MemTypeP2C(ymemtype), CEED_USE_POINTER, y);
59*e83e87a5Sjeremylt 
60*e83e87a5Sjeremylt   // Apply libCEED operator
61*e83e87a5Sjeremylt   CeedOperatorApply(user->op, user->Xceed, user->Yceed, CEED_REQUEST_IMMEDIATE);
62*e83e87a5Sjeremylt 
63*e83e87a5Sjeremylt   // Restore PETSc vectors
64*e83e87a5Sjeremylt   CeedVectorTakeArray(user->Xceed, MemTypeP2C(xmemtype), NULL);
65*e83e87a5Sjeremylt   CeedVectorTakeArray(user->Yceed, MemTypeP2C(ymemtype), NULL);
66*e83e87a5Sjeremylt   ierr = VecRestoreArrayReadAndMemType(user->Xloc, (const PetscScalar **)&x);
67*e83e87a5Sjeremylt   CHKERRQ(ierr);
68*e83e87a5Sjeremylt   ierr = VecRestoreArrayAndMemType(user->Yloc, &y); CHKERRQ(ierr);
69*e83e87a5Sjeremylt 
70*e83e87a5Sjeremylt   // Local-to-global
71*e83e87a5Sjeremylt   ierr = VecZeroEntries(Y); CHKERRQ(ierr);
72*e83e87a5Sjeremylt   ierr = DMLocalToGlobal(user->dm, user->Yloc, ADD_VALUES, Y); CHKERRQ(ierr);
73*e83e87a5Sjeremylt 
74*e83e87a5Sjeremylt   PetscFunctionReturn(0);
75*e83e87a5Sjeremylt };
76*e83e87a5Sjeremylt 
77*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
78*e83e87a5Sjeremylt // This function wraps the libCEED operator for a MatShell
79*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
80*e83e87a5Sjeremylt PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) {
81*e83e87a5Sjeremylt   PetscErrorCode ierr;
82*e83e87a5Sjeremylt   UserO user;
83*e83e87a5Sjeremylt 
84*e83e87a5Sjeremylt   PetscFunctionBeginUser;
85*e83e87a5Sjeremylt 
86*e83e87a5Sjeremylt   ierr = MatShellGetContext(A, &user); CHKERRQ(ierr);
87*e83e87a5Sjeremylt 
88*e83e87a5Sjeremylt   // libCEED for local action of residual evaluator
89*e83e87a5Sjeremylt   ierr = ApplyLocal_Ceed(X, Y, user); CHKERRQ(ierr);
90*e83e87a5Sjeremylt 
91*e83e87a5Sjeremylt   PetscFunctionReturn(0);
92*e83e87a5Sjeremylt };
93*e83e87a5Sjeremylt 
94*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
95*e83e87a5Sjeremylt // This function wraps the libCEED operator for a SNES residual evaluation
96*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
97*e83e87a5Sjeremylt PetscErrorCode FormResidual_Ceed(SNES snes, Vec X, Vec Y, void *ctx) {
98*e83e87a5Sjeremylt   PetscErrorCode ierr;
99*e83e87a5Sjeremylt   UserO user = (UserO)ctx;
100*e83e87a5Sjeremylt 
101*e83e87a5Sjeremylt   PetscFunctionBeginUser;
102*e83e87a5Sjeremylt 
103*e83e87a5Sjeremylt   // libCEED for local action of residual evaluator
104*e83e87a5Sjeremylt   ierr = ApplyLocal_Ceed(X, Y, user); CHKERRQ(ierr);
105*e83e87a5Sjeremylt 
106*e83e87a5Sjeremylt   PetscFunctionReturn(0);
107*e83e87a5Sjeremylt };
108*e83e87a5Sjeremylt 
109*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
110*e83e87a5Sjeremylt // This function uses libCEED to compute the action of the prolongation operator
111*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
112*e83e87a5Sjeremylt PetscErrorCode MatMult_Prolong(Mat A, Vec X, Vec Y) {
113*e83e87a5Sjeremylt   PetscErrorCode ierr;
114*e83e87a5Sjeremylt   UserProlongRestr user;
115*e83e87a5Sjeremylt   PetscScalar *c, *f;
116*e83e87a5Sjeremylt   PetscMemType cmemtype, fmemtype;
117*e83e87a5Sjeremylt 
118*e83e87a5Sjeremylt   PetscFunctionBeginUser;
119*e83e87a5Sjeremylt 
120*e83e87a5Sjeremylt   ierr = MatShellGetContext(A, &user); CHKERRQ(ierr);
121*e83e87a5Sjeremylt 
122*e83e87a5Sjeremylt   // Global-to-local
123*e83e87a5Sjeremylt   ierr = VecZeroEntries(user->locvecc); CHKERRQ(ierr);
124*e83e87a5Sjeremylt   ierr = DMGlobalToLocal(user->dmc, X, INSERT_VALUES, user->locvecc);
125*e83e87a5Sjeremylt   CHKERRQ(ierr);
126*e83e87a5Sjeremylt 
127*e83e87a5Sjeremylt   // Setup libCEED vectors
128*e83e87a5Sjeremylt   ierr = VecGetArrayReadAndMemType(user->locvecc, (const PetscScalar **)&c,
129*e83e87a5Sjeremylt                                    &cmemtype); CHKERRQ(ierr);
130*e83e87a5Sjeremylt   ierr = VecGetArrayAndMemType(user->locvecf, &f, &fmemtype); CHKERRQ(ierr);
131*e83e87a5Sjeremylt   CeedVectorSetArray(user->ceedvecc, MemTypeP2C(cmemtype), CEED_USE_POINTER, c);
132*e83e87a5Sjeremylt   CeedVectorSetArray(user->ceedvecf, MemTypeP2C(fmemtype), CEED_USE_POINTER, f);
133*e83e87a5Sjeremylt 
134*e83e87a5Sjeremylt   // Apply libCEED operator
135*e83e87a5Sjeremylt   CeedOperatorApply(user->opProlong, user->ceedvecc, user->ceedvecf,
136*e83e87a5Sjeremylt                     CEED_REQUEST_IMMEDIATE);
137*e83e87a5Sjeremylt 
138*e83e87a5Sjeremylt   // Restore PETSc vectors
139*e83e87a5Sjeremylt   CeedVectorTakeArray(user->ceedvecc, MemTypeP2C(cmemtype), NULL);
140*e83e87a5Sjeremylt   CeedVectorTakeArray(user->ceedvecf, MemTypeP2C(fmemtype), NULL);
141*e83e87a5Sjeremylt   ierr = VecRestoreArrayReadAndMemType(user->locvecc, (const PetscScalar **)&c);
142*e83e87a5Sjeremylt   CHKERRQ(ierr);
143*e83e87a5Sjeremylt   ierr = VecRestoreArrayAndMemType(user->locvecf, &f); CHKERRQ(ierr);
144*e83e87a5Sjeremylt 
145*e83e87a5Sjeremylt   // Multiplicity
146*e83e87a5Sjeremylt   ierr = VecPointwiseMult(user->locvecf, user->locvecf, user->multvec);
147*e83e87a5Sjeremylt 
148*e83e87a5Sjeremylt   // Local-to-global
149*e83e87a5Sjeremylt   ierr = VecZeroEntries(Y); CHKERRQ(ierr);
150*e83e87a5Sjeremylt   ierr = DMLocalToGlobal(user->dmf, user->locvecf, ADD_VALUES, Y);
151*e83e87a5Sjeremylt   CHKERRQ(ierr);
152*e83e87a5Sjeremylt 
153*e83e87a5Sjeremylt   PetscFunctionReturn(0);
154*e83e87a5Sjeremylt };
155*e83e87a5Sjeremylt 
156*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
157*e83e87a5Sjeremylt // This function uses libCEED to compute the action of the restriction operator
158*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
159*e83e87a5Sjeremylt PetscErrorCode MatMult_Restrict(Mat A, Vec X, Vec Y) {
160*e83e87a5Sjeremylt   PetscErrorCode ierr;
161*e83e87a5Sjeremylt   UserProlongRestr user;
162*e83e87a5Sjeremylt   PetscScalar *c, *f;
163*e83e87a5Sjeremylt   PetscMemType cmemtype, fmemtype;
164*e83e87a5Sjeremylt 
165*e83e87a5Sjeremylt   PetscFunctionBeginUser;
166*e83e87a5Sjeremylt 
167*e83e87a5Sjeremylt   ierr = MatShellGetContext(A, &user); CHKERRQ(ierr);
168*e83e87a5Sjeremylt 
169*e83e87a5Sjeremylt   // Global-to-local
170*e83e87a5Sjeremylt   ierr = VecZeroEntries(user->locvecf); CHKERRQ(ierr);
171*e83e87a5Sjeremylt   ierr = DMGlobalToLocal(user->dmf, X, INSERT_VALUES, user->locvecf);
172*e83e87a5Sjeremylt   CHKERRQ(ierr);
173*e83e87a5Sjeremylt 
174*e83e87a5Sjeremylt   // Multiplicity
175*e83e87a5Sjeremylt   ierr = VecPointwiseMult(user->locvecf, user->locvecf, user->multvec);
176*e83e87a5Sjeremylt   CHKERRQ(ierr);
177*e83e87a5Sjeremylt 
178*e83e87a5Sjeremylt   // Setup libCEED vectors
179*e83e87a5Sjeremylt   ierr = VecGetArrayReadAndMemType(user->locvecf, (const PetscScalar **)&f,
180*e83e87a5Sjeremylt                                    &fmemtype); CHKERRQ(ierr);
181*e83e87a5Sjeremylt   ierr = VecGetArrayAndMemType(user->locvecc, &c, &cmemtype); CHKERRQ(ierr);
182*e83e87a5Sjeremylt   CeedVectorSetArray(user->ceedvecf, MemTypeP2C(fmemtype), CEED_USE_POINTER, f);
183*e83e87a5Sjeremylt   CeedVectorSetArray(user->ceedvecc, MemTypeP2C(cmemtype), CEED_USE_POINTER, c);
184*e83e87a5Sjeremylt 
185*e83e87a5Sjeremylt   // Apply CEED operator
186*e83e87a5Sjeremylt   CeedOperatorApply(user->opRestrict, user->ceedvecf, user->ceedvecc,
187*e83e87a5Sjeremylt                     CEED_REQUEST_IMMEDIATE);
188*e83e87a5Sjeremylt 
189*e83e87a5Sjeremylt   // Restore PETSc vectors
190*e83e87a5Sjeremylt   CeedVectorTakeArray(user->ceedvecc, MemTypeP2C(cmemtype), NULL);
191*e83e87a5Sjeremylt   CeedVectorTakeArray(user->ceedvecf, MemTypeP2C(fmemtype), NULL);
192*e83e87a5Sjeremylt   ierr = VecRestoreArrayReadAndMemType(user->locvecf, (const PetscScalar **)&f);
193*e83e87a5Sjeremylt   CHKERRQ(ierr);
194*e83e87a5Sjeremylt   ierr = VecRestoreArrayAndMemType(user->locvecc, &c); CHKERRQ(ierr);
195*e83e87a5Sjeremylt 
196*e83e87a5Sjeremylt   // Local-to-global
197*e83e87a5Sjeremylt   ierr = VecZeroEntries(Y); CHKERRQ(ierr);
198*e83e87a5Sjeremylt   ierr = DMLocalToGlobal(user->dmc, user->locvecc, ADD_VALUES, Y);
199*e83e87a5Sjeremylt   CHKERRQ(ierr);
200*e83e87a5Sjeremylt 
201*e83e87a5Sjeremylt   PetscFunctionReturn(0);
202*e83e87a5Sjeremylt };
203*e83e87a5Sjeremylt 
204*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
205*e83e87a5Sjeremylt // This function calculates the error in the final solution
206*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
207*e83e87a5Sjeremylt PetscErrorCode ComputeErrorMax(UserO user, CeedOperator opError,
208*e83e87a5Sjeremylt                                Vec X, CeedVector target,
209*e83e87a5Sjeremylt                                PetscScalar *maxerror) {
210*e83e87a5Sjeremylt   PetscErrorCode ierr;
211*e83e87a5Sjeremylt   PetscScalar *x;
212*e83e87a5Sjeremylt   PetscMemType memtype;
213*e83e87a5Sjeremylt   CeedVector collocated_error;
214*e83e87a5Sjeremylt   CeedInt length;
215*e83e87a5Sjeremylt 
216*e83e87a5Sjeremylt   PetscFunctionBeginUser;
217*e83e87a5Sjeremylt   CeedVectorGetLength(target, &length);
218*e83e87a5Sjeremylt   CeedVectorCreate(user->ceed, length, &collocated_error);
219*e83e87a5Sjeremylt 
220*e83e87a5Sjeremylt   // Global-to-local
221*e83e87a5Sjeremylt   ierr = DMGlobalToLocal(user->dm, X, INSERT_VALUES, user->Xloc); CHKERRQ(ierr);
222*e83e87a5Sjeremylt 
223*e83e87a5Sjeremylt   // Setup CEED vector
224*e83e87a5Sjeremylt   ierr = VecGetArrayAndMemType(user->Xloc, &x, &memtype); CHKERRQ(ierr);
225*e83e87a5Sjeremylt   CeedVectorSetArray(user->Xceed, MemTypeP2C(memtype), CEED_USE_POINTER, x);
226*e83e87a5Sjeremylt 
227*e83e87a5Sjeremylt   // Apply CEED operator
228*e83e87a5Sjeremylt   CeedOperatorApply(opError, user->Xceed, collocated_error,
229*e83e87a5Sjeremylt                     CEED_REQUEST_IMMEDIATE);
230*e83e87a5Sjeremylt 
231*e83e87a5Sjeremylt   // Restore PETSc vector
232*e83e87a5Sjeremylt   CeedVectorTakeArray(user->Xceed, MemTypeP2C(memtype), NULL);
233*e83e87a5Sjeremylt   ierr = VecRestoreArrayReadAndMemType(user->Xloc, (const PetscScalar **)&x);
234*e83e87a5Sjeremylt   CHKERRQ(ierr);
235*e83e87a5Sjeremylt 
236*e83e87a5Sjeremylt   // Reduce max error
237*e83e87a5Sjeremylt   *maxerror = 0;
238*e83e87a5Sjeremylt   const CeedScalar *e;
239*e83e87a5Sjeremylt   CeedVectorGetArrayRead(collocated_error, CEED_MEM_HOST, &e);
240*e83e87a5Sjeremylt   for (CeedInt i=0; i<length; i++) {
241*e83e87a5Sjeremylt     *maxerror = PetscMax(*maxerror, PetscAbsScalar(e[i]));
242*e83e87a5Sjeremylt   }
243*e83e87a5Sjeremylt   CeedVectorRestoreArrayRead(collocated_error, &e);
244*e83e87a5Sjeremylt   ierr = MPI_Allreduce(MPI_IN_PLACE, maxerror, 1, MPIU_REAL, MPIU_MAX,
245*e83e87a5Sjeremylt                        user->comm);
246*e83e87a5Sjeremylt   CHKERRQ(ierr);
247*e83e87a5Sjeremylt 
248*e83e87a5Sjeremylt   // Cleanup
249*e83e87a5Sjeremylt   CeedVectorDestroy(&collocated_error);
250*e83e87a5Sjeremylt 
251*e83e87a5Sjeremylt   PetscFunctionReturn(0);
252*e83e87a5Sjeremylt };
253*e83e87a5Sjeremylt 
254*e83e87a5Sjeremylt // -----------------------------------------------------------------------------
255