xref: /honee/src/diff_flux_projection.c (revision 36038bbcf8b5827c2ae723a5a7c52ea5c4047506)
18c85b835SJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
28c85b835SJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
38c85b835SJames Wright /// @file
48c85b835SJames Wright /// Functions for setting up and projecting the divergence of the diffusive flux
58c85b835SJames Wright 
68c85b835SJames Wright #include "../qfunctions/diff_flux_projection.h"
78c85b835SJames Wright 
88c85b835SJames Wright #include <petscdmplex.h>
98c85b835SJames Wright 
108c85b835SJames Wright #include <navierstokes.h>
118c85b835SJames Wright 
128c85b835SJames Wright /**
13*36038bbcSJames Wright   @brief Create `DivDiffFluxProjectionData` for solution DM in `user`
148c85b835SJames Wright 
158c85b835SJames Wright   @param[in]  user                `User` context
16*36038bbcSJames Wright   @param[in]  num_diff_flux_comps Number of components that makes up the diffusive flux (e.g. 1 for scalar advection-diffusion)
17*36038bbcSJames Wright   @param[out] pdiff_flux_proj     The `DivDiffFluxProjectionData` object created, or `NULL` if not created
188c85b835SJames Wright **/
19*36038bbcSJames Wright PetscErrorCode DivDiffFluxProjectionCreate(User user, PetscInt num_diff_flux_comps, DivDiffFluxProjectionData *pdiff_flux_proj) {
20*36038bbcSJames Wright   PetscInt                  label_value = 0, height = 0, dm_field = 0, dim, degree = user->app_ctx->degree, q_extra = user->app_ctx->q_extra;
218c85b835SJames Wright   DMLabel                   domain_label = NULL;
228c85b835SJames Wright   DivDiffFluxProjectionData diff_flux_proj;
238c85b835SJames Wright   NodalProjectionData       projection;
248c85b835SJames Wright 
258c85b835SJames Wright   PetscFunctionBeginUser;
26*36038bbcSJames Wright   if (user->app_ctx->divFdiffproj_method == DIV_DIFF_FLUX_PROJ_NONE) {
27*36038bbcSJames Wright     *pdiff_flux_proj = NULL;
28*36038bbcSJames Wright     PetscFunctionReturn(PETSC_SUCCESS);
29*36038bbcSJames Wright   }
30*36038bbcSJames Wright   PetscCall(PetscNew(pdiff_flux_proj));
31*36038bbcSJames Wright   diff_flux_proj = *pdiff_flux_proj;
328c85b835SJames Wright   PetscCall(PetscNew(&user->diff_flux_proj->projection));
338c85b835SJames Wright   projection                          = user->diff_flux_proj->projection;
348c85b835SJames Wright   diff_flux_proj->method              = user->app_ctx->divFdiffproj_method;
35*36038bbcSJames Wright   diff_flux_proj->num_diff_flux_comps = num_diff_flux_comps;
368c85b835SJames Wright 
378c85b835SJames Wright   PetscCall(DMClone(user->dm, &projection->dm));
388c85b835SJames Wright   PetscCall(DMSetMatrixPreallocateSkip(projection->dm, PETSC_TRUE));
398c85b835SJames Wright   PetscCall(DMGetDimension(projection->dm, &dim));
408c85b835SJames Wright   switch (diff_flux_proj->method) {
418c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_DIRECT: {
428c85b835SJames Wright       projection->num_comp = diff_flux_proj->num_diff_flux_comps;
438c85b835SJames Wright       PetscCall(PetscObjectSetName((PetscObject)projection->dm, "DivDiffFluxProj"));
44*36038bbcSJames Wright       PetscCall(DMSetupByOrder_FEM(PETSC_TRUE, PETSC_TRUE, degree, 1, q_extra, 1, &projection->num_comp, projection->dm));
458c85b835SJames Wright 
46*36038bbcSJames Wright       PetscCall(DMPlexCeedElemRestrictionCreate(user->ceed, projection->dm, domain_label, label_value, height, dm_field,
47*36038bbcSJames Wright                                                 &diff_flux_proj->elem_restr_div_diff_flux));
48*36038bbcSJames Wright       PetscCallCeed(user->ceed, CeedElemRestrictionCreateVector(diff_flux_proj->elem_restr_div_diff_flux, &diff_flux_proj->div_diff_flux_ceed, NULL));
49*36038bbcSJames Wright       PetscCall(CreateBasisFromPlex(user->ceed, projection->dm, domain_label, label_value, height, dm_field, &diff_flux_proj->basis_div_diff_flux));
50*36038bbcSJames Wright       diff_flux_proj->eval_mode_div_diff_flux = CEED_EVAL_INTERP;
511af555e8SJames Wright 
521af555e8SJames Wright       {  // Create face labels on projection->dm for boundary integrals
531af555e8SJames Wright         DMLabel  face_sets_label;
541af555e8SJames Wright         PetscInt num_face_set_values, *face_set_values;
551af555e8SJames Wright 
561af555e8SJames Wright         PetscCall(DMGetLabel(user->dm, "Face Sets", &face_sets_label));
571af555e8SJames Wright         PetscCall(DMLabelCreateGlobalValueArray(user->dm, face_sets_label, &num_face_set_values, &face_set_values));
581af555e8SJames Wright         for (PetscInt f = 0; f < num_face_set_values; f++) {
591af555e8SJames Wright           DMLabel face_orientation_label;
601af555e8SJames Wright           char   *face_orientation_label_name;
611af555e8SJames Wright 
621af555e8SJames Wright           PetscCall(DMPlexCreateFaceLabel(user->dm, face_set_values[f], &face_orientation_label_name));
631af555e8SJames Wright           PetscCall(DMGetLabel(user->dm, face_orientation_label_name, &face_orientation_label));
641af555e8SJames Wright           PetscCall(DMAddLabel(projection->dm, face_orientation_label));
651af555e8SJames Wright           PetscCall(PetscFree(face_orientation_label_name));
661af555e8SJames Wright         }
67*36038bbcSJames Wright         PetscCall(PetscFree(face_set_values));
681af555e8SJames Wright       }
698c85b835SJames Wright     } break;
708c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_INDIRECT: {
718c85b835SJames Wright       projection->num_comp = diff_flux_proj->num_diff_flux_comps * dim;
728c85b835SJames Wright       PetscCall(PetscObjectSetName((PetscObject)projection->dm, "DiffFluxProj"));
73*36038bbcSJames Wright       PetscCall(DMSetupByOrder_FEM(PETSC_TRUE, PETSC_TRUE, degree, 1, q_extra, 1, &projection->num_comp, projection->dm));
748c85b835SJames Wright 
758c85b835SJames Wright       PetscCall(DMPlexCeedElemRestrictionQDataCreate(user->ceed, projection->dm, domain_label, label_value, height,
76*36038bbcSJames Wright                                                      diff_flux_proj->num_diff_flux_comps, &diff_flux_proj->elem_restr_div_diff_flux));
77*36038bbcSJames Wright       PetscCallCeed(user->ceed, CeedElemRestrictionCreateVector(diff_flux_proj->elem_restr_div_diff_flux, &diff_flux_proj->div_diff_flux_ceed, NULL));
78*36038bbcSJames Wright       diff_flux_proj->basis_div_diff_flux     = CEED_BASIS_NONE;
79*36038bbcSJames Wright       diff_flux_proj->eval_mode_div_diff_flux = CEED_EVAL_NONE;
808c85b835SJames Wright     } break;
818c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_NONE:
828c85b835SJames Wright       SETERRQ(PetscObjectComm((PetscObject)user->dm), PETSC_ERR_ARG_WRONG, "Should not reach here with div_diff_flux_projection_method %s",
838c85b835SJames Wright               DivDiffFluxProjectionMethods[user->app_ctx->divFdiffproj_method]);
848c85b835SJames Wright       break;
858c85b835SJames Wright   }
868c85b835SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
878c85b835SJames Wright };
888c85b835SJames Wright 
898c85b835SJames Wright /**
908c85b835SJames Wright   @brief Setup direct projection of divergence of diffusive flux
918c85b835SJames Wright 
928c85b835SJames Wright   @param[in] ceed      `Ceed` context
938c85b835SJames Wright   @param[in] user      `User` context
948c85b835SJames Wright   @param[in] ceed_data `CeedData` context
958c85b835SJames Wright   @param[in] problem   `ProblemData` context
968c85b835SJames Wright **/
978c85b835SJames Wright static PetscErrorCode DivDiffFluxProjectionSetup_Direct(Ceed ceed, User user, CeedData ceed_data, ProblemData problem) {
988c85b835SJames Wright   DivDiffFluxProjectionData diff_flux_proj = user->diff_flux_proj;
998c85b835SJames Wright   NodalProjectionData       projection     = diff_flux_proj->projection;
1008c85b835SJames Wright   CeedOperator              op_rhs;
1018c85b835SJames Wright   CeedBasis                 basis_diff_flux;
1028c85b835SJames Wright   CeedElemRestriction       elem_restr_diff_flux_volume, elem_restr_qd;
1038c85b835SJames Wright   CeedVector                q_data;
1048c85b835SJames Wright   CeedInt                   num_comp_q, q_data_size;
1058c85b835SJames Wright   PetscInt                  dim, label_value = 0;
1068c85b835SJames Wright   DMLabel                   domain_label = NULL;
107*36038bbcSJames Wright   MPI_Comm                  comm         = PetscObjectComm((PetscObject)projection->dm);
1088c85b835SJames Wright 
1098c85b835SJames Wright   PetscFunctionBeginUser;
1108c85b835SJames Wright   // -- Get Pre-requisite things
1118c85b835SJames Wright   PetscCall(DMGetDimension(projection->dm, &dim));
1128c85b835SJames Wright   PetscCallCeed(ceed, CeedBasisGetNumComponents(ceed_data->basis_q, &num_comp_q));
1138c85b835SJames Wright 
1148c85b835SJames Wright   {  // Get elem_restr_diff_flux and basis_diff_flux
1158c85b835SJames Wright     CeedOperator     *sub_ops;
1168c85b835SJames Wright     CeedOperatorField op_field;
1178c85b835SJames Wright     PetscInt          sub_op_index = 0;  // will be 0 for the volume op
1188c85b835SJames Wright 
1198c85b835SJames Wright     PetscCallCeed(ceed, CeedCompositeOperatorGetSubList(user->op_ifunction, &sub_ops));
1208c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_ops[sub_op_index], "div F_diff", &op_field));
1218c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(op_field, &elem_restr_diff_flux_volume));
1228c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorFieldGetBasis(op_field, &basis_diff_flux));
1238c85b835SJames Wright   }
1248c85b835SJames Wright   PetscCall(QDataGet(ceed, projection->dm, domain_label, label_value, ceed_data->elem_restr_x, ceed_data->basis_x, ceed_data->x_coord, &elem_restr_qd,
1258c85b835SJames Wright                      &q_data, &q_data_size));
1268c85b835SJames Wright 
127*36038bbcSJames Wright   {  // Create Projection RHS OperatorApplyContext
128*36038bbcSJames Wright     CeedOperator op_rhs;
1298c85b835SJames Wright 
130*36038bbcSJames Wright     PetscCheck(diff_flux_proj->CreateRHSOperator_Direct, comm, PETSC_ERR_ARG_WRONGSTATE,
131*36038bbcSJames Wright                "Must define CreateRHSOperator_Direct to use indirect div_diff_flux projection");
132*36038bbcSJames Wright     PetscCall(diff_flux_proj->CreateRHSOperator_Direct(user, ceed_data, diff_flux_proj, &op_rhs));
1338c85b835SJames Wright     PetscCall(DMCreateLocalVector(projection->dm, &diff_flux_proj->DivDiffFlux_loc));
1348c85b835SJames Wright     diff_flux_proj->ceed_vec_has_array = PETSC_FALSE;
135*36038bbcSJames Wright     PetscCall(OperatorApplyContextCreate(user->dm, projection->dm, ceed, op_rhs, NULL, NULL, NULL, diff_flux_proj->DivDiffFlux_loc,
136*36038bbcSJames Wright                                          &projection->l2_rhs_ctx));
137*36038bbcSJames Wright     PetscCallCeed(ceed, CeedOperatorDestroy(&op_rhs));
138*36038bbcSJames Wright   }
1398c85b835SJames Wright 
1408c85b835SJames Wright   {  // -- Build Mass operator
1418c85b835SJames Wright     CeedQFunction qf_mass;
1428c85b835SJames Wright     CeedOperator  op_mass;
1438c85b835SJames Wright 
1448c85b835SJames Wright     PetscCall(CreateMassQFunction(ceed, projection->num_comp, q_data_size, &qf_mass));
1458c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_mass, NULL, NULL, &op_mass));
1468c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_mass, "u", elem_restr_diff_flux_volume, basis_diff_flux, CEED_VECTOR_ACTIVE));
1478c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_mass, "qdata", elem_restr_qd, CEED_BASIS_NONE, q_data));
1488c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_mass, "v", elem_restr_diff_flux_volume, basis_diff_flux, CEED_VECTOR_ACTIVE));
1498c85b835SJames Wright 
1508c85b835SJames Wright     {  // -- Setup KSP for L^2 projection
1518c85b835SJames Wright       Mat mat_mass;
1528c85b835SJames Wright 
1538c85b835SJames Wright       PetscCall(MatCreateCeed(projection->dm, projection->dm, op_mass, NULL, &mat_mass));
1548c85b835SJames Wright 
1558c85b835SJames Wright       PetscCall(KSPCreate(comm, &projection->ksp));
1568c85b835SJames Wright       PetscCall(KSPSetOptionsPrefix(projection->ksp, "div_diff_flux_projection_"));
1578c85b835SJames Wright       {  // lumped by default
1588c85b835SJames Wright         PC pc;
1598c85b835SJames Wright         PetscCall(KSPGetPC(projection->ksp, &pc));
1608c85b835SJames Wright         PetscCall(PCSetType(pc, PCJACOBI));
1618c85b835SJames Wright         PetscCall(PCJacobiSetType(pc, PC_JACOBI_ROWSUM));
1628c85b835SJames Wright         PetscCall(KSPSetType(projection->ksp, KSPPREONLY));
1638c85b835SJames Wright       }
1648c85b835SJames Wright       PetscCall(KSPSetFromOptions_WithMatCeed(projection->ksp, mat_mass));
1658c85b835SJames Wright       PetscCall(MatDestroy(&mat_mass));
1668c85b835SJames Wright     }
1678c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_mass));
1688c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorDestroy(&op_mass));
1698c85b835SJames Wright   }
1708c85b835SJames Wright   PetscCallCeed(ceed, CeedVectorDestroy(&q_data));
1718c85b835SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd));
1728c85b835SJames Wright   PetscCallCeed(ceed, CeedOperatorDestroy(&op_rhs));
1738c85b835SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
1748c85b835SJames Wright }
1758c85b835SJames Wright 
1768c85b835SJames Wright /**
1778c85b835SJames Wright   @brief Setup indirect projection of divergence of diffusive flux
1788c85b835SJames Wright 
1798c85b835SJames Wright   @param[in]     ceed      `Ceed` context
1808c85b835SJames Wright   @param[in,out] user      `User` context
1818c85b835SJames Wright   @param[in]     ceed_data `CeedData` context
1828c85b835SJames Wright   @param[in]     problem   `ProblemData` context
1838c85b835SJames Wright **/
1848c85b835SJames Wright static PetscErrorCode DivDiffFluxProjectionSetup_Indirect(Ceed ceed, User user, CeedData ceed_data, ProblemData problem) {
1858c85b835SJames Wright   DivDiffFluxProjectionData diff_flux_proj = user->diff_flux_proj;
1868c85b835SJames Wright   NodalProjectionData       projection     = diff_flux_proj->projection;
1878c85b835SJames Wright   CeedBasis                 basis_diff_flux;
1888c85b835SJames Wright   CeedElemRestriction       elem_restr_diff_flux, elem_restr_qd;
1898c85b835SJames Wright   CeedVector                q_data;
1908c85b835SJames Wright   CeedInt                   num_comp_q, q_data_size;
1918c85b835SJames Wright   PetscInt                  dim;
1928c85b835SJames Wright   PetscInt                  label_value = 0, height = 0, dm_field = 0;
1938c85b835SJames Wright   DMLabel                   domain_label = NULL;
194*36038bbcSJames Wright   MPI_Comm                  comm         = PetscObjectComm((PetscObject)projection->dm);
1958c85b835SJames Wright 
1968c85b835SJames Wright   PetscFunctionBeginUser;
1978c85b835SJames Wright   PetscCall(DMGetDimension(projection->dm, &dim));
1988c85b835SJames Wright   PetscCallCeed(ceed, CeedBasisGetNumComponents(ceed_data->basis_q, &num_comp_q));
1998c85b835SJames Wright 
2008c85b835SJames Wright   PetscCall(DMPlexCeedElemRestrictionCreate(ceed, projection->dm, domain_label, label_value, height, dm_field, &elem_restr_diff_flux));
2018c85b835SJames Wright   PetscCall(CreateBasisFromPlex(ceed, projection->dm, domain_label, label_value, height, dm_field, &basis_diff_flux));
2028c85b835SJames Wright   PetscCall(QDataGet(ceed, projection->dm, domain_label, label_value, ceed_data->elem_restr_x, ceed_data->basis_x, ceed_data->x_coord, &elem_restr_qd,
2038c85b835SJames Wright                      &q_data, &q_data_size));
2048c85b835SJames Wright 
205*36038bbcSJames Wright   {
2068c85b835SJames Wright     CeedOperator op_rhs;
2078c85b835SJames Wright 
208*36038bbcSJames Wright     PetscCheck(diff_flux_proj->CreateRHSOperator_Indirect, comm, PETSC_ERR_ARG_WRONGSTATE,
209*36038bbcSJames Wright                "Must define CreateRHSOperator_Indirect to use indirect div_diff_flux projection");
210*36038bbcSJames Wright     PetscCall(diff_flux_proj->CreateRHSOperator_Indirect(user, ceed_data, diff_flux_proj, &op_rhs));
2118c85b835SJames Wright     PetscCall(OperatorApplyContextCreate(user->dm, projection->dm, ceed, op_rhs, NULL, NULL, NULL, NULL, &projection->l2_rhs_ctx));
2128c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorDestroy(&op_rhs));
2138c85b835SJames Wright   }
2148c85b835SJames Wright 
2158c85b835SJames Wright   {  // -- Build Mass operator
2168c85b835SJames Wright     CeedQFunction qf_mass;
2178c85b835SJames Wright     CeedOperator  op_mass;
2188c85b835SJames Wright 
2198c85b835SJames Wright     PetscCall(CreateMassQFunction(ceed, projection->num_comp, q_data_size, &qf_mass));
2208c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_mass, NULL, NULL, &op_mass));
2218c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_mass, "u", elem_restr_diff_flux, basis_diff_flux, CEED_VECTOR_ACTIVE));
2228c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_mass, "qdata", elem_restr_qd, CEED_BASIS_NONE, q_data));
2238c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_mass, "v", elem_restr_diff_flux, basis_diff_flux, CEED_VECTOR_ACTIVE));
2248c85b835SJames Wright 
2258c85b835SJames Wright     {  // -- Setup KSP for L^2 projection
2268c85b835SJames Wright       Mat mat_mass;
2278c85b835SJames Wright 
2288c85b835SJames Wright       PetscCall(MatCreateCeed(projection->dm, projection->dm, op_mass, NULL, &mat_mass));
2298c85b835SJames Wright 
2308c85b835SJames Wright       PetscCall(KSPCreate(comm, &projection->ksp));
2318c85b835SJames Wright       PetscCall(KSPSetOptionsPrefix(projection->ksp, "div_diff_flux_projection_"));
2328c85b835SJames Wright       {  // lumped by default
2338c85b835SJames Wright         PC pc;
2348c85b835SJames Wright         PetscCall(KSPGetPC(projection->ksp, &pc));
2358c85b835SJames Wright         PetscCall(PCSetType(pc, PCJACOBI));
2368c85b835SJames Wright         PetscCall(PCJacobiSetType(pc, PC_JACOBI_ROWSUM));
2378c85b835SJames Wright         PetscCall(KSPSetType(projection->ksp, KSPPREONLY));
2388c85b835SJames Wright       }
2398c85b835SJames Wright       PetscCall(KSPSetFromOptions_WithMatCeed(projection->ksp, mat_mass));
2408c85b835SJames Wright       PetscCall(MatDestroy(&mat_mass));
2418c85b835SJames Wright     }
2428c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_mass));
2438c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorDestroy(&op_mass));
2448c85b835SJames Wright   }
2458c85b835SJames Wright 
2468c85b835SJames Wright   {  // Create OperatorApplyContext to calculate divergence at quadrature points
2478c85b835SJames Wright     CeedQFunction       qf_calc_divergence;
2488c85b835SJames Wright     CeedOperator        op_calc_divergence;
2498c85b835SJames Wright     CeedElemRestriction elem_restr_div_diff_flux;
2508c85b835SJames Wright 
2518c85b835SJames Wright     {  // Get elem_restr_div_diff_flux
2528c85b835SJames Wright       CeedOperator     *sub_ops;
2538c85b835SJames Wright       CeedOperatorField op_field;
2548c85b835SJames Wright       PetscInt          sub_op_index = 0;  // will be 0 for the volume op
2558c85b835SJames Wright 
2568c85b835SJames Wright       PetscCallCeed(ceed, CeedCompositeOperatorGetSubList(user->op_ifunction, &sub_ops));
2578c85b835SJames Wright       PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_ops[sub_op_index], "div F_diff", &op_field));
2588c85b835SJames Wright       PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(op_field, &elem_restr_div_diff_flux));
2598c85b835SJames Wright     }
2608c85b835SJames Wright 
2618c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, ComputeDivDiffusiveFlux3D_4, ComputeDivDiffusiveFlux3D_4_loc, &qf_calc_divergence));
2628c85b835SJames Wright 
2638c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionAddInput(qf_calc_divergence, "Grad F_diff", projection->num_comp * dim, CEED_EVAL_GRAD));
2648c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionAddInput(qf_calc_divergence, "qdata", q_data_size, CEED_EVAL_NONE));
2658c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_calc_divergence, "Div F_diff", 4, CEED_EVAL_NONE));
2668c85b835SJames Wright 
2678c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_calc_divergence, NULL, NULL, &op_calc_divergence));
2688c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_calc_divergence, "Grad F_diff", elem_restr_diff_flux, basis_diff_flux, CEED_VECTOR_ACTIVE));
2698c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorSetField(op_calc_divergence, "qdata", elem_restr_qd, CEED_BASIS_NONE, q_data));
2708c85b835SJames Wright     PetscCallCeed(
2718c85b835SJames Wright         ceed, CeedOperatorSetField(op_calc_divergence, "Div F_diff", elem_restr_div_diff_flux, CEED_BASIS_NONE, diff_flux_proj->div_diff_flux_ceed));
2728c85b835SJames Wright 
273*36038bbcSJames Wright     PetscCall(
274*36038bbcSJames Wright         OperatorApplyContextCreate(projection->dm, NULL, ceed, op_calc_divergence, NULL, NULL, NULL, NULL, &diff_flux_proj->calc_div_diff_flux));
2758c85b835SJames Wright 
2768c85b835SJames Wright     PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_calc_divergence));
2778c85b835SJames Wright     PetscCallCeed(ceed, CeedOperatorDestroy(&op_calc_divergence));
2788c85b835SJames Wright   }
2798c85b835SJames Wright   PetscCallCeed(ceed, CeedBasisDestroy(&basis_diff_flux));
2808c85b835SJames Wright   PetscCallCeed(ceed, CeedVectorDestroy(&q_data));
2818c85b835SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd));
2828c85b835SJames Wright   PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_diff_flux));
2838c85b835SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
2848c85b835SJames Wright }
2858c85b835SJames Wright 
2868c85b835SJames Wright /**
2878c85b835SJames Wright   @brief Setup projection of divergence of diffusive flux
2888c85b835SJames Wright 
2898c85b835SJames Wright   @param[in]     ceed      `Ceed` context
2908c85b835SJames Wright   @param[in,out] user      `User` context
2918c85b835SJames Wright   @param[in]     ceed_data `CeedData` context
2928c85b835SJames Wright   @param[in]     problem   `ProblemData` context
2938c85b835SJames Wright **/
2948c85b835SJames Wright PetscErrorCode DivDiffFluxProjectionSetup(Ceed ceed, User user, CeedData ceed_data, ProblemData problem) {
2958c85b835SJames Wright   PetscFunctionBeginUser;
2968c85b835SJames Wright   switch (user->app_ctx->divFdiffproj_method) {
2978c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_DIRECT:
2988c85b835SJames Wright       PetscCall(DivDiffFluxProjectionSetup_Direct(ceed, user, ceed_data, problem));
2998c85b835SJames Wright       break;
3008c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_INDIRECT:
3018c85b835SJames Wright       PetscCall(DivDiffFluxProjectionSetup_Indirect(ceed, user, ceed_data, problem));
3028c85b835SJames Wright       break;
3038c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_NONE:
3048c85b835SJames Wright       SETERRQ(PetscObjectComm((PetscObject)user->dm), PETSC_ERR_ARG_WRONG, "Should not reach here with div_diff_flux_projection_method %s",
3058c85b835SJames Wright               DivDiffFluxProjectionMethods[user->app_ctx->divFdiffproj_method]);
3068c85b835SJames Wright       break;
3078c85b835SJames Wright   }
3088c85b835SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
3098c85b835SJames Wright }
3108c85b835SJames Wright 
3118c85b835SJames Wright /**
3128c85b835SJames Wright   @brief Project the divergence of diffusive flux
3138c85b835SJames Wright 
3148c85b835SJames Wright   This implicitly sets the `CeedVector` input (`div_diff_flux_ceed`) to the divergence of diffusive flux.
3158c85b835SJames Wright 
3168c85b835SJames Wright   @param[in]  diff_flux_proj `NodalProjectionData` for the projection
3178c85b835SJames Wright   @param[in]  Q_loc          Localized solution vector
3188c85b835SJames Wright **/
319*36038bbcSJames Wright PetscErrorCode DivDiffFluxProjectionApply(DivDiffFluxProjectionData diff_flux_proj, Vec Q_loc) {
3208c85b835SJames Wright   NodalProjectionData projection = diff_flux_proj->projection;
3218c85b835SJames Wright 
3228c85b835SJames Wright   PetscFunctionBeginUser;
3238c85b835SJames Wright   PetscCall(PetscLogEventBegin(FLUIDS_DivDiffFluxProjection, Q_loc, 0, 0, 0));
3248c85b835SJames Wright   switch (diff_flux_proj->method) {
3258c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_DIRECT: {
3268c85b835SJames Wright       Vec DivDiffFlux;
3278c85b835SJames Wright 
3288c85b835SJames Wright       PetscCall(DMGetGlobalVector(projection->dm, &DivDiffFlux));
3298c85b835SJames Wright       if (diff_flux_proj->ceed_vec_has_array) {
3308c85b835SJames Wright         PetscCall(VecReadCeedToPetsc(diff_flux_proj->div_diff_flux_ceed, diff_flux_proj->DivDiffFlux_memtype, diff_flux_proj->DivDiffFlux_loc));
3318c85b835SJames Wright         diff_flux_proj->ceed_vec_has_array = PETSC_FALSE;
3328c85b835SJames Wright       }
3338c85b835SJames Wright       PetscCall(ApplyCeedOperatorLocalToGlobal(Q_loc, DivDiffFlux, projection->l2_rhs_ctx));
3348c85b835SJames Wright       PetscCall(VecViewFromOptions(DivDiffFlux, NULL, "-div_diff_flux_projection_rhs_view"));
3358c85b835SJames Wright 
3368c85b835SJames Wright       PetscCall(KSPSolve(projection->ksp, DivDiffFlux, DivDiffFlux));
3378c85b835SJames Wright       PetscCall(VecViewFromOptions(DivDiffFlux, NULL, "-div_diff_flux_projection_view"));
3388c85b835SJames Wright 
3398c85b835SJames Wright       PetscCall(DMGlobalToLocal(projection->dm, DivDiffFlux, INSERT_VALUES, diff_flux_proj->DivDiffFlux_loc));
3408c85b835SJames Wright       PetscCall(VecReadPetscToCeed(diff_flux_proj->DivDiffFlux_loc, &diff_flux_proj->DivDiffFlux_memtype, diff_flux_proj->div_diff_flux_ceed));
3418c85b835SJames Wright       diff_flux_proj->ceed_vec_has_array = PETSC_TRUE;
3428c85b835SJames Wright 
3438c85b835SJames Wright       PetscCall(DMRestoreGlobalVector(projection->dm, &DivDiffFlux));
3448c85b835SJames Wright       break;
3458c85b835SJames Wright     }
3468c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_INDIRECT: {
3478c85b835SJames Wright       Vec DiffFlux;
3488c85b835SJames Wright 
3498c85b835SJames Wright       PetscCall(DMGetGlobalVector(projection->dm, &DiffFlux));
3508c85b835SJames Wright       PetscCall(ApplyCeedOperatorLocalToGlobal(Q_loc, DiffFlux, projection->l2_rhs_ctx));
3518c85b835SJames Wright       PetscCall(VecViewFromOptions(DiffFlux, NULL, "-div_diff_flux_projection_rhs_view"));
3528c85b835SJames Wright 
3538c85b835SJames Wright       PetscCall(KSPSolve(projection->ksp, DiffFlux, DiffFlux));
3548c85b835SJames Wright       PetscCall(VecViewFromOptions(DiffFlux, NULL, "-div_diff_flux_projection_view"));
3558c85b835SJames Wright 
3568c85b835SJames Wright       PetscCall(ApplyCeedOperatorGlobalToLocal(DiffFlux, NULL, diff_flux_proj->calc_div_diff_flux));
3578c85b835SJames Wright       PetscCall(DMRestoreGlobalVector(projection->dm, &DiffFlux));
3588c85b835SJames Wright     } break;
3598c85b835SJames Wright     case DIV_DIFF_FLUX_PROJ_NONE:
3608c85b835SJames Wright       SETERRQ(PetscObjectComm((PetscObject)projection->dm), PETSC_ERR_ARG_WRONG, "Should not reach here with div_diff_flux_projection_method %s",
3618c85b835SJames Wright               DivDiffFluxProjectionMethods[diff_flux_proj->method]);
3628c85b835SJames Wright       break;
3638c85b835SJames Wright   }
3648c85b835SJames Wright   PetscCall(PetscLogEventEnd(FLUIDS_DivDiffFluxProjection, Q_loc, 0, 0, 0));
3658c85b835SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
3668c85b835SJames Wright }
3678c85b835SJames Wright 
3688c85b835SJames Wright /**
3698c85b835SJames Wright   @brief Destroy `DivDiffFluxProjectionData` object
3708c85b835SJames Wright 
3718c85b835SJames Wright   @param[in,out] diff_flux_proj Object to destroy
3728c85b835SJames Wright **/
3738c85b835SJames Wright PetscErrorCode DivDiffFluxProjectionDataDestroy(DivDiffFluxProjectionData diff_flux_proj) {
3748c85b835SJames Wright   PetscFunctionBeginUser;
3758c85b835SJames Wright   if (diff_flux_proj == NULL) PetscFunctionReturn(PETSC_SUCCESS);
3768c85b835SJames Wright   PetscCall(NodalProjectionDataDestroy(diff_flux_proj->projection));
3778c85b835SJames Wright   PetscCall(OperatorApplyContextDestroy(diff_flux_proj->calc_div_diff_flux));
3788c85b835SJames Wright   if (diff_flux_proj->ceed_vec_has_array) {
3798c85b835SJames Wright     PetscCall(VecReadCeedToPetsc(diff_flux_proj->div_diff_flux_ceed, diff_flux_proj->DivDiffFlux_memtype, diff_flux_proj->DivDiffFlux_loc));
3808c85b835SJames Wright     diff_flux_proj->ceed_vec_has_array = PETSC_FALSE;
3818c85b835SJames Wright   }
3828c85b835SJames Wright   PetscCall(CeedVectorDestroy(&diff_flux_proj->div_diff_flux_ceed));
3838c85b835SJames Wright   PetscCall(VecDestroy(&diff_flux_proj->DivDiffFlux_loc));
3848c85b835SJames Wright   PetscCall(PetscFree(diff_flux_proj));
3858c85b835SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
3868c85b835SJames Wright }
387