ViennaLS
Loading...
Searching...
No Matches
lsAdvectIntegrationSchemes.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <lsDomain.hpp>
5
6namespace viennals {
7
24
25// Legacy naming (deprecated, will be removed in future versions)
26using IntegrationSchemeEnum [[deprecated("Use SpatialSchemeEnum instead")]] =
28
36
37// Forward declaration
38template <class T, int D> class Advect;
39} // namespace viennals
40
41namespace lsInternal {
42
43template <class T, int D> struct AdvectTimeIntegration {
45
46 static double evolveForwardEuler(AdvectType &kernel, double maxTimeStep,
47 bool updateLowerLayers = true) {
48 if (kernel.currentTimeStep < 0. || kernel.storedRates.empty())
49 kernel.computeRates(maxTimeStep);
50
51 kernel.updateLevelSet(kernel.currentTimeStep);
52
53 kernel.rebuildLS();
54
55 if (updateLowerLayers)
56 kernel.adjustLowerLayers();
57
58 return kernel.currentTimeStep;
59 }
60
61 static double evolveRungeKutta2(AdvectType &kernel, double maxTimeStep) {
62 // TVD Runge-Kutta 2nd Order (Heun's Method)
63
64 // Save initial level sets
65 if (kernel.initialLevelSets.size() != kernel.levelSets.size()) {
66 kernel.initialLevelSets.resize(kernel.levelSets.size());
67 for (auto &ls : kernel.initialLevelSets)
68 ls = viennals::Domain<T, D>::New(kernel.levelSets[0]->getGrid());
69 }
70 kernel.initialLevelSets.back()->deepCopy(kernel.levelSets.back());
71
72 // Save initial lower level sets only if Stage 1 will modify them (via
73 // callback)
74 if (kernel.velocityUpdateCallback) {
75 for (size_t i = 0; i < kernel.levelSets.size() - 1; ++i) {
76 kernel.initialLevelSets[i]->deepCopy(kernel.levelSets[i]);
77 }
78 }
79
80 // Stage 1: u^(1) = u^n + dt * L(u^n)
81 // Update lower layers only if we have a callback
82 double dt1 = evolveForwardEuler(kernel, maxTimeStep,
83 kernel.velocityUpdateCallback != nullptr);
84
85 if (dt1 <= 0.)
86 return 0.;
87
88 if (kernel.velocityUpdateCallback)
89 kernel.velocityUpdateCallback(kernel.levelSets.back());
90
91 // Stage 2: u^(n+1) = 1/2 u^n + 1/2 (u^(1) + dt * L(u^(1)))
92 // Current level set is u^(1). Compute L(u^(1)).
93 // Update to u* = u^(1) + dt * L(u^(1))
94 double dt2 = evolveForwardEuler(kernel, dt1, false);
95
96 // Combine: u^(n+1) = 0.5 * u^n + 0.5 * u*
97 bool etched = kernel.combineLevelSets(0.5, 0.5);
98
99 // Restore lower level sets if etched.
100 if (etched && kernel.velocityUpdateCallback) {
101 for (size_t i = 0; i < kernel.levelSets.size() - 1; ++i) {
102 kernel.levelSets[i]->deepCopy(kernel.initialLevelSets[i]);
103 }
104 }
105 kernel.adjustLowerLayers();
106
107 return 0.5 * dt1 + 0.5 * dt2;
108 }
109
110 static double evolveRungeKutta3(AdvectType &kernel, double maxTimeStep) {
111 // Save initial level sets
112 if (kernel.initialLevelSets.size() != kernel.levelSets.size()) {
113 kernel.initialLevelSets.resize(kernel.levelSets.size());
114 for (auto &ls : kernel.initialLevelSets)
115 ls = viennals::Domain<T, D>::New(kernel.levelSets[0]->getGrid());
116 }
117 for (size_t i = 0; i < kernel.levelSets.size(); ++i) {
118 kernel.initialLevelSets[i]->deepCopy(kernel.levelSets[i]);
119 }
120
121 // Stage 1: u^(1) = u^n + dt * L(u^n)
122 // This calculates dt based on u^n and advances to u^1.
123 double dt1 = evolveForwardEuler(kernel, maxTimeStep,
124 kernel.velocityUpdateCallback != nullptr);
125
126 if (dt1 <= 0.)
127 return 0.;
128
129 if (kernel.velocityUpdateCallback)
130 kernel.velocityUpdateCallback(kernel.levelSets.back());
131
132 // Stage 2: u^(2) = 3/4 u^n + 1/4 (u^(1) + dt * L(u^(1)))
133 // u* = u^(1) + dt * L(u^(1))
134 double dt2 = evolveForwardEuler(kernel, dt1, false);
135
136 // Combine to get u^(2) = 0.75 * u^n + 0.25 * u*.
137 bool etched1 = kernel.combineLevelSets(0.75, 0.25);
138
139 // Restore lower level sets if etched
140 if (etched1 && kernel.velocityUpdateCallback) {
141 for (size_t i = 0; i < kernel.levelSets.size() - 1; ++i) {
142 kernel.levelSets[i]->deepCopy(kernel.initialLevelSets[i]);
143 }
144 }
145
146 kernel.adjustLowerLayers();
147
148 if (kernel.velocityUpdateCallback) {
149 kernel.velocityUpdateCallback(kernel.levelSets.back());
150 }
151
152 // Stage 3: u^(n+1) = 1/3 u^n + 2/3 (u^(2) + dt * L(u^(2)))
153 // u** = u^(2) + dt * L(u^(2))
154 double dt3 = evolveForwardEuler(kernel, dt1, false);
155
156 // Combine to get u^(n+1) = 1/3 * u^n + 2/3 * u**.
157 bool etched2 = kernel.combineLevelSets(1.0 / 3.0, 2.0 / 3.0);
158
159 // Restore lower level sets if etched.
160 if (etched2) {
161 for (size_t i = 0; i < kernel.levelSets.size() - 1; ++i) {
162 kernel.levelSets[i]->deepCopy(kernel.initialLevelSets[i]);
163 }
164 }
165 kernel.adjustLowerLayers();
166
167 return (dt1 + dt2 + 4.0 * dt3) / 6.0;
168 }
169};
170
171} // namespace lsInternal
This class is used to advance level sets over time. Level sets are passed to the constructor in a std...
Definition lsAdvect.hpp:54
static auto New(Args &&...args)
Definition lsDomain.hpp:112
Definition lsAdvectIntegrationSchemes.hpp:41
Definition lsAdvect.hpp:41
SpatialSchemeEnum
Enumeration for the different spatial discretization schemes used by the advection kernel.
Definition lsAdvectIntegrationSchemes.hpp:10
@ LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER
Definition lsAdvectIntegrationSchemes.hpp:17
@ STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER
Definition lsAdvectIntegrationSchemes.hpp:20
@ LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER
Definition lsAdvectIntegrationSchemes.hpp:16
@ LAX_FRIEDRICHS_2ND_ORDER
Definition lsAdvectIntegrationSchemes.hpp:14
@ LOCAL_LAX_FRIEDRICHS_1ST_ORDER
Definition lsAdvectIntegrationSchemes.hpp:18
@ ENGQUIST_OSHER_2ND_ORDER
Definition lsAdvectIntegrationSchemes.hpp:12
@ LAX_FRIEDRICHS_1ST_ORDER
Definition lsAdvectIntegrationSchemes.hpp:13
@ LOCAL_LAX_FRIEDRICHS_2ND_ORDER
Definition lsAdvectIntegrationSchemes.hpp:19
@ WENO_3RD_ORDER
Definition lsAdvectIntegrationSchemes.hpp:21
@ ENGQUIST_OSHER_1ST_ORDER
Definition lsAdvectIntegrationSchemes.hpp:11
@ LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER
Definition lsAdvectIntegrationSchemes.hpp:15
@ WENO_5TH_ORDER
Definition lsAdvectIntegrationSchemes.hpp:22
TemporalSchemeEnum
Enumeration for the different time integration schemes used to select the advection kernel.
Definition lsAdvectIntegrationSchemes.hpp:31
@ RUNGE_KUTTA_2ND_ORDER
Definition lsAdvectIntegrationSchemes.hpp:33
@ RUNGE_KUTTA_3RD_ORDER
Definition lsAdvectIntegrationSchemes.hpp:34
@ FORWARD_EULER
Definition lsAdvectIntegrationSchemes.hpp:32
Definition lsAdvectIntegrationSchemes.hpp:43
viennals::Advect< T, D > AdvectType
Definition lsAdvectIntegrationSchemes.hpp:44
static double evolveRungeKutta3(AdvectType &kernel, double maxTimeStep)
Definition lsAdvectIntegrationSchemes.hpp:110
static double evolveForwardEuler(AdvectType &kernel, double maxTimeStep, bool updateLowerLayers=true)
Definition lsAdvectIntegrationSchemes.hpp:46
static double evolveRungeKutta2(AdvectType &kernel, double maxTimeStep)
Definition lsAdvectIntegrationSchemes.hpp:61