ViennaLS
Loading...
Searching...
No Matches
lsLocalLaxFriedrichs.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <hrleSparseBoxIterator.hpp>
4#include <hrleVectorType.hpp>
5
6#include <lsDomain.hpp>
7#include <lsExpand.hpp>
8#include <lsVelocityField.hpp>
9
10#include <vcVectorUtil.hpp>
11
12namespace lsInternal {
13
14using namespace viennacore;
15
21template <class T, int D, int order> class LocalLaxFriedrichs {
22 SmartPointer<viennals::Domain<T, D>> levelSet;
23 SmartPointer<viennals::VelocityField<T>> velocities;
24 hrleSparseBoxIterator<hrleDomain<T, D>> neighborIterator;
25 const double alphaFactor;
26 hrleVectorType<T, 3> finalAlphas;
27
28 static T pow2(const T &value) { return value * value; }
29
30 T calculateNormalComponent(T neg, T center, T pos, T delta) {
31 auto diffPos = (pos - center) / delta;
32 auto diffNeg = (center - neg) / delta;
33 return (diffPos + diffNeg) * 0.5;
34 }
35
36 void incrementIndices(hrleVectorType<hrleIndexType, D> &index,
37 hrleIndexType minIndex, hrleIndexType maxIndex) {
38 unsigned dir = 0;
39 for (; dir < D - 1; ++dir) {
40 if (index[dir] < maxIndex)
41 break;
42 index[dir] = minIndex;
43 }
44 ++index[dir];
45 }
46
47public:
48 static void prepareLS(SmartPointer<viennals::Domain<T, D>> passedlsDomain) {
49 assert(order == 1 || order == 2);
50 // at least order+1 layers since we need neighbor neighbors for
51 // dissipation alpha calculation
52 viennals::Expand<T, D>(passedlsDomain, 2 * (order + 2) + 1).apply();
53 }
54
55 // neighboriterator always needs order 2 for alpha calculation
56 LocalLaxFriedrichs(SmartPointer<viennals::Domain<T, D>> passedlsDomain,
57 SmartPointer<viennals::VelocityField<T>> vel,
58 double a = 1.0)
59 : levelSet(passedlsDomain), velocities(vel),
60 neighborIterator(levelSet->getDomain(), 2), alphaFactor(a) {
61 for (int i = 0; i < 3; ++i) {
62 finalAlphas[i] = 0;
63 }
64 }
65
66 std::pair<T, T> operator()(const hrleVectorType<hrleIndexType, D> &indices,
67 int material) {
68
69 auto &grid = levelSet->getGrid();
70 double gridDelta = grid.getGridDelta();
71
72 hrleVectorType<T, 3> coordinate(0., 0., 0.);
73 for (unsigned i = 0; i < D; ++i) {
74 coordinate[i] = indices[i] * gridDelta;
75 }
76
77 // move neighborIterator to current position
78 neighborIterator.goToIndicesSequential(indices);
79
80 // convert coordinate to std array for interface
81 Vec3D<T> coordArray = {coordinate[0], coordinate[1], coordinate[2]};
82
83 T gradPos[D];
84 T gradNeg[D];
85
86 T grad = 0.;
87 T dissipation = 0.;
88
89 Vec3D<T> normalVector = {};
90 T normalModulus = 0;
91
92 for (int i = 0; i < D; i++) { // iterate over dimensions
93 hrleVectorType<hrleIndexType, D> posUnit(0);
94 hrleVectorType<hrleIndexType, D> negUnit(0);
95 posUnit[i] = 1;
96 negUnit[i] = -1;
97
98 const T deltaPos = gridDelta;
99 const T deltaNeg = -gridDelta;
100
101 const T phi0 = neighborIterator.getCenter().getValue();
102 const T phiPos = neighborIterator.getNeighbor(posUnit).getValue();
103 const T phiNeg = neighborIterator.getNeighbor(negUnit).getValue();
104
105 T diffPos = (phiPos - phi0) / deltaPos;
106 T diffNeg = (phiNeg - phi0) / deltaNeg;
107
108 if (order == 2) { // if second order time integration scheme is used
109 posUnit[i] = 2;
110 negUnit[i] = -2;
111
112 const T deltaPosPos = 2 * gridDelta;
113 const T deltaNegNeg = -2 * gridDelta;
114
115 const T diff00 =
116 (((deltaNeg * phiPos - deltaPos * phiNeg) / (deltaPos - deltaNeg) +
117 phi0)) /
118 (deltaPos * deltaNeg);
119 const T phiPosPos = neighborIterator.getNeighbor(posUnit).getValue();
120 const T phiNegNeg = neighborIterator.getNeighbor(negUnit).getValue();
121
122 const T diffNegNeg = (((deltaNeg * phiNegNeg - deltaNegNeg * phiNeg) /
123 (deltaNegNeg - deltaNeg) +
124 phi0)) /
125 (deltaNegNeg * deltaNeg);
126 const T diffPosPos = (((deltaPos * phiPosPos - deltaPosPos * phiPos) /
127 (deltaPosPos - deltaPos) +
128 phi0)) /
129 (deltaPosPos * deltaPos);
130
131 if (std::signbit(diff00) == std::signbit(diffPosPos)) {
132 if (std::abs(diffPosPos * deltaPos) < std::abs(diff00 * deltaNeg)) {
133 diffPos -= deltaPos * diffPosPos;
134 } else {
135 diffPos += deltaNeg * diff00;
136 }
137 }
138
139 if (std::signbit(diff00) == std::signbit(diffNegNeg)) {
140 if (std::abs(diffNegNeg * deltaNeg) < std::abs(diff00 * deltaPos)) {
141 diffNeg -= deltaNeg * diffNegNeg;
142 } else {
143 diffNeg += deltaPos * diff00;
144 }
145 }
146 }
147
148 gradPos[i] = diffNeg;
149 gradNeg[i] = diffPos;
150
151 normalVector[i] = (diffNeg + diffPos) * 0.5;
152 normalModulus += normalVector[i] * normalVector[i];
153
154 grad += pow2((diffNeg + diffPos) * 0.5);
155 }
156
157 // normalise normal vector
158 normalModulus = std::sqrt(normalModulus);
159 for (unsigned i = 0; i < D; ++i) {
160 normalVector[i] /= normalModulus;
161 }
162
163 // Get velocities
164 double scalarVelocity = velocities->getScalarVelocity(
165 coordArray, material, normalVector,
166 neighborIterator.getCenter().getPointId());
167 Vec3D<T> vectorVelocity = velocities->getVectorVelocity(
168 coordArray, material, normalVector,
169 neighborIterator.getCenter().getPointId());
170
171 // calculate hamiltonian
172 T totalGrad = 0.;
173 if (scalarVelocity != 0.) {
174 totalGrad = scalarVelocity * std::sqrt(grad);
175 }
176
177 for (int w = 0; w < D; w++) {
178 if (vectorVelocity[w] > 0.) {
179 totalGrad += vectorVelocity[w] * gradPos[w];
180 } else {
181 totalGrad += vectorVelocity[w] * gradNeg[w];
182 }
183 }
184
185 // calculate alphas
186 T alpha[D] = {};
187 {
188 // alpha calculation is always on order 1 stencil
189 const hrleIndexType minIndex = -1;
190 const hrleIndexType maxIndex = 1;
191 const unsigned numNeighbors = std::pow((maxIndex - minIndex) + 1, D);
192
193 hrleVectorType<hrleIndexType, D> neighborIndex(minIndex);
194 for (unsigned i = 0; i < numNeighbors; ++i) {
195 Vec3D<T> coords;
196 for (unsigned dir = 0; dir < D; ++dir) {
197 coords[dir] = coordinate[dir] + neighborIndex[dir] * gridDelta;
198 }
199 Vec3D<T> normal = {};
200 double normalModulus = 0.;
201 auto center = neighborIterator.getNeighbor(neighborIndex).getValue();
202 for (unsigned dir = 0; dir < D; ++dir) {
203 hrleVectorType<hrleIndexType, D> unity(0);
204 unity[dir] = 1;
205 auto neg =
206 neighborIterator.getNeighbor(neighborIndex - unity).getValue();
207 auto pos =
208 neighborIterator.getNeighbor(neighborIndex + unity).getValue();
209 normal[dir] = calculateNormalComponent(neg, center, pos, gridDelta);
210 normalModulus += normal[dir] * normal[dir];
211 }
212 normalModulus = std::sqrt(normalModulus);
213 for (unsigned dir = 0; dir < D; ++dir)
214 normal[dir] /= normalModulus;
215
216 T scaVel = velocities->getScalarVelocity(
217 coords, material, normal,
218 neighborIterator.getCenter().getPointId());
219 auto vecVel = velocities->getVectorVelocity(
220 coords, material, normal,
221 neighborIterator.getCenter().getPointId());
222
223 for (unsigned dir = 0; dir < D; ++dir) {
224 // normalise normal vector
225 T tempAlpha = std::abs((scaVel + vecVel[dir]) * normal[dir]);
226 alpha[dir] = std::max(alpha[dir], tempAlpha);
227 finalAlphas[dir] = std::max(finalAlphas[dir], tempAlpha);
228 }
229
230 // advance to next index
231 incrementIndices(neighborIndex, minIndex, maxIndex);
232 }
233 }
234
235 // calculate local dissipation alphas for each direction
236 // and add to dissipation term
237 for (unsigned i = 0; i < D; ++i) {
238 dissipation += alphaFactor * alpha[i] * (gradNeg[i] - gradPos[i]) * 0.5;
239 }
240
241 return {totalGrad, ((totalGrad != 0.) ? dissipation : 0)};
242 }
243
244 void reduceTimeStepHamiltonJacobi(double &MaxTimeStep,
245 hrleCoordType gridDelta) {
246 const double alpha_maxCFL = 1.0;
247 // second time step test, based on alphas
248
249 double timeStep = 0;
250 for (int i = 0; i < D; ++i) {
251 timeStep += finalAlphas[i] / gridDelta;
252 }
253
254 timeStep = alpha_maxCFL / timeStep;
255 MaxTimeStep = std::min(timeStep, MaxTimeStep);
256 }
257};
258} // namespace lsInternal
static void prepareLS(SmartPointer< viennals::Domain< T, D > > passedlsDomain)
Definition lsLocalLaxFriedrichs.hpp:48
void reduceTimeStepHamiltonJacobi(double &MaxTimeStep, hrleCoordType gridDelta)
Definition lsLocalLaxFriedrichs.hpp:244
std::pair< T, T > operator()(const hrleVectorType< hrleIndexType, D > &indices, int material)
Definition lsLocalLaxFriedrichs.hpp:66
LocalLaxFriedrichs(SmartPointer< viennals::Domain< T, D > > passedlsDomain, SmartPointer< viennals::VelocityField< T > > vel, double a=1.0)
Definition lsLocalLaxFriedrichs.hpp:56
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:27
Expands the leveleSet to the specified number of layers. The largest value in the levelset is thus wi...
Definition lsExpand.hpp:16
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:13
Definition lsCurvatureFormulas.hpp:9
constexpr int D
Definition pyWrap.cpp:66
double T
Definition pyWrap.cpp:64