Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
a4b8976
Limit time step at material interfaces and test with python SquareEtc…
FilipovicLado Dec 6, 2025
c3fc0d4
Update logger
tobre1 Dec 7, 2025
1e43bb5
Reverted material interface behavior and added removeLastMaterial fun…
FilipovicLado Dec 9, 2025
ee65258
format
FilipovicLado Dec 9, 2025
a1dc1da
Fix material interface stability with adaptive sub-stepping of thin l…
FilipovicLado Dec 10, 2025
6112431
Added WENO integration scheme
FilipovicLado Dec 10, 2025
347fe7d
Add option to enable adaptive time stepping during advection
tobre1 Dec 10, 2025
2e305b4
Add python bindings
tobre1 Dec 12, 2025
b3fdb1c
Bump version
tobre1 Dec 15, 2025
500a15c
Add option to set the adaptive time stepping threshold
tobre1 Dec 15, 2025
7c04453
Fix MultiSurfaceMesh ctors
tobre1 Dec 15, 2025
9bc958c
Added Runge-Kutta 3 time integration
FilipovicLado Dec 15, 2025
a26061a
Merge remote-tracking branch 'origin/fix_material_interface' into fix…
FilipovicLado Dec 15, 2025
b284716
Added Runge Kutta time integration scheme
FilipovicLado Dec 15, 2025
6f3c4b2
Merge branch 'master' into fix_material_interface
FilipovicLado Dec 15, 2025
58628fd
Fixed errors from previous commit and format
FilipovicLado Dec 15, 2025
6e29432
Clean up
tobre1 Dec 16, 2025
594cd08
Update Python stubs
tobre1 Dec 16, 2025
6d8767f
Fixed time step differences between FE and RK3
FilipovicLado Dec 17, 2025
7cce26b
Format AirGapDeposition example
FilipovicLado Dec 17, 2025
d276af6
rename integration -> discretization where appropriate
kenyastyle Dec 18, 2025
cfdd2c4
fix formatting
kenyastyle Dec 18, 2025
07f825f
Updated AirGapDeposition, Deposition, and SquareEtch examples to work…
FilipovicLado Dec 19, 2025
6688fc9
format
FilipovicLado Dec 19, 2025
be39c43
fixed SquareEtch example
FilipovicLado Dec 19, 2025
916de96
prepareLS(); in computeRates was added again which made it redundant …
FilipovicLado Dec 19, 2025
04a7256
Rename to SpatialScheme, add legacy IntegrationSchemeEnum
tobre1 Dec 22, 2025
726ca99
Fixed RK3 time integration scheme to only need velocities on the spar…
FilipovicLado Dec 22, 2025
7c3db6f
Fixed RK3 (Strong-Stability preserving Runge-Kutta 3rd order) tempora…
FilipovicLado Dec 27, 2025
3ef818c
Merge remote-tracking branch 'origin/master' into fix_material_interface
FilipovicLado Dec 27, 2025
3b7f5a4
Merge remote-tracking branch 'origin/rename' into fix_material_interf…
FilipovicLado Dec 27, 2025
824bb7a
Added compile-time "IntegrationScheme" naming depreciation narning.
FilipovicLado Dec 28, 2025
10e4c0f
format
FilipovicLado Dec 28, 2025
13cafda
Refactor Advect to use TemporalSchemeEnum and consolidate time integr…
FilipovicLado Dec 29, 2025
0be959b
Allow for calculating intermediate velocities during higher order tim…
FilipovicLado Dec 30, 2025
10c07f5
Added python bindings to the velocity calculation callback function
FilipovicLado Dec 30, 2025
f6f5025
Merge remote-tracking branch 'origin/master' into int-velocities
FilipovicLado Jan 8, 2026
307e141
Small fixes in FromMesh and MarkVoidPoints, add velocityUpdateCallbac…
FilipovicLado Jan 8, 2026
f597f69
format
FilipovicLado Jan 8, 2026
10685ff
remove last velocity calculation when in single step mode
FilipovicLado Jan 8, 2026
0b687a9
fixed failing PatternedSubstrate and VolumeToLevelSets examples, adde…
FilipovicLado Jan 8, 2026
5a01389
format
FilipovicLado Jan 8, 2026
fea7a19
remove GIT_TAG for ViennaHRLE
FilipovicLado Jan 8, 2026
c4a8639
Merge remote-tracking branch 'origin/master' into int-velocities
FilipovicLado Jan 9, 2026
5d6921f
Merge remote-tracking branch 'origin/fix-examples' into int-velocities
FilipovicLado Jan 9, 2026
e920b82
Added 3D options and tests for comparing domains
FilipovicLado Jan 9, 2026
04fb487
format
FilipovicLado Jan 9, 2026
99552b7
use CompareVolume for 3D and CompareArea for 2D, fix minor errors, im…
FilipovicLado Jan 13, 2026
1ef34ab
Removed CompareArea from top level Python API, now it is only in d2
FilipovicLado Jan 13, 2026
f015792
Update python stubs
tobre1 Jan 13, 2026
b2680f0
Merge pull from origin
tobre1 Jan 13, 2026
15b87ee
Small fixes
tobre1 Jan 13, 2026
9a0a6ff
Correct inconsistency in custom z-increments.
kenyastyle Jan 13, 2026
0004c0f
Small fixes and improvements to tests.
kenyastyle Jan 13, 2026
0c8e61a
Minor fix
FilipovicLado Jan 13, 2026
1287623
Enhance test for lsCompareCriticalDimensions
kenyastyle Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions PythonAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ They must be imported from either `viennals.d2` or `viennals.d3`.
- `CalculateNormalVectors`
- `CalculateVisibilities`
- `Check`
- `CompareChamfer`
- `CompareCriticalDimensions`
- `CompareNarrowBand`
- `CompareSparseField`
- `CompareVolume`
- `PointCloud`
- `ConvexHull`
- `DetectFeatures`
Expand Down Expand Up @@ -49,8 +54,6 @@ They must be imported from either `viennals.d2` or `viennals.d3`.

### **2D-Only Functions**
- `CompareArea`
- `CompareNarrowBand`
- `CompareSparseField`

---

Expand Down
2 changes: 1 addition & 1 deletion examples/AirGapDeposition/AirGapDeposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ double runSimulation(AdvectKernelType &kernel,
int main() {

constexpr int D = 2;
omp_set_num_threads(8);
omp_set_num_threads(16);

NumericType extent = 30;
NumericType gridDelta = 0.5;
Expand Down
10 changes: 10 additions & 0 deletions include/viennals/lsAdvect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <lsPreCompileMacros.hpp>

#include <functional>
#include <limits>
#include <vector>

Expand Down Expand Up @@ -78,6 +79,8 @@ template <class T, int D> class Advect {
unsigned adaptiveTimeStepSubdivisions = 20;
static constexpr double wrappingLayerEpsilon = 1e-4;
SmartPointer<Domain<T, D>> originalLevelSet = nullptr;
std::function<bool(SmartPointer<Domain<T, D>>)> velocityUpdateCallback =
nullptr;

// this vector will hold the maximum time step for each point and the
// corresponding velocity
Expand Down Expand Up @@ -951,6 +954,13 @@ template <class T, int D> class Advect {
/// be translated to the advected LS. Defaults to true.
void setUpdatePointData(bool update) { updatePointData = update; }

/// Set a callback function that is called after the level set has been
/// updated during intermediate time integration steps (e.g. RK2, RK3).
void setVelocityUpdateCallback(
std::function<bool(SmartPointer<Domain<T, D>>)> callback) {
velocityUpdateCallback = callback;
}

// Prepare the levelset for advection, based on the provided spatial
// discretization scheme.
void prepareLS() {
Expand Down
19 changes: 19 additions & 0 deletions include/viennals/lsAdvectIntegrationSchemes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ template <class T, int D> struct AdvectTimeIntegration {
// Stage 1: u^(1) = u^n + dt * L(u^n)
kernel.updateLevelSet(dt);

if (kernel.velocityUpdateCallback)
kernel.velocityUpdateCallback(kernel.levelSets.back());

// Stage 2: u^(n+1) = 1/2 u^n + 1/2 (u^(1) + dt * L(u^(1)))
// Current level set is u^(1). Compute L(u^(1)).
kernel.computeRates(dt);
Expand All @@ -82,6 +85,11 @@ template <class T, int D> struct AdvectTimeIntegration {
// Combine: u^(n+1) = 0.5 * u^n + 0.5 * u*
kernel.combineLevelSets(0.5, 0.5);

// If we are in single step mode, the level set will be rebuilt immediately
// after this, invalidating the velocity field. Thus, we skip the update.
if (kernel.velocityUpdateCallback && !kernel.performOnlySingleStep)
kernel.velocityUpdateCallback(kernel.levelSets.back());

// Finalize
kernel.rebuildLS();

Expand Down Expand Up @@ -109,18 +117,29 @@ template <class T, int D> struct AdvectTimeIntegration {
// Stage 1: u^(1) = u^n + dt * L(u^n)
kernel.updateLevelSet(dt);

if (kernel.velocityUpdateCallback)
kernel.velocityUpdateCallback(kernel.levelSets.back());

// Stage 2: u^(2) = 3/4 u^n + 1/4 (u^(1) + dt * L(u^(1)))
kernel.computeRates(dt);
kernel.updateLevelSet(dt);
// Combine to get u^(2) = 0.75 * u^n + 0.25 * u*.
kernel.combineLevelSets(0.75, 0.25);

if (kernel.velocityUpdateCallback)
kernel.velocityUpdateCallback(kernel.levelSets.back());

// Stage 3: u^(n+1) = 1/3 u^n + 2/3 (u^(2) + dt * L(u^(2)))
kernel.computeRates(dt);
kernel.updateLevelSet(dt);
// Combine to get u^(n+1) = 1/3 * u^n + 2/3 * u**.
kernel.combineLevelSets(1.0 / 3.0, 2.0 / 3.0);

// If we are in single step mode, the level set will be rebuilt immediately
// after this, invalidating the velocity field. Thus, we skip the update.
if (kernel.velocityUpdateCallback && !kernel.performOnlySingleStep)
kernel.velocityUpdateCallback(kernel.levelSets.back());

// Finalize: Re-segment and renormalize the final result.
kernel.rebuildLS();

Expand Down
167 changes: 89 additions & 78 deletions include/viennals/lsCalculateVisibilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,109 +26,120 @@ template <class T, int D> class CalculateVisibilities {
auto &domain = levelSet->getDomain();
auto &grid = levelSet->getGrid();

// *** Determine extents of domain ***
Vec3D<T> minDefinedPoint;
Vec3D<T> maxDefinedPoint;
// Initialize with extreme values
// Invert the vector
auto dir = Normalize(Inv(direction));
std::vector<T> visibilities(domain.getNumberOfPoints(), static_cast<T>(-1));

// Check if the direction vector has a component in the simulation
// dimensions
T dirNorm = 0;
for (int i = 0; i < D; ++i) {
minDefinedPoint[i] = std::numeric_limits<T>::max();
maxDefinedPoint[i] = std::numeric_limits<T>::lowest();
dirNorm += dir[i] * dir[i];
}
// Iterate through all defined points in the domain
for (viennahrle::SparseIterator<hrleDomainType> it(domain);
!it.isFinished(); it.next()) {
if (!it.isDefined())
continue; // Skip undefined points

// Get the coordinate of the current point
auto point = it.getStartIndices();

if (dirNorm < epsilon) {
std::fill(visibilities.begin(), visibilities.end(), static_cast<T>(1.0));
} else {
// *** Determine extents of domain ***
Vec3D<T> minDefinedPoint;
Vec3D<T> maxDefinedPoint;
// Initialize with extreme values
for (int i = 0; i < D; ++i) {
// Compare to update min and max defined points
T coord = point[i]; // * grid.getGridDelta();
minDefinedPoint[i] = std::min(minDefinedPoint[i], coord);
maxDefinedPoint[i] = std::max(maxDefinedPoint[i], coord);
minDefinedPoint[i] = std::numeric_limits<T>::max();
maxDefinedPoint[i] = std::numeric_limits<T>::lowest();
}
}
//****************************
// Iterate through all defined points in the domain
for (viennahrle::SparseIterator<hrleDomainType> it(domain);
!it.isFinished(); it.next()) {
if (!it.isDefined())
continue; // Skip undefined points

// Invert the vector
auto dir = Normalize(Inv(direction));
std::vector<T> visibilities(domain.getNumberOfPoints(), static_cast<T>(-1));
// Get the coordinate of the current point
auto point = it.getStartIndices();
for (int i = 0; i < D; ++i) {
// Compare to update min and max defined points
T coord = point[i]; // * grid.getGridDelta();
minDefinedPoint[i] = std::min(minDefinedPoint[i], coord);
maxDefinedPoint[i] = std::max(maxDefinedPoint[i], coord);
}
}
//****************************

#pragma omp parallel num_threads(levelSet->getNumberOfSegments())
{
int p = 0;
{
int p = 0;
#ifdef _OPENMP
p = omp_get_thread_num();
p = omp_get_thread_num();
#endif

const viennahrle::Index<D> startVector =
(p == 0) ? grid.getMinGridPoint() : domain.getSegmentation()[p - 1];
const viennahrle::Index<D> startVector =
(p == 0) ? grid.getMinGridPoint() : domain.getSegmentation()[p - 1];

const viennahrle::Index<D> endVector =
(p != static_cast<int>(domain.getNumberOfSegments() - 1))
? domain.getSegmentation()[p]
: grid.incrementIndices(grid.getMaxGridPoint());
const viennahrle::Index<D> endVector =
(p != static_cast<int>(domain.getNumberOfSegments() - 1))
? domain.getSegmentation()[p]
: grid.incrementIndices(grid.getMaxGridPoint());

for (viennahrle::SparseIterator<hrleDomainType> it(domain, startVector);
it.getStartIndices() < endVector; ++it) {
for (viennahrle::SparseIterator<hrleDomainType> it(domain, startVector);
it.getStartIndices() < endVector; ++it) {

if (!it.isDefined())
continue;
if (!it.isDefined())
continue;

// Starting position of the point
Vec3D<T> currentPos;
for (int i = 0; i < D; ++i) {
currentPos[i] = it.getStartIndices(i);
}

// Start tracing the ray
T minLevelSetValue = it.getValue(); // Starting level set value
Vec3D<T> rayPos = currentPos;

// Step once to skip immediate neighbor
for (int i = 0; i < D; ++i)
rayPos[i] += dir[i];
// Starting position of the point
Vec3D<T> currentPos;
for (int i = 0; i < D; ++i) {
currentPos[i] = it.getStartIndices(i);
}

bool visibility = true;
// Start tracing the ray
T minLevelSetValue = it.getValue(); // Starting level set value
Vec3D<T> rayPos = currentPos;

while (true) {
// Update the ray position
// Step once to skip immediate neighbor
for (int i = 0; i < D; ++i)
rayPos[i] += dir[i];

// Determine the nearest grid cell (round to nearest index)
viennahrle::Index<D> nearestCell;
for (int i = 0; i < D; ++i)
nearestCell[i] = static_cast<viennahrle::IndexType>(rayPos[i]);

// Check if the nearest cell is within bounds
bool outOfBounds = false;
for (int i = 0; i < D; ++i) {
if (nearestCell[i] < minDefinedPoint[i] ||
nearestCell[i] > maxDefinedPoint[i]) {
outOfBounds = true;
break;
bool visibility = true;

while (true) {
// Update the ray position
for (int i = 0; i < D; ++i)
rayPos[i] += dir[i];

// Determine the nearest grid cell (round to nearest index)
viennahrle::Index<D> nearestCell;
for (int i = 0; i < D; ++i)
nearestCell[i] = static_cast<viennahrle::IndexType>(rayPos[i]);

// Check if the nearest cell is within bounds
bool outOfBounds = false;
for (int i = 0; i < D; ++i) {
if (nearestCell[i] < minDefinedPoint[i] ||
nearestCell[i] > maxDefinedPoint[i]) {
outOfBounds = true;
break;
}
}
}

if (outOfBounds)
break; // Ray is outside the grid
if (outOfBounds)
break; // Ray is outside the grid

// Access the level set value at the nearest cell
T value =
viennahrle::SparseIterator<hrleDomainType>(domain, nearestCell)
.getValue();
// Access the level set value at the nearest cell
T value =
viennahrle::SparseIterator<hrleDomainType>(domain, nearestCell)
.getValue();

// Update the minimum value encountered
if (value < minLevelSetValue) {
visibility = false;
break;
// Update the minimum value encountered
if (value < minLevelSetValue) {
visibility = false;
break;
}
}
}

// Update visibility for this point
visibilities[it.getPointId()] = visibility ? 1.0 : 0.0;
// Update visibility for this point
visibilities[it.getPointId()] = visibility ? 1.0 : 0.0;
}
}
}

Expand Down
Loading
Loading