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 **/
BCDefinitionInitalize()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 **/
BCDefinitionCreate(MPI_Comm comm,const char * name,PetscInt num_label_values,PetscInt label_values[],BCDefinition * bc_def)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(PetscHeaderCreate(bc_def_, BC_DEFINITION_CLASSID, "BCDefinition", "BCDefinition", "BCDefinition", comm, BCDefinitionDestroy,
43 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 **/
BCDefinitionDestroy(BCDefinition * bc_def)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 **/
BCDefinitionView(BCDefinition bc_def,PetscViewer viewer)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 **/
BCDefinitionViewFromOptions(BCDefinition bc_def,PetscObject obj,const char name[])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 **/
BCDefinitionGetInfo(BCDefinition bc_def,const char * name[],PetscInt * num_label_values,const PetscInt * label_values[])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 **/
BCDefinitionSetEssential(BCDefinition bc_def,PetscInt num_essential_comps,PetscInt essential_comps[])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 **/
BCDefinitionGetEssential(BCDefinition bc_def,PetscInt * num_essential_comps,const PetscInt * essential_comps[])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`
PetscOptionsBCDefinition_Private(PetscOptionItems PetscOptionsObject,const char opt[],const char text[],const char man[],const char name[],BCDefinition * bc_def,PetscBool * set)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 **/
BCDefinitionSetDM(BCDefinition bc_def,DM dm)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 **/
BCDefinitionGetDM(BCDefinition bc_def,DM * dm)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 **/
BCDefinitionSetContext(BCDefinition bc_def,PetscCtxDestroyFn * destroy_ctx,void * ctx)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 **/
BCDefinitionGetContext(BCDefinition bc_def,void * ctx)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 **/
BCDefinitionSetIFunction(BCDefinition bc_def,BCDefinitionCreateQFunction create_qf,BCDefinitionAddIFunctionOperator add_op)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 **/
BCDefinitionSetIJacobian(BCDefinition bc_def,BCDefinitionCreateQFunction create_qf,BCDefinitionAddIJacobianOperator add_op)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 **/
BCDefinitionAddOperators(BCDefinition bc_def,CeedOperator op_ifunc,CeedOperator op_ijac)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