xref: /honee/src/boundary_condition.c (revision 5e79d5629814bf0aae86ae210d3bec329a078911)
1ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
3487a3b6eSJames Wright 
4149fb536SJames Wright #include <navierstokes.h>
5*5e79d562SJames Wright #include "petscerror.h"
6487a3b6eSJames Wright 
7487a3b6eSJames Wright /**
8487a3b6eSJames Wright    @brief Add `BCDefinition` to a `PetscSegBuffer`
9487a3b6eSJames Wright 
10487a3b6eSJames Wright    @param[in]     bc_def      `BCDefinition` to add
11487a3b6eSJames Wright    @param[in,out] bc_defs_seg `PetscSegBuffer` to add to
12487a3b6eSJames Wright **/
13487a3b6eSJames Wright static PetscErrorCode AddBCDefinitionToSegBuffer(BCDefinition bc_def, PetscSegBuffer bc_defs_seg) {
14487a3b6eSJames Wright   BCDefinition *bc_def_ptr;
15487a3b6eSJames Wright 
16487a3b6eSJames Wright   PetscFunctionBeginUser;
17487a3b6eSJames Wright   if (bc_def == NULL) PetscFunctionReturn(PETSC_SUCCESS);
18487a3b6eSJames Wright   PetscCall(PetscSegBufferGet(bc_defs_seg, 1, &bc_def_ptr));
19487a3b6eSJames Wright   *bc_def_ptr = bc_def;
20487a3b6eSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
21487a3b6eSJames Wright }
22487a3b6eSJames Wright 
23487a3b6eSJames Wright /**
24487a3b6eSJames Wright    @brief Create and setup `BCDefinition`s and `SimpleBC` from commandline options
25487a3b6eSJames Wright 
260c373b74SJames Wright    @param[in]     honee   `Honee`
27487a3b6eSJames Wright    @param[in,out] problem `ProblemData`
28487a3b6eSJames Wright    @param[in]     app_ctx `AppCtx`
29487a3b6eSJames Wright    @param[in,out] bc      `SimpleBC`
30487a3b6eSJames Wright **/
310c373b74SJames Wright PetscErrorCode BoundaryConditionSetUp(Honee honee, ProblemData problem, AppCtx app_ctx, SimpleBC bc) {
32487a3b6eSJames Wright   PetscSegBuffer bc_defs_seg;
33487a3b6eSJames Wright   PetscBool      flg;
34487a3b6eSJames Wright   BCDefinition   bc_def;
35487a3b6eSJames Wright 
36487a3b6eSJames Wright   PetscFunctionBeginUser;
37487a3b6eSJames Wright   PetscCall(PetscSegBufferCreate(sizeof(BCDefinition), 4, &bc_defs_seg));
38487a3b6eSJames Wright 
390c373b74SJames Wright   PetscOptionsBegin(honee->comm, NULL, "Boundary Condition Options", NULL);
40487a3b6eSJames Wright 
41487a3b6eSJames Wright   PetscCall(PetscOptionsBCDefinition("-bc_wall", "Face IDs to apply wall BC", NULL, "wall", &bc_def, NULL));
42487a3b6eSJames Wright   PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg));
43487a3b6eSJames Wright   if (bc_def) {
44487a3b6eSJames Wright     PetscInt num_essential_comps = 16, essential_comps[16];
45487a3b6eSJames Wright 
46487a3b6eSJames Wright     PetscCall(PetscOptionsIntArray("-wall_comps", "An array of constrained component numbers", NULL, essential_comps, &num_essential_comps, &flg));
47487a3b6eSJames Wright     PetscCall(BCDefinitionSetEssential(bc_def, num_essential_comps, essential_comps));
48487a3b6eSJames Wright 
49487a3b6eSJames Wright     app_ctx->wall_forces.num_wall = bc_def->num_label_values;
50487a3b6eSJames Wright     PetscCall(PetscMalloc1(bc_def->num_label_values, &app_ctx->wall_forces.walls));
51487a3b6eSJames Wright     PetscCall(PetscArraycpy(app_ctx->wall_forces.walls, bc_def->label_values, bc_def->num_label_values));
52487a3b6eSJames Wright   }
53487a3b6eSJames Wright 
54487a3b6eSJames Wright   {  // Symmetry Boundary Conditions
55487a3b6eSJames Wright     const char *deprecated[3] = {"-bc_slip_x", "-bc_slip_y", "-bc_slip_z"};
56487a3b6eSJames Wright     const char *flags[3]      = {"-bc_symmetry_x", "-bc_symmetry_y", "-bc_symmetry_z"};
57487a3b6eSJames Wright 
58487a3b6eSJames Wright     for (PetscInt j = 0; j < 3; j++) {
59487a3b6eSJames Wright       PetscCall(PetscOptionsDeprecated(deprecated[j], flags[j], "libCEED 0.12.0",
60487a3b6eSJames Wright                                        "Use -bc_symmetry_[x,y,z] for direct equivalency, or -bc_slip for weak, Riemann-based, direction-invariant "
61487a3b6eSJames Wright                                        "slip/no-penatration boundary conditions"));
62487a3b6eSJames Wright       PetscCall(PetscOptionsBCDefinition(flags[j], "Face IDs to apply symmetry BC", NULL, "symmetry", &bc_def, NULL));
63487a3b6eSJames Wright       if (!bc_def) {
64487a3b6eSJames Wright         PetscCall(PetscOptionsBCDefinition(deprecated[j], "Face IDs to apply symmetry BC", NULL, "symmetry", &bc_def, NULL));
65487a3b6eSJames Wright       }
66487a3b6eSJames Wright       PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg));
67487a3b6eSJames Wright       if (bc_def) {
68487a3b6eSJames Wright         PetscInt essential_comps[1] = {j + 1};
69487a3b6eSJames Wright 
70487a3b6eSJames Wright         PetscCall(BCDefinitionSetEssential(bc_def, 1, essential_comps));
71487a3b6eSJames Wright       }
72487a3b6eSJames Wright     }
73487a3b6eSJames Wright   }
74487a3b6eSJames Wright 
75487a3b6eSJames Wright   // Inflow BCs
76487a3b6eSJames Wright   bc->num_inflow = 16;
77487a3b6eSJames Wright   PetscCall(PetscOptionsIntArray("-bc_inflow", "Face IDs to apply inflow BC", NULL, bc->inflows, &bc->num_inflow, NULL));
78487a3b6eSJames Wright   // Outflow BCs
79487a3b6eSJames Wright   bc->num_outflow = 16;
80487a3b6eSJames Wright   PetscCall(PetscOptionsIntArray("-bc_outflow", "Face IDs to apply outflow BC", NULL, bc->outflows, &bc->num_outflow, NULL));
81487a3b6eSJames Wright   // Freestream BCs
82487a3b6eSJames Wright   bc->num_freestream = 16;
83487a3b6eSJames Wright   PetscCall(PetscOptionsIntArray("-bc_freestream", "Face IDs to apply freestream BC", NULL, bc->freestreams, &bc->num_freestream, NULL));
84487a3b6eSJames Wright 
85*5e79d562SJames Wright   PetscCall(PetscOptionsBCDefinition("-bc_slip", "Face IDs to apply slip BC", NULL, "slip", &bc_def, NULL));
86*5e79d562SJames Wright   PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg));
87487a3b6eSJames Wright 
88487a3b6eSJames Wright   PetscOptionsEnd();
89487a3b6eSJames Wright 
90487a3b6eSJames Wright   PetscCall(PetscSegBufferGetSize(bc_defs_seg, &problem->num_bc_defs));
91487a3b6eSJames Wright   PetscCall(PetscSegBufferExtractAlloc(bc_defs_seg, &problem->bc_defs));
92487a3b6eSJames Wright   PetscCall(PetscSegBufferDestroy(&bc_defs_seg));
93487a3b6eSJames Wright 
94487a3b6eSJames Wright   //TODO: Verify that the BCDefinition don't have overlapping claims to boundary faces
95487a3b6eSJames Wright 
96487a3b6eSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
97487a3b6eSJames Wright }
98*5e79d562SJames Wright 
99*5e79d562SJames Wright /**
100*5e79d562SJames Wright   @brief Destroy `HoneeBCStruct` object
101*5e79d562SJames Wright 
102*5e79d562SJames Wright   @param[in] ctx Pointer to `HoneeBCStruct`
103*5e79d562SJames Wright **/
104*5e79d562SJames Wright PetscErrorCode HoneeBCDestroy(void **ctx) {
105*5e79d562SJames Wright   HoneeBCStruct honee_bc = *(HoneeBCStruct *)ctx;
106*5e79d562SJames Wright   Ceed          ceed     = honee_bc->honee->ceed;
107*5e79d562SJames Wright 
108*5e79d562SJames Wright   PetscFunctionBeginUser;
109*5e79d562SJames Wright   if (honee_bc->qfctx) PetscCallCeed(ceed, CeedQFunctionContextDestroy(&honee_bc->qfctx));
110*5e79d562SJames Wright   if (honee_bc->DestroyCtx) PetscCall((*(honee_bc->DestroyCtx))(&honee_bc->ctx));
111*5e79d562SJames Wright   PetscCall(PetscFree(honee_bc));
112*5e79d562SJames Wright   *ctx = NULL;
113*5e79d562SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
114*5e79d562SJames Wright }
115*5e79d562SJames Wright 
116*5e79d562SJames Wright /**
117*5e79d562SJames Wright   @brief Create a QFunction matching the "standard" HONEE inputs for IFunctions
118*5e79d562SJames Wright 
119*5e79d562SJames Wright   This assumes the `bc_def` context is a `HoneeBCStruct` and inputs/outputs of the IFunction QFunction are in the correct order.
120*5e79d562SJames Wright 
121*5e79d562SJames Wright   @param[in]  bc_def      `BCDefinition` that hosts the IFunction
122*5e79d562SJames Wright   @param[in]  qf_func_ptr `CeedQFunctionUser` for the IFunction
123*5e79d562SJames Wright   @param[in]  qf_loc      Absolute path to source of `CeedQFunctionUser`
124*5e79d562SJames Wright   @param[in]  qfctx       `CeedQFunctionContext` for the IFunction (also shared with the IJacobian, if applicable)
125*5e79d562SJames Wright   @param[out] qf_ifunc    QFunction for the IFunction
126*5e79d562SJames Wright **/
127*5e79d562SJames Wright PetscErrorCode HoneeBCCreateIFunctionQF(BCDefinition bc_def, CeedQFunctionUser qf_func_ptr, const char *qf_loc, CeedQFunctionContext qfctx,
128*5e79d562SJames Wright                                         CeedQFunction *qf_ifunc) {
129*5e79d562SJames Wright   Ceed          ceed;
130*5e79d562SJames Wright   DM            dm;
131*5e79d562SJames Wright   PetscInt      dim, dim_sur, height = 1, num_comp_x, num_comp_q;
132*5e79d562SJames Wright   CeedInt       q_data_size_sur, jac_data_size_sur;
133*5e79d562SJames Wright   HoneeBCStruct honee_bc;
134*5e79d562SJames Wright 
135*5e79d562SJames Wright   PetscFunctionBeginUser;
136*5e79d562SJames Wright   PetscCall(BCDefinitionGetDM(bc_def, &dm));
137*5e79d562SJames Wright   PetscCall(BCDefinitionGetContext(bc_def, &honee_bc));
138*5e79d562SJames Wright   ceed              = honee_bc->honee->ceed;
139*5e79d562SJames Wright   jac_data_size_sur = honee_bc->jac_data_size_sur;
140*5e79d562SJames Wright 
141*5e79d562SJames Wright   PetscCall(DMGetDimension(dm, &dim));
142*5e79d562SJames Wright   dim_sur = dim - height;
143*5e79d562SJames Wright   PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size_sur));
144*5e79d562SJames Wright   PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x));
145*5e79d562SJames Wright   {
146*5e79d562SJames Wright     PetscSection section;
147*5e79d562SJames Wright 
148*5e79d562SJames Wright     PetscCall(DMGetLocalSection(dm, &section));
149*5e79d562SJames Wright     PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q));
150*5e79d562SJames Wright   }
151*5e79d562SJames Wright 
152*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, qf_func_ptr, qf_loc, qf_ifunc));
153*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionSetContext(*qf_ifunc, qfctx));
154*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(*qf_ifunc, 0));
155*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "q", num_comp_q, CEED_EVAL_INTERP));
156*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "Grad_q", num_comp_q * dim_sur, CEED_EVAL_GRAD));
157*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "surface qdata", q_data_size_sur, CEED_EVAL_NONE));
158*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "x", num_comp_x, CEED_EVAL_INTERP));
159*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddOutput(*qf_ifunc, "v", num_comp_q, CEED_EVAL_INTERP));
160*5e79d562SJames Wright   if (jac_data_size_sur) PetscCallCeed(ceed, CeedQFunctionAddOutput(*qf_ifunc, "surface jacobian data", jac_data_size_sur, CEED_EVAL_NONE));
161*5e79d562SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
162*5e79d562SJames Wright }
163*5e79d562SJames Wright 
164*5e79d562SJames Wright /**
165*5e79d562SJames Wright   @brief Create a QFunction matching the "standard" HONEE inputs for IJacobian
166*5e79d562SJames Wright 
167*5e79d562SJames Wright   This assumes the `bc_def` context is a `HoneeBCStruct` and inputs/outputs of the IJacobian QFunction are in the correct order.
168*5e79d562SJames Wright 
169*5e79d562SJames Wright   @param[in]  bc_def      `BCDefinition` that hosts the IJacobian
170*5e79d562SJames Wright   @param[in]  qf_func_ptr `CeedQFunctionUser` for the IJacobian
171*5e79d562SJames Wright   @param[in]  qf_loc      Absolute path to source of `CeedQFunctionUser`
172*5e79d562SJames Wright   @param[in]  qfctx       `CeedQFunctionContext` for the IJacobian (also shared with the IFunction)
173*5e79d562SJames Wright   @param[out] qf_ijac     QFunction for the IJacobian
174*5e79d562SJames Wright **/
175*5e79d562SJames Wright PetscErrorCode HoneeBCCreateIJacobianQF(BCDefinition bc_def, CeedQFunctionUser qf_func_ptr, const char *qf_loc, CeedQFunctionContext qfctx,
176*5e79d562SJames Wright                                         CeedQFunction *qf_ijac) {
177*5e79d562SJames Wright   Ceed          ceed;
178*5e79d562SJames Wright   DM            dm;
179*5e79d562SJames Wright   PetscInt      dim, dim_sur, height = 1, num_comp_x, num_comp_q;
180*5e79d562SJames Wright   CeedInt       q_data_size_sur, jac_data_size_sur;
181*5e79d562SJames Wright   HoneeBCStruct honee_bc;
182*5e79d562SJames Wright 
183*5e79d562SJames Wright   PetscFunctionBeginUser;
184*5e79d562SJames Wright   PetscCall(BCDefinitionGetDM(bc_def, &dm));
185*5e79d562SJames Wright   PetscCall(BCDefinitionGetContext(bc_def, &honee_bc));
186*5e79d562SJames Wright   ceed              = honee_bc->honee->ceed;
187*5e79d562SJames Wright   jac_data_size_sur = honee_bc->jac_data_size_sur;
188*5e79d562SJames Wright 
189*5e79d562SJames Wright   PetscCall(DMGetDimension(dm, &dim));
190*5e79d562SJames Wright   dim_sur = dim - height;
191*5e79d562SJames Wright   PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size_sur));
192*5e79d562SJames Wright   PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x));
193*5e79d562SJames Wright   {
194*5e79d562SJames Wright     PetscSection section;
195*5e79d562SJames Wright 
196*5e79d562SJames Wright     PetscCall(DMGetLocalSection(dm, &section));
197*5e79d562SJames Wright     PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q));
198*5e79d562SJames Wright   }
199*5e79d562SJames Wright 
200*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, qf_func_ptr, qf_loc, qf_ijac));
201*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionSetContext(*qf_ijac, qfctx));
202*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(*qf_ijac, 0));
203*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "dq", num_comp_q, CEED_EVAL_INTERP));
204*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "Grad_dq", num_comp_q * dim_sur, CEED_EVAL_GRAD));
205*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "surface qdata", q_data_size_sur, CEED_EVAL_NONE));
206*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "x", num_comp_x, CEED_EVAL_INTERP));
207*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "surface jacobian data", jac_data_size_sur, CEED_EVAL_NONE));
208*5e79d562SJames Wright   PetscCallCeed(ceed, CeedQFunctionAddOutput(*qf_ijac, "v", num_comp_q, CEED_EVAL_INTERP));
209*5e79d562SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
210*5e79d562SJames Wright }
211*5e79d562SJames Wright 
212*5e79d562SJames Wright /**
213*5e79d562SJames Wright   @brief Setups and adds IFunction operator to given composite operator
214*5e79d562SJames Wright 
215*5e79d562SJames Wright   @param[in]     bc_def       `BCDefinition` for the boundary condition IFunction
216*5e79d562SJames Wright   @param[in]     domain_label `DMLabel` for the face orientation label
217*5e79d562SJames Wright   @param[in]     label_value  Orientation value
218*5e79d562SJames Wright   @param[in]     qf_ifunc     QFunction for the IFunction
219*5e79d562SJames Wright   @param[in,out] op_ifunc     Composite operator to be added to
220*5e79d562SJames Wright   @param[out]    sub_op_ifunc Non-composite operator that is added in this function. To be passed to `HoneeBCAddIJacobianOp()`
221*5e79d562SJames Wright **/
222*5e79d562SJames Wright PetscErrorCode HoneeBCAddIFunctionOp(BCDefinition bc_def, DMLabel domain_label, PetscInt label_value, CeedQFunction qf_ifunc, CeedOperator op_ifunc,
223*5e79d562SJames Wright                                      CeedOperator *sub_op_ifunc) {
224*5e79d562SJames Wright   Honee               honee;
225*5e79d562SJames Wright   Ceed                ceed;
226*5e79d562SJames Wright   DM                  dm, dm_coord;
227*5e79d562SJames Wright   HoneeBCStruct       honee_bc;
228*5e79d562SJames Wright   PetscInt            dim, height = 1, num_comp_x, num_comp_q;
229*5e79d562SJames Wright   CeedInt             q_data_size, jac_data_size;
230*5e79d562SJames Wright   CeedVector          q_data, jac_data;
231*5e79d562SJames Wright   CeedOperator        sub_op_ifunc_;
232*5e79d562SJames Wright   CeedElemRestriction elem_restr_qd, elem_restr_q, elem_restr_x, elem_restr_jac;
233*5e79d562SJames Wright   CeedBasis           basis_x, basis_q;
234*5e79d562SJames Wright 
235*5e79d562SJames Wright   PetscFunctionBeginUser;
236*5e79d562SJames Wright   PetscCall(BCDefinitionGetDM(bc_def, &dm));
237*5e79d562SJames Wright   PetscCall(BCDefinitionGetContext(bc_def, &honee_bc));
238*5e79d562SJames Wright   honee         = honee_bc->honee;
239*5e79d562SJames Wright   ceed          = honee_bc->honee->ceed;
240*5e79d562SJames Wright   jac_data_size = honee_bc->jac_data_size_sur;
241*5e79d562SJames Wright 
242*5e79d562SJames Wright   PetscCall(DMGetDimension(dm, &dim));
243*5e79d562SJames Wright   PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size));
244*5e79d562SJames Wright   PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x));
245*5e79d562SJames Wright 
246*5e79d562SJames Wright   {
247*5e79d562SJames Wright     PetscSection section;
248*5e79d562SJames Wright 
249*5e79d562SJames Wright     PetscCall(DMGetLocalSection(dm, &section));
250*5e79d562SJames Wright     PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q));
251*5e79d562SJames Wright   }
252*5e79d562SJames Wright 
253*5e79d562SJames Wright   PetscCall(DMGetCoordinateDM(dm, &dm_coord));
254*5e79d562SJames Wright   PetscCall(CreateBasisFromPlex(ceed, dm, domain_label, label_value, height, bc_def->dm_field, &basis_q));
255*5e79d562SJames Wright   PetscCall(CreateBasisFromPlex(ceed, dm_coord, domain_label, label_value, height, bc_def->dm_field, &basis_x));
256*5e79d562SJames Wright   PetscCall(DMPlexCeedElemRestrictionCreate(ceed, dm, domain_label, label_value, height, bc_def->dm_field, &elem_restr_q));
257*5e79d562SJames Wright   PetscCall(DMPlexCeedElemRestrictionCoordinateCreate(ceed, dm, domain_label, label_value, height, &elem_restr_x));
258*5e79d562SJames Wright   if (jac_data_size > 0) {
259*5e79d562SJames Wright     PetscCall(DMPlexCeedElemRestrictionQDataCreate(ceed, dm, domain_label, label_value, height, jac_data_size, &elem_restr_jac));
260*5e79d562SJames Wright     PetscCallCeed(ceed, CeedElemRestrictionCreateVector(elem_restr_jac, &jac_data, NULL));
261*5e79d562SJames Wright   }
262*5e79d562SJames Wright 
263*5e79d562SJames Wright   PetscCall(QDataBoundaryGet(ceed, dm, domain_label, label_value, elem_restr_x, basis_x, honee->x_coord, &elem_restr_qd, &q_data, &q_data_size));
264*5e79d562SJames Wright 
265*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_ifunc, NULL, NULL, &sub_op_ifunc_));
266*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "q", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
267*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "Grad_q", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
268*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "surface qdata", elem_restr_qd, CEED_BASIS_NONE, q_data));
269*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "x", elem_restr_x, basis_x, honee->x_coord));
270*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "v", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
271*5e79d562SJames Wright   if (jac_data_size > 0) PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "surface jacobian data", elem_restr_jac, CEED_BASIS_NONE, jac_data));
272*5e79d562SJames Wright 
273*5e79d562SJames Wright   PetscCallCeed(ceed, CeedCompositeOperatorAddSub(op_ifunc, sub_op_ifunc_));
274*5e79d562SJames Wright   *sub_op_ifunc = sub_op_ifunc_;
275*5e79d562SJames Wright 
276*5e79d562SJames Wright   PetscCallCeed(ceed, CeedVectorDestroy(&q_data));
277*5e79d562SJames Wright   PetscCallCeed(ceed, CeedBasisDestroy(&basis_q));
278*5e79d562SJames Wright   PetscCallCeed(ceed, CeedBasisDestroy(&basis_x));
279*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd));
280*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_q));
281*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_x));
282*5e79d562SJames Wright   if (jac_data_size > 0) {
283*5e79d562SJames Wright     PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_jac));
284*5e79d562SJames Wright     PetscCallCeed(ceed, CeedVectorDestroy(&jac_data));
285*5e79d562SJames Wright   }
286*5e79d562SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
287*5e79d562SJames Wright }
288*5e79d562SJames Wright 
289*5e79d562SJames Wright /**
290*5e79d562SJames Wright   @brief Setups and adds IJacobian operator to given composite operator
291*5e79d562SJames Wright 
292*5e79d562SJames Wright   The field data (element restriction, vector, etc) is read from `sub_op_ifunc` and used for the IJacobian.
293*5e79d562SJames Wright 
294*5e79d562SJames Wright   @param[in]     bc_def       `BCDefinition` for the boundary condition IJacobian
295*5e79d562SJames Wright   @param[out]    sub_op_ifunc IFunction operator corresponding to this IJacobian operator.
296*5e79d562SJames Wright   @param[in]     domain_label `DMLabel` for the face orientation label
297*5e79d562SJames Wright   @param[in]     label_value  Orientation value
298*5e79d562SJames Wright   @param[in]     qf_ijac      QFunction for the IJacobian
299*5e79d562SJames Wright   @param[in,out] op_ijac      Composite operator to be added to
300*5e79d562SJames Wright **/
301*5e79d562SJames Wright PetscErrorCode HoneeBCAddIJacobianOp(BCDefinition bc_def, CeedOperator sub_op_ifunc, DMLabel domain_label, PetscInt label_value,
302*5e79d562SJames Wright                                      CeedQFunction qf_ijac, CeedOperator op_ijac) {
303*5e79d562SJames Wright   Honee               honee;
304*5e79d562SJames Wright   Ceed                ceed;
305*5e79d562SJames Wright   DM                  dm, dm_coord;
306*5e79d562SJames Wright   HoneeBCStruct       honee_bc;
307*5e79d562SJames Wright   PetscInt            dim, height = 1, num_comp_x, num_comp_q;
308*5e79d562SJames Wright   CeedInt             q_data_size;
309*5e79d562SJames Wright   CeedVector          q_data, jac_data;
310*5e79d562SJames Wright   CeedElemRestriction elem_restr_qd, elem_restr_q, elem_restr_x, elem_restr_jac;
311*5e79d562SJames Wright   CeedOperator        sub_op_ijac;
312*5e79d562SJames Wright   CeedBasis           basis_x, basis_q;
313*5e79d562SJames Wright 
314*5e79d562SJames Wright   PetscFunctionBeginUser;
315*5e79d562SJames Wright   PetscCall(BCDefinitionGetContext(bc_def, &honee_bc));
316*5e79d562SJames Wright   if (honee_bc->jac_data_size_sur == 0) PetscFunctionReturn(PETSC_SUCCESS);
317*5e79d562SJames Wright   PetscCall(BCDefinitionGetDM(bc_def, &dm));
318*5e79d562SJames Wright   honee = honee_bc->honee;
319*5e79d562SJames Wright   ceed  = honee_bc->honee->ceed;
320*5e79d562SJames Wright 
321*5e79d562SJames Wright   PetscCall(DMGetDimension(dm, &dim));
322*5e79d562SJames Wright   PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size));
323*5e79d562SJames Wright   PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x));
324*5e79d562SJames Wright 
325*5e79d562SJames Wright   {
326*5e79d562SJames Wright     PetscSection section;
327*5e79d562SJames Wright 
328*5e79d562SJames Wright     PetscCall(DMGetLocalSection(dm, &section));
329*5e79d562SJames Wright     PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q));
330*5e79d562SJames Wright   }
331*5e79d562SJames Wright 
332*5e79d562SJames Wright   PetscCall(DMGetCoordinateDM(dm, &dm_coord));
333*5e79d562SJames Wright   PetscCall(CreateBasisFromPlex(ceed, dm, domain_label, label_value, height, bc_def->dm_field, &basis_q));
334*5e79d562SJames Wright   PetscCall(CreateBasisFromPlex(ceed, dm_coord, domain_label, label_value, height, bc_def->dm_field, &basis_x));
335*5e79d562SJames Wright 
336*5e79d562SJames Wright   {  // Get restriction and basis from the RHS function
337*5e79d562SJames Wright     CeedOperatorField op_field;
338*5e79d562SJames Wright 
339*5e79d562SJames Wright     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_op_ifunc, "q", &op_field));
340*5e79d562SJames Wright     PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(op_field, &elem_restr_q));
341*5e79d562SJames Wright 
342*5e79d562SJames Wright     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_op_ifunc, "x", &op_field));
343*5e79d562SJames Wright     PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(op_field, &elem_restr_x));
344*5e79d562SJames Wright 
345*5e79d562SJames Wright     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_op_ifunc, "surface jacobian data", &op_field));
346*5e79d562SJames Wright     PetscCallCeed(ceed, CeedOperatorFieldGetData(op_field, NULL, &elem_restr_jac, NULL, &jac_data));
347*5e79d562SJames Wright   }
348*5e79d562SJames Wright 
349*5e79d562SJames Wright   PetscCall(QDataBoundaryGet(ceed, dm, domain_label, label_value, elem_restr_x, basis_x, honee->x_coord, &elem_restr_qd, &q_data, &q_data_size));
350*5e79d562SJames Wright 
351*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_ijac, NULL, NULL, &sub_op_ijac));
352*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "dq", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
353*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "Grad_dq", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
354*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "surface qdata", elem_restr_qd, CEED_BASIS_NONE, q_data));
355*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "x", elem_restr_x, basis_x, honee->x_coord));
356*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "surface jacobian data", elem_restr_jac, CEED_BASIS_NONE, jac_data));
357*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "v", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
358*5e79d562SJames Wright 
359*5e79d562SJames Wright   PetscCallCeed(ceed, CeedCompositeOperatorAddSub(op_ijac, sub_op_ijac));
360*5e79d562SJames Wright 
361*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_q));
362*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_x));
363*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_jac));
364*5e79d562SJames Wright   PetscCallCeed(ceed, CeedVectorDestroy(&jac_data));
365*5e79d562SJames Wright   PetscCallCeed(ceed, CeedVectorDestroy(&q_data));
366*5e79d562SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd));
367*5e79d562SJames Wright   PetscCallCeed(ceed, CeedBasisDestroy(&basis_q));
368*5e79d562SJames Wright   PetscCallCeed(ceed, CeedBasisDestroy(&basis_x));
369*5e79d562SJames Wright   PetscCallCeed(ceed, CeedOperatorDestroy(&sub_op_ijac));
370*5e79d562SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
371*5e79d562SJames Wright }
372