ViennaLS
Loading...
Searching...
No Matches
lsLocalLaxFriedrichsAnalytical.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 LocalLaxFriedrichsAnalytical {
22 SmartPointer<viennals::Domain<T, D>> levelSet;
23 SmartPointer<viennals::VelocityField<T>> velocities;
24 hrleSparseBoxIterator<hrleDomain<T, D>> neighborIterator;
25
26 static T pow2(const T &value) { return value * value; }
27
28 T calculateNormalComponent(T neg, T center, T pos, T delta) {
29 auto diffPos = (pos - center) / delta;
30 auto diffNeg = (center - neg) / delta;
31 return (diffPos + diffNeg) * 0.5;
32 }
33
34 void incrementIndices(hrleVectorType<hrleIndexType, D> &index,
35 hrleIndexType minIndex, hrleIndexType maxIndex) {
36 unsigned dir = 0;
37 for (; dir < D - 1; ++dir) {
38 if (index[dir] < maxIndex)
39 break;
40 index[dir] = minIndex;
41 }
42 ++index[dir];
43 }
44
45public:
46 static void prepareLS(SmartPointer<viennals::Domain<T, D>> passedlsDomain) {
47 assert(order == 1 || order == 2);
48 // at least order+1 layers since we need neighbor neighbors for
49 // dissipation alpha calculation
50 viennals::Expand<T, D>(passedlsDomain, 2 * (order + 2) + 1).apply();
51 }
52
53 // neighboriterator always needs order 2 for alpha calculation
55 SmartPointer<viennals::Domain<T, D>> passedlsDomain,
56 SmartPointer<viennals::VelocityField<T>> vel)
57 : levelSet(passedlsDomain), velocities(vel),
58 neighborIterator(levelSet->getDomain(), 2) {}
59
60 T operator()(const hrleVectorType<hrleIndexType, D> &indices, int material) {
61
62 auto &grid = levelSet->getGrid();
63 double gridDelta = grid.getGridDelta();
64
65 hrleVectorType<T, 3> coordinate(0., 0., 0.);
66 for (unsigned i = 0; i < D; ++i) {
67 coordinate[i] = indices[i] * gridDelta;
68 }
69
70 // move neighborIterator to current position
71 neighborIterator.goToIndicesSequential(indices);
72
73 // convert coordinate to std array for interface
74 Vec3D<T> coordArray = {coordinate[0], coordinate[1], coordinate[2]};
75
76 T gradPos[D];
77 T gradNeg[D];
78
79 T grad = 0.;
80 T dissipation = 0.;
81
82 Vec3D<T> normalVector = {};
83 T normalModulus = 0;
84
85 for (int i = 0; i < D; i++) { // iterate over dimensions
86 hrleVectorType<hrleIndexType, D> posUnit(0);
87 hrleVectorType<hrleIndexType, D> negUnit(0);
88 posUnit[i] = 1;
89 negUnit[i] = -1;
90
91 const T deltaPos = gridDelta;
92 const T deltaNeg = -gridDelta;
93
94 const T phi0 = neighborIterator.getCenter().getValue();
95 const T phiPos = neighborIterator.getNeighbor(posUnit).getValue();
96 const T phiNeg = neighborIterator.getNeighbor(negUnit).getValue();
97
98 T diffPos = (phiPos - phi0) / deltaPos;
99 T diffNeg = (phiNeg - phi0) / deltaNeg;
100
101 if (order == 2) { // if second order time integration scheme is used
102 posUnit[i] = 2;
103 negUnit[i] = -2;
104
105 const T deltaPosPos = 2 * gridDelta;
106 const T deltaNegNeg = -2 * gridDelta;
107
108 const T diff00 =
109 (((deltaNeg * phiPos - deltaPos * phiNeg) / (deltaPos - deltaNeg) +
110 phi0)) /
111 (deltaPos * deltaNeg);
112 const T phiPosPos = neighborIterator.getNeighbor(posUnit).getValue();
113 const T phiNegNeg = neighborIterator.getNeighbor(negUnit).getValue();
114
115 const T diffNegNeg = (((deltaNeg * phiNegNeg - deltaNegNeg * phiNeg) /
116 (deltaNegNeg - deltaNeg) +
117 phi0)) /
118 (deltaNegNeg * deltaNeg);
119 const T diffPosPos = (((deltaPos * phiPosPos - deltaPosPos * phiPos) /
120 (deltaPosPos - deltaPos) +
121 phi0)) /
122 (deltaPosPos * deltaPos);
123
124 if (std::signbit(diff00) == std::signbit(diffPosPos)) {
125 if (std::abs(diffPosPos * deltaPos) < std::abs(diff00 * deltaNeg)) {
126 diffPos -= deltaPos * diffPosPos;
127 } else {
128 diffPos += deltaNeg * diff00;
129 }
130 }
131
132 if (std::signbit(diff00) == std::signbit(diffNegNeg)) {
133 if (std::abs(diffNegNeg * deltaNeg) < std::abs(diff00 * deltaPos)) {
134 diffNeg -= deltaNeg * diffNegNeg;
135 } else {
136 diffNeg += deltaPos * diff00;
137 }
138 }
139 }
140
141 gradPos[i] = diffNeg;
142 gradNeg[i] = diffPos;
143
144 normalVector[i] = (diffNeg + diffPos) * 0.5;
145 normalModulus += normalVector[i] * normalVector[i];
146
147 grad += pow2((diffNeg + diffPos) * 0.5);
148 }
149
150 // normalise normal vector
151 normalModulus = std::sqrt(normalModulus);
152 for (unsigned i = 0; i < D; ++i) {
153 normalVector[i] /= normalModulus;
154 }
155
156 // Get velocities
157 double scalarVelocity = velocities->getScalarVelocity(
158 coordArray, material, normalVector,
159 neighborIterator.getCenter().getPointId());
160 Vec3D<T> vectorVelocity = velocities->getVectorVelocity(
161 coordArray, material, normalVector,
162 neighborIterator.getCenter().getPointId());
163
164 // calculate hamiltonian
165 T totalGrad = 0.;
166 if (scalarVelocity != 0.) {
167 totalGrad = scalarVelocity * std::sqrt(grad);
168 }
169
170 for (int w = 0; w < D; w++) {
171 if (vectorVelocity[w] > 0.) {
172 totalGrad += vectorVelocity[w] * gradPos[w];
173 } else {
174 totalGrad += vectorVelocity[w] * gradNeg[w];
175 }
176 }
177
178 // calculate alphas
179 T alpha[D] = {};
180 {
181 // alpha calculation is always on order 1 stencil
182 const hrleIndexType minIndex = -1;
183 const hrleIndexType maxIndex = 1;
184 const unsigned numNeighbors = std::pow((maxIndex - minIndex), D);
185
186 hrleVectorType<hrleIndexType, D> neighborIndex(minIndex);
187 for (unsigned i = 0; i < numNeighbors; ++i) {
188
189 Vec3D<T> normal = {};
190 auto center = neighborIterator.getNeighbor(neighborIndex).getValue();
191 for (unsigned dir = 0; dir < D; ++dir) {
192 hrleVectorType<hrleIndexType, D> unity(0);
193 unity[dir] = 1;
194 auto neg =
195 neighborIterator.getNeighbor(neighborIndex - unity).getValue();
196 auto pos =
197 neighborIterator.getNeighbor(neighborIndex + unity).getValue();
198 normal[dir] = calculateNormalComponent(neg, center, pos, gridDelta);
199 }
200
201 for (unsigned dir = 0; dir < D; ++dir) {
202 T tempAlpha = velocities->getDissipationAlpha(dir, material, normal);
203 alpha[dir] = std::max(alpha[dir], tempAlpha);
204 }
205
206 // advance to next index
207 incrementIndices(neighborIndex, minIndex, maxIndex);
208 }
209 }
210
211 // calculate local dissipation alphas for each direction
212 // and add to dissipation term
213 for (unsigned i = 0; i < D; ++i) {
214 dissipation += alpha[i] * (gradNeg[i] - gradPos[i]) * 0.5;
215 }
216
217 // std::cout << neighborIterator.getCenter().getPointId() << " dissipation:
218 // " << dissipation << std::endl;
219 return totalGrad - ((totalGrad != 0.) ? dissipation : 0);
220 }
221};
222} // namespace lsInternal
Lax Friedrichs integration scheme, which uses alpha values provided by the user in getDissipationAlph...
Definition lsLocalLaxFriedrichsAnalytical.hpp:21
T operator()(const hrleVectorType< hrleIndexType, D > &indices, int material)
Definition lsLocalLaxFriedrichsAnalytical.hpp:60
LocalLaxFriedrichsAnalytical(SmartPointer< viennals::Domain< T, D > > passedlsDomain, SmartPointer< viennals::VelocityField< T > > vel)
Definition lsLocalLaxFriedrichsAnalytical.hpp:54
static void prepareLS(SmartPointer< viennals::Domain< T, D > > passedlsDomain)
Definition lsLocalLaxFriedrichsAnalytical.hpp:46
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
Abstract class defining the interface for the velocity field used during advection using lsAdvect.
Definition lsVelocityField.hpp:13
Definition lsAdvect.hpp:37
constexpr int D
Definition pyWrap.cpp:65
double T
Definition pyWrap.cpp:63