1 // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors. 2 // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause 3 4 #include <navierstokes.h> 5 #include "petscerror.h" 6 7 /** 8 @brief Add `BCDefinition` to a `PetscSegBuffer` 9 10 @param[in] bc_def `BCDefinition` to add 11 @param[in,out] bc_defs_seg `PetscSegBuffer` to add to 12 **/ 13 static PetscErrorCode AddBCDefinitionToSegBuffer(BCDefinition bc_def, PetscSegBuffer bc_defs_seg) { 14 BCDefinition *bc_def_ptr; 15 16 PetscFunctionBeginUser; 17 if (bc_def == NULL) PetscFunctionReturn(PETSC_SUCCESS); 18 PetscCall(PetscSegBufferGet(bc_defs_seg, 1, &bc_def_ptr)); 19 *bc_def_ptr = bc_def; 20 PetscFunctionReturn(PETSC_SUCCESS); 21 } 22 23 /** 24 @brief Create and setup `BCDefinition`s and `SimpleBC` from commandline options 25 26 @param[in] honee `Honee` 27 @param[in,out] problem `ProblemData` 28 @param[in] app_ctx `AppCtx` 29 @param[in,out] bc `SimpleBC` 30 **/ 31 PetscErrorCode BoundaryConditionSetUp(Honee honee, ProblemData problem, AppCtx app_ctx, SimpleBC bc) { 32 PetscSegBuffer bc_defs_seg; 33 PetscBool flg; 34 BCDefinition bc_def; 35 36 PetscFunctionBeginUser; 37 PetscCall(PetscSegBufferCreate(sizeof(BCDefinition), 4, &bc_defs_seg)); 38 39 PetscOptionsBegin(honee->comm, NULL, "Boundary Condition Options", NULL); 40 41 PetscCall(PetscOptionsBCDefinition("-bc_wall", "Face IDs to apply wall BC", NULL, "wall", &bc_def, NULL)); 42 PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg)); 43 if (bc_def) { 44 PetscInt num_essential_comps = 16, essential_comps[16]; 45 46 PetscCall(PetscOptionsIntArray("-wall_comps", "An array of constrained component numbers", NULL, essential_comps, &num_essential_comps, &flg)); 47 PetscCall(BCDefinitionSetEssential(bc_def, num_essential_comps, essential_comps)); 48 49 app_ctx->wall_forces.num_wall = bc_def->num_label_values; 50 PetscCall(PetscMalloc1(bc_def->num_label_values, &app_ctx->wall_forces.walls)); 51 PetscCall(PetscArraycpy(app_ctx->wall_forces.walls, bc_def->label_values, bc_def->num_label_values)); 52 } 53 54 { // Symmetry Boundary Conditions 55 const char *deprecated[3] = {"-bc_slip_x", "-bc_slip_y", "-bc_slip_z"}; 56 const char *flags[3] = {"-bc_symmetry_x", "-bc_symmetry_y", "-bc_symmetry_z"}; 57 58 for (PetscInt j = 0; j < 3; j++) { 59 PetscCall(PetscOptionsDeprecated(deprecated[j], flags[j], "libCEED 0.12.0", 60 "Use -bc_symmetry_[x,y,z] for direct equivalency, or -bc_slip for weak, Riemann-based, direction-invariant " 61 "slip/no-penatration boundary conditions")); 62 PetscCall(PetscOptionsBCDefinition(flags[j], "Face IDs to apply symmetry BC", NULL, "symmetry", &bc_def, NULL)); 63 if (!bc_def) { 64 PetscCall(PetscOptionsBCDefinition(deprecated[j], "Face IDs to apply symmetry BC", NULL, "symmetry", &bc_def, NULL)); 65 } 66 PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg)); 67 if (bc_def) { 68 PetscInt essential_comps[1] = {j + 1}; 69 70 PetscCall(BCDefinitionSetEssential(bc_def, 1, essential_comps)); 71 } 72 } 73 } 74 75 PetscCall(PetscOptionsBCDefinition("-bc_inflow", "Face IDs to apply inflow BC", NULL, "inflow", &bc_def, NULL)); 76 PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg)); 77 78 PetscCall(PetscOptionsBCDefinition("-bc_outflow", "Face IDs to apply outflow BC", NULL, "outflow", &bc_def, NULL)); 79 PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg)); 80 81 PetscCall(PetscOptionsBCDefinition("-bc_freestream", "Face IDs to apply freestream BC", NULL, "freestream", &bc_def, NULL)); 82 PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg)); 83 84 PetscCall(PetscOptionsBCDefinition("-bc_slip", "Face IDs to apply slip BC", NULL, "slip", &bc_def, NULL)); 85 PetscCall(AddBCDefinitionToSegBuffer(bc_def, bc_defs_seg)); 86 87 PetscOptionsEnd(); 88 89 PetscCall(PetscSegBufferGetSize(bc_defs_seg, &problem->num_bc_defs)); 90 PetscCall(PetscSegBufferExtractAlloc(bc_defs_seg, &problem->bc_defs)); 91 PetscCall(PetscSegBufferDestroy(&bc_defs_seg)); 92 93 //TODO: Verify that the BCDefinition don't have overlapping claims to boundary faces 94 95 PetscFunctionReturn(PETSC_SUCCESS); 96 } 97 98 /** 99 @brief Destroy `HoneeBCStruct` object 100 101 @param[in] ctx Pointer to `HoneeBCStruct` 102 **/ 103 PetscErrorCode HoneeBCDestroy(void **ctx) { 104 HoneeBCStruct honee_bc = *(HoneeBCStruct *)ctx; 105 Ceed ceed = honee_bc->honee->ceed; 106 107 PetscFunctionBeginUser; 108 if (honee_bc->qfctx) PetscCallCeed(ceed, CeedQFunctionContextDestroy(&honee_bc->qfctx)); 109 if (honee_bc->DestroyCtx) PetscCall((*(honee_bc->DestroyCtx))(&honee_bc->ctx)); 110 PetscCall(PetscFree(honee_bc)); 111 *ctx = NULL; 112 PetscFunctionReturn(PETSC_SUCCESS); 113 } 114 115 /** 116 @brief Create a QFunction matching the "standard" HONEE inputs for IFunctions 117 118 This assumes the `bc_def` context is a `HoneeBCStruct` and inputs/outputs of the IFunction QFunction are in the correct order. 119 120 @param[in] bc_def `BCDefinition` that hosts the IFunction 121 @param[in] qf_func_ptr `CeedQFunctionUser` for the IFunction 122 @param[in] qf_loc Absolute path to source of `CeedQFunctionUser` 123 @param[in] qfctx `CeedQFunctionContext` for the IFunction (also shared with the IJacobian, if applicable) 124 @param[out] qf_ifunc QFunction for the IFunction 125 **/ 126 PetscErrorCode HoneeBCCreateIFunctionQF(BCDefinition bc_def, CeedQFunctionUser qf_func_ptr, const char *qf_loc, CeedQFunctionContext qfctx, 127 CeedQFunction *qf_ifunc) { 128 Ceed ceed; 129 DM dm; 130 PetscInt dim, dim_sur, height = 1, num_comp_x, num_comp_q; 131 CeedInt q_data_size_sur, jac_data_size_sur; 132 HoneeBCStruct honee_bc; 133 134 PetscFunctionBeginUser; 135 PetscCall(BCDefinitionGetDM(bc_def, &dm)); 136 PetscCall(BCDefinitionGetContext(bc_def, &honee_bc)); 137 ceed = honee_bc->honee->ceed; 138 jac_data_size_sur = honee_bc->jac_data_size_sur; 139 140 PetscCall(DMGetDimension(dm, &dim)); 141 dim_sur = dim - height; 142 PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size_sur)); 143 PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x)); 144 { 145 PetscSection section; 146 147 PetscCall(DMGetLocalSection(dm, §ion)); 148 PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q)); 149 } 150 151 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, qf_func_ptr, qf_loc, qf_ifunc)); 152 PetscCallCeed(ceed, CeedQFunctionSetContext(*qf_ifunc, qfctx)); 153 PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(*qf_ifunc, 0)); 154 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "q", num_comp_q, CEED_EVAL_INTERP)); 155 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "Grad_q", num_comp_q * dim_sur, CEED_EVAL_GRAD)); 156 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "surface qdata", q_data_size_sur, CEED_EVAL_NONE)); 157 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ifunc, "x", num_comp_x, CEED_EVAL_INTERP)); 158 PetscCallCeed(ceed, CeedQFunctionAddOutput(*qf_ifunc, "v", num_comp_q, CEED_EVAL_INTERP)); 159 if (jac_data_size_sur) PetscCallCeed(ceed, CeedQFunctionAddOutput(*qf_ifunc, "surface jacobian data", jac_data_size_sur, CEED_EVAL_NONE)); 160 PetscFunctionReturn(PETSC_SUCCESS); 161 } 162 163 /** 164 @brief Create a QFunction matching the "standard" HONEE inputs for IJacobian 165 166 This assumes the `bc_def` context is a `HoneeBCStruct` and inputs/outputs of the IJacobian QFunction are in the correct order. 167 168 @param[in] bc_def `BCDefinition` that hosts the IJacobian 169 @param[in] qf_func_ptr `CeedQFunctionUser` for the IJacobian 170 @param[in] qf_loc Absolute path to source of `CeedQFunctionUser` 171 @param[in] qfctx `CeedQFunctionContext` for the IJacobian (also shared with the IFunction) 172 @param[out] qf_ijac QFunction for the IJacobian 173 **/ 174 PetscErrorCode HoneeBCCreateIJacobianQF(BCDefinition bc_def, CeedQFunctionUser qf_func_ptr, const char *qf_loc, CeedQFunctionContext qfctx, 175 CeedQFunction *qf_ijac) { 176 Ceed ceed; 177 DM dm; 178 PetscInt dim, dim_sur, height = 1, num_comp_x, num_comp_q; 179 CeedInt q_data_size_sur, jac_data_size_sur; 180 HoneeBCStruct honee_bc; 181 182 PetscFunctionBeginUser; 183 PetscCall(BCDefinitionGetDM(bc_def, &dm)); 184 PetscCall(BCDefinitionGetContext(bc_def, &honee_bc)); 185 ceed = honee_bc->honee->ceed; 186 jac_data_size_sur = honee_bc->jac_data_size_sur; 187 188 PetscCall(DMGetDimension(dm, &dim)); 189 dim_sur = dim - height; 190 PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size_sur)); 191 PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x)); 192 { 193 PetscSection section; 194 195 PetscCall(DMGetLocalSection(dm, §ion)); 196 PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q)); 197 } 198 199 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, qf_func_ptr, qf_loc, qf_ijac)); 200 PetscCallCeed(ceed, CeedQFunctionSetContext(*qf_ijac, qfctx)); 201 PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(*qf_ijac, 0)); 202 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "dq", num_comp_q, CEED_EVAL_INTERP)); 203 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "Grad_dq", num_comp_q * dim_sur, CEED_EVAL_GRAD)); 204 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "surface qdata", q_data_size_sur, CEED_EVAL_NONE)); 205 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "x", num_comp_x, CEED_EVAL_INTERP)); 206 PetscCallCeed(ceed, CeedQFunctionAddInput(*qf_ijac, "surface jacobian data", jac_data_size_sur, CEED_EVAL_NONE)); 207 PetscCallCeed(ceed, CeedQFunctionAddOutput(*qf_ijac, "v", num_comp_q, CEED_EVAL_INTERP)); 208 PetscFunctionReturn(PETSC_SUCCESS); 209 } 210 211 /** 212 @brief Setups and adds IFunction operator to given composite operator 213 214 @param[in] bc_def `BCDefinition` for the boundary condition IFunction 215 @param[in] domain_label `DMLabel` for the face orientation label 216 @param[in] label_value Orientation value 217 @param[in] qf_ifunc QFunction for the IFunction 218 @param[in,out] op_ifunc Composite operator to be added to 219 @param[out] sub_op_ifunc Non-composite operator that is added in this function. To be passed to `HoneeBCAddIJacobianOp()` 220 **/ 221 PetscErrorCode HoneeBCAddIFunctionOp(BCDefinition bc_def, DMLabel domain_label, PetscInt label_value, CeedQFunction qf_ifunc, CeedOperator op_ifunc, 222 CeedOperator *sub_op_ifunc) { 223 Honee honee; 224 Ceed ceed; 225 DM dm, dm_coord; 226 HoneeBCStruct honee_bc; 227 PetscInt dim, height = 1, num_comp_x, num_comp_q; 228 CeedInt q_data_size, jac_data_size; 229 CeedVector q_data, jac_data; 230 CeedOperator sub_op_ifunc_; 231 CeedElemRestriction elem_restr_qd, elem_restr_q, elem_restr_x, elem_restr_jac; 232 CeedBasis basis_x, basis_q; 233 234 PetscFunctionBeginUser; 235 PetscCall(BCDefinitionGetDM(bc_def, &dm)); 236 PetscCall(BCDefinitionGetContext(bc_def, &honee_bc)); 237 honee = honee_bc->honee; 238 ceed = honee_bc->honee->ceed; 239 jac_data_size = honee_bc->jac_data_size_sur; 240 241 PetscCall(DMGetDimension(dm, &dim)); 242 PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size)); 243 PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x)); 244 245 { 246 PetscSection section; 247 248 PetscCall(DMGetLocalSection(dm, §ion)); 249 PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q)); 250 } 251 252 PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 253 PetscCall(CreateBasisFromPlex(ceed, dm, domain_label, label_value, height, bc_def->dm_field, &basis_q)); 254 PetscCall(CreateBasisFromPlex(ceed, dm_coord, domain_label, label_value, height, bc_def->dm_field, &basis_x)); 255 PetscCall(DMPlexCeedElemRestrictionCreate(ceed, dm, domain_label, label_value, height, bc_def->dm_field, &elem_restr_q)); 256 PetscCall(DMPlexCeedElemRestrictionCoordinateCreate(ceed, dm, domain_label, label_value, height, &elem_restr_x)); 257 if (jac_data_size > 0) { 258 PetscCall(DMPlexCeedElemRestrictionQDataCreate(ceed, dm, domain_label, label_value, height, jac_data_size, &elem_restr_jac)); 259 PetscCallCeed(ceed, CeedElemRestrictionCreateVector(elem_restr_jac, &jac_data, NULL)); 260 } 261 262 PetscCall(QDataBoundaryGet(ceed, dm, domain_label, label_value, elem_restr_x, basis_x, honee->x_coord, &elem_restr_qd, &q_data, &q_data_size)); 263 264 PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_ifunc, NULL, NULL, &sub_op_ifunc_)); 265 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "q", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE)); 266 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "Grad_q", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE)); 267 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "surface qdata", elem_restr_qd, CEED_BASIS_NONE, q_data)); 268 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "x", elem_restr_x, basis_x, honee->x_coord)); 269 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "v", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE)); 270 if (jac_data_size > 0) PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ifunc_, "surface jacobian data", elem_restr_jac, CEED_BASIS_NONE, jac_data)); 271 272 PetscCallCeed(ceed, CeedCompositeOperatorAddSub(op_ifunc, sub_op_ifunc_)); 273 *sub_op_ifunc = sub_op_ifunc_; 274 275 PetscCallCeed(ceed, CeedVectorDestroy(&q_data)); 276 PetscCallCeed(ceed, CeedBasisDestroy(&basis_q)); 277 PetscCallCeed(ceed, CeedBasisDestroy(&basis_x)); 278 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd)); 279 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_q)); 280 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_x)); 281 if (jac_data_size > 0) { 282 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_jac)); 283 PetscCallCeed(ceed, CeedVectorDestroy(&jac_data)); 284 } 285 PetscFunctionReturn(PETSC_SUCCESS); 286 } 287 288 /** 289 @brief Setups and adds IJacobian operator to given composite operator 290 291 The field data (element restriction, vector, etc) is read from `sub_op_ifunc` and used for the IJacobian. 292 293 @param[in] bc_def `BCDefinition` for the boundary condition IJacobian 294 @param[out] sub_op_ifunc IFunction operator corresponding to this IJacobian operator. 295 @param[in] domain_label `DMLabel` for the face orientation label 296 @param[in] label_value Orientation value 297 @param[in] qf_ijac QFunction for the IJacobian 298 @param[in,out] op_ijac Composite operator to be added to 299 **/ 300 PetscErrorCode HoneeBCAddIJacobianOp(BCDefinition bc_def, CeedOperator sub_op_ifunc, DMLabel domain_label, PetscInt label_value, 301 CeedQFunction qf_ijac, CeedOperator op_ijac) { 302 Honee honee; 303 Ceed ceed; 304 DM dm, dm_coord; 305 HoneeBCStruct honee_bc; 306 PetscInt dim, height = 1, num_comp_x, num_comp_q; 307 CeedInt q_data_size; 308 CeedVector q_data, jac_data; 309 CeedElemRestriction elem_restr_qd, elem_restr_q, elem_restr_x, elem_restr_jac; 310 CeedOperator sub_op_ijac; 311 CeedBasis basis_x, basis_q; 312 313 PetscFunctionBeginUser; 314 PetscCall(BCDefinitionGetContext(bc_def, &honee_bc)); 315 if (honee_bc->jac_data_size_sur == 0) PetscFunctionReturn(PETSC_SUCCESS); 316 PetscCall(BCDefinitionGetDM(bc_def, &dm)); 317 honee = honee_bc->honee; 318 ceed = honee_bc->honee->ceed; 319 320 PetscCall(DMGetDimension(dm, &dim)); 321 PetscCall(QDataBoundaryGetNumComponents(dm, &q_data_size)); 322 PetscCall(DMGetCoordinateNumComps(dm, &num_comp_x)); 323 324 { 325 PetscSection section; 326 327 PetscCall(DMGetLocalSection(dm, §ion)); 328 PetscCall(PetscSectionGetFieldComponents(section, bc_def->dm_field, &num_comp_q)); 329 } 330 331 PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 332 PetscCall(CreateBasisFromPlex(ceed, dm, domain_label, label_value, height, bc_def->dm_field, &basis_q)); 333 PetscCall(CreateBasisFromPlex(ceed, dm_coord, domain_label, label_value, height, bc_def->dm_field, &basis_x)); 334 335 { // Get restriction and basis from the RHS function 336 CeedOperatorField op_field; 337 338 PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_op_ifunc, "q", &op_field)); 339 PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(op_field, &elem_restr_q)); 340 341 PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_op_ifunc, "x", &op_field)); 342 PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(op_field, &elem_restr_x)); 343 344 PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_op_ifunc, "surface jacobian data", &op_field)); 345 PetscCallCeed(ceed, CeedOperatorFieldGetData(op_field, NULL, &elem_restr_jac, NULL, &jac_data)); 346 } 347 348 PetscCall(QDataBoundaryGet(ceed, dm, domain_label, label_value, elem_restr_x, basis_x, honee->x_coord, &elem_restr_qd, &q_data, &q_data_size)); 349 350 PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_ijac, NULL, NULL, &sub_op_ijac)); 351 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "dq", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE)); 352 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "Grad_dq", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE)); 353 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "surface qdata", elem_restr_qd, CEED_BASIS_NONE, q_data)); 354 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "x", elem_restr_x, basis_x, honee->x_coord)); 355 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "surface jacobian data", elem_restr_jac, CEED_BASIS_NONE, jac_data)); 356 PetscCallCeed(ceed, CeedOperatorSetField(sub_op_ijac, "v", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE)); 357 358 PetscCallCeed(ceed, CeedCompositeOperatorAddSub(op_ijac, sub_op_ijac)); 359 360 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_q)); 361 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_x)); 362 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_jac)); 363 PetscCallCeed(ceed, CeedVectorDestroy(&jac_data)); 364 PetscCallCeed(ceed, CeedVectorDestroy(&q_data)); 365 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd)); 366 PetscCallCeed(ceed, CeedBasisDestroy(&basis_q)); 367 PetscCallCeed(ceed, CeedBasisDestroy(&basis_x)); 368 PetscCallCeed(ceed, CeedOperatorDestroy(&sub_op_ijac)); 369 PetscFunctionReturn(PETSC_SUCCESS); 370 } 371