Skip to content

Commit 4edaef6

Browse files
committed
Merge branch 'dev' of https://github.com/topology-tool-kit/ttk into mtnn_refactor
2 parents 17ef957 + de954d3 commit 4edaef6

33 files changed

+7599
-3
lines changed

ChangeLog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
## TTK - ChangeLog
22
=
33
### dev
4-
- Cycle-aware dimensionality reduction (TopoAE++)
4+
- Cycle-aware dimensionality reduction (TopoAE++, IEEE TVCG 2026)
55
- Distributed computation of persistent homology! (IEEE TPDS 2025)
6+
- Discrete vector field topology! (IEEE VIS 2024)
67
- New backend for TrackingFromFields (critical point based)
78
- Fast planar Rips filtration persistence computation
89
- Migration to ParaView 6

core/base/common/welcomeMsg.inl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Julien Tierny <[email protected]>
33
// January 2020.
44

5-
// "TTK (c) 2025"
5+
// "TTK (c) 2026"
66

77
printMsg(
88
debug::output::BOLD
@@ -12,7 +12,7 @@ printMsg(
1212
debug::LineMode::NEW,
1313
stream);
1414
printMsg(debug::output::BOLD
15-
+ "|_ _|_ _| |/ / / /__\\ \\ |___ \\ / _ \\___ \\ / /"
15+
+ "|_ _|_ _| |/ / / /__\\ \\ |___ \\ / _ \\___ \\ / /_"
1616
+ debug::output::ENDCOLOR,
1717
debug::Priority::PERFORMANCE,
1818
debug::LineMode::NEW,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ttk_add_base_library(discreteVectorField
2+
SOURCES
3+
DiscreteVectorField.cpp
4+
HEADERS
5+
DiscreteVectorField.h
6+
DiscreteVectorField_Template.h
7+
DEPENDS
8+
triangulation
9+
surfaceGeometrySmoother
10+
discreteGradient
11+
)
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#include <DiscreteVectorField.h>
2+
3+
using namespace std;
4+
using namespace ttk;
5+
using namespace dcvf;
6+
7+
int DiscreteVectorField::getDimensionality() const {
8+
return dimensionality_;
9+
}
10+
11+
int DiscreteVectorField::getNumberOfDimensions() const {
12+
return dimensionality_ + 1;
13+
}
14+
15+
void DiscreteVectorField::initMemory(
16+
const AbstractTriangulation &triangulation) {
17+
18+
Timer tm{};
19+
const int numberOfDimensions = this->getNumberOfDimensions();
20+
21+
// init number of cells by dimension
22+
std::vector<SimplexId> numberOfCells(numberOfDimensions);
23+
for(int i = 0; i < numberOfDimensions; ++i) {
24+
numberOfCells[i] = this->getNumberOfCells(i, triangulation);
25+
}
26+
27+
// clear & init discrete vectors memory
28+
for(int i = 0; i < dimensionality_; ++i) {
29+
(*vectors_)[2 * i].clear();
30+
(*vectors_)[2 * i].resize(numberOfCells[i], -1);
31+
(*vectors_)[2 * i + 1].clear();
32+
(*vectors_)[2 * i + 1].resize(numberOfCells[i + 1], -1);
33+
}
34+
35+
std::vector<std::vector<std::string>> rows{
36+
{"#Vertices", std::to_string(numberOfCells[0])},
37+
{"#Edges", std::to_string(numberOfCells[1])},
38+
};
39+
40+
if(dimensionality_ >= 2) {
41+
rows.emplace_back(
42+
std::vector<std::string>{"#Triangles", std::to_string(numberOfCells[2])});
43+
}
44+
45+
if(dimensionality_ == 3) {
46+
rows.emplace_back(
47+
std::vector<std::string>{"#Tetras", std::to_string(numberOfCells[3])});
48+
}
49+
50+
this->printMsg(rows);
51+
this->printMsg("Initialized discrete vectors memory", 1.0,
52+
tm.getElapsedTime(), this->threadNumber_);
53+
}
54+
55+
std::pair<size_t, SimplexId>
56+
DiscreteVectorField::numUnpairedFaces(const CellOutExt &c,
57+
const outwardStarType &ls) const {
58+
// c.dim_ cannot be <= 1
59+
if(c.dim_ == 2) {
60+
return numUnpairedFacesTriangle(c, ls);
61+
} else if(c.dim_ == 3) {
62+
return numUnpairedFacesTetra(c, ls);
63+
}
64+
65+
return {0, -1};
66+
}
67+
68+
std::pair<size_t, SimplexId> DiscreteVectorField::numUnpairedFacesTriangle(
69+
const CellOutExt &c, const outwardStarType &ls) const {
70+
// number of unpaired faces
71+
std::pair<size_t, SimplexId> res{0, -1};
72+
73+
// loop over edge faces of triangle
74+
// (2 edges per triangle in outward star)
75+
for(size_t i = 0; i < 2; ++i) {
76+
if(!ls[1][c.faces_[i]].paired_) {
77+
res.first++;
78+
res.second = c.faces_[i];
79+
}
80+
}
81+
82+
return res;
83+
}
84+
85+
std::pair<size_t, SimplexId>
86+
DiscreteVectorField::numUnpairedFacesTetra(const CellOutExt &c,
87+
const outwardStarType &ls) const {
88+
// number of unpaired faces
89+
std::pair<size_t, SimplexId> res{0, -1};
90+
91+
// loop over triangle faces of tetra
92+
for(const auto f : c.faces_) {
93+
if(!ls[2][f].paired_) {
94+
res.first++;
95+
res.second = f;
96+
}
97+
}
98+
99+
return res;
100+
}
101+
102+
bool DiscreteVectorField::isCellCritical(const int cellDim,
103+
const SimplexId cellId) const {
104+
105+
if(cellDim > this->dimensionality_) {
106+
return false;
107+
}
108+
#ifndef TTK_ENABLE_KAMIKAZE
109+
if(cellId < 0) {
110+
this->printErr("Invalid cell ID given to isCellCritical");
111+
return false;
112+
}
113+
#endif
114+
115+
if(cellDim == 0) {
116+
return ((*vectors_)[0][cellId] == NULL_CONNECTION);
117+
}
118+
119+
if(cellDim == 1) {
120+
return (
121+
(*vectors_)[1][cellId] == NULL_CONNECTION
122+
&& (dimensionality_ == 1 || (*vectors_)[2][cellId] == NULL_CONNECTION));
123+
}
124+
125+
if(cellDim == 2) {
126+
return (
127+
(*vectors_)[3][cellId] == NULL_CONNECTION
128+
&& (dimensionality_ == 2 || (*vectors_)[4][cellId] == NULL_CONNECTION));
129+
}
130+
131+
if(cellDim == 3) {
132+
return ((*vectors_)[5][cellId] == NULL_CONNECTION);
133+
}
134+
135+
return false;
136+
}
137+
138+
bool DiscreteVectorField::isCellCritical(const Cell &cell) const {
139+
return isCellCritical(cell.dim_, cell.id_);
140+
}
141+
142+
int DiscreteVectorField::setManifoldSize(
143+
const std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
144+
const SimplexId *const ascendingManifold,
145+
const SimplexId *const descendingManifold,
146+
std::vector<SimplexId> &manifoldSize) const {
147+
148+
const auto nCritPoints{
149+
criticalCellsByDim[0].size() + criticalCellsByDim[1].size()
150+
+ criticalCellsByDim[2].size() + criticalCellsByDim[3].size()};
151+
152+
const auto dim{this->dimensionality_};
153+
154+
if(nCritPoints == 0
155+
|| (criticalCellsByDim[0].empty() && criticalCellsByDim[dim].empty())) {
156+
// no critical points || no extrema
157+
return 0;
158+
}
159+
160+
manifoldSize.resize(nCritPoints, 0);
161+
162+
// descending manifold cells size
163+
if(!criticalCellsByDim[0].empty()) {
164+
const SimplexId nMin = static_cast<SimplexId>(criticalCellsByDim[0].size());
165+
for(SimplexId i = 0; i < numberOfVertices_; ++i) {
166+
if(descendingManifold[i] != -1 && descendingManifold[i] < nMin) {
167+
manifoldSize[descendingManifold[i]]++;
168+
}
169+
}
170+
}
171+
172+
if(!criticalCellsByDim[dim].empty()) {
173+
// index of first maximum in critical points array
174+
const auto nFirstMaximum{nCritPoints - criticalCellsByDim[dim].size()};
175+
const SimplexId nMax
176+
= static_cast<SimplexId>(criticalCellsByDim[dim].size());
177+
// ascending manifold cells size
178+
for(SimplexId i = 0; i < numberOfVertices_; ++i) {
179+
if(ascendingManifold[i] != -1 && ascendingManifold[i] < nMax) {
180+
manifoldSize[ascendingManifold[i] + nFirstMaximum]++;
181+
}
182+
}
183+
}
184+
185+
return 0;
186+
}
187+
188+
#ifdef TTK_ENABLE_MPI
189+
void DiscreteVectorField::setCellToGhost(const int cellDim,
190+
const SimplexId cellId) {
191+
if(cellDim == 0) {
192+
(*vectors_)[0][cellId] = GHOST_CONNECTION;
193+
}
194+
195+
if(cellDim == 1) {
196+
(*vectors_)[1][cellId] = GHOST_CONNECTION;
197+
(*vectors_)[2][cellId] = GHOST_CONNECTION;
198+
}
199+
200+
if(cellDim == 2) {
201+
(*vectors_)[3][cellId] = GHOST_CONNECTION;
202+
(*vectors_)[4][cellId] = GHOST_CONNECTION;
203+
}
204+
205+
if(cellDim == 3) {
206+
(*vectors_)[5][cellId] = GHOST_CONNECTION;
207+
}
208+
}
209+
#endif

0 commit comments

Comments
 (0)