ViennaLS
Loading...
Searching...
No Matches
lsStencilLocalLaxFriedrichsScalar.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>
9#include <lsVelocityField.hpp>
10
11namespace lsInternal {
12
13using namespace viennacore;
14
21template <class T, int D, int order> class StencilLocalLaxFriedrichsScalar {
22 using LevelSetType = SmartPointer<viennals::Domain<T, D>>;
23 using LevelSetsType = std::vector<LevelSetType>;
24
25 LevelSetType levelSet;
26 SmartPointer<viennals::VelocityField<T>> velocities;
27 const DifferentiationSchemeEnum finiteDifferenceScheme =
29 hrleSparseBoxIterator<hrleDomain<T, D>> neighborIterator;
30 const double alphaFactor;
31 const double normalEpsilon =
32 std::cbrt(std::numeric_limits<double>::epsilon());
33
34 // Final dissipation coefficients that are used by the time integrator. If
35 // D==2 last entries are 0.
36 hrleVectorType<T, 3> finalAlphas;
37 const unsigned numStencilPoints;
38
39 static T pow2(const T &value) { return value * value; }
40
41 hrleVectorType<T, D>
42 calculateNormal(const hrleVectorType<hrleIndexType, D> &offset) {
43 hrleVectorType<T, D> normal;
44 const int startIndex = -1;
45 T modulus = 0.;
46
47 for (unsigned i = 0; i < D; ++i) {
48 hrleVectorType<hrleIndexType, D> index(offset);
49 std::vector<T> values;
50 for (unsigned j = 0; j < 3; ++j) {
51 index[i] = startIndex + j;
52 values.push_back(neighborIterator.getNeighbor(index).getValue());
53 }
55 &(values[0]), levelSet->getGrid().getGridDelta());
56 modulus += normal[i] * normal[i];
57 }
58 modulus = std::sqrt(modulus);
59 for (unsigned i = 0; i < D; ++i) {
60 normal[i] /= modulus;
61 }
62 return normal;
63 }
64
65 hrleVectorType<T, D>
66 calculateGradient(const hrleVectorType<hrleIndexType, D> &offset) {
67 hrleVectorType<T, D> gradient;
68
69 const unsigned numValues =
70 FiniteDifferences<T>::getNumberOfValues(finiteDifferenceScheme);
71 const int startIndex = -std::floor(numValues / 2);
72
73 for (unsigned i = 0; i < D; ++i) {
74 hrleVectorType<hrleIndexType, D> index(offset);
75 std::vector<T> values;
76 for (unsigned j = 0; j < numValues; ++j) {
77 index[i] = startIndex + j;
78 values.push_back(neighborIterator.getNeighbor(index).getValue());
79 }
80
81 if (finiteDifferenceScheme == DifferentiationSchemeEnum::FIRST_ORDER) {
82 gradient[i] =
84 calculateGradient(&(values[0]),
85 levelSet->getGrid().getGridDelta());
86 } else if (finiteDifferenceScheme == DifferentiationSchemeEnum::WENO3) {
88 calculateGradient(&(values[0]), levelSet->getGrid().getGridDelta());
89 } else if (finiteDifferenceScheme == DifferentiationSchemeEnum::WENO5)
91 calculateGradient(&(values[0]), levelSet->getGrid().getGridDelta());
92 }
93
94 return gradient;
95 }
96
97 hrleVectorType<T, D> calculateGradientDiff() {
98 hrleVectorType<T, D> gradient;
99
100 const unsigned numValues =
101 FiniteDifferences<T>::getNumberOfValues(finiteDifferenceScheme);
102 const int startIndex = -std::floor(numValues / 2);
103
104 for (unsigned i = 0; i < D; ++i) {
105 hrleVectorType<hrleIndexType, D> index(hrleIndexType(0));
106 std::vector<T> values;
107 for (unsigned j = 0; j < numValues; ++j) {
108 index[i] = startIndex + j;
109 values.push_back(neighborIterator.getNeighbor(index).getValue());
110 }
111
112 if (finiteDifferenceScheme == DifferentiationSchemeEnum::FIRST_ORDER) {
113 gradient[i] =
115 calculateGradientDiff(&(values[0]),
116 levelSet->getGrid().getGridDelta());
117 } else if (finiteDifferenceScheme == DifferentiationSchemeEnum::WENO3) {
119 calculateGradientDiff(&(values[0]),
120 levelSet->getGrid().getGridDelta());
121 } else if (finiteDifferenceScheme == DifferentiationSchemeEnum::WENO5)
123 calculateGradientDiff(&(values[0]),
124 levelSet->getGrid().getGridDelta());
125 }
126
127 return gradient;
128 }
129
130public:
131 static void prepareLS(LevelSetType passedlsDomain) {
132 // Expansion of sparse field must depend on spatial derivative order
133 // AND slf stencil order! --> currently assume scheme = 3rd order always
134 viennals::Expand<T, D>(passedlsDomain, 2 * (order + 1) + 4).apply();
135 }
136
138 LevelSetType passedlsDomain, SmartPointer<viennals::VelocityField<T>> vel,
139 double a = 1.0,
141 : levelSet(passedlsDomain), velocities(vel),
142 finiteDifferenceScheme(scheme),
143 neighborIterator(hrleSparseBoxIterator<hrleDomain<T, D>>(
144 levelSet->getDomain(), static_cast<unsigned>(scheme) + 1 + order)),
145 alphaFactor(a), numStencilPoints(std::pow(2 * order + 1, D)) {
146 for (int i = 0; i < 3; ++i) {
147 finalAlphas[i] = 0;
148 }
149 }
150
151 std::pair<T, T> operator()(const hrleVectorType<hrleIndexType, D> &indices,
152 int material) {
153 auto &grid = levelSet->getGrid();
154 double gridDelta = grid.getGridDelta();
155
156 hrleVectorType<T, 3> coordinate(0., 0., 0.);
157 for (unsigned i = 0; i < D; ++i) {
158 coordinate[i] = indices[i] * gridDelta;
159 }
160
161 // move neighborIterator to current position
162 neighborIterator.goToIndicesSequential(indices);
163
164 // convert coordinate to std array for interface
165 std::array<T, 3> coordArray = {coordinate[0], coordinate[1], coordinate[2]};
166
167 // if there is a vector velocity, we need to project it onto a scalar
168 // velocity first using its normal vector
169 // /*if (vectorVelocity != std::array<T, 3>({}))*/ {
170 std::array<T, 3> normalVector = {};
171 T denominator = 0; // normal modulus
172 for (unsigned i = 0; i < D; i++) {
173 hrleVectorType<T, 3> neighborIndex(T(0));
174 neighborIndex[i] = 1;
175 // normal vector calculation
176 T pos = neighborIterator.getNeighbor(neighborIndex).getValue() -
177 neighborIterator.getCenter().getValue();
178 T neg = neighborIterator.getCenter().getValue() -
179 neighborIterator.getNeighbor(-neighborIndex).getValue();
180 normalVector[i] = (pos + neg) * 0.5;
181 // normalise normal vector
182 denominator += normalVector[i] * normalVector[i];
183 }
184 denominator = std::sqrt(denominator);
185
186 for (unsigned i = 0; i < D; ++i) {
187 normalVector[i] /= denominator;
188 }
189
190 double scalarVelocity = velocities->getScalarVelocity(
191 coordArray, material, normalVector,
192 neighborIterator.getCenter().getPointId());
193 std::array<T, 3> vectorVelocity = velocities->getVectorVelocity(
194 coordArray, material, normalVector,
195 neighborIterator.getCenter().getPointId());
196
197 // now calculate scalar product of normal vector with velocity
198 for (unsigned i = 0; i < D; ++i) {
199 scalarVelocity += vectorVelocity[i] * normalVector[i];
200 }
201
202 if (scalarVelocity == T(0)) {
203 return {0, 0};
204 }
205
206 T hamiltonian =
207 NormL2(calculateGradient(hrleVectorType<hrleIndexType, D>(0))) *
208 scalarVelocity;
209 T dissipation = 0.; // dissipation
210
211 // dissipation block
212 {
213 // reserve alphas for all points in local stencil
214 std::vector<hrleVectorType<T, D>> alphas;
215 alphas.reserve(numStencilPoints);
216
217 hrleVectorType<hrleIndexType, D> currentIndex(-order);
218 for (size_t i = 0; i < numStencilPoints; ++i) {
219 hrleVectorType<T, D> alpha;
220 hrleVectorType<T, 3> normal(calculateNormal(currentIndex));
221 if (D == 2)
222 normal[2] = 0;
223
224 // Check for corrupted normal
225 if ((std::abs(normal[0]) < 1e-6) && (std::abs(normal[1]) < 1e-6) &&
226 (std::abs(normal[2]) < 1e-6)) {
227 alphas.push_back(hrleVectorType<T, D>(T(0)));
228 continue;
229 }
230
231 std::array<T, 3> normal_p = {normal[0], normal[1], normal[2]};
232 std::array<T, 3> normal_n = {normal[0], normal[1], normal[2]};
233
234 hrleVectorType<T, D> velocityDelta(T(0));
235
236 // get local velocity
237 std::array<T, 3> localCoordArray = coordArray;
238 for (unsigned dir = 0; dir < D; ++dir)
239 localCoordArray[dir] += currentIndex[dir];
240
241 T localScalarVelocity = velocities->getScalarVelocity(
242 localCoordArray, material, normal_p,
243 neighborIterator.getCenter().getPointId());
244 std::array<T, 3> localVectorVelocity = velocities->getVectorVelocity(
245 localCoordArray, material, normal_p,
246 neighborIterator.getCenter().getPointId());
247 // now calculate scalar product of normal vector with velocity
248 for (unsigned i = 0; i < D; ++i) {
249 localScalarVelocity += localVectorVelocity[i] * normal[i];
250 }
251
252 const T DN = std::abs(normalEpsilon * scalarVelocity);
253
254 for (int k = 0; k < D; ++k) {
255
256 normal_p[k] -= DN; // p=previous
257 normal_n[k] += DN; // n==next
258
259 T vp = velocities->getScalarVelocity(
260 localCoordArray, material, normal_p,
261 neighborIterator.getCenter().getPointId());
262 T vn = velocities->getScalarVelocity(
263 localCoordArray, material, normal_n,
264 neighborIterator.getCenter().getPointId());
265 // central difference
266 velocityDelta[k] = (vn - vp) / (2.0 * DN);
267
268 normal_p[k] += DN;
269 normal_n[k] -= DN;
270 }
271
272 // determine \partial H / \partial phi_l
273 for (int k = 0; k < D; ++k) { // iterate over dimensions
274
275 // Monti term
276 T monti = 0;
277 // Toifl Quell term
278 T toifl = 0;
279
280 hrleVectorType<T, D> gradient = calculateGradient(currentIndex);
281
282 for (int j = 0; j < D - 1; ++j) { // phi_p**2 + phi_q**2
283 int idx = (k + 1 + j) % D;
284 monti += gradient[idx] * gradient[idx];
285 toifl += gradient[idx] * velocityDelta[idx];
286 }
287 // denominator: |grad(phi)|^2
288 T denominator = Norm2(gradient);
289 monti *= velocityDelta[k] / denominator;
290 toifl *= -gradient[k] / denominator;
291
292 // Osher (constant V) term
293 T osher = localScalarVelocity * normal[k];
294 // Total derivative is sum of terms given above
295 alpha[k] = std::fabs(monti + toifl + osher);
296 }
297
298 alphas.push_back(alpha);
299
300 // increment current index
301 {
302 int dim = 0;
303 for (; dim < D - 1; ++dim) {
304 if (currentIndex[dim] < order)
305 break;
306 currentIndex[dim] = -order;
307 }
308 ++currentIndex[dim];
309 }
310 }
311
312 // determine max alphas for every axis
313 hrleVectorType<T, D> gradientDiff = calculateGradientDiff();
314 for (int d = 0; d < D; ++d) {
315 T maxAlpha = 0;
316
317 for (size_t i = 0; i < numStencilPoints; ++i) {
318 maxAlpha = std::max(maxAlpha, alphas[i][d]);
319 }
320
321 finalAlphas[d] = maxAlpha;
322 dissipation += maxAlpha * gradientDiff[d];
323 }
324
325 return {hamiltonian, dissipation};
326 }
327 }
328
329 void reduceTimeStepHamiltonJacobi(double &MaxTimeStep,
330 hrleCoordType gridDelta) {
331 const double alpha_maxCFL = 1.0;
332 // second time step test, based on alphas
333
334 double timeStep = 0;
335 for (int i = 0; i < D; ++i) {
336 timeStep += finalAlphas[i] / gridDelta;
337 }
338
339 timeStep = alpha_maxCFL / timeStep;
340 MaxTimeStep = std::min(timeStep, MaxTimeStep);
341 }
342};
343} // namespace lsInternal
344
345namespace viennals {
346
347using namespace viennacore;
348
360template <class T, int D>
362 std::vector<SmartPointer<Domain<T, D>>> &levelSets,
363 std::vector<bool> isDepo) {
364 if (isDepo.size() < levelSets.size()) {
365 Logger::getInstance()
366 .addWarning(
367 "PrepareStencilLocalLaxFriedrichs: isDepo does not have enough "
368 "elements. Assuming all higher layers are not depo layers.")
369 .print();
370 }
371 // always resize, so it has the correct number of elements
372 isDepo.resize(levelSets.size(), false);
373
374 // Begin with biggest level set (top LS wrapped around all others)
375 auto layerIt = levelSets.rbegin();
376
377 // make empty LS which will contain the final top layer
378 auto finalTop = SmartPointer<Domain<T, D>>::New(levelSets[0]->getGrid());
379
380 bool layerAboveIsDepo = false;
381 auto depoIt = isDepo.rbegin();
382
383 // subtract each first non-depo layer below a depo layer from the latter
384 // then union these results to the final layer
385 for (auto maskIt = levelSets.rbegin(); maskIt != levelSets.rend(); ++maskIt) {
386 if (isDepo[*depoIt]) {
387 // this layer will be deposited on
388 if (!layerAboveIsDepo) {
389 layerIt = maskIt;
390 layerAboveIsDepo = true;
391 }
392 } else {
393 // no depo on this layer
394 if (layerAboveIsDepo) {
395 auto layerAbove = SmartPointer<Domain<T, D>>::New(*layerIt);
396 BooleanOperation<T, D>(layerAbove, *maskIt,
398 .apply();
399
400 BooleanOperation<T, D>(finalTop, layerAbove,
402 .apply();
403 Prune<T, D>(finalTop).apply();
404 }
405 layerAboveIsDepo = false;
406 }
407 ++depoIt;
408 }
409
410 // If the lowest layer is a depo substrate, add it to the final top layer
411 if (layerAboveIsDepo) {
413 .apply();
414 }
415
417 levelSets.back()->deepCopy(finalTop);
418}
419
422template <class T, int D>
424 std::vector<SmartPointer<Domain<T, D>>> &levelSets) {
425 auto layerIt = levelSets.rbegin();
426 auto lastIt = ++levelSets.rbegin();
427
430 .apply();
431}
432
433} // namespace viennals
static T calculateGradient(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:179
static T calculateGradientDiff(const T *values, const double &delta)
Definition lsFiniteDifferences.hpp:185
static unsigned getNumberOfValues(DifferentiationSchemeEnum s)
Definition lsFiniteDifferences.hpp:27
static void prepareLS(LevelSetType passedlsDomain)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:131
void reduceTimeStepHamiltonJacobi(double &MaxTimeStep, hrleCoordType gridDelta)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:329
std::pair< T, T > operator()(const hrleVectorType< hrleIndexType, D > &indices, int material)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:151
StencilLocalLaxFriedrichsScalar(LevelSetType passedlsDomain, SmartPointer< viennals::VelocityField< T > > vel, double a=1.0, DifferentiationSchemeEnum scheme=DifferentiationSchemeEnum::FIRST_ORDER)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:137
This class is used to perform boolean operations on two level sets and write the resulting level set ...
Definition lsBooleanOperation.hpp:43
void apply()
Perform operation.
Definition lsBooleanOperation.hpp:312
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
Removes all level set points, which do not have at least one oppositely signed neighbour (Meaning the...
Definition lsPrune.hpp:19
void apply()
removes all grid points, which do not have at least one opposite signed neighbour returns the number ...
Definition lsPrune.hpp:76
Abstract class defining the interface for the velocity field used during advection using lsAdvect.
Definition lsVelocityField.hpp:13
Definition lsCurvatureFormulas.hpp:9
DifferentiationSchemeEnum
Definition lsFiniteDifferences.hpp:12
@ FIRST_ORDER
Definition lsFiniteDifferences.hpp:13
@ WENO3
Definition lsFiniteDifferences.hpp:15
@ WENO5
Definition lsFiniteDifferences.hpp:16
Definition lsAdvect.hpp:37
void PrepareStencilLocalLaxFriedrichs(std::vector< SmartPointer< Domain< T, D > > > &levelSets, std::vector< bool > isDepo)
This function creates the specialized layer wrapping which produces better results for the SSLF integ...
Definition lsStencilLocalLaxFriedrichsScalar.hpp:361
void FinalizeStencilLocalLaxFriedrichs(std::vector< SmartPointer< Domain< T, D > > > &levelSets)
After advection using the SLLF layer wrapping approach is done, restore the original layer wrapping u...
Definition lsStencilLocalLaxFriedrichsScalar.hpp:423
@ INVERT
Definition lsBooleanOperation.hpp:29
@ RELATIVE_COMPLEMENT
Definition lsBooleanOperation.hpp:28
@ UNION
Definition lsBooleanOperation.hpp:27
constexpr int D
Definition pyWrap.cpp:66
double T
Definition pyWrap.cpp:64