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