xref: /libCEED/examples/petsc/src/libceedsetup.c (revision 4baa7aec0dd4cb16a4e44df395cefec334617a2e)
1 // Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 #include "../include/libceedsetup.h"
9 
10 #include <stdio.h>
11 
12 #include "../include/libceedsetup.h"
13 #include "../include/petscutils.h"
14 
15 // -----------------------------------------------------------------------------
16 // Destroy libCEED operator objects
17 // -----------------------------------------------------------------------------
18 PetscErrorCode CeedDataDestroy(CeedInt i, CeedData data) {
19   PetscFunctionBeginUser;
20   CeedVectorDestroy(&data->q_data);
21   CeedVectorDestroy(&data->x_ceed);
22   CeedVectorDestroy(&data->y_ceed);
23   CeedBasisDestroy(&data->basis_x);
24   CeedBasisDestroy(&data->basis_u);
25   CeedElemRestrictionDestroy(&data->elem_restr_u);
26   CeedElemRestrictionDestroy(&data->elem_restr_x);
27   CeedElemRestrictionDestroy(&data->elem_restr_u_i);
28   CeedElemRestrictionDestroy(&data->elem_restr_qd_i);
29   CeedQFunctionDestroy(&data->qf_apply);
30   CeedOperatorDestroy(&data->op_apply);
31   if (i > 0) {
32     CeedOperatorDestroy(&data->op_prolong);
33     CeedOperatorDestroy(&data->op_restrict);
34   }
35   PetscCall(PetscFree(data));
36   PetscFunctionReturn(PETSC_SUCCESS);
37 };
38 
39 // -----------------------------------------------------------------------------
40 // Set up libCEED for a given degree
41 // -----------------------------------------------------------------------------
42 PetscErrorCode SetupLibceedByDegree(DM dm, Ceed ceed, CeedInt degree, CeedInt topo_dim, CeedInt q_extra, PetscInt num_comp_x, PetscInt num_comp_u,
43                                     PetscInt g_size, PetscInt xl_size, BPData bp_data, CeedData data, PetscBool setup_rhs, PetscBool is_fine_level,
44                                     CeedVector rhs_ceed, CeedVector *target) {
45   DM                  dm_coord;
46   Vec                 coords;
47   const PetscScalar  *coord_array;
48   CeedBasis           basis_x, basis_u;
49   CeedElemRestriction elem_restr_x, elem_restr_u, elem_restr_u_i, elem_restr_qd_i;
50   CeedQFunction       qf_setup_geo = NULL, qf_apply = NULL;
51   CeedOperator        op_setup_geo, op_apply;
52   CeedVector          x_coord, q_data, x_ceed, y_ceed;
53   PetscInt            c_start, c_end, num_elem;
54   CeedInt             num_qpts, q_data_size = bp_data.q_data_size;
55   CeedScalar          R = 1;                         // radius of the sphere
56   CeedScalar          l = 1.0 / PetscSqrtReal(3.0);  // half edge of the inscribed cube
57 
58   PetscFunctionBeginUser;
59   PetscCall(DMGetCoordinateDM(dm, &dm_coord));
60 
61   // CEED bases
62   PetscCall(CreateBasisFromPlex(ceed, dm_coord, 0, 0, 0, 0, bp_data, &basis_x));
63   PetscCall(CreateBasisFromPlex(ceed, dm, 0, 0, 0, 0, bp_data, &basis_u));
64 
65   // CEED restrictions
66   PetscCall(CreateRestrictionFromPlex(ceed, dm_coord, 0, 0, 0, &elem_restr_x));
67   PetscCall(CreateRestrictionFromPlex(ceed, dm, 0, 0, 0, &elem_restr_u));
68 
69   PetscCall(DMPlexGetHeightStratum(dm, 0, &c_start, &c_end));
70   num_elem = c_end - c_start;
71   CeedBasisGetNumQuadraturePoints(basis_u, &num_qpts);
72 
73   CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, num_comp_u, num_comp_u * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_u_i);
74   CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, q_data_size, q_data_size * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_qd_i);
75 
76   // Element coordinates
77   PetscCall(DMGetCoordinatesLocal(dm, &coords));
78   PetscCall(VecGetArrayRead(coords, &coord_array));
79 
80   CeedElemRestrictionCreateVector(elem_restr_x, &x_coord, NULL);
81   CeedVectorSetArray(x_coord, CEED_MEM_HOST, CEED_COPY_VALUES, (PetscScalar *)coord_array);
82   PetscCall(VecRestoreArrayRead(coords, &coord_array));
83 
84   // Create the persistent vectors that will be needed in setup and apply
85   CeedVectorCreate(ceed, q_data_size * num_elem * num_qpts, &q_data);
86   CeedVectorCreate(ceed, xl_size, &x_ceed);
87   CeedVectorCreate(ceed, xl_size, &y_ceed);
88 
89   if (is_fine_level) {
90     // Create the QFunction that builds the context data
91     CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_geo, bp_data.setup_geo_loc, &qf_setup_geo);
92     CeedQFunctionAddInput(qf_setup_geo, "x", num_comp_x, CEED_EVAL_INTERP);
93     CeedQFunctionAddInput(qf_setup_geo, "dx", num_comp_x * topo_dim, CEED_EVAL_GRAD);
94     CeedQFunctionAddInput(qf_setup_geo, "weight", 1, CEED_EVAL_WEIGHT);
95     CeedQFunctionAddOutput(qf_setup_geo, "qdata", q_data_size, CEED_EVAL_NONE);
96 
97     // Create the operator that builds the quadrature data
98     CeedOperatorCreate(ceed, qf_setup_geo, NULL, NULL, &op_setup_geo);
99     CeedOperatorSetField(op_setup_geo, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
100     CeedOperatorSetField(op_setup_geo, "dx", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
101     CeedOperatorSetField(op_setup_geo, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
102     CeedOperatorSetField(op_setup_geo, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
103 
104     // Setup q_data
105     CeedOperatorApply(op_setup_geo, x_coord, q_data, CEED_REQUEST_IMMEDIATE);
106 
107     // Set up PDE operator
108     PetscBool is_interp = bp_data.in_mode == CEED_EVAL_INTERP;
109     CeedInt   in_scale  = bp_data.in_mode == CEED_EVAL_GRAD ? topo_dim : 1;
110     CeedInt   out_scale = bp_data.out_mode == CEED_EVAL_GRAD ? topo_dim : 1;
111 
112     CeedQFunctionCreateInterior(ceed, 1, bp_data.apply, bp_data.apply_loc, &qf_apply);
113     if (bp_data.in_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
114       CeedQFunctionAddInput(qf_apply, "u", num_comp_u, CEED_EVAL_INTERP);
115       CeedQFunctionAddInput(qf_apply, "du", num_comp_u * topo_dim, CEED_EVAL_GRAD);
116     } else {
117       CeedQFunctionAddInput(qf_apply, is_interp ? "u" : "du", num_comp_u * in_scale, bp_data.in_mode);
118     }
119     CeedQFunctionAddInput(qf_apply, "qdata", q_data_size, CEED_EVAL_NONE);
120     if (bp_data.out_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
121       CeedQFunctionAddOutput(qf_apply, "v", num_comp_u, CEED_EVAL_INTERP);
122       CeedQFunctionAddOutput(qf_apply, "dv", num_comp_u * topo_dim, CEED_EVAL_GRAD);
123     } else {
124       CeedQFunctionAddOutput(qf_apply, is_interp ? "v" : "dv", num_comp_u * out_scale, bp_data.out_mode);
125     }
126 
127     // Create the mass or diff operator
128     CeedOperatorCreate(ceed, qf_apply, NULL, NULL, &op_apply);
129     if (bp_data.in_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
130       CeedOperatorSetField(op_apply, "u", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
131       CeedOperatorSetField(op_apply, "du", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
132     } else {
133       CeedOperatorSetField(op_apply, is_interp ? "u" : "du", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
134     }
135     CeedOperatorSetField(op_apply, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
136     if (bp_data.out_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
137       CeedOperatorSetField(op_apply, "v", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
138       CeedOperatorSetField(op_apply, "dv", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
139     } else {
140       CeedOperatorSetField(op_apply, is_interp ? "v" : "dv", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
141     }
142 
143     // Cleanup
144     CeedQFunctionDestroy(&qf_setup_geo);
145     CeedOperatorDestroy(&op_setup_geo);
146   }
147 
148   // Set up RHS if needed
149   if (setup_rhs) {
150     CeedQFunction qf_setup_rhs;
151     CeedOperator  op_setup_rhs;
152     CeedVectorCreate(ceed, num_elem * num_qpts * num_comp_u, target);
153     // Create the q-function that sets up the RHS and true solution
154     CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_rhs, bp_data.setup_rhs_loc, &qf_setup_rhs);
155     CeedQFunctionAddInput(qf_setup_rhs, "x", num_comp_x, CEED_EVAL_INTERP);
156     CeedQFunctionAddInput(qf_setup_rhs, "qdata", q_data_size, CEED_EVAL_NONE);
157     CeedQFunctionAddOutput(qf_setup_rhs, "true solution", num_comp_u, CEED_EVAL_NONE);
158     CeedQFunctionAddOutput(qf_setup_rhs, "rhs", num_comp_u, CEED_EVAL_INTERP);
159 
160     // Create the operator that builds the RHS and true solution
161     CeedOperatorCreate(ceed, qf_setup_rhs, NULL, NULL, &op_setup_rhs);
162     CeedOperatorSetField(op_setup_rhs, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
163     CeedOperatorSetField(op_setup_rhs, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
164     CeedOperatorSetField(op_setup_rhs, "true solution", elem_restr_u_i, CEED_BASIS_NONE, *target);
165     CeedOperatorSetField(op_setup_rhs, "rhs", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
166 
167     // Set up the libCEED context
168     CeedQFunctionContext ctx_rhs_setup;
169     CeedQFunctionContextCreate(ceed, &ctx_rhs_setup);
170     CeedScalar rhs_setup_data[2] = {R, l};
171     CeedQFunctionContextSetData(ctx_rhs_setup, CEED_MEM_HOST, CEED_COPY_VALUES, sizeof rhs_setup_data, &rhs_setup_data);
172     CeedQFunctionSetContext(qf_setup_rhs, ctx_rhs_setup);
173     CeedQFunctionContextDestroy(&ctx_rhs_setup);
174 
175     // Setup RHS and target
176     CeedOperatorApply(op_setup_rhs, x_coord, rhs_ceed, CEED_REQUEST_IMMEDIATE);
177 
178     // Cleanup
179     CeedQFunctionDestroy(&qf_setup_rhs);
180     CeedOperatorDestroy(&op_setup_rhs);
181   }
182   // Cleanup
183   CeedVectorDestroy(&x_coord);
184 
185   // Save libCEED data required for level
186   data->basis_x         = basis_x;
187   data->basis_u         = basis_u;
188   data->elem_restr_x    = elem_restr_x;
189   data->elem_restr_u    = elem_restr_u;
190   data->elem_restr_u_i  = elem_restr_u_i;
191   data->elem_restr_qd_i = elem_restr_qd_i;
192   data->qf_apply        = qf_apply;
193   data->op_apply        = op_apply;
194   data->q_data          = q_data;
195   data->x_ceed          = x_ceed;
196   data->y_ceed          = y_ceed;
197   data->q_data_size     = q_data_size;
198   PetscFunctionReturn(PETSC_SUCCESS);
199 };
200 
201 // -----------------------------------------------------------------------------
202 // Setup libCEED level transfer operator objects
203 // -----------------------------------------------------------------------------
204 PetscErrorCode CeedLevelTransferSetup(DM dm, Ceed ceed, CeedInt level, CeedInt num_comp_u, CeedData *data, BPData bp_data, Vec fine_mult) {
205   PetscFunctionBeginUser;
206   // Restriction - Fine to corse
207   CeedOperator op_restrict;
208   // Interpolation - Corse to fine
209   CeedOperator op_prolong;
210   // Coarse grid operator
211   CeedOperator op_apply;
212   // Basis
213   CeedBasis basis_u;
214   PetscCall(CreateBasisFromPlex(ceed, dm, 0, 0, 0, 0, bp_data, &basis_u));
215 
216   // ---------------------------------------------------------------------------
217   // Coarse Grid, Prolongation, and Restriction Operators
218   // ---------------------------------------------------------------------------
219   // Create the Operators that compute the prolongation and
220   //   restriction between the p-multigrid levels and the coarse grid eval.
221   // ---------------------------------------------------------------------------
222   // Place in libCEED array
223   PetscMemType m_mem_type;
224   PetscCall(VecReadP2C(fine_mult, &m_mem_type, data[level]->x_ceed));
225 
226   CeedOperatorMultigridLevelCreate(data[level]->op_apply, data[level]->x_ceed, data[level - 1]->elem_restr_u, basis_u, &op_apply, &op_prolong,
227                                    &op_restrict);
228 
229   // Restore PETSc vector
230   PetscCall(VecReadC2P(data[level]->x_ceed, m_mem_type, fine_mult));
231   PetscCall(VecZeroEntries(fine_mult));
232   // -- Save libCEED data
233   data[level - 1]->op_apply = op_apply;
234   data[level]->op_prolong   = op_prolong;
235   data[level]->op_restrict  = op_restrict;
236 
237   CeedBasisDestroy(&basis_u);
238   PetscFunctionReturn(PETSC_SUCCESS);
239 };
240 
241 PetscErrorCode SetupErrorOperator(DM dm, Ceed ceed, BPData bp_data, CeedInt topo_dim, PetscInt num_comp_x, PetscInt num_comp_u,
242                                   CeedOperator *op_error) {
243   DM                  dm_coord;
244   Vec                 coords;
245   const PetscScalar  *coord_array;
246   CeedBasis           basis_x, basis_u;
247   CeedElemRestriction elem_restr_x, elem_restr_u, elem_restr_u_i, elem_restr_qd_i;
248   CeedQFunction       qf_setup_geo, qf_setup_rhs, qf_error;
249   CeedOperator        op_setup_geo, op_setup_rhs;
250   CeedVector          x_coord, q_data, target, rhs;
251   PetscInt            c_start, c_end, num_elem;
252   CeedInt             num_qpts, q_data_size = bp_data.q_data_size;
253   CeedScalar          R = 1;                         // radius of the sphere
254   CeedScalar          l = 1.0 / PetscSqrtReal(3.0);  // half edge of the inscribed cube
255 
256   PetscFunctionBeginUser;
257   PetscCall(DMGetCoordinateDM(dm, &dm_coord));
258 
259   // CEED bases
260   PetscCall(CreateBasisFromPlex(ceed, dm_coord, 0, 0, 0, 0, bp_data, &basis_x));
261   PetscCall(CreateBasisFromPlex(ceed, dm, 0, 0, 0, 0, bp_data, &basis_u));
262 
263   // CEED restrictions
264   PetscCall(CreateRestrictionFromPlex(ceed, dm_coord, 0, 0, 0, &elem_restr_x));
265   PetscCall(CreateRestrictionFromPlex(ceed, dm, 0, 0, 0, &elem_restr_u));
266 
267   PetscCall(DMPlexGetHeightStratum(dm, 0, &c_start, &c_end));
268   num_elem = c_end - c_start;
269   CeedBasisGetNumQuadraturePoints(basis_u, &num_qpts);
270 
271   CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, num_comp_u, num_comp_u * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_u_i);
272   CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, q_data_size, q_data_size * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_qd_i);
273 
274   // Element coordinates
275   PetscCall(DMGetCoordinatesLocal(dm, &coords));
276   PetscCall(VecGetArrayRead(coords, &coord_array));
277 
278   CeedElemRestrictionCreateVector(elem_restr_x, &x_coord, NULL);
279   CeedVectorSetArray(x_coord, CEED_MEM_HOST, CEED_COPY_VALUES, (PetscScalar *)coord_array);
280   PetscCall(VecRestoreArrayRead(coords, &coord_array));
281 
282   // Create the persistent vectors that will be needed in setup and apply
283   CeedVectorCreate(ceed, q_data_size * num_elem * num_qpts, &q_data);
284 
285   // Create the QFunction that builds the context data
286   CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_geo, bp_data.setup_geo_loc, &qf_setup_geo);
287   CeedQFunctionAddInput(qf_setup_geo, "x", num_comp_x, CEED_EVAL_INTERP);
288   CeedQFunctionAddInput(qf_setup_geo, "dx", num_comp_x * topo_dim, CEED_EVAL_GRAD);
289   CeedQFunctionAddInput(qf_setup_geo, "weight", 1, CEED_EVAL_WEIGHT);
290   CeedQFunctionAddOutput(qf_setup_geo, "qdata", q_data_size, CEED_EVAL_NONE);
291 
292   // Create the operator that builds the quadrature data
293   CeedOperatorCreate(ceed, qf_setup_geo, NULL, NULL, &op_setup_geo);
294   CeedOperatorSetField(op_setup_geo, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
295   CeedOperatorSetField(op_setup_geo, "dx", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
296   CeedOperatorSetField(op_setup_geo, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
297   CeedOperatorSetField(op_setup_geo, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
298 
299   // Setup q_data
300   CeedOperatorApply(op_setup_geo, x_coord, q_data, CEED_REQUEST_IMMEDIATE);
301 
302   // Set up target vector
303   CeedElemRestrictionCreateVector(elem_restr_u, &rhs, NULL);
304   CeedVectorCreate(ceed, num_elem * num_qpts * num_comp_u, &target);
305   // Create the q-function that sets up the RHS and true solution
306   CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_rhs, bp_data.setup_rhs_loc, &qf_setup_rhs);
307   CeedQFunctionAddInput(qf_setup_rhs, "x", num_comp_x, CEED_EVAL_INTERP);
308   CeedQFunctionAddInput(qf_setup_rhs, "qdata", q_data_size, CEED_EVAL_NONE);
309   CeedQFunctionAddOutput(qf_setup_rhs, "true solution", num_comp_u, CEED_EVAL_NONE);
310   CeedQFunctionAddOutput(qf_setup_rhs, "rhs", num_comp_u, CEED_EVAL_INTERP);
311 
312   // Create the operator that builds the RHS and true solution
313   CeedOperatorCreate(ceed, qf_setup_rhs, NULL, NULL, &op_setup_rhs);
314   CeedOperatorSetField(op_setup_rhs, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
315   CeedOperatorSetField(op_setup_rhs, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
316   CeedOperatorSetField(op_setup_rhs, "true solution", elem_restr_u_i, CEED_BASIS_NONE, target);
317   CeedOperatorSetField(op_setup_rhs, "rhs", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
318 
319   // Set up the libCEED context
320   CeedQFunctionContext ctx_rhs_setup;
321   CeedQFunctionContextCreate(ceed, &ctx_rhs_setup);
322   CeedScalar rhs_setup_data[2] = {R, l};
323   CeedQFunctionContextSetData(ctx_rhs_setup, CEED_MEM_HOST, CEED_COPY_VALUES, sizeof rhs_setup_data, &rhs_setup_data);
324   CeedQFunctionSetContext(qf_setup_rhs, ctx_rhs_setup);
325   CeedQFunctionContextDestroy(&ctx_rhs_setup);
326 
327   // Setup RHS and target
328   CeedOperatorApply(op_setup_rhs, x_coord, rhs, CEED_REQUEST_IMMEDIATE);
329 
330   // Set up error operator
331   // Create the error QFunction
332   CeedQFunctionCreateInterior(ceed, 1, bp_data.error, bp_data.error_loc, &qf_error);
333   CeedQFunctionAddInput(qf_error, "u", num_comp_u, CEED_EVAL_INTERP);
334   CeedQFunctionAddInput(qf_error, "true_soln", num_comp_u, CEED_EVAL_NONE);
335   CeedQFunctionAddInput(qf_error, "qdata", q_data_size, CEED_EVAL_NONE);
336   CeedQFunctionAddOutput(qf_error, "error", num_comp_u, CEED_EVAL_INTERP);
337 
338   // Create the error operator
339   CeedOperatorCreate(ceed, qf_error, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_error);
340   CeedOperatorSetField(*op_error, "u", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
341   CeedOperatorSetField(*op_error, "true_soln", elem_restr_u_i, CEED_BASIS_NONE, target);
342   CeedOperatorSetField(*op_error, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
343   CeedOperatorSetField(*op_error, "error", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
344 
345   // Cleanup
346   CeedQFunctionDestroy(&qf_setup_rhs);
347   CeedOperatorDestroy(&op_setup_rhs);
348   CeedQFunctionDestroy(&qf_setup_geo);
349   CeedOperatorDestroy(&op_setup_geo);
350   CeedQFunctionDestroy(&qf_error);
351   CeedVectorDestroy(&x_coord);
352   CeedVectorDestroy(&rhs);
353   CeedVectorDestroy(&target);
354   CeedVectorDestroy(&q_data);
355   CeedElemRestrictionDestroy(&elem_restr_u_i);
356   CeedElemRestrictionDestroy(&elem_restr_qd_i);
357   CeedElemRestrictionDestroy(&elem_restr_x);
358   CeedElemRestrictionDestroy(&elem_restr_u);
359   CeedBasisDestroy(&basis_x);
360   CeedBasisDestroy(&basis_u);
361 
362   PetscFunctionReturn(PETSC_SUCCESS);
363 }
364