ViennaLS
Loading...
Searching...
No Matches
lsWENO5.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <hrleSparseStarIterator.hpp>
5#include <lsDomain.hpp>
6#include <lsExpand.hpp>
7#include <lsVelocityField.hpp>
8#include <vcVectorType.hpp>
9
10// Include your existing math library
12
13namespace lsInternal {
14
15using namespace viennacore;
16
20template <class T, int D, int order = 3> class WENO5 {
21 SmartPointer<viennals::Domain<T, D>> levelSet;
22 SmartPointer<viennals::VelocityField<T>> velocities;
23
24 // Iterator depth: WENO5 needs 3 neighbors on each side.
25 viennahrle::SparseStarIterator<viennahrle::Domain<T, D>, order>
26 neighborIterator;
27
28 const bool calculateNormalVectors = true;
29
30 // Use the existing math engine with WENO5 scheme
32
33 static T pow2(const T &value) { return value * value; }
34
35public:
36 static void prepareLS(SmartPointer<viennals::Domain<T, D>> passedlsDomain) {
37 // WENO5 uses a 7-point stencil (radius 3).
38 // Ensure we expand enough layers to access neighbors at +/- 3.
39 static_assert(order >= 3, "WENO5 requires an iterator order of at least 3");
40 viennals::Expand<T, D>(passedlsDomain, 2 * order + 1).apply();
41 }
42
43 WENO5(SmartPointer<viennals::Domain<T, D>> passedlsDomain,
44 SmartPointer<viennals::VelocityField<T>> vel, bool calcNormal = true)
45 : levelSet(passedlsDomain), velocities(vel),
46 neighborIterator(levelSet->getDomain()),
47 calculateNormalVectors(calcNormal) {}
48
49 std::pair<T, T> operator()(const viennahrle::Index<D> &indices,
50 int material) {
51 auto &grid = levelSet->getGrid();
52 double gridDelta = grid.getGridDelta();
53
54 VectorType<T, 3> coordinate{0., 0., 0.};
55 for (unsigned i = 0; i < D; ++i) {
56 coordinate[i] = indices[i] * gridDelta;
57 }
58
59 // Move iterator to the current grid point
60 neighborIterator.goToIndicesSequential(indices);
61
62 T gradPosTotal = 0;
63 T gradNegTotal = 0;
64
65 // --- OPTIMIZATION: Store derivatives to avoid re-calculation ---
66 T wenoGradMinus[D]; // Approximates derivative from left (phi_x^-)
67 T wenoGradPlus[D]; // Approximates derivative from right (phi_x^+)
68
69 // Array to hold the stencil values: [x-3, x-2, x-1, Center, x+1, x+2, x+3]
70 T stencil[7];
71
72 for (int i = 0; i < D; i++) {
73 // 1. GATHER STENCIL
74 // We map the SparseStarIterator (which uses encoded directions)
75 // to the flat array expected by FiniteDifferences.
76
77 // Center (Index 3 in the size-7 array)
78 stencil[3] = neighborIterator.getCenter().getValue();
79
80 // Neighbors +/- 1
81 stencil[4] = neighborIterator.getNeighbor(i).getValue(); // +1
82 stencil[2] = neighborIterator.getNeighbor(i + D).getValue(); // -1
83
84 // Neighbors +/- 2
85 // Note: SparseStarIterator encodes higher distances sequentially
86 stencil[5] = neighborIterator.getNeighbor(D * 2 + i).getValue(); // +2
87 stencil[1] = neighborIterator.getNeighbor(D * 2 + D + i).getValue(); // -2
88
89 // Neighbors +/- 3
90 stencil[6] = neighborIterator.getNeighbor(D * 4 + i).getValue(); // +3
91 stencil[0] = neighborIterator.getNeighbor(D * 4 + D + i).getValue(); // -3
92
93 // 2. COMPUTE DERIVATIVES
94 // Delegate the math to your existing library and store results
95 wenoGradMinus[i] = MathScheme::differenceNegative(stencil, gridDelta);
96 wenoGradPlus[i] = MathScheme::differencePositive(stencil, gridDelta);
97
98 // 3. GODUNOV FLUX PREPARATION
99 // We accumulate the gradient magnitudes for the scalar velocity case.
100 // This is part of the standard level set equation logic (Osher-Sethian).
101
102 // For Positive Scalar Velocity (Deposition): Use upwind selection
103 gradPosTotal += pow2(std::max(wenoGradMinus[i], T(0))) +
104 pow2(std::min(wenoGradPlus[i], T(0)));
105
106 // For Negative Scalar Velocity (Etching): Use upwind selection
107 gradNegTotal += pow2(std::min(wenoGradMinus[i], T(0))) +
108 pow2(std::max(wenoGradPlus[i], T(0)));
109 }
110
111 T vel_grad = 0.;
112
113 // --- Standard Normal Vector Calculation (for velocity lookup) ---
114 Vec3D<T> normalVector = {};
115 if (calculateNormalVectors) {
116 T denominator = 0;
117 for (int i = 0; i < D; i++) {
118 // Simple Central Difference for the normal vector is sufficient
119 // and robust for velocity direction lookup.
120 T pos = neighborIterator.getNeighbor(i).getValue();
121 T neg = neighborIterator.getNeighbor(i + D).getValue();
122 normalVector[i] = (pos - neg) * 0.5;
123 denominator += normalVector[i] * normalVector[i];
124 }
125 if (denominator > 0) {
126 denominator = 1. / std::sqrt(denominator);
127 for (unsigned i = 0; i < D; ++i) {
128 normalVector[i] *= denominator;
129 }
130 }
131 }
132
133 // --- Retrieve Velocity ---
134 double scalarVelocity = velocities->getScalarVelocity(
135 coordinate, material, normalVector,
136 neighborIterator.getCenter().getPointId());
137 Vec3D<T> vectorVelocity = velocities->getVectorVelocity(
138 coordinate, material, normalVector,
139 neighborIterator.getCenter().getPointId());
140
141 // --- Apply Velocities ---
142
143 // Scalar term (Etching/Deposition)
144 if (scalarVelocity > 0) {
145 vel_grad += std::sqrt(gradPosTotal) * scalarVelocity;
146 } else {
147 vel_grad += std::sqrt(gradNegTotal) * scalarVelocity;
148 }
149
150 // Vector term (Advection)
151 // Here we REUSE the derivatives stored in wenoGradMinus/Plus.
152 // This is the optimization compared to recalculating.
153 for (int w = 0; w < D; w++) {
154 if (vectorVelocity[w] > 0.) {
155 vel_grad += vectorVelocity[w] * wenoGradMinus[w];
156 } else {
157 vel_grad += vectorVelocity[w] * wenoGradPlus[w];
158 }
159 }
160
161 // WENO is an upwind scheme, so explicit dissipation is 0.
162 return {vel_grad, 0.};
163 }
164
165 void reduceTimeStepHamiltonJacobi(double &MaxTimeStep,
166 double gridDelta) const {
167 // --- STABILITY IMPROVEMENT ---
168 // High-order schemes like WENO5 combined with simple time integration (like
169 // the likely Forward Euler used in Advect) can be less stable at CFL=0.5.
170 // We enforce a safety factor here to ensure robustness.
171 constexpr double wenoSafetyFactor = 0.5;
172 MaxTimeStep *= wenoSafetyFactor;
173 }
174};
175
176} // namespace lsInternal
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
Definition lsFiniteDifferences.hpp:19
static T differencePositive(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:176
static T differenceNegative(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:153
static void prepareLS(SmartPointer< viennals::Domain< T, D > > passedlsDomain)
Definition lsWENO5.hpp:36
void reduceTimeStepHamiltonJacobi(double &MaxTimeStep, double gridDelta) const
Definition lsWENO5.hpp:165
WENO5(SmartPointer< viennals::Domain< T, D > > passedlsDomain, SmartPointer< viennals::VelocityField< T > > vel, bool calcNormal=true)
Definition lsWENO5.hpp:43
std::pair< T, T > operator()(const viennahrle::Index< D > &indices, int material)
Definition lsWENO5.hpp:49
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:27
Expands the levelSet to the specified number of layers. The largest value in the levelset is thus wid...
Definition lsExpand.hpp:17
void apply()
Apply the expansion to the specified width.
Definition lsExpand.hpp:44
Abstract class defining the interface for the velocity field used during advection using lsAdvect.
Definition lsVelocityField.hpp:11
Definition lsCurvatureFormulas.hpp:9