xref: /honee/src/bc_definition.c (revision 14bd2a07a64d3eb0c7fc395a41fb4052a9a41171)
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