54template <
class T,
int D>
class Advect {
55 using ConstSparseIterator =
56 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>;
57 using hrleIndexType = viennahrle::IndexType;
62 std::vector<SmartPointer<Domain<T, D>>> levelSets;
63 SmartPointer<VelocityField<T>> velocities =
nullptr;
66 double timeStepRatio = 0.4999;
67 double dissipationAlpha = 1.0;
68 bool calculateNormalVectors =
true;
69 bool ignoreVoids =
false;
70 double advectionTime = 0.;
71 bool performOnlySingleStep =
false;
72 double advectedTime = 0.;
73 unsigned numberOfTimeSteps = 0;
74 bool saveAdvectionVelocities =
false;
75 bool updatePointData =
true;
76 bool checkDissipation =
true;
77 double integrationCutoff = 0.5;
78 bool adaptiveTimeStepping =
false;
79 unsigned adaptiveTimeStepSubdivisions = 20;
80 static constexpr double wrappingLayerEpsilon = 1e-4;
81 std::vector<SmartPointer<Domain<T, D>>> initialLevelSets;
82 std::function<bool(SmartPointer<
Domain<T, D>>)> velocityUpdateCallback =
87 std::vector<std::vector<std::pair<std::pair<T, T>,
T>>> storedRates;
88 double currentTimeStep = -1.;
90 VectorType<T, D> findGlobalAlphas()
const {
92 auto &topDomain = levelSets.back()->getDomain();
93 auto &grid = levelSets.back()->getGrid();
95 const T gridDelta = grid.getGridDelta();
96 const T deltaPos = gridDelta;
97 const T deltaNeg = -gridDelta;
99 VectorType<T, D> finalAlphas{};
101#pragma omp parallel for
102 for (
unsigned p = 0; p < levelSets.back()->getNumberOfSegments(); ++p) {
103 VectorType<T, D> localAlphas{};
105 viennahrle::Index<D> startVector =
106 (p == 0) ? grid.getMinGridPoint()
107 : topDomain.getSegmentation()[p - 1];
108 viennahrle::Index<D> endVector =
109 (p !=
static_cast<int>(topDomain.getNumberOfSegments() - 1))
110 ? topDomain.getSegmentation()[p]
111 : grid.incrementIndices(grid.getMaxGridPoint());
114 std::vector<ConstSparseIterator> iterators;
115 for (
auto const &
ls : levelSets) {
116 iterators.emplace_back(
ls->getDomain());
120 viennahrle::ConstSparseStarIterator<typename Domain<T, D>::DomainType, 1>
121 neighborIterator(topDomain);
123 for (ConstSparseIterator it(topDomain, startVector);
124 it.getStartIndices() < endVector; ++it) {
126 if (!it.isDefined() || std::abs(it.getValue()) > integrationCutoff)
129 const T value = it.getValue();
130 const auto indices = it.getStartIndices();
134 for (
unsigned lowerLevelSetId = 0; lowerLevelSetId < levelSets.size();
137 iterators[lowerLevelSetId].goToIndicesSequential(indices);
141 if (iterators[lowerLevelSetId].getValue() <=
142 value + wrappingLayerEpsilon) {
145 neighborIterator.goToIndicesSequential(indices);
148 for (
unsigned i = 0; i <
D; ++i) {
149 coords[i] = indices[i] * gridDelta;
153 T normalModulus = 0.;
154 for (
unsigned i = 0; i <
D; ++i) {
155 const T phiPos = neighborIterator.getNeighbor(i).getValue();
156 const T phiNeg = neighborIterator.getNeighbor(i +
D).getValue();
158 normal[i] = phiPos - phiNeg;
159 normalModulus += normal[i] * normal[i];
161 normalModulus = 1. / std::sqrt(normalModulus);
162 for (
unsigned i = 0; i <
D; ++i)
163 normal[i] *= normalModulus;
165 T scaVel = velocities->getScalarVelocity(
166 coords, lowerLevelSetId, normal,
167 neighborIterator.getCenter().getPointId());
168 auto vecVel = velocities->getVectorVelocity(
169 coords, lowerLevelSetId, normal,
170 neighborIterator.getCenter().getPointId());
172 for (
unsigned i = 0; i <
D; ++i) {
173 T tempAlpha = std::abs((scaVel + vecVel[i]) * normal[i]);
174 localAlphas[i] = std::max(localAlphas[i], tempAlpha);
185 for (
unsigned i = 0; i <
D; ++i) {
186 finalAlphas[i] = std::max(finalAlphas[i], localAlphas[i]);
196 bool combineLevelSets(
T wTarget,
T wSource) {
206 int expansionWidth = std::ceil(2.0 * steps * timeStepRatio + 1);
210 bool movedDown =
false;
213 initialLevelSets.back(),
216 [wTarget, wSource, &movedDown](
const T &a,
const T &b) {
219 T res = wSource * a + wTarget * b;
222 return std::make_pair(res,
true);
225 return std::make_pair(a,
false);
226 return std::make_pair(b,
false);
240 auto &grid = levelSets.back()->getGrid();
241 auto newlsDomain = SmartPointer<Domain<T, D>>::New(grid);
242 auto &newDomain = newlsDomain->getDomain();
243 auto &domain = levelSets.back()->getDomain();
255 newDomain.initialize(domain.getNewSegmentation(),
256 domain.getAllocation() *
257 (2.0 / levelSets.back()->getLevelSetWidth()));
259 const bool updateData = updatePointData;
262 std::vector<std::vector<unsigned>> newDataSourceIds;
264 newDataSourceIds.resize(newDomain.getNumberOfSegments());
266#ifdef DEBUG_LS_ADVECT_HPP
268 auto mesh = SmartPointer<Mesh<T>>::New();
274#pragma omp parallel for
275 for (
unsigned p = 0; p < newDomain.getNumberOfSegments(); ++p) {
276 auto &domainSegment = newDomain.getDomainSegment(p);
278 viennahrle::Index<D> startVector =
279 (p == 0) ? grid.getMinGridPoint()
280 : newDomain.getSegmentation()[p - 1];
282 viennahrle::Index<D> endVector =
283 (p != newDomain.getNumberOfSegments() - 1)
284 ? newDomain.getSegmentation()[p]
285 : grid.incrementIndices(grid.getMaxGridPoint());
290 newDataSourceIds[p].reserve(2.5 * domainSegment.getNumberOfPoints());
292 for (viennahrle::ConstSparseStarIterator<
294 it(domain, startVector);
295 it.getIndices() < endVector; ++it) {
299 if (std::abs(it.getCenter().getValue()) <= 1.0) {
302 for (; k < 2 *
D; k++)
303 if (std::signbit(it.getNeighbor(k).getValue() - 1e-7) !=
304 std::signbit(it.getCenter().getValue() + 1e-7))
309 if (it.getCenter().getDefinedValue() > 0.5) {
311 for (; j < 2 *
D; j++) {
312 if (std::abs(it.getNeighbor(j).getValue()) <= 1.0)
313 if (it.getNeighbor(j).getDefinedValue() < -0.5)
317 domainSegment.insertNextDefinedPoint(
318 it.getIndices(), it.getCenter().getDefinedValue());
320 newDataSourceIds[p].push_back(it.getCenter().getPointId());
323 domainSegment.insertNextDefinedPoint(it.getIndices(), 0.5);
325 newDataSourceIds[p].push_back(it.getNeighbor(j).getPointId());
327 }
else if (it.getCenter().getDefinedValue() < -0.5) {
329 for (; j < 2 *
D; j++) {
330 if (std::abs(it.getNeighbor(j).getValue()) <= 1.0)
331 if (it.getNeighbor(j).getDefinedValue() > 0.5)
336 domainSegment.insertNextDefinedPoint(
337 it.getIndices(), it.getCenter().getDefinedValue());
339 newDataSourceIds[p].push_back(it.getCenter().getPointId());
342 domainSegment.insertNextDefinedPoint(it.getIndices(), -0.5);
344 newDataSourceIds[p].push_back(it.getNeighbor(j).getPointId());
347 domainSegment.insertNextDefinedPoint(
348 it.getIndices(), it.getCenter().getDefinedValue());
350 newDataSourceIds[p].push_back(it.getCenter().getPointId());
353 domainSegment.insertNextUndefinedPoint(
354 it.getIndices(), (it.getCenter().getDefinedValue() < 0)
360 if (it.getCenter().getValue() >= 0) {
361 int usedNeighbor = -1;
363 for (
int i = 0; i < 2 *
D; i++) {
364 T value = it.getNeighbor(i).getValue();
365 if (std::abs(value) <= 1.0 && (value < 0.)) {
366 if (distance > value + 1.0) {
367 distance = value + 1.0;
373 if (distance <= cutoff) {
374 domainSegment.insertNextDefinedPoint(it.getIndices(), distance);
376 newDataSourceIds[p].push_back(
377 it.getNeighbor(usedNeighbor).getPointId());
379 domainSegment.insertNextUndefinedPoint(it.getIndices(),
384 int usedNeighbor = -1;
386 for (
int i = 0; i < 2 *
D; i++) {
387 T value = it.getNeighbor(i).getValue();
388 if (std::abs(value) <= 1.0 && (value > 0)) {
389 if (distance < value - 1.0) {
391 distance = value - 1.0;
397 if (distance >= -cutoff) {
398 domainSegment.insertNextDefinedPoint(it.getIndices(), distance);
400 newDataSourceIds[p].push_back(
401 it.getNeighbor(usedNeighbor).getPointId());
403 domainSegment.insertNextUndefinedPoint(it.getIndices(),
413 auto &pointData = levelSets.back()->getPointData();
414 newlsDomain->getPointData().translateFromMultiData(pointData,
418 newDomain.finalize();
420 levelSets.back()->deepCopy(newlsDomain);
421 levelSets.back()->finalize(finalWidth);
428 template <
class DiscretizationSchemeType>
429 double integrateTime(DiscretizationSchemeType spatialScheme,
430 double maxTimeStep) {
432 auto &topDomain = levelSets.back()->getDomain();
433 auto &grid = levelSets.back()->getGrid();
435 typename PointData<T>::ScalarDataType *voidMarkerPointer;
438 auto &pointData = levelSets.back()->getPointData();
441 if (voidMarkerPointer ==
nullptr) {
442 VIENNACORE_LOG_WARNING(
"Advect: Cannot find void point markers. Not "
443 "ignoring void points.");
447 const bool ignoreVoidPoints = ignoreVoids;
448 const bool useAdaptiveTimeStepping = adaptiveTimeStepping;
449 const auto adaptiveFactor = 1.0 / adaptiveTimeStepSubdivisions;
451 if (!storedRates.empty()) {
452 VIENNACORE_LOG_WARNING(
"Advect: Overwriting previously stored rates.");
455 storedRates.resize(topDomain.getNumberOfSegments());
457#pragma omp parallel for
458 for (
unsigned p = 0; p < topDomain.getNumberOfSegments(); ++p) {
460 viennahrle::Index<D> startVector =
461 (p == 0) ? grid.getMinGridPoint()
462 : topDomain.getSegmentation()[p - 1];
464 viennahrle::Index<D> endVector =
465 (p != topDomain.getNumberOfSegments() - 1)
466 ? topDomain.getSegmentation()[p]
467 : grid.incrementIndices(grid.getMaxGridPoint());
469 double tempMaxTimeStep = maxTimeStep;
471 auto &rates = storedRates[p];
473 topDomain.getNumberOfPoints() /
474 static_cast<double>((levelSets.back())->getNumberOfSegments()) +
478 std::vector<ConstSparseIterator> iterators;
479 for (
auto const &
ls : levelSets) {
480 iterators.emplace_back(
ls->getDomain());
483 DiscretizationSchemeType scheme(spatialScheme);
485 for (ConstSparseIterator it(topDomain, startVector);
486 it.getStartIndices() < endVector; it.next()) {
488 if (!it.isDefined() || std::abs(it.getValue()) > integrationCutoff)
491 T value = it.getValue();
492 double maxStepTime = 0;
493 double cfl = timeStepRatio;
495 for (
int currentLevelSetId = levelSets.size() - 1;
496 currentLevelSetId >= 0; --currentLevelSetId) {
498 std::pair<T, T> gradNDissipation;
500 if (!(ignoreVoidPoints && (*voidMarkerPointer)[it.getPointId()])) {
503 for (
unsigned lowerLevelSetId = 0;
504 lowerLevelSetId < levelSets.size(); ++lowerLevelSetId) {
506 iterators[lowerLevelSetId].goToIndicesSequential(
507 it.getStartIndices());
511 if (iterators[lowerLevelSetId].getValue() <=
512 value + wrappingLayerEpsilon) {
514 scheme(it.getStartIndices(), lowerLevelSetId);
520 T velocity = gradNDissipation.first - gradNDissipation.second;
524 maxStepTime += cfl / velocity;
525 rates.emplace_back(gradNDissipation,
526 -std::numeric_limits<T>::max());
528 }
else if (velocity == 0.) {
531 maxStepTime = std::numeric_limits<T>::max();
532 rates.emplace_back(gradNDissipation, std::numeric_limits<T>::max());
538 if (currentLevelSetId > 0) {
539 iterators[currentLevelSetId - 1].goToIndicesSequential(
540 it.getStartIndices());
541 valueBelow = iterators[currentLevelSetId - 1].getValue();
543 valueBelow = std::numeric_limits<T>::max();
546 T difference = std::abs(valueBelow - value);
548 if (difference >= cfl) {
551 maxStepTime -= cfl / velocity;
552 rates.emplace_back(gradNDissipation,
553 std::numeric_limits<T>::max());
558 if (useAdaptiveTimeStepping &&
559 difference > adaptiveFactor * cfl) {
564 maxStepTime -= adaptiveFactor * cfl / velocity;
565 rates.emplace_back(gradNDissipation,
566 std::numeric_limits<T>::max());
574 maxStepTime -= difference / velocity;
575 rates.emplace_back(gradNDissipation, valueBelow);
581 if (maxStepTime < tempMaxTimeStep)
582 tempMaxTimeStep = maxStepTime;
590 scheme.reduceTimeStepHamiltonJacobi(
591 tempMaxTimeStep, levelSets.back()->getGrid().getGridDelta());
594 if (tempMaxTimeStep < maxTimeStep)
595 maxTimeStep = tempMaxTimeStep;
606 void computeRates(
double maxTimeStep = std::numeric_limits<double>::max()) {
610 calculateNormalVectors);
611 currentTimeStep = integrateTime(is, maxTimeStep);
614 calculateNormalVectors);
615 currentTimeStep = integrateTime(is, maxTimeStep);
617 auto alphas = findGlobalAlphas();
619 dissipationAlpha, alphas,
620 calculateNormalVectors);
621 currentTimeStep = integrateTime(is, maxTimeStep);
623 auto alphas = findGlobalAlphas();
625 dissipationAlpha, alphas,
626 calculateNormalVectors);
627 currentTimeStep = integrateTime(is, maxTimeStep);
628 }
else if (spatialScheme ==
631 levelSets.back(), velocities);
632 currentTimeStep = integrateTime(is, maxTimeStep);
633 }
else if (spatialScheme ==
636 levelSets.back(), velocities, dissipationAlpha);
637 currentTimeStep = integrateTime(is, maxTimeStep);
638 }
else if (spatialScheme ==
641 levelSets.back(), velocities, dissipationAlpha);
642 currentTimeStep = integrateTime(is, maxTimeStep);
643 }
else if (spatialScheme ==
646 levelSets.back(), velocities, dissipationAlpha);
647 currentTimeStep = integrateTime(is, maxTimeStep);
648 }
else if (spatialScheme ==
651 levelSets.back(), velocities, dissipationAlpha);
652 currentTimeStep = integrateTime(is, maxTimeStep);
653 }
else if (spatialScheme ==
656 levelSets.back(), velocities, dissipationAlpha);
657 currentTimeStep = integrateTime(is, maxTimeStep);
662 currentTimeStep = integrateTime(is, maxTimeStep);
667 currentTimeStep = integrateTime(is, maxTimeStep);
669 VIENNACORE_LOG_ERROR(
"Advect: Discretization scheme not found.");
670 currentTimeStep = -1.;
676 void updateLevelSet(
double dt) {
677 if (timeStepRatio >= 0.5) {
678 VIENNACORE_LOG_WARNING(
679 "Integration time step ratio should be smaller than 0.5. "
680 "Advection might fail!");
683 auto &topDomain = levelSets.back()->getDomain();
685 assert(dt >= 0. &&
"No time step set!");
686 assert(storedRates.size() == topDomain.getNumberOfSegments());
692 const bool saveVelocities = saveAdvectionVelocities;
693 std::vector<std::vector<double>> dissipationVectors(
694 levelSets.back()->getNumberOfSegments());
695 std::vector<std::vector<double>> velocityVectors(
696 levelSets.back()->getNumberOfSegments());
698 const bool checkDiss = checkDissipation;
700#pragma omp parallel for
701 for (
unsigned p = 0; p < topDomain.getNumberOfSegments(); ++p) {
703 auto itRS = storedRates[p].cbegin();
704 auto &segment = topDomain.getDomainSegment(p);
705 const unsigned maxId = segment.getNumberOfPoints();
707 if (saveVelocities) {
708 velocityVectors[p].resize(maxId);
709 dissipationVectors[p].resize(maxId);
712 for (
unsigned localId = 0; localId < maxId; ++localId) {
713 T &value = segment.definedValues[localId];
716 if (std::abs(value) > integrationCutoff)
724 auto const [gradient, dissipation] = itRS->first;
725 T velocity = gradient - dissipation;
728 if (checkDiss && ((gradient < 0 && velocity > 0) ||
729 (gradient > 0 && velocity < 0))) {
733 T rate = time * velocity;
734 while (std::abs(itRS->second - value) < std::abs(rate)) {
735 time -= std::abs((itRS->second - value) / velocity);
736 value = itRS->second;
740 velocity = itRS->first.first - itRS->first.second;
741 if (checkDiss && ((itRS->first.first < 0 && velocity > 0) ||
742 (itRS->first.first > 0 && velocity < 0))) {
745 rate = time * velocity;
751 if (saveVelocities) {
752 velocityVectors[p][localId] = rate;
753 dissipationVectors[p][localId] = itRS->first.second;
759 while (std::abs(itRS->second) != std::numeric_limits<T>::max())
767 if (saveVelocities) {
768 auto &pointData = levelSets.back()->getPointData();
770 typename PointData<T>::ScalarDataType vels;
771 typename PointData<T>::ScalarDataType diss;
773 for (
unsigned i = 0; i < velocityVectors.size(); ++i) {
774 vels.insert(vels.end(),
775 std::make_move_iterator(velocityVectors[i].begin()),
776 std::make_move_iterator(velocityVectors[i].end()));
777 diss.insert(diss.end(),
778 std::make_move_iterator(dissipationVectors[i].begin()),
779 std::make_move_iterator(dissipationVectors[i].end()));
781 pointData.insertReplaceScalarData(std::move(vels),
velocityLabel);
789 void adjustLowerLayers() {
793 for (
unsigned i = 0; i < levelSets.size() - 1; ++i) {
795 levelSets[i], levelSets.back(),
804 double advect(
double maxTimeStep) {
805 switch (temporalScheme) {
826 levelSets.push_back(passedlsDomain);
831 levelSets.push_back(passedlsDomain);
832 velocities = passedVelocities;
837 : levelSets(passedlsDomains) {
838 velocities = passedVelocities;
844 levelSets.push_back(passedlsDomain);
852 velocities = passedVelocities;
892 adaptiveTimeStepping = aTS;
893 if (subdivisions < 1) {
894 VIENNACORE_LOG_WARNING(
"Advect: Adaptive time stepping subdivisions must "
895 "be at least 1. Setting to 1.");
898 adaptiveTimeStepSubdivisions = subdivisions;
927 [[deprecated(
"Use setSpatialScheme instead")]]
void
929 VIENNACORE_LOG_WARNING(
930 "Advect::setIntegrationScheme is deprecated and will be removed in "
931 "future versions. Use setSpatialScheme instead.");
932 spatialScheme = scheme;
954 std::function<
bool(SmartPointer<
Domain<T, D>>)> callback) {
955 velocityUpdateCallback = callback;
962 if (levelSets.empty()) {
963 VIENNACORE_LOG_ERROR(
"No level sets passed to Advect.");
975 }
else if (spatialScheme ==
979 }
else if (spatialScheme ==
982 }
else if (spatialScheme ==
985 }
else if (spatialScheme ==
988 }
else if (spatialScheme ==
991 }
else if (spatialScheme ==
1000 VIENNACORE_LOG_ERROR(
"Advect: Discretization scheme not found.");
1006 if (levelSets.empty()) {
1007 VIENNACORE_LOG_ERROR(
"No level sets passed to Advect. Not advecting.");
1010 if (velocities ==
nullptr) {
1011 VIENNACORE_LOG_ERROR(
1012 "No velocity field passed to Advect. Not advecting.");
1016 if (advectionTime == 0.) {
1017 advectedTime = advect(std::numeric_limits<double>::max());
1018 numberOfTimeSteps = 1;
1020 double currentTime = 0.0;
1021 numberOfTimeSteps = 0;
1022 while (currentTime < advectionTime) {
1023 currentTime += advect(advectionTime - currentTime);
1024 ++numberOfTimeSteps;
1025 if (performOnlySingleStep)
1028 advectedTime = currentTime;