xref: /libCEED/examples/fluids/problems/advection.c (revision d1d777230063fd92fc0f547b5443317655656d64)
1 // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 /// @file
9 /// Utility functions for setting up ADVECTION
10 
11 #include "../qfunctions/advection.h"
12 
13 #include <ceed.h>
14 #include <petscdm.h>
15 
16 #include "../navierstokes.h"
17 #include "../qfunctions/setupgeo.h"
18 #include "../qfunctions/setupgeo2d.h"
19 
20 // @brief Create CeedOperator for stabilized mass KSP for explicit timestepping
21 //
22 // Only used for SUPG stabilization
23 PetscErrorCode CreateKSPMassOperator_AdvectionStabilized(User user, CeedOperator *op_mass) {
24   Ceed                 ceed = user->ceed;
25   CeedInt              num_comp_q, q_data_size;
26   CeedQFunction        qf_mass;
27   CeedElemRestriction  elem_restr_q, elem_restr_qd_i;
28   CeedBasis            basis_q;
29   CeedVector           q_data;
30   CeedQFunctionContext qf_ctx = NULL;
31   PetscInt             dim;
32 
33   PetscFunctionBeginUser;
34   PetscCall(DMGetDimension(user->dm, &dim));
35   {  // Get restriction and basis from the RHS function
36     CeedOperator     *sub_ops;
37     CeedOperatorField field;
38     PetscInt          sub_op_index = 0;  // will be 0 for the volume op
39 
40     PetscCallCeed(ceed, CeedCompositeOperatorGetSubList(user->op_rhs_ctx->op, &sub_ops));
41     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_ops[sub_op_index], "q", &field));
42     PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(field, &elem_restr_q));
43     PetscCallCeed(ceed, CeedOperatorFieldGetBasis(field, &basis_q));
44 
45     PetscCallCeed(ceed, CeedOperatorGetFieldByName(sub_ops[sub_op_index], "qdata", &field));
46     PetscCallCeed(ceed, CeedOperatorFieldGetElemRestriction(field, &elem_restr_qd_i));
47     PetscCallCeed(ceed, CeedOperatorFieldGetVector(field, &q_data));
48 
49     PetscCallCeed(ceed, CeedOperatorGetContext(sub_ops[sub_op_index], &qf_ctx));
50   }
51 
52   PetscCallCeed(ceed, CeedElemRestrictionGetNumComponents(elem_restr_q, &num_comp_q));
53   PetscCallCeed(ceed, CeedElemRestrictionGetNumComponents(elem_restr_qd_i, &q_data_size));
54 
55   switch (dim) {
56     case 2:
57       PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MassFunction_Advection2D, MassFunction_Advection2D_loc, &qf_mass));
58       break;
59     case 3:
60       PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, MassFunction_Advection, MassFunction_Advection_loc, &qf_mass));
61       break;
62   }
63 
64   PetscCallCeed(ceed, CeedQFunctionSetContext(qf_mass, qf_ctx));
65   PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(qf_mass, 0));
66   PetscCallCeed(ceed, CeedQFunctionAddInput(qf_mass, "q_dot", 5, CEED_EVAL_INTERP));
67   PetscCallCeed(ceed, CeedQFunctionAddInput(qf_mass, "q", 5, CEED_EVAL_INTERP));
68   PetscCallCeed(ceed, CeedQFunctionAddInput(qf_mass, "qdata", q_data_size, CEED_EVAL_NONE));
69   PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_mass, "v", 5, CEED_EVAL_INTERP));
70   PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_mass, "Grad_v", 5 * dim, CEED_EVAL_GRAD));
71 
72   PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_mass, NULL, NULL, op_mass));
73   PetscCallCeed(ceed, CeedOperatorSetField(*op_mass, "q_dot", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
74   PetscCallCeed(ceed, CeedOperatorSetField(*op_mass, "q", elem_restr_q, basis_q, user->q_ceed));
75   PetscCallCeed(ceed, CeedOperatorSetField(*op_mass, "qdata", elem_restr_qd_i, CEED_BASIS_NONE, q_data));
76   PetscCallCeed(ceed, CeedOperatorSetField(*op_mass, "v", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
77   PetscCallCeed(ceed, CeedOperatorSetField(*op_mass, "Grad_v", elem_restr_q, basis_q, CEED_VECTOR_ACTIVE));
78 
79   PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_mass));
80   PetscFunctionReturn(PETSC_SUCCESS);
81 }
82 
83 PetscErrorCode NS_ADVECTION(ProblemData *problem, DM dm, void *ctx, SimpleBC bc) {
84   WindType             wind_type;
85   AdvectionICType      advectionic_type;
86   BubbleContinuityType bubble_continuity_type;
87   StabilizationType    stab;
88   StabilizationTauType stab_tau;
89   SetupContextAdv      setup_context;
90   User                 user = *(User *)ctx;
91   MPI_Comm             comm = user->comm;
92   Ceed                 ceed = user->ceed;
93   PetscBool            implicit;
94   AdvectionContext     advection_ctx;
95   CeedQFunctionContext advection_context;
96   PetscInt             dim;
97 
98   PetscFunctionBeginUser;
99   PetscCall(PetscCalloc1(1, &setup_context));
100   PetscCall(PetscCalloc1(1, &advection_ctx));
101   PetscCall(DMGetDimension(dm, &dim));
102 
103   // ------------------------------------------------------
104   //               SET UP ADVECTION
105   // ------------------------------------------------------
106   switch (dim) {
107     case 2:
108       problem->dim                               = 2;
109       problem->q_data_size_vol                   = 5;
110       problem->q_data_size_sur                   = 3;
111       problem->setup_vol.qfunction               = Setup2d;
112       problem->setup_vol.qfunction_loc           = Setup2d_loc;
113       problem->setup_sur.qfunction               = SetupBoundary2d;
114       problem->setup_sur.qfunction_loc           = SetupBoundary2d_loc;
115       problem->ics.qfunction                     = ICsAdvection2d;
116       problem->ics.qfunction_loc                 = ICsAdvection2d_loc;
117       problem->apply_vol_rhs.qfunction           = RHS_Advection2d;
118       problem->apply_vol_rhs.qfunction_loc       = RHS_Advection2d_loc;
119       problem->apply_vol_ifunction.qfunction     = IFunction_Advection2d;
120       problem->apply_vol_ifunction.qfunction_loc = IFunction_Advection2d_loc;
121       problem->apply_inflow.qfunction            = Advection2d_InOutFlow;
122       problem->apply_inflow.qfunction_loc        = Advection2d_InOutFlow_loc;
123       problem->non_zero_time                     = PETSC_TRUE;
124       problem->print_info                        = PRINT_ADVECTION;
125       break;
126     case 3:
127       problem->dim                               = 3;
128       problem->q_data_size_vol                   = 10;
129       problem->q_data_size_sur                   = 10;
130       problem->setup_vol.qfunction               = Setup;
131       problem->setup_vol.qfunction_loc           = Setup_loc;
132       problem->setup_sur.qfunction               = SetupBoundary;
133       problem->setup_sur.qfunction_loc           = SetupBoundary_loc;
134       problem->ics.qfunction                     = ICsAdvection;
135       problem->ics.qfunction_loc                 = ICsAdvection_loc;
136       problem->apply_vol_rhs.qfunction           = RHS_Advection;
137       problem->apply_vol_rhs.qfunction_loc       = RHS_Advection_loc;
138       problem->apply_vol_ifunction.qfunction     = IFunction_Advection;
139       problem->apply_vol_ifunction.qfunction_loc = IFunction_Advection_loc;
140       problem->apply_inflow.qfunction            = Advection_InOutFlow;
141       problem->apply_inflow.qfunction_loc        = Advection_InOutFlow_loc;
142       problem->non_zero_time                     = PETSC_FALSE;
143       problem->print_info                        = PRINT_ADVECTION;
144       break;
145   }
146 
147   // ------------------------------------------------------
148   //             Create the libCEED context
149   // ------------------------------------------------------
150   CeedScalar rc              = 1000.;  // m (Radius of bubble)
151   CeedScalar CtauS           = 0.;     // dimensionless
152   PetscBool  strong_form     = PETSC_FALSE;
153   CeedScalar E_wind          = 1.e6;  // J
154   CeedScalar Ctau_a          = PetscPowScalarInt(user->app_ctx->degree, 2);
155   CeedScalar Ctau_t          = 0.;
156   PetscReal  wind[3]         = {1., 0, 0};  // m/s
157   CeedScalar diffusion_coeff = 0.;
158   PetscReal  domain_min[3], domain_max[3], domain_size[3];
159   PetscCall(DMGetBoundingBox(dm, domain_min, domain_max));
160   for (PetscInt i = 0; i < problem->dim; i++) domain_size[i] = domain_max[i] - domain_min[i];
161 
162   // ------------------------------------------------------
163   //             Create the PETSc context
164   // ------------------------------------------------------
165   PetscScalar meter    = 1e-2;  // 1 meter in scaled length units
166   PetscScalar kilogram = 1e-6;  // 1 kilogram in scaled mass units
167   PetscScalar second   = 1e-2;  // 1 second in scaled time units
168   PetscScalar Joule;
169 
170   // ------------------------------------------------------
171   //              Command line Options
172   // ------------------------------------------------------
173   PetscOptionsBegin(comm, NULL, "Options for ADVECTION problem", NULL);
174   // -- Physics
175   PetscCall(PetscOptionsScalar("-rc", "Characteristic radius of thermal bubble", NULL, rc, &rc, NULL));
176   PetscBool translation;
177   PetscCall(PetscOptionsEnum("-wind_type", "Wind type in Advection", NULL, WindTypes, (PetscEnum)(wind_type = WIND_ROTATION), (PetscEnum *)&wind_type,
178                              &translation));
179   PetscInt  n = problem->dim;
180   PetscBool user_wind;
181   PetscCall(PetscOptionsRealArray("-wind_translation", "Constant wind vector", NULL, wind, &n, &user_wind));
182   PetscCall(PetscOptionsScalar("-diffusion_coeff", "Diffusion coefficient", NULL, diffusion_coeff, &diffusion_coeff, NULL));
183   PetscCall(PetscOptionsScalar("-CtauS", "Scale coefficient for tau (nondimensional)", NULL, CtauS, &CtauS, NULL));
184   PetscCall(PetscOptionsBool("-strong_form", "Strong (true) or weak/integrated by parts (false) advection residual", NULL, strong_form, &strong_form,
185                              NULL));
186   PetscCall(PetscOptionsScalar("-E_wind", "Total energy of inflow wind", NULL, E_wind, &E_wind, NULL));
187   PetscCall(PetscOptionsEnum("-advection_ic_type", "Initial condition for Advection problem", NULL, AdvectionICTypes,
188                              (PetscEnum)(advectionic_type = ADVECTIONIC_BUBBLE_SPHERE), (PetscEnum *)&advectionic_type, NULL));
189   bubble_continuity_type = problem->dim == 3 ? BUBBLE_CONTINUITY_SMOOTH : BUBBLE_CONTINUITY_COSINE;
190   PetscCall(PetscOptionsEnum("-bubble_continuity", "Smooth, back_sharp, or thick", NULL, BubbleContinuityTypes, (PetscEnum)bubble_continuity_type,
191                              (PetscEnum *)&bubble_continuity_type, NULL));
192   PetscCall(PetscOptionsEnum("-stab", "Stabilization method", NULL, StabilizationTypes, (PetscEnum)(stab = STAB_NONE), (PetscEnum *)&stab, NULL));
193   PetscCall(PetscOptionsEnum("-stab_tau", "Stabilization constant, tau", NULL, StabilizationTauTypes, (PetscEnum)(stab_tau = STAB_TAU_CTAU),
194                              (PetscEnum *)&stab_tau, NULL));
195   PetscCall(PetscOptionsScalar("-Ctau_t", "Stabilization time constant", NULL, Ctau_t, &Ctau_t, NULL));
196   PetscCall(PetscOptionsScalar("-Ctau_a", "Coefficient for the stabilization ", NULL, Ctau_a, &Ctau_a, NULL));
197   PetscCall(PetscOptionsBool("-implicit", "Use implicit (IFunction) formulation", NULL, implicit = PETSC_FALSE, &implicit, NULL));
198 
199   // -- Units
200   PetscCall(PetscOptionsScalar("-units_meter", "1 meter in scaled length units", NULL, meter, &meter, NULL));
201   meter = fabs(meter);
202   PetscCall(PetscOptionsScalar("-units_kilogram", "1 kilogram in scaled mass units", NULL, kilogram, &kilogram, NULL));
203   kilogram = fabs(kilogram);
204   PetscCall(PetscOptionsScalar("-units_second", "1 second in scaled time units", NULL, second, &second, NULL));
205   second = fabs(second);
206 
207   // -- Warnings
208   if (wind_type == WIND_ROTATION && user_wind) {
209     PetscCall(PetscPrintf(comm, "Warning! Use -wind_translation only with -wind_type translation\n"));
210   }
211   if (wind_type == WIND_TRANSLATION && advectionic_type == ADVECTIONIC_BUBBLE_CYLINDER && wind[2] != 0.) {
212     wind[2] = 0;
213     PetscCall(
214         PetscPrintf(comm, "Warning! Background wind in the z direction should be zero (-wind_translation x,x,0) with -advection_ic_type cylinder\n"));
215   }
216   if (stab == STAB_NONE && CtauS != 0) {
217     PetscCall(PetscPrintf(comm, "Warning! Use -CtauS only with -stab su or -stab supg\n"));
218   }
219   PetscOptionsEnd();
220 
221   if (stab == STAB_SUPG) problem->create_mass_operator = CreateKSPMassOperator_AdvectionStabilized;
222 
223   // ------------------------------------------------------
224   //           Set up the PETSc context
225   // ------------------------------------------------------
226   // -- Define derived units
227   Joule = kilogram * PetscSqr(meter) / PetscSqr(second);
228 
229   user->units->meter    = meter;
230   user->units->kilogram = kilogram;
231   user->units->second   = second;
232   user->units->Joule    = Joule;
233 
234   // ------------------------------------------------------
235   //           Set up the libCEED context
236   // ------------------------------------------------------
237   // -- Scale variables to desired units
238   E_wind *= Joule;
239   rc = fabs(rc) * meter;
240   for (PetscInt i = 0; i < problem->dim; i++) {
241     wind[i] *= (meter / second);
242     domain_size[i] *= meter;
243   }
244   problem->dm_scale = meter;
245 
246   // -- Setup Context
247   setup_context->rc                     = rc;
248   setup_context->lx                     = domain_size[0];
249   setup_context->ly                     = domain_size[1];
250   setup_context->lz                     = problem->dim == 3 ? domain_size[2] : 0.;
251   setup_context->wind[0]                = wind[0];
252   setup_context->wind[1]                = wind[1];
253   setup_context->wind[2]                = problem->dim == 3 ? wind[2] : 0.;
254   setup_context->wind_type              = wind_type;
255   setup_context->initial_condition_type = advectionic_type;
256   setup_context->bubble_continuity_type = bubble_continuity_type;
257   setup_context->time                   = 0;
258 
259   // -- QFunction Context
260   user->phys->implicit             = implicit;
261   advection_ctx->CtauS             = CtauS;
262   advection_ctx->E_wind            = E_wind;
263   advection_ctx->implicit          = implicit;
264   advection_ctx->strong_form       = strong_form;
265   advection_ctx->stabilization     = stab;
266   advection_ctx->stabilization_tau = stab_tau;
267   advection_ctx->Ctau_a            = Ctau_a;
268   advection_ctx->Ctau_t            = Ctau_t;
269   advection_ctx->diffusion_coeff   = diffusion_coeff;
270 
271   PetscCallCeed(ceed, CeedQFunctionContextCreate(user->ceed, &problem->ics.qfunction_context));
272   PetscCallCeed(ceed,
273                 CeedQFunctionContextSetData(problem->ics.qfunction_context, CEED_MEM_HOST, CEED_USE_POINTER, sizeof(*setup_context), setup_context));
274   PetscCallCeed(ceed, CeedQFunctionContextSetDataDestroy(problem->ics.qfunction_context, CEED_MEM_HOST, FreeContextPetsc));
275 
276   PetscCallCeed(ceed, CeedQFunctionContextCreate(user->ceed, &advection_context));
277   PetscCallCeed(ceed, CeedQFunctionContextSetData(advection_context, CEED_MEM_HOST, CEED_USE_POINTER, sizeof(*advection_ctx), advection_ctx));
278   PetscCallCeed(ceed, CeedQFunctionContextSetDataDestroy(advection_context, CEED_MEM_HOST, FreeContextPetsc));
279   PetscCallCeed(ceed, CeedQFunctionContextRegisterDouble(advection_context, "timestep size", offsetof(struct AdvectionContext_, dt), 1,
280                                                          "Size of timestep, delta t"));
281   problem->apply_vol_rhs.qfunction_context = advection_context;
282   PetscCallCeed(ceed, CeedQFunctionContextReferenceCopy(advection_context, &problem->apply_vol_ifunction.qfunction_context));
283   PetscCallCeed(ceed, CeedQFunctionContextReferenceCopy(advection_context, &problem->apply_inflow.qfunction_context));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 PetscErrorCode PRINT_ADVECTION(User user, ProblemData *problem, AppCtx app_ctx) {
288   MPI_Comm         comm = user->comm;
289   Ceed             ceed = user->ceed;
290   SetupContextAdv  setup_ctx;
291   AdvectionContext advection_ctx;
292 
293   PetscFunctionBeginUser;
294   PetscCallCeed(ceed, CeedQFunctionContextGetData(problem->ics.qfunction_context, CEED_MEM_HOST, &setup_ctx));
295   PetscCallCeed(ceed, CeedQFunctionContextGetData(problem->apply_vol_rhs.qfunction_context, CEED_MEM_HOST, &advection_ctx));
296   PetscCall(PetscPrintf(comm,
297                         "  Problem:\n"
298                         "    Problem Name                       : %s\n"
299                         "    Stabilization                      : %s\n"
300                         "    Initial Condition Type             : %s\n"
301                         "    Bubble Continuity                  : %s\n"
302                         "    Wind Type                          : %s\n",
303                         app_ctx->problem_name, StabilizationTypes[advection_ctx->stabilization], AdvectionICTypes[setup_ctx->initial_condition_type],
304                         BubbleContinuityTypes[setup_ctx->bubble_continuity_type], WindTypes[setup_ctx->wind_type]));
305 
306   if (setup_ctx->wind_type == WIND_TRANSLATION) {
307     switch (problem->dim) {
308       case 2:
309         PetscCall(PetscPrintf(comm, "    Background Wind                    : %f,%f\n", setup_ctx->wind[0], setup_ctx->wind[1]));
310         break;
311       case 3:
312         PetscCall(
313             PetscPrintf(comm, "    Background Wind                    : %f,%f,%f\n", setup_ctx->wind[0], setup_ctx->wind[1], setup_ctx->wind[2]));
314         break;
315     }
316   }
317   PetscCallCeed(ceed, CeedQFunctionContextRestoreData(problem->ics.qfunction_context, &setup_ctx));
318   PetscCallCeed(ceed, CeedQFunctionContextRestoreData(problem->apply_vol_rhs.qfunction_context, &advection_ctx));
319   PetscFunctionReturn(PETSC_SUCCESS);
320 }
321