1 // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors. 2 // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause 3 4 #include <bc_definition.h> 5 #include <dm-utils.h> 6 #include <petsc-ceed.h> 7 #include <petsc/private/petscimpl.h> 8 9 PetscClassId BC_DEFINITION_CLASSID; 10 11 /** 12 @brief Initalize `BCDefinition` class. 13 14 Not collective across MPI processes. 15 16 @return An error code: 0 - success, otherwise - failure 17 **/ 18 static PetscErrorCode BCDefinitionInitalize() { 19 static PetscBool registered = PETSC_FALSE; 20 21 PetscFunctionBeginUser; 22 if (registered) PetscFunctionReturn(PETSC_SUCCESS); 23 PetscCall(PetscClassIdRegister("BCDefinition", &BC_DEFINITION_CLASSID)); 24 registered = PETSC_TRUE; 25 PetscFunctionReturn(PETSC_SUCCESS); 26 } 27 28 /** 29 @brief Create `BCDefinition` 30 31 @param[in] comm `MPI_Comm` for the object 32 @param[in] name Name of the boundary condition 33 @param[in] num_label_values Number of `DMLabel` values 34 @param[in] label_values Array of label values that define the boundaries controlled by the `BCDefinition`, size `num_label_values` 35 @param[out] bc_def The new `BCDefinition` 36 **/ 37 PetscErrorCode BCDefinitionCreate(MPI_Comm comm, const char *name, PetscInt num_label_values, PetscInt label_values[], BCDefinition *bc_def) { 38 BCDefinition bc_def_; 39 40 PetscFunctionBeginUser; 41 PetscCall(BCDefinitionInitalize()); 42 PetscCall( 43 PetscHeaderCreate(bc_def_, BC_DEFINITION_CLASSID, "BCDefinition", "BCDefinition", "BCDefinition", comm, BCDefinitionDestroy, BCDefinitionView)); 44 45 PetscCall(PetscStrallocpy(name, &bc_def_->name)); 46 PetscCall(PetscObjectSetName((PetscObject)bc_def_, name)); 47 bc_def_->num_label_values = num_label_values; 48 PetscCall(PetscMalloc1(num_label_values, &bc_def_->label_values)); 49 for (PetscInt i = 0; i < num_label_values; i++) bc_def_->label_values[i] = label_values[i]; 50 *bc_def = bc_def_; 51 PetscFunctionReturn(PETSC_SUCCESS); 52 } 53 54 /** 55 @brief Destory a `BCDefinition` object 56 57 @param[in,out] bc_def `BCDefinition` to be destroyed 58 **/ 59 PetscErrorCode BCDefinitionDestroy(BCDefinition *bc_def) { 60 BCDefinition bc_def_ = *bc_def; 61 PetscFunctionBeginUser; 62 if (!bc_def_) PetscFunctionReturn(PETSC_SUCCESS); 63 PetscValidHeaderSpecific(bc_def_, BC_DEFINITION_CLASSID, 1); 64 if (bc_def_->name) PetscCall(PetscFree(bc_def_->name)); 65 if (bc_def_->label_values) PetscCall(PetscFree(bc_def_->label_values)); 66 if (bc_def_->essential_comps) PetscCall(PetscFree(bc_def_->essential_comps)); 67 if (bc_def_->dm) PetscCall(DMDestroy(&bc_def_->dm)); 68 if (bc_def_->DestroyCtx) PetscCall((*(bc_def_->DestroyCtx))(&bc_def_->ctx)); 69 PetscCall(PetscHeaderDestroy(&bc_def_)); 70 *bc_def = NULL; 71 PetscFunctionReturn(PETSC_SUCCESS); 72 } 73 74 /** 75 @brief View a `BCDefinition` object. 76 77 Not collective across MPI processes. 78 79 @param[in] bc_def `BCDefinition` object 80 @param[in] viewer Optional `PetscViewer` context or `NULL` 81 82 @return An error code: 0 - success, otherwise - failure 83 **/ 84 PetscErrorCode BCDefinitionView(BCDefinition bc_def, PetscViewer viewer) { 85 PetscBool is_ascii; 86 PetscViewerFormat format; 87 PetscMPIInt size; 88 89 PetscFunctionBeginUser; 90 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 91 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 92 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)bc_def), &viewer)); 93 94 PetscCall(PetscViewerGetFormat(viewer, &format)); 95 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)bc_def), &size)); 96 if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS); 97 98 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii)); 99 { 100 PetscBool is_detailed = format == PETSC_VIEWER_ASCII_INFO_DETAIL; 101 102 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)bc_def, viewer)); 103 PetscCall(PetscViewerASCIIPushTab(viewer)); // BCDefinition 104 105 if (is_detailed) PetscCall(DMView(bc_def->dm, viewer)); 106 PetscCall(PetscViewerASCIIPrintf(viewer, "DM Field: %" PetscInt_FMT "\n", bc_def->dm_field)); 107 PetscCall(PetscViewerASCIIPrintf(viewer, "Face Sets:")); 108 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 109 if (bc_def->num_label_values > 0) { 110 for (PetscInt i = 0; i < bc_def->num_label_values; i++) { 111 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, bc_def->label_values[i])); 112 } 113 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 114 } else { 115 PetscCall(PetscViewerASCIIPrintf(viewer, " None\n")); 116 } 117 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 118 119 PetscCall(PetscViewerASCIIPrintf(viewer, "Essential Components:")); 120 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 121 if (bc_def->num_essential_comps > 0) { 122 for (PetscInt i = 0; i < bc_def->num_essential_comps; i++) { 123 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, bc_def->essential_comps[i])); 124 } 125 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 126 } else { 127 PetscCall(PetscViewerASCIIPrintf(viewer, " None\n")); 128 } 129 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 130 131 PetscCall(PetscViewerASCIIPopTab(viewer)); // BCDefinition 132 } 133 PetscFunctionReturn(PETSC_SUCCESS); 134 } 135 136 /** 137 @brief View `BCDefinition` from options database (command line/YAML) 138 139 @param[in] bc_def `BCDefintion` to view 140 @param[in] obj Optional object that provides the prefix for the options database (if `NULL` then the prefix in `bc_def` is used) 141 @param[in] name Option string that is used to activate viewing 142 **/ 143 PetscErrorCode BCDefinitionViewFromOptions(BCDefinition bc_def, PetscObject obj, const char name[]) { 144 PetscFunctionBegin; 145 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 146 PetscCall(PetscObjectViewFromOptions((PetscObject)bc_def, obj, name)); 147 PetscFunctionReturn(PETSC_SUCCESS); 148 } 149 150 /** 151 @brief Get base information for `BCDefinition` 152 153 @param[in] bc_def `BCDefinition` to get information from 154 @param[out] name Name of the `BCDefinition` 155 @param[out] num_label_values Number of `DMLabel` values 156 @param[out] label_values Array of label values that define the boundaries controlled by the `BCDefinition`, size `num_label_values` 157 **/ 158 PetscErrorCode BCDefinitionGetInfo(BCDefinition bc_def, const char *name[], PetscInt *num_label_values, const PetscInt *label_values[]) { 159 PetscFunctionBeginUser; 160 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 161 if (name) { 162 PetscAssertPointer(name, 2); 163 *name = bc_def->name; 164 } 165 if (label_values) { 166 PetscAssertPointer(num_label_values, 3); 167 PetscAssertPointer(label_values, 4); 168 *num_label_values = bc_def->num_label_values; 169 *label_values = bc_def->label_values; 170 } 171 PetscFunctionReturn(PETSC_SUCCESS); 172 } 173 174 /** 175 @brief Set `DM_BC_ESSENTIAL` boundary condition values 176 177 @param[in,out] bc_def `BCDefinition` to set values to 178 @param[in] num_essential_comps Number of components to set 179 @param[in] essential_comps Array of components to set, size `num_essential_comps` 180 **/ 181 PetscErrorCode BCDefinitionSetEssential(BCDefinition bc_def, PetscInt num_essential_comps, PetscInt essential_comps[]) { 182 PetscFunctionBeginUser; 183 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 184 bc_def->num_essential_comps = num_essential_comps; 185 PetscCall(PetscMalloc1(num_essential_comps, &bc_def->essential_comps)); 186 PetscCall(PetscArraycpy(bc_def->essential_comps, essential_comps, num_essential_comps)); 187 PetscFunctionReturn(PETSC_SUCCESS); 188 } 189 190 /** 191 @brief Get `DM_BC_ESSENTIAL` boundary condition values 192 193 @param[in] bc_def `BCDefinition` to set values to 194 @param[out] num_essential_comps Number of components to set 195 @param[out] essential_comps Array of components to set, size `num_essential_comps` 196 **/ 197 PetscErrorCode BCDefinitionGetEssential(BCDefinition bc_def, PetscInt *num_essential_comps, const PetscInt *essential_comps[]) { 198 PetscFunctionBeginUser; 199 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 200 PetscAssertPointer(num_essential_comps, 2); 201 PetscAssertPointer(essential_comps, 3); 202 *num_essential_comps = bc_def->num_essential_comps; 203 *essential_comps = bc_def->essential_comps; 204 PetscFunctionReturn(PETSC_SUCCESS); 205 } 206 207 #define LABEL_ARRAY_SIZE 256 208 209 // @brief See `PetscOptionsBCDefinition` 210 PetscErrorCode PetscOptionsBCDefinition_Private(PetscOptionItems PetscOptionsObject, const char opt[], const char text[], const char man[], 211 const char name[], BCDefinition *bc_def, PetscBool *set) { 212 PetscInt num_label_values = LABEL_ARRAY_SIZE, label_values[LABEL_ARRAY_SIZE] = {0}; 213 214 PetscFunctionBeginUser; 215 PetscCall(PetscOptionsIntArray(opt, text, man, label_values, &num_label_values, set)); 216 if (num_label_values > 0) { 217 PetscCall(BCDefinitionCreate(PetscOptionsObject->comm, name, num_label_values, label_values, bc_def)); 218 } else { 219 *bc_def = NULL; 220 } 221 PetscFunctionReturn(PETSC_SUCCESS); 222 } 223 224 /** 225 @brief Set `DM` for BCDefinition 226 227 @param[in,out] bc_def `BCDefinition` to add `dm` to 228 @param[in] dm `DM` to assign to BCDefinition, or `NULL` to remove `DM` 229 **/ 230 PetscErrorCode BCDefinitionSetDM(BCDefinition bc_def, DM dm) { 231 PetscFunctionBeginUser; 232 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 233 if (bc_def->dm) PetscCall(DMDestroy(&bc_def->dm)); 234 if (dm) { 235 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 236 PetscCall(PetscObjectReference((PetscObject)dm)); 237 bc_def->dm = dm; 238 } 239 PetscFunctionReturn(PETSC_SUCCESS); 240 } 241 242 /** 243 @brief Get `DM` assigned to BCDefinition 244 245 @param[in] bc_def `BCDefinition` to get `dm` from 246 @param[out] dm `DM` assigned to BCDefinition 247 **/ 248 PetscErrorCode BCDefinitionGetDM(BCDefinition bc_def, DM *dm) { 249 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 250 PetscFunctionBeginUser; 251 PetscAssertPointer(dm, 2); 252 *dm = bc_def->dm; 253 PetscFunctionReturn(PETSC_SUCCESS); 254 } 255 256 /** 257 @brief Set custom context struct for use in BCDefinition 258 259 @param[in,out] bc_def `BCDefinition` to add `ctx` to 260 @param[in] destroy_ctx Optional function pointer that destroys the user context on `BCDefinitionDestroy()` 261 @param[in] ctx Pointer to context struct 262 **/ 263 PetscErrorCode BCDefinitionSetContext(BCDefinition bc_def, PetscCtxDestroyFn *destroy_ctx, void *ctx) { 264 PetscFunctionBeginUser; 265 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 266 if (bc_def->DestroyCtx) PetscCall((*(bc_def->DestroyCtx))(&bc_def->ctx)); 267 bc_def->ctx = ctx; 268 bc_def->DestroyCtx = destroy_ctx; 269 PetscFunctionReturn(PETSC_SUCCESS); 270 } 271 272 /** 273 @brief Set custom context struct for use in BCDefinition 274 275 @param[in] bc_def `BCDefinition` to get `ctx` from 276 @param[out] ctx Pointer to context struct 277 **/ 278 PetscErrorCode BCDefinitionGetContext(BCDefinition bc_def, void *ctx) { 279 PetscFunctionBeginUser; 280 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 281 PetscAssertPointer(ctx, 2); 282 *(void **)ctx = bc_def->ctx; 283 PetscFunctionReturn(PETSC_SUCCESS); 284 } 285 286 /** 287 @brief Add function pointers to create `CeedQFunction` and `CeedOperator` for IFunction of boundary condition 288 289 @param[in,out] bc_def `BCDefinition` to add function pointers to 290 @param[in] create_qf Function to create `CeedQFunction` 291 @param[in] add_op Function to create and add `CeedOperator` to composite `CeedOperator` 292 **/ 293 PetscErrorCode BCDefinitionSetIFunction(BCDefinition bc_def, BCDefinitionCreateQFunction create_qf, BCDefinitionAddIFunctionOperator add_op) { 294 PetscFunctionBeginUser; 295 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 296 bc_def->CreateIFunctionQF = create_qf; 297 bc_def->AddIFunctionOperator = add_op; 298 PetscFunctionReturn(PETSC_SUCCESS); 299 } 300 301 /** 302 @brief Add function pointers to create `CeedQFunction` and `CeedOperator` for IJacobian of boundary condition 303 304 @param[in,out] bc_def `BCDefinition` to add function pointers to 305 @param[in] create_qf Function to create `CeedQFunction` 306 @param[in] add_op Function to create and add `CeedOperator` to composite `CeedOperator` 307 **/ 308 PetscErrorCode BCDefinitionSetIJacobian(BCDefinition bc_def, BCDefinitionCreateQFunction create_qf, BCDefinitionAddIJacobianOperator add_op) { 309 PetscFunctionBeginUser; 310 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 311 bc_def->CreateIJacobianQF = create_qf; 312 bc_def->AddIJacobianOperator = add_op; 313 PetscFunctionReturn(PETSC_SUCCESS); 314 } 315 316 /** 317 @brief Add operators (IFunction, IJacobian) to composite operator 318 319 This loops over orientations for each face label specified by `bc_def` and adds the IFunction and IJacobian operator to respective composite operator. 320 321 @param[in] bc_def `BCDefinition` from which operators are created and added 322 @param[in,out] op_ifunc Composite operator for IFunction operators to be added to 323 @param[in,out] op_ijac Composite operator for IJacobian operators to be added to 324 **/ 325 PetscErrorCode BCDefinitionAddOperators(BCDefinition bc_def, CeedOperator op_ifunc, CeedOperator op_ijac) { 326 Ceed ceed = CeedOperatorReturnCeed(op_ifunc); 327 CeedQFunction qf_ifunction, qf_ijacobian; 328 DMLabel face_sets_label; 329 PetscInt num_face_set_values; 330 const PetscInt *face_set_values; 331 332 PetscFunctionBeginUser; 333 PetscValidHeaderSpecific(bc_def, BC_DEFINITION_CLASSID, 1); 334 if (!bc_def->CreateIFunctionQF || !bc_def->AddIFunctionOperator) PetscFunctionReturn(PETSC_SUCCESS); 335 PetscBool add_ijac = (!bc_def->CreateIJacobianQF || !bc_def->AddIJacobianOperator || !op_ijac) ? PETSC_FALSE : PETSC_TRUE; 336 PetscCheck(bc_def->dm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "BCDefinition must have DM set using BCDefinitionSetDM()"); 337 338 PetscCall(bc_def->CreateIFunctionQF(bc_def, &qf_ifunction)); 339 if (add_ijac) PetscCall(bc_def->CreateIJacobianQF(bc_def, &qf_ijacobian)); 340 341 PetscCall(DMGetLabel(bc_def->dm, "Face Sets", &face_sets_label)); 342 PetscCall(BCDefinitionGetInfo(bc_def, NULL, &num_face_set_values, &face_set_values)); 343 for (PetscInt f = 0; f < num_face_set_values; f++) { 344 DMLabel face_orientation_label; 345 PetscInt num_orientations_values, *orientation_values; 346 347 { 348 char *face_orientation_label_name; 349 350 PetscCall(DMPlexCreateFaceLabel(bc_def->dm, face_set_values[f], &face_orientation_label_name)); 351 PetscCall(DMGetLabel(bc_def->dm, face_orientation_label_name, &face_orientation_label)); 352 PetscCall(PetscFree(face_orientation_label_name)); 353 } 354 PetscCall(DMLabelCreateGlobalValueArray(bc_def->dm, face_orientation_label, &num_orientations_values, &orientation_values)); 355 for (PetscInt o = 0; o < num_orientations_values; o++) { 356 CeedOperator sub_op_ifunc; 357 PetscInt orientation = orientation_values[o]; 358 359 PetscCall(bc_def->AddIFunctionOperator(bc_def, face_orientation_label, orientation, qf_ifunction, op_ifunc, &sub_op_ifunc)); 360 if (add_ijac) PetscCall(bc_def->AddIJacobianOperator(bc_def, sub_op_ifunc, face_orientation_label, orientation, qf_ijacobian, op_ijac)); 361 PetscCallCeed(ceed, CeedOperatorDestroy(&sub_op_ifunc)); 362 } 363 PetscCall(PetscFree(orientation_values)); 364 } 365 PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_ifunction)); 366 if (add_ijac) PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_ijacobian)); 367 PetscFunctionReturn(PETSC_SUCCESS); 368 PetscFunctionReturn(PETSC_SUCCESS); 369 } 370