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