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 const hrleVectorType<T, 3> &getFinalAlphas() const { return finalAlphas; }
132
133 static void prepareLS(LevelSetType passedlsDomain) {
134 // Expansion of sparse field must depend on spatial derivative order
135 // AND slf stencil order! --> currently assume scheme = 3rd order always
136 viennals::Expand<T, D>(passedlsDomain, 2 * (order + 1) + 4).apply();
137 }
138
140 LevelSetType passedlsDomain, SmartPointer<viennals::VelocityField<T>> vel,
141 double a = 1.0,
143 : levelSet(passedlsDomain), velocities(vel),
144 finiteDifferenceScheme(scheme),
145 neighborIterator(hrleSparseBoxIterator<hrleDomain<T, D>>(
146 levelSet->getDomain(), static_cast<unsigned>(scheme) + 1 + order)),
147 alphaFactor(a), numStencilPoints(std::pow(2 * order + 1, D)) {
148
149 for (int i = 0; i < 3; ++i) {
150 finalAlphas[i] = 0;
151 }
152 }
153
154 T operator()(const hrleVectorType<hrleIndexType, D> &indices, int material) {
155 auto &grid = levelSet->getGrid();
156 double gridDelta = grid.getGridDelta();
157
158 hrleVectorType<T, 3> coordinate(0., 0., 0.);
159 for (unsigned i = 0; i < D; ++i) {
160 coordinate[i] = indices[i] * gridDelta;
161 }
162
163 // move neighborIterator to current position
164 neighborIterator.goToIndicesSequential(indices);
165
166 // convert coordinate to std array for interface
167 std::array<T, 3> coordArray = {coordinate[0], coordinate[1], coordinate[2]};
168
169 // if there is a vector velocity, we need to project it onto a scalar
170 // velocity first using its normal vector
171 // /*if (vectorVelocity != std::array<T, 3>({}))*/ {
172 std::array<T, 3> normalVector = {};
173 T denominator = 0; // normal modulus
174 for (unsigned i = 0; i < D; i++) {
175 hrleVectorType<T, 3> neighborIndex(T(0));
176 neighborIndex[i] = 1;
177 // normal vector calculation
178 T pos = neighborIterator.getNeighbor(neighborIndex).getValue() -
179 neighborIterator.getCenter().getValue();
180 T neg = neighborIterator.getCenter().getValue() -
181 neighborIterator.getNeighbor(-neighborIndex).getValue();
182 normalVector[i] = (pos + neg) * 0.5;
183 // normalise normal vector
184 denominator += normalVector[i] * normalVector[i];
185 }
186 denominator = std::sqrt(denominator);
187
188 for (unsigned i = 0; i < D; ++i) {
189 normalVector[i] /= denominator;
190 }
191
192 double scalarVelocity = velocities->getScalarVelocity(
193 coordArray, material, normalVector,
194 neighborIterator.getCenter().getPointId());
195 std::array<T, 3> vectorVelocity = velocities->getVectorVelocity(
196 coordArray, material, normalVector,
197 neighborIterator.getCenter().getPointId());
198
199 // now calculate scalar product of normal vector with velocity
200 for (unsigned i = 0; i < D; ++i) {
201 scalarVelocity += vectorVelocity[i] * normalVector[i];
202 }
203
204 if (scalarVelocity == T(0)) {
205 return 0;
206 }
207
208 T hamiltonian =
209 NormL2(calculateGradient(hrleVectorType<hrleIndexType, D>(0))) *
210 scalarVelocity;
211 T dissipation = 0.; // dissipation
212
213 // dissipation block
214 {
215 // reserve alphas for all points in local stencil
216 std::vector<hrleVectorType<T, D>> alphas;
217 alphas.reserve(numStencilPoints);
218
219 hrleVectorType<hrleIndexType, D> currentIndex(-order);
220 for (size_t i = 0; i < numStencilPoints; ++i) {
221 hrleVectorType<T, D> alpha;
222 hrleVectorType<T, 3> normal(calculateNormal(currentIndex));
223 if (D == 2)
224 normal[2] = 0;
225
226 // Check for corrupted normal
227 if ((std::abs(normal[0]) < 1e-6) && (std::abs(normal[1]) < 1e-6) &&
228 (std::abs(normal[2]) < 1e-6)) {
229 alphas.push_back(hrleVectorType<T, D>(T(0)));
230 continue;
231 }
232
233 std::array<T, 3> normal_p = {normal[0], normal[1], normal[2]};
234 std::array<T, 3> normal_n = {normal[0], normal[1], normal[2]};
235
236 hrleVectorType<T, D> velocityDelta(T(0));
237
238 // get local velocity
239 std::array<T, 3> localCoordArray = coordArray;
240 for (unsigned dir = 0; dir < D; ++dir)
241 localCoordArray[dir] += currentIndex[dir];
242
243 T localScalarVelocity = velocities->getScalarVelocity(
244 localCoordArray, material, normal_p,
245 neighborIterator.getCenter().getPointId());
246 std::array<T, 3> localVectorVelocity = velocities->getVectorVelocity(
247 localCoordArray, material, normal_p,
248 neighborIterator.getCenter().getPointId());
249 // now calculate scalar product of normal vector with velocity
250 for (unsigned i = 0; i < D; ++i) {
251 localScalarVelocity += localVectorVelocity[i] * normal[i];
252 }
253
254 const T DN = std::abs(normalEpsilon * scalarVelocity);
255
256 for (int k = 0; k < D; ++k) {
257
258 normal_p[k] -= DN; // p=previous
259 normal_n[k] += DN; // n==next
260
261 T vp = velocities->getScalarVelocity(
262 localCoordArray, material, normal_p,
263 neighborIterator.getCenter().getPointId());
264 T vn = velocities->getScalarVelocity(
265 localCoordArray, material, normal_n,
266 neighborIterator.getCenter().getPointId());
267 // central difference
268 velocityDelta[k] = (vn - vp) / (2.0 * DN);
269
270 normal_p[k] += DN;
271 normal_n[k] -= DN;
272 }
273
274 // determine \partial H / \partial phi_l
275 for (int k = 0; k < D; ++k) { // iterate over dimensions
276
277 // Monti term
278 T monti = 0;
279 // Toifl Quell term
280 T toifl = 0;
281
282 hrleVectorType<T, D> gradient = calculateGradient(currentIndex);
283
284 for (int j = 0; j < D - 1; ++j) { // phi_p**2 + phi_q**2
285 int idx = (k + 1 + j) % D;
286 monti += gradient[idx] * gradient[idx];
287 toifl += gradient[idx] * velocityDelta[idx];
288 }
289 // denominator: |grad(phi)|^2
290 T denominator = Norm2(gradient);
291 monti *= velocityDelta[k] / denominator;
292 toifl *= -gradient[k] / denominator;
293
294 // Osher (constant V) term
295 T osher = localScalarVelocity * normal[k];
296 // Total derivative is sum of terms given above
297 alpha[k] = std::fabs(monti + toifl + osher);
298 }
299
300 alphas.push_back(alpha);
301
302 // increment current index
303 {
304 int dim = 0;
305 for (; dim < D - 1; ++dim) {
306 if (currentIndex[dim] < order)
307 break;
308 currentIndex[dim] = -order;
309 }
310 ++currentIndex[dim];
311 }
312 }
313
314 // determine max alphas for every axis
315 hrleVectorType<T, D> gradientDiff = calculateGradientDiff();
316 for (int d = 0; d < D; ++d) {
317 T maxAlpha = 0;
318
319 for (size_t i = 0; i < numStencilPoints; ++i) {
320 maxAlpha = std::max(maxAlpha, alphas[i][d]);
321 }
322
323 finalAlphas[d] = maxAlpha;
324 dissipation += maxAlpha * gradientDiff[d];
325 }
326
327 return hamiltonian - dissipation;
328 }
329 }
330};
331
332namespace advect {
333template <
334 class IntegrationSchemeType, class T, int D,
335 lsConcepts::IsSame<IntegrationSchemeType,
338void reduceTimeStepHamiltonJacobi(IntegrationSchemeType &scheme,
339 double &MaxTimeStep,
340 hrleCoordType gridDelta) {
341 const double alpha_maxCFL = 1.0;
342 // second time step test, based on alphas
343 hrleVectorType<T, 3> alphas = scheme.getFinalAlphas();
344
345 double timeStep = 0;
346 for (int i = 0; i < D; ++i) {
347 timeStep += alphas[i] / gridDelta;
348 }
349
350 timeStep = alpha_maxCFL / timeStep;
351 MaxTimeStep = std::min(timeStep, MaxTimeStep);
352}
353} // namespace advect
354} // namespace lsInternal
355
356namespace viennals {
357
358using namespace viennacore;
359
371template <class T, int D>
373 std::vector<SmartPointer<Domain<T, D>>> &levelSets,
374 std::vector<bool> isDepo) {
375 if (isDepo.size() < levelSets.size()) {
376 Logger::getInstance()
377 .addWarning(
378 "PrepareStencilLocalLaxFriedrichs: isDepo does not have enough "
379 "elements. Assuming all higher layers are not depo layers.")
380 .print();
381 }
382 // always resize, so it has the correct number of elements
383 isDepo.resize(levelSets.size(), false);
384
385 // Begin with biggest level set (top LS wrapped around all others)
386 auto layerIt = levelSets.rbegin();
387
388 // make empty LS which will contain the final top layer
389 auto finalTop = SmartPointer<Domain<T, D>>::New(levelSets[0]->getGrid());
390
391 bool layerAboveIsDepo = false;
392 auto depoIt = isDepo.rbegin();
393
394 // subtract each first non-depo layer below a depo layer from the latter
395 // then union these results to the final layer
396 for (auto maskIt = levelSets.rbegin(); maskIt != levelSets.rend(); ++maskIt) {
397 if (isDepo[*depoIt]) {
398 // this layer will be deposited on
399 if (!layerAboveIsDepo) {
400 layerIt = maskIt;
401 layerAboveIsDepo = true;
402 }
403 } else {
404 // no depo on this layer
405 if (layerAboveIsDepo) {
406 auto layerAbove = SmartPointer<Domain<T, D>>::New(*layerIt);
407 BooleanOperation<T, D>(layerAbove, *maskIt,
409 .apply();
410
411 BooleanOperation<T, D>(finalTop, layerAbove,
413 .apply();
414 Prune<T, D>(finalTop).apply();
415 }
416 layerAboveIsDepo = false;
417 }
418 ++depoIt;
419 }
420
421 // If the lowest layer is a depo substrate, add it to the final top layer
422 if (layerAboveIsDepo) {
424 .apply();
425 }
426
428 levelSets.back()->deepCopy(finalTop);
429}
430
433template <class T, int D>
435 std::vector<SmartPointer<Domain<T, D>>> &levelSets) {
436 auto layerIt = levelSets.rbegin();
437 auto lastIt = ++levelSets.rbegin();
438
441 .apply();
442}
443
444} // 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
Stencil Local Lax Friedrichs Integration Scheme. It uses a stencil of order around active points,...
Definition lsStencilLocalLaxFriedrichsScalar.hpp:21
const hrleVectorType< T, 3 > & getFinalAlphas() const
Definition lsStencilLocalLaxFriedrichsScalar.hpp:131
static void prepareLS(LevelSetType passedlsDomain)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:133
T operator()(const hrleVectorType< hrleIndexType, D > &indices, int material)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:154
StencilLocalLaxFriedrichsScalar(LevelSetType passedlsDomain, SmartPointer< viennals::VelocityField< T > > vel, double a=1.0, DifferentiationSchemeEnum scheme=DifferentiationSchemeEnum::FIRST_ORDER)
Definition lsStencilLocalLaxFriedrichsScalar.hpp:139
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:28
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
constexpr AssignType assignable
Definition lsConcepts.hpp:10
std::enable_if_t< std::is_same< A, B >::value, AssignType > IsSame
Definition lsConcepts.hpp:17
void reduceTimeStepHamiltonJacobi(IntegrationSchemeType &, double &, hrleCoordType)
Definition lsAdvect.hpp:42
Definition lsAdvect.hpp:37
DifferentiationSchemeEnum
Definition lsFiniteDifferences.hpp:12
Definition lsAdvect.hpp:46
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:372
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:434
constexpr int D
Definition pyWrap.cpp:65
double T
Definition pyWrap.cpp:63