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