74template <
class T,
int D>
class Advect {
75 std::vector<SmartPointer<Domain<T, D>>> levelSets;
76 SmartPointer<VelocityField<T>> velocities =
nullptr;
79 double timeStepRatio = 0.4999;
80 double dissipationAlpha = 1.0;
81 bool calculateNormalVectors =
true;
82 bool ignoreVoids =
false;
83 double advectionTime = 0.;
84 bool performOnlySingleStep =
false;
85 double advectedTime = 0.;
86 unsigned numberOfTimeSteps = 0;
87 bool saveAdvectionVelocities =
false;
88 bool updatePointData =
true;
89 static constexpr double wrappingLayerEpsilon = 1e-4;
96 auto &grid = levelSets.back()->getGrid();
97 auto newlsDomain = SmartPointer<Domain<T, D>>::New(grid);
101 newDomain.initialize(domain.getNewSegmentation(),
102 domain.getAllocation() *
103 (2.0 / levelSets.back()->getLevelSetWidth()));
105 const bool updateData = updatePointData;
108 std::vector<std::vector<unsigned>> newDataSourceIds;
112#ifdef DEBUG_LS_ADVECT_HPP
114 auto mesh = SmartPointer<Mesh<T>>::New();
120#pragma omp parallel num_threads(newDomain.getNumberOfSegments())
124 p = omp_get_thread_num();
127 auto &domainSegment = newDomain.getDomainSegment(p);
129 hrleVectorType<hrleIndexType, D> startVector =
130 (p == 0) ? grid.getMinGridPoint()
131 : newDomain.getSegmentation()[p - 1];
133 hrleVectorType<hrleIndexType, D> endVector =
135 ? newDomain.getSegmentation()[p]
136 : grid.incrementIndices(grid.getMaxGridPoint());
141 newDataSourceIds[p].reserve(2.5 * domainSegment.getNumberOfPoints());
144 domain, startVector);
145 it.getIndices() < endVector; ++it) {
149 if (std::abs(it.getCenter().getValue()) <= 1.0) {
152 for (; k < 2 *
D; k++)
153 if (std::signbit(it.getNeighbor(k).getValue() - 1e-7) !=
154 std::signbit(it.getCenter().getValue() + 1e-7))
159 if (it.getCenter().getDefinedValue() > 0.5) {
161 for (; j < 2 *
D; j++) {
162 if (std::abs(it.getNeighbor(j).getValue()) <= 1.0)
163 if (it.getNeighbor(j).getDefinedValue() < -0.5)
167 domainSegment.insertNextDefinedPoint(
168 it.getIndices(), it.getCenter().getDefinedValue());
170 newDataSourceIds[p].push_back(it.getCenter().getPointId());
173 domainSegment.insertNextDefinedPoint(it.getIndices(), 0.5);
175 newDataSourceIds[p].push_back(it.getNeighbor(j).getPointId());
177 }
else if (it.getCenter().getDefinedValue() < -0.5) {
179 for (; j < 2 *
D; j++) {
180 if (std::abs(it.getNeighbor(j).getValue()) <= 1.0)
181 if (it.getNeighbor(j).getDefinedValue() > 0.5)
186 domainSegment.insertNextDefinedPoint(
187 it.getIndices(), it.getCenter().getDefinedValue());
189 newDataSourceIds[p].push_back(it.getCenter().getPointId());
192 domainSegment.insertNextDefinedPoint(it.getIndices(), -0.5);
194 newDataSourceIds[p].push_back(it.getNeighbor(j).getPointId());
197 domainSegment.insertNextDefinedPoint(
198 it.getIndices(), it.getCenter().getDefinedValue());
200 newDataSourceIds[p].push_back(it.getCenter().getPointId());
203 domainSegment.insertNextUndefinedPoint(
204 it.getIndices(), (it.getCenter().getDefinedValue() < 0)
210 if (it.getCenter().getValue() >= 0) {
211 int usedNeighbor = -1;
213 for (
int i = 0; i < 2 *
D; i++) {
214 T value = it.getNeighbor(i).getValue();
215 if (std::abs(value) <= 1.0 && (value < 0.)) {
216 if (distance > value + 1.0) {
217 distance = value + 1.0;
223 if (distance <= 1.) {
224 domainSegment.insertNextDefinedPoint(it.getIndices(), distance);
226 newDataSourceIds[p].push_back(
227 it.getNeighbor(usedNeighbor).getPointId());
229 domainSegment.insertNextUndefinedPoint(it.getIndices(),
234 int usedNeighbor = -1;
236 for (
int i = 0; i < 2 *
D; i++) {
237 T value = it.getNeighbor(i).getValue();
238 if (std::abs(value) <= 1.0 && (value > 0)) {
239 if (distance < value - 1.0) {
241 distance = value - 1.0;
247 if (distance >= -1.) {
248 domainSegment.insertNextDefinedPoint(it.getIndices(), distance);
250 newDataSourceIds[p].push_back(
251 it.getNeighbor(usedNeighbor).getPointId());
253 domainSegment.insertNextUndefinedPoint(it.getIndices(),
263 auto &pointData = levelSets.back()->getPointData();
264 newlsDomain->getPointData().translateFromMultiData(pointData,
270 levelSets.back()->
deepCopy(newlsDomain);
271 levelSets.back()->finalize(2);
276 double advect(
double maxTimeStep = std::numeric_limits<double>::max()) {
278 if (levelSets.size() < 1) {
279 Logger::getInstance()
280 .addWarning(
"No level sets passed to Advect. Not advecting.")
282 return std::numeric_limits<double>::max();
284 if (velocities ==
nullptr) {
285 Logger::getInstance()
286 .addWarning(
"No velocity field passed to Advect. Not advecting.")
288 return std::numeric_limits<double>::max();
293 double currentTime = 0.;
296 calculateNormalVectors);
297 currentTime = integrateTime(is, maxTimeStep);
298 }
else if (integrationScheme ==
301 calculateNormalVectors);
302 currentTime = integrateTime(is, maxTimeStep);
303 }
else if (integrationScheme ==
307 calculateNormalVectors);
308 currentTime = integrateTime(is, maxTimeStep);
309 }
else if (integrationScheme ==
313 calculateNormalVectors);
314 currentTime = integrateTime(is, maxTimeStep);
315 }
else if (integrationScheme ==
319 levelSets.back(), velocities);
320 currentTime = integrateTime(is, maxTimeStep);
321 }
else if (integrationScheme ==
324 levelSets.back(), velocities, dissipationAlpha);
325 currentTime = integrateTime(is, maxTimeStep);
326 }
else if (integrationScheme ==
329 levelSets.back(), velocities, dissipationAlpha);
330 currentTime = integrateTime(is, maxTimeStep);
331 }
else if (integrationScheme ==
334 levelSets.back(), velocities, dissipationAlpha);
335 currentTime = integrateTime(is, maxTimeStep);
336 }
else if (integrationScheme ==
339 levelSets.back(), velocities, dissipationAlpha);
340 currentTime = integrateTime(is, maxTimeStep);
341 }
else if (integrationScheme ==
344 levelSets.back(), velocities, dissipationAlpha);
345 currentTime = integrateTime(is, maxTimeStep);
347 Logger::getInstance()
348 .addWarning(
"Advect: Integration scheme not found. Not advecting.")
353 return std::numeric_limits<double>::max();
363 if (integrationScheme !=
365 for (
unsigned i = 0; i < levelSets.size() - 1; ++i) {
379 template <
class IntegrationSchemeType>
381 integrateTime(IntegrationSchemeType IntegrationScheme,
382 double maxTimeStep = std::numeric_limits<double>::max()) {
383 if (timeStepRatio >= 0.5) {
384 Logger::getInstance()
385 .addWarning(
"Integration time step ratio should be smaller than 0.5. "
386 "Advection might fail!")
390 auto &topDomain = levelSets.back()->getDomain();
391 auto &grid = levelSets.back()->getGrid();
393 std::vector<std::vector<std::pair<T, T>>> totalTempRates;
394 totalTempRates.resize((levelSets.back())->getNumberOfSegments());
399 auto &pointData = levelSets.back()->getPointData();
402 if (voidMarkerPointer ==
nullptr) {
403 Logger::getInstance()
404 .addWarning(
"Advect: Cannot find void point markers. Not "
405 "ignoring void points.")
411 const bool ignoreVoidPoints = ignoreVoids;
413#pragma omp parallel num_threads((levelSets.back())->getNumberOfSegments())
417 p = omp_get_thread_num();
420 hrleVectorType<hrleIndexType, D> startVector =
421 (p == 0) ? grid.getMinGridPoint()
422 : topDomain.getSegmentation()[p - 1];
424 hrleVectorType<hrleIndexType, D> endVector =
425 (p !=
static_cast<int>(topDomain.getNumberOfSegments() - 1))
426 ? topDomain.getSegmentation()[p]
427 : grid.incrementIndices(grid.getMaxGridPoint());
429 double tempMaxTimeStep = maxTimeStep;
430 auto &tempRates = totalTempRates[p];
431 tempRates.reserve(topDomain.getNumberOfPoints() /
432 double((levelSets.back())->getNumberOfSegments()) +
436 std::vector<hrleSparseIterator<typename Domain<T, D>::DomainType>>
438 for (
auto it = levelSets.begin(); it != levelSets.end(); ++it) {
441 (*it)->getDomain()));
444 IntegrationSchemeType scheme(IntegrationScheme);
447 topDomain, startVector);
448 it.getStartIndices() < endVector; ++it) {
450 if (!it.isDefined() || std::abs(it.getValue()) > 0.5)
453 T value = it.getValue();
454 double maxStepTime = 0;
455 double cfl = timeStepRatio;
457 for (
int currentLevelSetId = levelSets.size() - 1;
458 currentLevelSetId >= 0; --currentLevelSetId) {
462 if (!(ignoreVoidPoints && (*voidMarkerPointer)[it.getPointId()])) {
465 for (
unsigned lowerLevelSetId = 0;
466 lowerLevelSetId < levelSets.size(); ++lowerLevelSetId) {
468 iterators[lowerLevelSetId].goToIndicesSequential(
469 it.getStartIndices());
473 if (iterators[lowerLevelSetId].getValue() <=
474 value + wrappingLayerEpsilon) {
475 velocity = scheme(it.getStartIndices(), lowerLevelSetId);
483 if (currentLevelSetId > 0) {
484 iterators[currentLevelSetId - 1].goToIndicesSequential(
485 it.getStartIndices());
486 valueBelow = iterators[currentLevelSetId - 1].getValue();
488 valueBelow = std::numeric_limits<T>::max();
494 maxStepTime += cfl / velocity;
496 std::make_pair(velocity, -std::numeric_limits<T>::max()));
499 }
else if (velocity == 0.) {
500 maxStepTime = std::numeric_limits<T>::max();
502 std::make_pair(velocity, std::numeric_limits<T>::max()));
507 T difference = std::abs(valueBelow - value);
509 if (difference >= cfl) {
510 maxStepTime -= cfl / velocity;
512 std::make_pair(velocity, std::numeric_limits<T>::max()));
515 maxStepTime -= difference / velocity;
518 tempRates.push_back(std::make_pair(velocity, valueBelow));
526 if (maxStepTime < tempMaxTimeStep)
527 tempMaxTimeStep = maxStepTime;
537 scheme, tempMaxTimeStep,
538 levelSets.back()->getGrid().getGridDelta());
541 if (tempMaxTimeStep < maxTimeStep)
542 maxTimeStep = tempMaxTimeStep;
550 const bool saveVelocities = saveAdvectionVelocities;
551 std::vector<std::vector<double>> velocityVectors(
552 levelSets.back()->getNumberOfSegments());
554#pragma omp parallel num_threads((levelSets.back())->getNumberOfSegments())
558 p = omp_get_thread_num();
561 typename std::vector<std::pair<T, T>>::const_iterator itRS =
562 totalTempRates[p].begin();
563 auto &segment = topDomain.getDomainSegment(p);
564 unsigned maxId = segment.getNumberOfPoints();
566 if (saveVelocities) {
567 velocityVectors[p].resize(maxId);
570 for (
unsigned localId = 0; localId < maxId; ++localId) {
571 T &value = segment.definedValues[localId];
572 double time = maxTimeStep;
577 while (std::abs(itRS->second - value) < std::abs(time * itRS->first)) {
578 time -= std::abs((itRS->second - value) / itRS->first);
579 value = itRS->second;
584 value -= time * itRS->first;
586 if (saveVelocities) {
587 velocityVectors[p][localId] = time * itRS->first;
594 while (std::abs(itRS->second) != std::numeric_limits<T>::max())
602 if (saveVelocities) {
603 auto &pointData = levelSets.back()->getPointData();
605 if (
int i = pointData.getScalarDataIndex(
velocityLabel); i != -1) {
606 pointData.eraseScalarData(i);
611 for (
unsigned i = 0; i < velocityVectors.size(); ++i) {
612 vels.insert(vels.end(),
613 std::make_move_iterator(velocityVectors[i].begin()),
614 std::make_move_iterator(velocityVectors[i].end()));
616 pointData.insertNextScalarData(std::move(vels),
velocityLabel);
628 levelSets.push_back(passedlsDomain);
633 levelSets.push_back(passedlsDomain);
634 velocities = passedVelocities;
639 : levelSets(passedlsDomains) {
640 velocities = passedVelocities;
646 levelSets.push_back(passedlsDomain);
652 velocities = passedVelocities;
708 integrationScheme = scheme;
725 if (levelSets.size() < 1) {
726 Logger::getInstance()
727 .addWarning(
"No level sets passed to Advect.")
734 }
else if (integrationScheme ==
737 }
else if (integrationScheme ==
740 }
else if (integrationScheme ==
743 }
else if (integrationScheme ==
748 }
else if (integrationScheme ==
751 }
else if (integrationScheme ==
754 }
else if (integrationScheme ==
757 }
else if (integrationScheme ==
760 }
else if (integrationScheme ==
765 Logger::getInstance()
766 .addWarning(
"Advect: Integration scheme not found. Not advecting.")
773 if (advectionTime == 0.) {
774 advectedTime = advect();
775 numberOfTimeSteps = 1;
777 double currentTime = 0.0;
778 numberOfTimeSteps = 0;
779 while (currentTime < advectionTime) {
780 currentTime += advect(advectionTime - currentTime);
782 if (performOnlySingleStep)
785 advectedTime = currentTime;