1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors.
298285ab4SZach Atkins // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
398285ab4SZach Atkins //
498285ab4SZach Atkins // SPDX-License-Identifier: BSD-2-Clause
598285ab4SZach Atkins //
698285ab4SZach Atkins // This file is part of CEED: http://github.com/ceed
798285ab4SZach Atkins
8e83e87a5Sjeremylt #include "../include/libceedsetup.h"
92b730f8bSJeremy L Thompson
102b730f8bSJeremy L Thompson #include <stdio.h>
112b730f8bSJeremy L Thompson
1278f7fce3SZach Atkins #include "../include/libceedsetup.h"
13e83e87a5Sjeremylt #include "../include/petscutils.h"
14e83e87a5Sjeremylt
15e83e87a5Sjeremylt // -----------------------------------------------------------------------------
16e83e87a5Sjeremylt // Destroy libCEED operator objects
17e83e87a5Sjeremylt // -----------------------------------------------------------------------------
CeedDataDestroy(CeedInt i,CeedData data)18e83e87a5Sjeremylt PetscErrorCode CeedDataDestroy(CeedInt i, CeedData data) {
195dfaedb8SJed Brown PetscFunctionBeginUser;
209b072555Sjeremylt CeedVectorDestroy(&data->q_data);
219b072555Sjeremylt CeedVectorDestroy(&data->x_ceed);
229b072555Sjeremylt CeedVectorDestroy(&data->y_ceed);
239b072555Sjeremylt CeedBasisDestroy(&data->basis_x);
249b072555Sjeremylt CeedBasisDestroy(&data->basis_u);
259b072555Sjeremylt CeedElemRestrictionDestroy(&data->elem_restr_u);
269b072555Sjeremylt CeedElemRestrictionDestroy(&data->elem_restr_x);
279b072555Sjeremylt CeedElemRestrictionDestroy(&data->elem_restr_u_i);
289b072555Sjeremylt CeedElemRestrictionDestroy(&data->elem_restr_qd_i);
299b072555Sjeremylt CeedQFunctionDestroy(&data->qf_apply);
309b072555Sjeremylt CeedOperatorDestroy(&data->op_apply);
31e83e87a5Sjeremylt if (i > 0) {
329b072555Sjeremylt CeedOperatorDestroy(&data->op_prolong);
339b072555Sjeremylt CeedOperatorDestroy(&data->op_restrict);
34e83e87a5Sjeremylt }
352b730f8bSJeremy L Thompson PetscCall(PetscFree(data));
36ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
37e83e87a5Sjeremylt };
38e83e87a5Sjeremylt
39e83e87a5Sjeremylt // -----------------------------------------------------------------------------
40e83e87a5Sjeremylt // Set up libCEED for a given degree
41e83e87a5Sjeremylt // -----------------------------------------------------------------------------
SetupLibceedByDegree(DM dm,Ceed ceed,CeedInt degree,CeedInt topo_dim,CeedInt q_extra,PetscInt num_comp_x,PetscInt num_comp_u,PetscInt g_size,PetscInt xl_size,BPData bp_data,CeedData data,PetscBool setup_rhs,PetscBool is_fine_level,CeedVector rhs_ceed,CeedVector * target)422b730f8bSJeremy L Thompson PetscErrorCode SetupLibceedByDegree(DM dm, Ceed ceed, CeedInt degree, CeedInt topo_dim, CeedInt q_extra, PetscInt num_comp_x, PetscInt num_comp_u,
434dbe2ad5SJeremy L Thompson PetscInt g_size, PetscInt xl_size, BPData bp_data, CeedData data, PetscBool setup_rhs, PetscBool is_fine_level,
444dbe2ad5SJeremy L Thompson CeedVector rhs_ceed, CeedVector *target) {
459b072555Sjeremylt DM dm_coord;
46e83e87a5Sjeremylt Vec coords;
479b072555Sjeremylt const PetscScalar *coord_array;
489b072555Sjeremylt CeedBasis basis_x, basis_u;
499b072555Sjeremylt CeedElemRestriction elem_restr_x, elem_restr_u, elem_restr_u_i, elem_restr_qd_i;
504dbe2ad5SJeremy L Thompson CeedQFunction qf_setup_geo = NULL, qf_apply = NULL;
519b072555Sjeremylt CeedOperator op_setup_geo, op_apply;
529b072555Sjeremylt CeedVector x_coord, q_data, x_ceed, y_ceed;
534d00b080SJeremy L Thompson PetscInt c_start, c_end, num_elem;
544d00b080SJeremy L Thompson CeedInt num_qpts, q_data_size = bp_data.q_data_size;
552b730f8bSJeremy L Thompson CeedScalar R = 1; // radius of the sphere
562b730f8bSJeremy L Thompson CeedScalar l = 1.0 / PetscSqrtReal(3.0); // half edge of the inscribed cube
57e83e87a5Sjeremylt
585dfaedb8SJed Brown PetscFunctionBeginUser;
592b730f8bSJeremy L Thompson PetscCall(DMGetCoordinateDM(dm, &dm_coord));
60129d8736Srezgarshakeri
61129d8736Srezgarshakeri // CEED bases
622b730f8bSJeremy L Thompson PetscCall(CreateBasisFromPlex(ceed, dm_coord, 0, 0, 0, 0, bp_data, &basis_x));
632b730f8bSJeremy L Thompson PetscCall(CreateBasisFromPlex(ceed, dm, 0, 0, 0, 0, bp_data, &basis_u));
64129d8736Srezgarshakeri
65129d8736Srezgarshakeri // CEED restrictions
662b730f8bSJeremy L Thompson PetscCall(CreateRestrictionFromPlex(ceed, dm_coord, 0, 0, 0, &elem_restr_x));
672b730f8bSJeremy L Thompson PetscCall(CreateRestrictionFromPlex(ceed, dm, 0, 0, 0, &elem_restr_u));
68e83e87a5Sjeremylt
692b730f8bSJeremy L Thompson PetscCall(DMPlexGetHeightStratum(dm, 0, &c_start, &c_end));
709b072555Sjeremylt num_elem = c_end - c_start;
71129d8736Srezgarshakeri CeedBasisGetNumQuadraturePoints(basis_u, &num_qpts);
72e83e87a5Sjeremylt
732b730f8bSJeremy L Thompson CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, num_comp_u, num_comp_u * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_u_i);
742b730f8bSJeremy L Thompson CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, q_data_size, q_data_size * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_qd_i);
75e83e87a5Sjeremylt
76e83e87a5Sjeremylt // Element coordinates
772b730f8bSJeremy L Thompson PetscCall(DMGetCoordinatesLocal(dm, &coords));
782b730f8bSJeremy L Thompson PetscCall(VecGetArrayRead(coords, &coord_array));
79e83e87a5Sjeremylt
809b072555Sjeremylt CeedElemRestrictionCreateVector(elem_restr_x, &x_coord, NULL);
812b730f8bSJeremy L Thompson CeedVectorSetArray(x_coord, CEED_MEM_HOST, CEED_COPY_VALUES, (PetscScalar *)coord_array);
822b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayRead(coords, &coord_array));
83e83e87a5Sjeremylt
84e83e87a5Sjeremylt // Create the persistent vectors that will be needed in setup and apply
859b072555Sjeremylt CeedVectorCreate(ceed, q_data_size * num_elem * num_qpts, &q_data);
869b072555Sjeremylt CeedVectorCreate(ceed, xl_size, &x_ceed);
879b072555Sjeremylt CeedVectorCreate(ceed, xl_size, &y_ceed);
88e83e87a5Sjeremylt
894dbe2ad5SJeremy L Thompson if (is_fine_level) {
90e83e87a5Sjeremylt // Create the QFunction that builds the context data
912b730f8bSJeremy L Thompson CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_geo, bp_data.setup_geo_loc, &qf_setup_geo);
929b072555Sjeremylt CeedQFunctionAddInput(qf_setup_geo, "x", num_comp_x, CEED_EVAL_INTERP);
939b072555Sjeremylt CeedQFunctionAddInput(qf_setup_geo, "dx", num_comp_x * topo_dim, CEED_EVAL_GRAD);
949b072555Sjeremylt CeedQFunctionAddInput(qf_setup_geo, "weight", 1, CEED_EVAL_WEIGHT);
95a61c78d6SJeremy L Thompson CeedQFunctionAddOutput(qf_setup_geo, "qdata", q_data_size, CEED_EVAL_NONE);
96e83e87a5Sjeremylt
97e83e87a5Sjeremylt // Create the operator that builds the quadrature data
989b072555Sjeremylt CeedOperatorCreate(ceed, qf_setup_geo, NULL, NULL, &op_setup_geo);
992b730f8bSJeremy L Thompson CeedOperatorSetField(op_setup_geo, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
1002b730f8bSJeremy L Thompson CeedOperatorSetField(op_setup_geo, "dx", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
1012b730f8bSJeremy L Thompson CeedOperatorSetField(op_setup_geo, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
102356036faSJeremy L Thompson CeedOperatorSetField(op_setup_geo, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
103e83e87a5Sjeremylt
1049b072555Sjeremylt // Setup q_data
1059b072555Sjeremylt CeedOperatorApply(op_setup_geo, x_coord, q_data, CEED_REQUEST_IMMEDIATE);
106e83e87a5Sjeremylt
107e83e87a5Sjeremylt // Set up PDE operator
1083c11f1fcSJeremy L Thompson PetscBool is_interp = bp_data.in_mode == CEED_EVAL_INTERP;
1099b072555Sjeremylt CeedInt in_scale = bp_data.in_mode == CEED_EVAL_GRAD ? topo_dim : 1;
1109b072555Sjeremylt CeedInt out_scale = bp_data.out_mode == CEED_EVAL_GRAD ? topo_dim : 1;
1113c11f1fcSJeremy L Thompson
1122b730f8bSJeremy L Thompson CeedQFunctionCreateInterior(ceed, 1, bp_data.apply, bp_data.apply_loc, &qf_apply);
1133c11f1fcSJeremy L Thompson if (bp_data.in_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
1143c11f1fcSJeremy L Thompson CeedQFunctionAddInput(qf_apply, "u", num_comp_u, CEED_EVAL_INTERP);
1153c11f1fcSJeremy L Thompson CeedQFunctionAddInput(qf_apply, "du", num_comp_u * topo_dim, CEED_EVAL_GRAD);
1163c11f1fcSJeremy L Thompson } else {
1173c11f1fcSJeremy L Thompson CeedQFunctionAddInput(qf_apply, is_interp ? "u" : "du", num_comp_u * in_scale, bp_data.in_mode);
1183c11f1fcSJeremy L Thompson }
119a61c78d6SJeremy L Thompson CeedQFunctionAddInput(qf_apply, "qdata", q_data_size, CEED_EVAL_NONE);
1203c11f1fcSJeremy L Thompson if (bp_data.out_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
1213c11f1fcSJeremy L Thompson CeedQFunctionAddOutput(qf_apply, "v", num_comp_u, CEED_EVAL_INTERP);
1223c11f1fcSJeremy L Thompson CeedQFunctionAddOutput(qf_apply, "dv", num_comp_u * topo_dim, CEED_EVAL_GRAD);
1233c11f1fcSJeremy L Thompson } else {
1243c11f1fcSJeremy L Thompson CeedQFunctionAddOutput(qf_apply, is_interp ? "v" : "dv", num_comp_u * out_scale, bp_data.out_mode);
1253c11f1fcSJeremy L Thompson }
126e83e87a5Sjeremylt
127e83e87a5Sjeremylt // Create the mass or diff operator
1289b072555Sjeremylt CeedOperatorCreate(ceed, qf_apply, NULL, NULL, &op_apply);
1293c11f1fcSJeremy L Thompson if (bp_data.in_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
1309b072555Sjeremylt CeedOperatorSetField(op_apply, "u", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
1313c11f1fcSJeremy L Thompson CeedOperatorSetField(op_apply, "du", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
1323c11f1fcSJeremy L Thompson } else {
1333c11f1fcSJeremy L Thompson CeedOperatorSetField(op_apply, is_interp ? "u" : "du", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
1343c11f1fcSJeremy L Thompson }
135356036faSJeremy L Thompson CeedOperatorSetField(op_apply, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
1363c11f1fcSJeremy L Thompson if (bp_data.out_mode == CEED_EVAL_INTERP + CEED_EVAL_GRAD) {
1379b072555Sjeremylt CeedOperatorSetField(op_apply, "v", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
1383c11f1fcSJeremy L Thompson CeedOperatorSetField(op_apply, "dv", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
1393c11f1fcSJeremy L Thompson } else {
1403c11f1fcSJeremy L Thompson CeedOperatorSetField(op_apply, is_interp ? "v" : "dv", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
1413c11f1fcSJeremy L Thompson }
142e83e87a5Sjeremylt
1434dbe2ad5SJeremy L Thompson // Cleanup
1444dbe2ad5SJeremy L Thompson CeedQFunctionDestroy(&qf_setup_geo);
1454dbe2ad5SJeremy L Thompson CeedOperatorDestroy(&op_setup_geo);
1464dbe2ad5SJeremy L Thompson }
1474dbe2ad5SJeremy L Thompson
148e83e87a5Sjeremylt // Set up RHS if needed
149e83e87a5Sjeremylt if (setup_rhs) {
1509b072555Sjeremylt CeedQFunction qf_setup_rhs;
1519b072555Sjeremylt CeedOperator op_setup_rhs;
1529b072555Sjeremylt CeedVectorCreate(ceed, num_elem * num_qpts * num_comp_u, target);
153e83e87a5Sjeremylt // Create the q-function that sets up the RHS and true solution
1542b730f8bSJeremy L Thompson CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_rhs, bp_data.setup_rhs_loc, &qf_setup_rhs);
1559b072555Sjeremylt CeedQFunctionAddInput(qf_setup_rhs, "x", num_comp_x, CEED_EVAL_INTERP);
156a61c78d6SJeremy L Thompson CeedQFunctionAddInput(qf_setup_rhs, "qdata", q_data_size, CEED_EVAL_NONE);
1572b730f8bSJeremy L Thompson CeedQFunctionAddOutput(qf_setup_rhs, "true solution", num_comp_u, CEED_EVAL_NONE);
1589b072555Sjeremylt CeedQFunctionAddOutput(qf_setup_rhs, "rhs", num_comp_u, CEED_EVAL_INTERP);
159e83e87a5Sjeremylt
160e83e87a5Sjeremylt // Create the operator that builds the RHS and true solution
1619b072555Sjeremylt CeedOperatorCreate(ceed, qf_setup_rhs, NULL, NULL, &op_setup_rhs);
1622b730f8bSJeremy L Thompson CeedOperatorSetField(op_setup_rhs, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
163356036faSJeremy L Thompson CeedOperatorSetField(op_setup_rhs, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
164356036faSJeremy L Thompson CeedOperatorSetField(op_setup_rhs, "true solution", elem_restr_u_i, CEED_BASIS_NONE, *target);
1652b730f8bSJeremy L Thompson CeedOperatorSetField(op_setup_rhs, "rhs", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
166e83e87a5Sjeremylt
167e83e87a5Sjeremylt // Set up the libCEED context
1689b072555Sjeremylt CeedQFunctionContext ctx_rhs_setup;
1699b072555Sjeremylt CeedQFunctionContextCreate(ceed, &ctx_rhs_setup);
1709b072555Sjeremylt CeedScalar rhs_setup_data[2] = {R, l};
1712b730f8bSJeremy L Thompson CeedQFunctionContextSetData(ctx_rhs_setup, CEED_MEM_HOST, CEED_COPY_VALUES, sizeof rhs_setup_data, &rhs_setup_data);
1729b072555Sjeremylt CeedQFunctionSetContext(qf_setup_rhs, ctx_rhs_setup);
1739b072555Sjeremylt CeedQFunctionContextDestroy(&ctx_rhs_setup);
174e83e87a5Sjeremylt
175e83e87a5Sjeremylt // Setup RHS and target
1769b072555Sjeremylt CeedOperatorApply(op_setup_rhs, x_coord, rhs_ceed, CEED_REQUEST_IMMEDIATE);
177e83e87a5Sjeremylt
178e83e87a5Sjeremylt // Cleanup
1799b072555Sjeremylt CeedQFunctionDestroy(&qf_setup_rhs);
1809b072555Sjeremylt CeedOperatorDestroy(&op_setup_rhs);
181e83e87a5Sjeremylt }
182e83e87a5Sjeremylt // Cleanup
1839b072555Sjeremylt CeedVectorDestroy(&x_coord);
184e83e87a5Sjeremylt
185e83e87a5Sjeremylt // Save libCEED data required for level
1862b730f8bSJeremy L Thompson data->basis_x = basis_x;
1872b730f8bSJeremy L Thompson data->basis_u = basis_u;
1889b072555Sjeremylt data->elem_restr_x = elem_restr_x;
1899b072555Sjeremylt data->elem_restr_u = elem_restr_u;
1909b072555Sjeremylt data->elem_restr_u_i = elem_restr_u_i;
1919b072555Sjeremylt data->elem_restr_qd_i = elem_restr_qd_i;
1929b072555Sjeremylt data->qf_apply = qf_apply;
1939b072555Sjeremylt data->op_apply = op_apply;
1949b072555Sjeremylt data->q_data = q_data;
1959b072555Sjeremylt data->x_ceed = x_ceed;
1969b072555Sjeremylt data->y_ceed = y_ceed;
197d4d45553Srezgarshakeri data->q_data_size = q_data_size;
198ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
199e83e87a5Sjeremylt };
200e83e87a5Sjeremylt
201e83e87a5Sjeremylt // -----------------------------------------------------------------------------
202e83e87a5Sjeremylt // Setup libCEED level transfer operator objects
203e83e87a5Sjeremylt // -----------------------------------------------------------------------------
CeedLevelTransferSetup(DM dm,Ceed ceed,CeedInt level,CeedInt num_comp_u,CeedData * data,BPData bp_data,Vec fine_mult)2042b730f8bSJeremy L Thompson PetscErrorCode CeedLevelTransferSetup(DM dm, Ceed ceed, CeedInt level, CeedInt num_comp_u, CeedData *data, BPData bp_data, Vec fine_mult) {
205751eb813Srezgarshakeri PetscFunctionBeginUser;
206e83e87a5Sjeremylt // Restriction - Fine to corse
2079b072555Sjeremylt CeedOperator op_restrict;
208e83e87a5Sjeremylt // Interpolation - Corse to fine
2099b072555Sjeremylt CeedOperator op_prolong;
2101c9a79dbSrezgarshakeri // Coarse grid operator
2111c9a79dbSrezgarshakeri CeedOperator op_apply;
2121c9a79dbSrezgarshakeri // Basis
2131c9a79dbSrezgarshakeri CeedBasis basis_u;
2142b730f8bSJeremy L Thompson PetscCall(CreateBasisFromPlex(ceed, dm, 0, 0, 0, 0, bp_data, &basis_u));
215e83e87a5Sjeremylt
2161c9a79dbSrezgarshakeri // ---------------------------------------------------------------------------
2171c9a79dbSrezgarshakeri // Coarse Grid, Prolongation, and Restriction Operators
2181c9a79dbSrezgarshakeri // ---------------------------------------------------------------------------
2191c9a79dbSrezgarshakeri // Create the Operators that compute the prolongation and
2201c9a79dbSrezgarshakeri // restriction between the p-multigrid levels and the coarse grid eval.
2211c9a79dbSrezgarshakeri // ---------------------------------------------------------------------------
2221c9a79dbSrezgarshakeri // Place in libCEED array
2231c9a79dbSrezgarshakeri PetscMemType m_mem_type;
224179e5961SZach Atkins PetscCall(VecReadP2C(fine_mult, &m_mem_type, data[level]->x_ceed));
225e83e87a5Sjeremylt
2262b730f8bSJeremy L Thompson CeedOperatorMultigridLevelCreate(data[level]->op_apply, data[level]->x_ceed, data[level - 1]->elem_restr_u, basis_u, &op_apply, &op_prolong,
2272b730f8bSJeremy L Thompson &op_restrict);
228e83e87a5Sjeremylt
2291c9a79dbSrezgarshakeri // Restore PETSc vector
230179e5961SZach Atkins PetscCall(VecReadC2P(data[level]->x_ceed, m_mem_type, fine_mult));
2312b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(fine_mult));
2321c9a79dbSrezgarshakeri // -- Save libCEED data
2331c9a79dbSrezgarshakeri data[level - 1]->op_apply = op_apply;
2341c9a79dbSrezgarshakeri data[level]->op_prolong = op_prolong;
2351c9a79dbSrezgarshakeri data[level]->op_restrict = op_restrict;
2361c9a79dbSrezgarshakeri
2371c9a79dbSrezgarshakeri CeedBasisDestroy(&basis_u);
238ee4ca9cbSJames Wright PetscFunctionReturn(PETSC_SUCCESS);
239e83e87a5Sjeremylt };
240e83e87a5Sjeremylt
SetupErrorOperator(DM dm,Ceed ceed,BPData bp_data,CeedInt topo_dim,PetscInt num_comp_x,PetscInt num_comp_u,CeedOperator * op_error)24178f7fce3SZach Atkins PetscErrorCode SetupErrorOperator(DM dm, Ceed ceed, BPData bp_data, CeedInt topo_dim, PetscInt num_comp_x, PetscInt num_comp_u,
24278f7fce3SZach Atkins CeedOperator *op_error) {
24378f7fce3SZach Atkins DM dm_coord;
24478f7fce3SZach Atkins Vec coords;
24578f7fce3SZach Atkins const PetscScalar *coord_array;
24678f7fce3SZach Atkins CeedBasis basis_x, basis_u;
24778f7fce3SZach Atkins CeedElemRestriction elem_restr_x, elem_restr_u, elem_restr_u_i, elem_restr_qd_i;
24878f7fce3SZach Atkins CeedQFunction qf_setup_geo, qf_setup_rhs, qf_error;
24978f7fce3SZach Atkins CeedOperator op_setup_geo, op_setup_rhs;
25078f7fce3SZach Atkins CeedVector x_coord, q_data, target, rhs;
2514d00b080SJeremy L Thompson PetscInt c_start, c_end, num_elem;
2524d00b080SJeremy L Thompson CeedInt num_qpts, q_data_size = bp_data.q_data_size;
25378f7fce3SZach Atkins CeedScalar R = 1; // radius of the sphere
25478f7fce3SZach Atkins CeedScalar l = 1.0 / PetscSqrtReal(3.0); // half edge of the inscribed cube
25578f7fce3SZach Atkins
25678f7fce3SZach Atkins PetscFunctionBeginUser;
25778f7fce3SZach Atkins PetscCall(DMGetCoordinateDM(dm, &dm_coord));
25878f7fce3SZach Atkins
25978f7fce3SZach Atkins // CEED bases
26078f7fce3SZach Atkins PetscCall(CreateBasisFromPlex(ceed, dm_coord, 0, 0, 0, 0, bp_data, &basis_x));
26178f7fce3SZach Atkins PetscCall(CreateBasisFromPlex(ceed, dm, 0, 0, 0, 0, bp_data, &basis_u));
26278f7fce3SZach Atkins
26378f7fce3SZach Atkins // CEED restrictions
26478f7fce3SZach Atkins PetscCall(CreateRestrictionFromPlex(ceed, dm_coord, 0, 0, 0, &elem_restr_x));
26578f7fce3SZach Atkins PetscCall(CreateRestrictionFromPlex(ceed, dm, 0, 0, 0, &elem_restr_u));
26678f7fce3SZach Atkins
26778f7fce3SZach Atkins PetscCall(DMPlexGetHeightStratum(dm, 0, &c_start, &c_end));
26878f7fce3SZach Atkins num_elem = c_end - c_start;
26978f7fce3SZach Atkins CeedBasisGetNumQuadraturePoints(basis_u, &num_qpts);
27078f7fce3SZach Atkins
27178f7fce3SZach Atkins CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, num_comp_u, num_comp_u * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_u_i);
27278f7fce3SZach Atkins CeedElemRestrictionCreateStrided(ceed, num_elem, num_qpts, q_data_size, q_data_size * num_elem * num_qpts, CEED_STRIDES_BACKEND, &elem_restr_qd_i);
27378f7fce3SZach Atkins
27478f7fce3SZach Atkins // Element coordinates
27578f7fce3SZach Atkins PetscCall(DMGetCoordinatesLocal(dm, &coords));
27678f7fce3SZach Atkins PetscCall(VecGetArrayRead(coords, &coord_array));
27778f7fce3SZach Atkins
27878f7fce3SZach Atkins CeedElemRestrictionCreateVector(elem_restr_x, &x_coord, NULL);
27978f7fce3SZach Atkins CeedVectorSetArray(x_coord, CEED_MEM_HOST, CEED_COPY_VALUES, (PetscScalar *)coord_array);
28078f7fce3SZach Atkins PetscCall(VecRestoreArrayRead(coords, &coord_array));
28178f7fce3SZach Atkins
28278f7fce3SZach Atkins // Create the persistent vectors that will be needed in setup and apply
28378f7fce3SZach Atkins CeedVectorCreate(ceed, q_data_size * num_elem * num_qpts, &q_data);
28478f7fce3SZach Atkins
28578f7fce3SZach Atkins // Create the QFunction that builds the context data
28678f7fce3SZach Atkins CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_geo, bp_data.setup_geo_loc, &qf_setup_geo);
28778f7fce3SZach Atkins CeedQFunctionAddInput(qf_setup_geo, "x", num_comp_x, CEED_EVAL_INTERP);
28878f7fce3SZach Atkins CeedQFunctionAddInput(qf_setup_geo, "dx", num_comp_x * topo_dim, CEED_EVAL_GRAD);
28978f7fce3SZach Atkins CeedQFunctionAddInput(qf_setup_geo, "weight", 1, CEED_EVAL_WEIGHT);
29078f7fce3SZach Atkins CeedQFunctionAddOutput(qf_setup_geo, "qdata", q_data_size, CEED_EVAL_NONE);
29178f7fce3SZach Atkins
29278f7fce3SZach Atkins // Create the operator that builds the quadrature data
29378f7fce3SZach Atkins CeedOperatorCreate(ceed, qf_setup_geo, NULL, NULL, &op_setup_geo);
29478f7fce3SZach Atkins CeedOperatorSetField(op_setup_geo, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
29578f7fce3SZach Atkins CeedOperatorSetField(op_setup_geo, "dx", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
29678f7fce3SZach Atkins CeedOperatorSetField(op_setup_geo, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
29778f7fce3SZach Atkins CeedOperatorSetField(op_setup_geo, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
29878f7fce3SZach Atkins
29978f7fce3SZach Atkins // Setup q_data
30078f7fce3SZach Atkins CeedOperatorApply(op_setup_geo, x_coord, q_data, CEED_REQUEST_IMMEDIATE);
30178f7fce3SZach Atkins
30278f7fce3SZach Atkins // Set up target vector
30378f7fce3SZach Atkins CeedElemRestrictionCreateVector(elem_restr_u, &rhs, NULL);
30478f7fce3SZach Atkins CeedVectorCreate(ceed, num_elem * num_qpts * num_comp_u, &target);
30578f7fce3SZach Atkins // Create the q-function that sets up the RHS and true solution
30678f7fce3SZach Atkins CeedQFunctionCreateInterior(ceed, 1, bp_data.setup_rhs, bp_data.setup_rhs_loc, &qf_setup_rhs);
30778f7fce3SZach Atkins CeedQFunctionAddInput(qf_setup_rhs, "x", num_comp_x, CEED_EVAL_INTERP);
30878f7fce3SZach Atkins CeedQFunctionAddInput(qf_setup_rhs, "qdata", q_data_size, CEED_EVAL_NONE);
30978f7fce3SZach Atkins CeedQFunctionAddOutput(qf_setup_rhs, "true solution", num_comp_u, CEED_EVAL_NONE);
31078f7fce3SZach Atkins CeedQFunctionAddOutput(qf_setup_rhs, "rhs", num_comp_u, CEED_EVAL_INTERP);
31178f7fce3SZach Atkins
31278f7fce3SZach Atkins // Create the operator that builds the RHS and true solution
31378f7fce3SZach Atkins CeedOperatorCreate(ceed, qf_setup_rhs, NULL, NULL, &op_setup_rhs);
31478f7fce3SZach Atkins CeedOperatorSetField(op_setup_rhs, "x", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE);
31578f7fce3SZach Atkins CeedOperatorSetField(op_setup_rhs, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
31678f7fce3SZach Atkins CeedOperatorSetField(op_setup_rhs, "true solution", elem_restr_u_i, CEED_BASIS_NONE, target);
31778f7fce3SZach Atkins CeedOperatorSetField(op_setup_rhs, "rhs", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
31878f7fce3SZach Atkins
31978f7fce3SZach Atkins // Set up the libCEED context
32078f7fce3SZach Atkins CeedQFunctionContext ctx_rhs_setup;
32178f7fce3SZach Atkins CeedQFunctionContextCreate(ceed, &ctx_rhs_setup);
32278f7fce3SZach Atkins CeedScalar rhs_setup_data[2] = {R, l};
32378f7fce3SZach Atkins CeedQFunctionContextSetData(ctx_rhs_setup, CEED_MEM_HOST, CEED_COPY_VALUES, sizeof rhs_setup_data, &rhs_setup_data);
32478f7fce3SZach Atkins CeedQFunctionSetContext(qf_setup_rhs, ctx_rhs_setup);
32578f7fce3SZach Atkins CeedQFunctionContextDestroy(&ctx_rhs_setup);
32678f7fce3SZach Atkins
32778f7fce3SZach Atkins // Setup RHS and target
32878f7fce3SZach Atkins CeedOperatorApply(op_setup_rhs, x_coord, rhs, CEED_REQUEST_IMMEDIATE);
32978f7fce3SZach Atkins
33078f7fce3SZach Atkins // Set up error operator
33178f7fce3SZach Atkins // Create the error QFunction
33278f7fce3SZach Atkins CeedQFunctionCreateInterior(ceed, 1, bp_data.error, bp_data.error_loc, &qf_error);
33378f7fce3SZach Atkins CeedQFunctionAddInput(qf_error, "u", num_comp_u, CEED_EVAL_INTERP);
33478f7fce3SZach Atkins CeedQFunctionAddInput(qf_error, "true_soln", num_comp_u, CEED_EVAL_NONE);
33578f7fce3SZach Atkins CeedQFunctionAddInput(qf_error, "qdata", q_data_size, CEED_EVAL_NONE);
33678f7fce3SZach Atkins CeedQFunctionAddOutput(qf_error, "error", num_comp_u, CEED_EVAL_INTERP);
33778f7fce3SZach Atkins
33878f7fce3SZach Atkins // Create the error operator
33978f7fce3SZach Atkins CeedOperatorCreate(ceed, qf_error, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, op_error);
34078f7fce3SZach Atkins CeedOperatorSetField(*op_error, "u", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
34178f7fce3SZach Atkins CeedOperatorSetField(*op_error, "true_soln", elem_restr_u_i, CEED_BASIS_NONE, target);
34278f7fce3SZach Atkins CeedOperatorSetField(*op_error, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data);
34378f7fce3SZach Atkins CeedOperatorSetField(*op_error, "error", elem_restr_u, basis_u, CEED_VECTOR_ACTIVE);
34478f7fce3SZach Atkins
34578f7fce3SZach Atkins // Cleanup
34678f7fce3SZach Atkins CeedQFunctionDestroy(&qf_setup_rhs);
34778f7fce3SZach Atkins CeedOperatorDestroy(&op_setup_rhs);
34878f7fce3SZach Atkins CeedQFunctionDestroy(&qf_setup_geo);
34978f7fce3SZach Atkins CeedOperatorDestroy(&op_setup_geo);
35078f7fce3SZach Atkins CeedQFunctionDestroy(&qf_error);
35178f7fce3SZach Atkins CeedVectorDestroy(&x_coord);
35278f7fce3SZach Atkins CeedVectorDestroy(&rhs);
35378f7fce3SZach Atkins CeedVectorDestroy(&target);
35478f7fce3SZach Atkins CeedVectorDestroy(&q_data);
35578f7fce3SZach Atkins CeedElemRestrictionDestroy(&elem_restr_u_i);
35678f7fce3SZach Atkins CeedElemRestrictionDestroy(&elem_restr_qd_i);
35778f7fce3SZach Atkins CeedElemRestrictionDestroy(&elem_restr_x);
35878f7fce3SZach Atkins CeedElemRestrictionDestroy(&elem_restr_u);
35978f7fce3SZach Atkins CeedBasisDestroy(&basis_x);
36078f7fce3SZach Atkins CeedBasisDestroy(&basis_u);
36178f7fce3SZach Atkins
36278f7fce3SZach Atkins PetscFunctionReturn(PETSC_SUCCESS);
36378f7fce3SZach Atkins }
364