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 d[3];
60 if (plus) {
61 d[0] = x[2] - x[1];
62 d[1] = x[3] - x[2];
63 d[2] = x[4] - x[3];
64
65 T N = eps + FiniteDifferences::square(d[2] - d[1]);
66 T D = eps + FiniteDifferences::square(d[1] - d[0]);
67 T D2 = D * D;
68 T wp = D2 / (D2 + 2 * N * N);
69
70 return (d[0] + d[1] - wp * (d[2] - 2 * d[1] + d[0])) / (2 * delta);
71 } else {
72 d[0] = x[1] - x[0];
73 d[1] = x[2] - x[1];
74 d[2] = x[3] - x[2];
75
76 T N = eps + FiniteDifferences::square(d[1] - d[0]);
77 T D = eps + FiniteDifferences::square(d[2] - d[1]);
78 T D2 = D * D;
79 T wp = D2 / (D2 + 2 * N * N);
80
81 return (d[1] + d[2] - wp * (d[0] - 2 * d[1] + d[2])) / (2 * delta);
82 }
83 }
84
85 // Weighted essentially non-oscillatory differentiation scheme 5th order
86 // x1 ... x7 stencil points from left to right
87 // plus == true => right-sided
88 static T weno5(const T *x, T dx, bool plus, T eps = 1e-6) {
89 // Optimized implementation avoiding multiple divisions by dx
90 T d[5];
91 if (!plus) {
92 for (int i = 0; i < 5; ++i)
93 d[i] = x[i + 1] - x[i];
94 } else {
95 for (int i = 0; i < 5; ++i)
96 d[i] = x[6 - i] - x[5 - i];
97 }
98
99 // Smoothness indicators (scaled by dx^2)
100 T s1 = T(13.0 / 12.0) * FiniteDifferences::square(d[0] - 2 * d[1] + d[2]) +
101 T(1.0 / 4.0) * FiniteDifferences::square(d[0] - 4 * d[1] + 3 * d[2]);
102 T s2 = T(13.0 / 12.0) * FiniteDifferences::square(d[1] - 2 * d[2] + d[3]) +
103 T(1.0 / 4.0) * FiniteDifferences::square(d[1] - d[3]);
104 T s3 = T(13.0 / 12.0) * FiniteDifferences::square(d[2] - 2 * d[3] + d[4]) +
105 T(1.0 / 4.0) * FiniteDifferences::square(3 * d[2] - 4 * d[3] + d[4]);
106
107 // Scale epsilon by dx^2 to match scaled smoothness indicators
108 T eps_scaled = eps * dx * dx;
109
110 T al1 = T(0.1) / (eps_scaled + s1);
111 T al2 = T(0.6) / (eps_scaled + s2);
112 T al3 = T(0.3) / (eps_scaled + s3);
113
114 T alsum = al1 + al2 + al3;
115
116 // Polynomials (scaled by dx)
117 T p1 = T(1.0 / 6.0) * (2 * d[0] - 7 * d[1] + 11 * d[2]);
118 T p2 = T(1.0 / 6.0) * (-d[1] + 5 * d[2] + 2 * d[3]);
119 T p3 = T(1.0 / 6.0) * (2 * d[2] + 5 * d[3] - d[4]);
120
121 // Final result divides by dx once
122 return (al1 * p1 + al2 * p2 + al3 * p3) / (alsum * dx);
123 }
124
125 // Finite difference in the negative direction using the scheme specified
126 // by scheme. The passed vector contains the required neighbouring values,
127 // with the center point being in the centre of the vector.
128 // First order: x_-1, x, x_+1
129 // Second order: x_-2, x_-1, x, x_+1, x_+2
130 // WENO3: x_-2, x_-1, x, x_+1, x_+2
131 // WENO5: x_-3, x_-2, x_-1, x, x_+1, x_+2, x_+3
132 static T differenceNegative(const T *values, const double &delta) {
133 if constexpr (scheme == DifferentiationSchemeEnum::FIRST_ORDER) {
134 return (values[1] - values[0]) / delta;
135 } else if (scheme == DifferentiationSchemeEnum::SECOND_ORDER) {
136 // TODO: implement second order differentiation here
137 Logger::getInstance().addError("Second order scheme not implemented!");
138 return 0;
139 } else if (scheme == DifferentiationSchemeEnum::WENO3) {
140 return weno3(values, delta, false);
141 } else if (scheme == DifferentiationSchemeEnum::WENO5) {
142 return weno5(values, delta, false);
143 } else {
144 Logger::getInstance().addError("Invalid finite differences scheme!");
145 return 0;
146 }
147 }
148
149 // Finite difference in the negative direction using the scheme specified
150 // by scheme. The passed vector contains the required neighbouring values,
151 // with the center point being in the centre of the vector.
152 // First order: x_-1, x, x_+1
153 // WENO3: x_-2, x_-1, x, x_+1, x_+2
154 // WENO5: x_-3, x_-2, x_-1, x, x_+1, x_+2, x_+3
155 static T differencePositive(const T *values, const double &delta) {
156 if constexpr (scheme == DifferentiationSchemeEnum::FIRST_ORDER) {
157 return (values[2] - values[1]) / delta;
158 } else if (scheme == DifferentiationSchemeEnum::SECOND_ORDER) {
159 // TODO: implement second order differentiation here
160 Logger::getInstance().addError("Second order scheme not implemented!");
161 return 0;
162 } else if (scheme == DifferentiationSchemeEnum::WENO3) {
163 return weno3(values, delta, true);
164 } else if (scheme == DifferentiationSchemeEnum::WENO5) {
165 return weno5(values, delta, true);
166 } else {
167 Logger::getInstance().addError("Invalid finite differences scheme!");
168 return 0;
169 }
170 }
171
172 // Calculates the gradient around the central point in the passed vector
173 // Depending on the scheme, the passed vector takes a different size:
174 // First order: x_-1, x, x_+1
175 // WENO3: x_-2, x_-1, x, x_+1, x_+2
176 // WENO5: x_-3, x_-2, x_-1, x, x_+1, x_+2, x_+3
177 static T calculateGradient(const T *values, const double &delta) {
178 return (differencePositive(values, delta) +
179 differenceNegative(values, delta)) *
180 0.5;
181 }
182
183 static T calculateGradientDiff(const T *values, const double &delta) {
184 return (differencePositive(values, delta) -
185 differenceNegative(values, delta)) *
186 0.5;
187 }
188};
189
190} // namespace lsInternal
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
static T differencePositive(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:155
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:88
static T calculateGradient(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:177
static T differenceNegative(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:132
static T calculateGradientDiff(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:183
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 lsAdvectIntegrationSchemes.hpp:41
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