HybridADRSolver
Loading...
Searching...
No Matches
problem_definition.h
Go to the documentation of this file.
1
11
12#ifndef HYBRIDADRSOLVER_PROBLEM_DEFINITION_H
13#define HYBRIDADRSOLVER_PROBLEM_DEFINITION_H
14
15#ifndef HYBRIDADRSOLVER_PROBLEM_BASE_H
16#define HYBRIDADRSOLVER_PROBLEM_BASE_H
17
18#include <cmath>
19#include <deal.II/base/function.h>
20#include <deal.II/base/point.h>
21#include <deal.II/base/tensor.h>
22#include <set>
23#include <string>
24
25namespace HybridADRSolver {
26using namespace dealii;
27using numbers::PI;
28
39template <int dim> class ProblemInterface {
40public:
41 virtual ~ProblemInterface() = default;
42
46 virtual double diffusion_coefficient(const Point<dim>& p) const = 0;
47
52 virtual Tensor<1, dim> advection_field(const Point<dim>& p) const = 0;
53
57 virtual double reaction_coefficient(const Point<dim>& p) const = 0;
58
62 virtual double source_term(const Point<dim>& p) const = 0;
63
68 [[nodiscard]] virtual std::set<types::boundary_id>
69 get_dirichlet_ids() const = 0;
70
75 [[nodiscard]] virtual std::set<types::boundary_id>
76 get_neumann_ids() const = 0;
77
82 virtual const Function<dim>&
83 get_dirichlet_function(types::boundary_id id) const = 0;
84
89 virtual const Function<dim>&
90 get_neumann_function(types::boundary_id id) const = 0;
91
95 [[nodiscard]] virtual bool has_exact_solution() const = 0;
96
100 virtual const Function<dim>& get_exact_solution() const = 0;
101
107 [[nodiscard]] virtual bool is_symmetric() const = 0;
108
112 [[nodiscard]] virtual std::string get_name() const = 0;
113};
114
115namespace Problems {
116
125template <int dim> class ExactSolution : public Function<dim> {
126public:
131 double value(const Point<dim>& p, const unsigned int) const override {
132 double val = 1.0;
133 for (unsigned int d = 0; d < dim; ++d)
134 val *= std::sin(PI * p[d]);
135 return val;
136 }
137
141 Tensor<1, dim> gradient(const Point<dim>& p,
142 const unsigned int) const override {
143 Tensor<1, dim> grad;
144 for (unsigned int d = 0; d < dim; ++d) {
145 grad[d] = PI * std::cos(PI * p[d]);
146 for (unsigned int other = 0; other < dim; ++other)
147 if (d != other)
148 grad[d] *= std::sin(PI * p[other]);
149 }
150 return grad;
151 }
152};
153
160template <int dim> class NeumannFluxRight : public Function<dim> {
161public:
162 double value(const Point<dim>& p, const unsigned int) const override {
163 // Flux = du/dx at x=1.
164 // u = sin(pi*x) * sin(pi*y)...
165 // du/dx = pi * cos(pi*x) * sin(pi*y)...
166 // At x=1, cos(pi*x) = -1.
167 double val = -1.0 * PI;
168 for (unsigned int d = 1; d < dim; ++d)
169 val *= std::sin(PI * p[d]);
170 return val;
171 }
172};
173
183template <int dim> class ADRProblem : public ProblemInterface<dim> {
184public:
185 ADRProblem() : zero_function(1), neumann_flux(), exact_solution() {}
186
188 double diffusion_coefficient(const Point<dim>&) const override {
189 return 1.0;
190 }
191
193 double reaction_coefficient(const Point<dim>&) const override {
194 return 0.1;
195 }
196
202 Tensor<1, dim> advection_field(const Point<dim>& p) const override {
203 Tensor<1, dim> beta;
204 beta[0] = -p[1];
205 beta[1] = p[0];
206 if (dim == 3)
207 beta[2] = 0.1;
208 return beta;
209 }
210
219 double source_term(const Point<dim>& p) const override {
220 const double u = exact_solution.value(p, 0);
221 Tensor<1, dim> grad = exact_solution.gradient(p, 0);
222
223 const double mu = diffusion_coefficient(p);
224 const double gamma = reaction_coefficient(p);
225 Tensor<1, dim> beta = advection_field(p);
226
227 // Laplacian of u = product(sin(pi*x_i)) is -d * pi^2 * u
228 const double lap = -1.0 * dim * PI * PI * u;
229
230 return -mu * lap + beta * grad + gamma * u;
231 }
232
237 [[nodiscard]] std::set<types::boundary_id>
238 get_dirichlet_ids() const override {
239 std::set<types::boundary_id> ids;
240 ids.insert(0); // Left
241 ids.insert(2); // Bottom
242 ids.insert(3); // Top
243 if (dim == 3) {
244 ids.insert(4);
245 ids.insert(5);
246 }
247 return ids;
248 }
249
254 [[nodiscard]] std::set<types::boundary_id>
255 get_neumann_ids() const override {
256 return {1};
257 }
258
260 const Function<dim>&
261 get_dirichlet_function(types::boundary_id) const override {
262 return zero_function;
263 }
264
266 const Function<dim>&
267 get_neumann_function(const types::boundary_id id) const override {
268 if (id == 1)
269 return neumann_flux;
270 Assert(false, ExcMessage("Unknown Neumann ID requested"));
271 return zero_function;
272 }
273
274 [[nodiscard]] bool has_exact_solution() const override { return true; }
275 const Function<dim>& get_exact_solution() const override {
276 return exact_solution;
277 }
278
280 [[nodiscard]] bool is_symmetric() const override { return false; }
281
282 [[nodiscard]] std::string get_name() const override {
283 return "Manufactured ADR (Dirichlet + Neumann)";
284 }
285
286private:
287 Functions::ZeroFunction<dim> zero_function;
288 NeumannFluxRight<dim> neumann_flux;
289 ExactSolution<dim> exact_solution;
290};
291
292} // namespace Problems
293} // namespace HybridADRSolver
294
295#endif
296
297#endif // HYBRIDADRSOLVER_PROBLEM_DEFINITION_H
Abstract interface for defining a physical problem.
Definition problem_definition.h:39
virtual const Function< dim > & get_exact_solution() const =0
Returns the exact solution function object (if available).
virtual std::set< types::boundary_id > get_dirichlet_ids() const =0
Returns the set of boundary IDs where Dirichlet conditions are applied.
virtual const Function< dim > & get_dirichlet_function(types::boundary_id id) const =0
Gets the function describing the Dirichlet boundary value for a specific boundary ID.
virtual ~ProblemInterface()=default
virtual double reaction_coefficient(const Point< dim > &p) const =0
Returns the reaction coefficient .
virtual const Function< dim > & get_neumann_function(types::boundary_id id) const =0
Gets the function describing the Neumann flux for a specific boundary ID.
virtual std::string get_name() const =0
Returns a descriptive name of the problem.
virtual double diffusion_coefficient(const Point< dim > &p) const =0
Returns the diffusion coefficient .
virtual bool has_exact_solution() const =0
Checks if an analytical exact solution is available.
virtual Tensor< 1, dim > advection_field(const Point< dim > &p) const =0
Returns the advection velocity field .
virtual double source_term(const Point< dim > &p) const =0
Returns the source term .
virtual bool is_symmetric() const =0
Checks if the problem system matrix is symmetric.
virtual std::set< types::boundary_id > get_neumann_ids() const =0
Returns the set of boundary IDs where Neumann conditions are applied.
const Function< dim > & get_neumann_function(const types::boundary_id id) const override
Returns analytic flux for Neumann BCs.
Definition problem_definition.h:267
bool is_symmetric() const override
Problem is non-symmetric due to advection term.
Definition problem_definition.h:280
bool has_exact_solution() const override
Checks if an analytical exact solution is available.
Definition problem_definition.h:274
double diffusion_coefficient(const Point< dim > &) const override
Constant diffusion coefficient .
Definition problem_definition.h:188
const Function< dim > & get_dirichlet_function(types::boundary_id) const override
Returns zero function for Dirichlet BCs.
Definition problem_definition.h:261
std::string get_name() const override
Returns a descriptive name of the problem.
Definition problem_definition.h:282
Tensor< 1, dim > advection_field(const Point< dim > &p) const override
Rotational advection field. 2D: 3D: .
Definition problem_definition.h:202
ADRProblem()
Definition problem_definition.h:185
std::set< types::boundary_id > get_dirichlet_ids() const override
Defines Dirichlet boundaries. All boundaries except Right (ID 1) are Dirichlet (0,...
Definition problem_definition.h:238
const Function< dim > & get_exact_solution() const override
Returns the exact solution function object (if available).
Definition problem_definition.h:275
std::set< types::boundary_id > get_neumann_ids() const override
Defines Neumann boundaries. Only the Right boundary (ID 1) is Neumann.
Definition problem_definition.h:255
double source_term(const Point< dim > &p) const override
Computes the source term using the Method of Manufactured Solutions.
Definition problem_definition.h:219
double reaction_coefficient(const Point< dim > &) const override
Constant reaction coefficient .
Definition problem_definition.h:193
Manufactured exact solution: .
Definition problem_definition.h:125
Tensor< 1, dim > gradient(const Point< dim > &p, const unsigned int) const override
Evaluates the gradient of the exact solution at point p.
Definition problem_definition.h:141
double value(const Point< dim > &p, const unsigned int) const override
Evaluates the exact solution at point p.
Definition problem_definition.h:131
Analytic Neumann flux for the Right boundary (x=1).
Definition problem_definition.h:160
double value(const Point< dim > &p, const unsigned int) const override
Definition problem_definition.h:162
Definition problem_definition.h:115
Definition problem_definition.h:25