ViennaLS
Loading...
Searching...
No Matches
lsFiniteDifferences.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <hrleVectorType.hpp>
4
5#include <vcLogger.hpp>
6
7namespace lsInternal {
8
9using namespace viennacore;
10
11// Numerical scheme definitions, central is default
12enum class DifferentiationSchemeEnum : unsigned {
13 FIRST_ORDER = 0,
14 SECOND_ORDER = 1,
15 WENO3 = 2,
16 WENO5 = 3
17};
18
19template <class T, DifferentiationSchemeEnum scheme =
22 template <class V> static V square(V x) { return x * x; }
23
24public:
26
28 switch (s) {
30 return 3;
33 return 5;
35 return 7;
36 default:
37 Logger::getInstance().addError("Invalid finite differences scheme!");
38 return 0;
39 }
40 }
41
45 static T weno3(const T *x, T delta, bool plus, T eps = 1e-6) {
46 T dx[4];
47 for (unsigned i = 0; i < 4; ++i) {
48 dx[i] = x[i + 1] - x[i];
49 }
50
51 T result = 0;
52 if (plus) {
53 T rp = (eps + FiniteDifferences::square(dx[3] - dx[2])) /
54 (eps + FiniteDifferences::square(dx[2] - dx[1]));
55 T wp = 1.0 / (1 + 2.0 * FiniteDifferences::square(rp));
56 result = dx[1] + dx[2] - wp * (dx[3] - 2.0 * dx[2] + dx[1]);
57 } else {
58 T rp = (eps + FiniteDifferences::square(dx[1] - dx[0])) /
59 (eps + FiniteDifferences::square(dx[2] - dx[1]));
60 T wp = 1.0 / (1 + 2.0 * FiniteDifferences::square(rp));
61 result = dx[1] + dx[2] - wp * (dx[0] - 2.0 * dx[1] + dx[2]);
62 }
63
64 return result / (2.0 * delta);
65 }
66
67 // Weighted essentially non-oscillatory differentiation scheme 5th order
68 // x1 ... x7 stencil points from left to right
69 // plus == true => right-sided
70 static T weno5(const T *x, T dx, bool plus, T eps = 1e-6) {
71
72 if (plus == false) {
73 T v1 = (x[1] - x[0]) / dx; // i-3
74 T v2 = (x[2] - x[1]) / dx; // i-2
75 T v3 = (x[3] - x[2]) / dx; // i-1
76 T v4 = (x[4] - x[3]) / dx; // i
77 T v5 = (x[5] - x[4]) / dx; // i+1
78
79 T p1 = v1 / 3.0 - 7 * v2 / 6.0 + 11 * v3 / 6.0;
80 T p2 = -v2 / 6.0 + 5 * v3 / 6.0 + v4 / 3.0;
81 T p3 = v3 / 3.0 + 5 * v4 / 6.0 - v5 / 6.0;
82
83 T s1 = 13 / 12.0 * FiniteDifferences::square(v1 - 2 * v2 + v3) +
84 1 / 4.0 * FiniteDifferences::square(v1 - 4 * v2 + 3 * v3);
85 T s2 = 13 / 12.0 * FiniteDifferences::square(v2 - 2 * v3 + v4) +
86 1 / 4.0 * FiniteDifferences::square(v2 - v4);
87 T s3 = 13 / 12.0 * FiniteDifferences::square(v3 - 2 * v4 + v5) +
88 1 / 4.0 * FiniteDifferences::square(3 * v3 - 4 * v4 + v5);
89
90 T al1 = 0.1 / (eps + s1);
91 T al2 = 0.6 / (eps + s2);
92 T al3 = 0.3 / (eps + s3);
93
94 T alsum = al1 + al2 + al3;
95
96 T w1 = al1 / alsum;
97 T w2 = al2 / alsum;
98 T w3 = al3 / alsum;
99
100 return w1 * p1 + w2 * p2 + w3 * p3;
101 } else {
102 T v1 = (x[6] - x[5]) / dx;
103 T v2 = (x[5] - x[4]) / dx;
104 T v3 = (x[4] - x[3]) / dx;
105 T v4 = (x[3] - x[2]) / dx;
106 T v5 = (x[2] - x[1]) / dx;
107
108 T p1 = v1 / 3.0 - 7 * v2 / 6.0 + 11 * v3 / 6.0;
109 T p2 = -v2 / 6.0 + 5 * v3 / 6.0 + v4 / 3.0;
110 T p3 = v3 / 3.0 + 5 * v4 / 6.0 - v5 / 6.0;
111
112 T s1 = 13 / 12.0 * FiniteDifferences::square(v1 - 2 * v2 + v3) +
113 1 / 4.0 * FiniteDifferences::square(v1 - 4 * v2 + 3 * v3);
114 T s2 = 13 / 12.0 * FiniteDifferences::square(v2 - 2 * v3 + v4) +
115 1 / 4.0 * FiniteDifferences::square(v2 - v4);
116 T s3 = 13 / 12.0 * FiniteDifferences::square(v3 - 2 * v4 + v5) +
117 1 / 4.0 * FiniteDifferences::square(3 * v3 - 4 * v4 + v5);
118
119 T al1 = 0.1 / (eps + s1);
120 T al2 = 0.6 / (eps + s2);
121 T al3 = 0.3 / (eps + s3);
122
123 T alsum = al1 + al2 + al3;
124
125 T w1 = al1 / alsum;
126 T w2 = al2 / alsum;
127 T w3 = al3 / alsum;
128
129 return w1 * p1 + w2 * p2 + w3 * p3;
130 }
131 }
132
133 // Finite difference in the negative direction using the scheme specified
134 // by scheme. The passed vector contains the required neighbouring values,
135 // with the center point being in the centre of the vector.
136 // First order: x_-1, x, x_+1
137 // Second order: x_-2, x_-1, x, x_+1, x_+2
138 // WENO3: x_-2, x_-1, x, x_+1, x_+2
139 // WENO5: x_-3, x_-2, x_-1, x, x_+1, x_+2, x_+3
140 static T differenceNegative(const T *values, const double &delta) {
141 if constexpr (scheme == DifferentiationSchemeEnum::FIRST_ORDER) {
142 return (values[1] - values[0]) / delta;
143 } else if (scheme == DifferentiationSchemeEnum::SECOND_ORDER) {
144 // TODO: implement second order integration here
145 } else if (scheme == DifferentiationSchemeEnum::WENO3) {
146 return weno3(values, delta, false);
147 } else if (scheme == DifferentiationSchemeEnum::WENO5) {
148 return weno5(values, delta, false);
149 } else {
150 Logger::getInstance().addError("Invalid finite differences scheme!");
151 }
152 }
153
154 // Finite difference in the negative direction using the scheme specified
155 // by scheme. The passed vector contains the required neighbouring values,
156 // with the center point being in the centre of the vector.
157 // First order: x_-1, x, x_+1
158 // WENO3: x_-2, x_-1, x, x_+1, x_+2
159 // WENO5: x_-3, x_-2, x_-1, x, x_+1, x_+2, x_+3
160 static T differencePositive(const T *values, const double &delta) {
161 if constexpr (scheme == DifferentiationSchemeEnum::FIRST_ORDER) {
162 return (values[2] - values[1]) / delta;
163 } else if (scheme == DifferentiationSchemeEnum::SECOND_ORDER) {
164 // TODO: implement second order integration here
165 } else if (scheme == DifferentiationSchemeEnum::WENO3) {
166 return weno3(values, delta, true);
167 } else if (scheme == DifferentiationSchemeEnum::WENO5) {
168 return weno5(values, delta, true);
169 } else {
170 Logger::getInstance().addError("Invalid finite differences scheme!");
171 }
172 }
173
174 // Calculates the gradient around the central point in the passed vector
175 // Depending on the scheme, the passed vector takes a different size:
176 // First order: x_-1, x, x_+1
177 // WENO3: x_-2, x_-1, x, x_+1, x_+2
178 // WENO5: x_-3, x_-2, x_-1, x, x_+1, x_+2, x_+3
179 static T calculateGradient(const T *values, const double &delta) {
180 return (differencePositive(values, delta) +
181 differenceNegative(values, delta)) *
182 0.5;
183 }
184
185 static T calculateGradientDiff(const T *values, const double &delta) {
186 return (differencePositive(values, delta) -
187 differenceNegative(values, delta)) *
188 0.5;
189 }
190};
191
192} // namespace lsInternal
Definition lsFiniteDifferences.hpp:21
static T differencePositive(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:160
static T weno5(const T *x, T dx, bool plus, T eps=1e-6)
Definition lsFiniteDifferences.hpp:70
FiniteDifferences()
Definition lsFiniteDifferences.hpp:25
static T calculateGradient(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:179
static T differenceNegative(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:140
static T calculateGradientDiff(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:185
static T weno3(const T *x, T delta, bool plus, T eps=1e-6)
Weighted essentially non-oscillatory differentiation scheme 3rd order x1 ... x5 stencil points from l...
Definition lsFiniteDifferences.hpp:45
static unsigned getNumberOfValues(DifferentiationSchemeEnum s)
Definition lsFiniteDifferences.hpp:27
Definition lsAdvect.hpp:37
DifferentiationSchemeEnum
Definition lsFiniteDifferences.hpp:12
double T
Definition pyWrap.cpp:63