From 459b6091ef1ce81c997fda9714288ffd118bb33e Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Fri, 22 May 2026 17:37:32 +0200 Subject: [PATCH 01/46] [il-ext] setting up gui --- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 17 ++++++++++ core/vtk/ttkIntegralLines/ttkIntegralLines.h | 11 +++++++ paraview/xmls/IntegralLines.xml | 31 +++++++++++++++---- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index a7432747aa..513f0775af 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -225,6 +225,23 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkDataArray *inputOffsets = this->GetOrderArray( domain, 0, triangulation, false, 1, ForceInputOffsetScalarField); +#ifndef TTK_ENABLE_MPI + if(BackEnd == BACKEND::NUMERICAL){ + printMsg("Selected numerical backend"); + return 1; + } + else if(BackEnd == BACKEND::DISCRETE){ + printMsg("Selected discrete backend"); + return 1; + } +#endif + +#ifdef TTK_ENABLE_MPI + if(BackEnd != BACKEND::ONESKELETON){ + printWrn("Distributed run, defaulting to `OneSkeleton` backend."); + } +#endif + const ttk::SimplexId numberOfPointsInDomain = domain->GetNumberOfPoints(); this->setVertexNumber(numberOfPointsInDomain); int numberOfPointsInSeeds = seeds->GetNumberOfPoints(); diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.h b/core/vtk/ttkIntegralLines/ttkIntegralLines.h index d3ffee41f9..27f9264640 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.h +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.h @@ -71,6 +71,7 @@ // ttk code includes #include #include +#include class vtkUnstructuredGrid; @@ -82,6 +83,12 @@ class TTKINTEGRALLINES_EXPORT ttkIntegralLines : public ttkAlgorithm, vtkTypeMacro(ttkIntegralLines, ttkAlgorithm); + enum class BACKEND{ + ONESKELETON = 0, + NUMERICAL = 1, + DISCRETE = 2, + }; + vtkGetMacro(Direction, int); vtkSetMacro(Direction, int); @@ -91,6 +98,9 @@ class TTKINTEGRALLINES_EXPORT ttkIntegralLines : public ttkAlgorithm, vtkSetMacro(ForceInputOffsetScalarField, bool); vtkGetMacro(ForceInputOffsetScalarField, bool); + ttkSetEnumMacro(BackEnd, BACKEND); + vtkGetEnumMacro(BackEnd, BACKEND); + vtkSetMacro(EnableForking, bool); vtkGetMacro(EnableForking, bool); @@ -123,6 +133,7 @@ class TTKINTEGRALLINES_EXPORT ttkIntegralLines : public ttkAlgorithm, vtkInformationVector *outputVector) override; private: + BACKEND BackEnd{BACKEND::ONESKELETON}; int Direction{0}; bool ForceInputVertexScalarField{false}; bool ForceInputOffsetScalarField{false}; diff --git a/paraview/xmls/IntegralLines.xml b/paraview/xmls/IntegralLines.xml index 461e96dbfc..00b8cbb187 100644 --- a/paraview/xmls/IntegralLines.xml +++ b/paraview/xmls/IntegralLines.xml @@ -13,13 +13,13 @@ lines of the gradient of an input scalar field."> The filter takes on its input a scalar field attached as point data to an input geometry (either 2D or 3D, either regular grids or triangulations) -and computes the forward or backward integral lines along the edges of the -input mesh, given a list of input sources. +and computes the forward or backward integral lines, given a list of input sources. Several backends are available: -The sources are specified with a vtkPointSet on which is attached as point -data a scalar field that represent the vertex identifiers of the sources in -the input geometry (use the Identifiers plugin prior to the selection of the -sources if necessary to create such an identifier field). +- the 'OneSkeleton' backend follows the flow along the edges of the mesh. This backend supports MPI computation. +- the 'Numerical' backend computes integral lines following the piecewise constant gradient of each simplex (i.e., it is going through the simplices) +- the 'Discrete' backend computes a discrete integral line (a.k.a. v-path), following the discrete Morse theory model. + +The sources are specified with a vtkPointSet, containing the simplices from which to start the integral lines. Each simplex is associated to its global identifier, passed as a point data array for vertices or cell data array in general for simplices of arbitrary dimension. Use PointAndCellIds to compute those in advance (the name of the generated field must then be provided to this filter). Online examples: @@ -178,6 +178,24 @@ plateaus). + + + + + + + + Backend for the computation of the persistence diagram. + The progressive and approximate approaches only allow the computation of saddle-extremum pairs on regular grids. + + + + From 7ee52a89f66359984e3b42251b98b075623a1807 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 23 May 2026 09:05:57 +0200 Subject: [PATCH 02/46] [il-ext] vpath helper --- core/base/vpath/CMakeLists.txt | 10 +++++++ core/base/vpath/VPath.cpp | 10 +++++++ core/base/vpath/VPath.h | 54 ++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 core/base/vpath/CMakeLists.txt create mode 100644 core/base/vpath/VPath.cpp create mode 100644 core/base/vpath/VPath.h diff --git a/core/base/vpath/CMakeLists.txt b/core/base/vpath/CMakeLists.txt new file mode 100644 index 0000000000..06e07934ec --- /dev/null +++ b/core/base/vpath/CMakeLists.txt @@ -0,0 +1,10 @@ +ttk_add_base_library(vPath + SOURCES + VPath.cpp + HEADERS + VPath.h + DEPENDS + discreteGradient + geometry + triangulation + ) diff --git a/core/base/vpath/VPath.cpp b/core/base/vpath/VPath.cpp new file mode 100644 index 0000000000..239379768b --- /dev/null +++ b/core/base/vpath/VPath.cpp @@ -0,0 +1,10 @@ +#include + +using namespace std; +using namespace ttk; + +VPath::VPath(){ + this->setDebugMsgPrefix("VPath"); +} + +VPath::~VPath() = default; diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h new file mode 100644 index 0000000000..56a6ac5abb --- /dev/null +++ b/core/base/vpath/VPath.h @@ -0,0 +1,54 @@ +/// \ingroup base +/// \class ttk::VPath +/// \author Julien Tierny +/// \date May 2026 +/// \date VPath extractor wrapping the DiscreteGradient class. +/// +/// \brief TTK convenience class wrapping the DiscreteGradient class for +/// the easy extraction of vpaths. +/// +/// Given a simplexId and dimension, this class returns a descending (or +/// ascending) vpath started in the given input simplex. +/// +/// \sa VPath.cpp %for an alternative integral line backend. +/// \sa DiscreteGradient.cpp %for the core mechanisms. +/// \sa ttkVPath.cpp %for a usage example. +/// + +#pragma once + +// base code includes +#include +// std includes + +namespace ttk { + namespace vp { + + class VPath : virtual public Debug { + + public: + VPath(); + ~VPath() override; + + // template + // int execute(triangulationType *triangulation); + + /** + * @brief Computes the integral line starting at the vertex of global id + * seedIdentifier. + * + * @tparam triangulationType + * @param triangulation + * @param integralLine integral line to compute + * @param offsets Order array of the scalar array + */ + // template + // void computeIntegralLine(const triangulationType *triangulation, + // ttk::intgl::IntegralLine *integralLine, + // const ttk::SimplexId *offsets) const; + + protected: + +#endif + }; +} // namespace ttk From 05c69ecc8072dea894a91109c8c44863bc160256 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 23 May 2026 11:09:34 +0200 Subject: [PATCH 03/46] [il-ext] setting up classes --- core/base/vpath/VPath.cpp | 8 +++ core/base/vpath/VPath.h | 64 +++++++++++-------- core/vtk/ttkIntegralLines/ttk.module | 1 + .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 34 ++++++++-- core/vtk/ttkIntegralLines/ttkIntegralLines.h | 1 + paraview/xmls/IntegralLines.xml | 6 +- 6 files changed, 81 insertions(+), 33 deletions(-) diff --git a/core/base/vpath/VPath.cpp b/core/base/vpath/VPath.cpp index 239379768b..af5c53e441 100644 --- a/core/base/vpath/VPath.cpp +++ b/core/base/vpath/VPath.cpp @@ -2,9 +2,17 @@ using namespace std; using namespace ttk; +using namespace vp; VPath::VPath(){ this->setDebugMsgPrefix("VPath"); } VPath::~VPath() = default; + +int VPath::execute(vector &output, const bool &isForward){ + + printMsg("Computing VPath..."); + + return 0; +} diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 56a6ac5abb..6da19e61f1 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -18,37 +18,47 @@ #pragma once // base code includes +#include #include // std includes namespace ttk { namespace vp { - class VPath : virtual public Debug { - - public: - VPath(); - ~VPath() override; - - // template - // int execute(triangulationType *triangulation); - - /** - * @brief Computes the integral line starting at the vertex of global id - * seedIdentifier. - * - * @tparam triangulationType - * @param triangulation - * @param integralLine integral line to compute - * @param offsets Order array of the scalar array - */ - // template - // void computeIntegralLine(const triangulationType *triangulation, - // ttk::intgl::IntegralLine *integralLine, - // const ttk::SimplexId *offsets) const; - - protected: - -#endif - }; + class VPath : virtual public Debug { + + public: + VPath(); + ~VPath() override; + + // template + // int execute(triangulationType *triangulation); + + /* + * @brief Extract a vpath. + * + * @param output Vector storing the output vpath. + * @param isForward Forward or backward vpath (default: forward). + */ + int execute(std::vector &output, + const bool &isForward = true); + + /** + * @brief Computes the integral line starting at the vertex of global id + * seedIdentifier. + * + * @tparam triangulationType + * @param triangulation + * @param integralLine integral line to compute + * @param offsets Order array of the scalar array + */ + // template + // void computeIntegralLine(const triangulationType *triangulation, + // ttk::intgl::IntegralLine *integralLine, + // const ttk::SimplexId *offsets) const; + + protected: + + }; + } // namespace vp } // namespace ttk diff --git a/core/vtk/ttkIntegralLines/ttk.module b/core/vtk/ttkIntegralLines/ttk.module index daed81a33a..b6ce63c0df 100644 --- a/core/vtk/ttkIntegralLines/ttk.module +++ b/core/vtk/ttkIntegralLines/ttk.module @@ -6,4 +6,5 @@ HEADERS ttkIntegralLines.h DEPENDS integralLines + vPath ttkAlgorithm diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 513f0775af..0b80c54707 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -226,12 +226,42 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), domain, 0, triangulation, false, 1, ForceInputOffsetScalarField); #ifndef TTK_ENABLE_MPI + + std::vector idSpareStorage{}; + ttk::SimplexId *identifiers = this->GetIdentifierArrayPtr( + ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, + idSpareStorage); + if(BackEnd == BACKEND::NUMERICAL){ printMsg("Selected numerical backend"); return 1; } else if(BackEnd == BACKEND::DISCRETE){ printMsg("Selected discrete backend"); + + ttk::vp::VPath vpath; + vpath.setDebugLevel(debugLevel_); + vpath.setThreadNumber(threadNumber_); + + std::vector outputPath; + + // TODO + // double-check ttkDiscreteGradient for initialization + + vpath.execute(outputPath); + + // TODO + // double check ttkMorseSmaleComplex for vpath2geometry + + // this->setVertexNumber(numberOfPointsInDomain); + // this->setSeedNumber(numberOfPointsInSeeds); + // this->setDirection(Direction); + // this->setInputScalarField(inputScalars->GetVoidPointer(0)); + // this->setInputOffsets(ttkUtils::GetPointer(inputOffsets)); + // this->setVertexIdentifierScalarField(&inputIdentifiers); + // this->setOutputIntegralLines(&integralLines); + // this->preconditionTriangulation(triangulation); + return 1; } #endif @@ -330,10 +360,6 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), } } #else - std::vector idSpareStorage{}; - ttk::SimplexId *identifiers = this->GetIdentifierArrayPtr( - ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, - idSpareStorage); std::unordered_set isSeed; for(ttk::SimplexId k = 0; k < numberOfPointsInSeeds; ++k) { isSeed.insert(identifiers[k]); diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.h b/core/vtk/ttkIntegralLines/ttkIntegralLines.h index 27f9264640..dc24c7a5fb 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.h +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.h @@ -70,6 +70,7 @@ // ttk code includes #include +#include #include #include diff --git a/paraview/xmls/IntegralLines.xml b/paraview/xmls/IntegralLines.xml index 00b8cbb187..754c18499c 100644 --- a/paraview/xmls/IntegralLines.xml +++ b/paraview/xmls/IntegralLines.xml @@ -191,8 +191,10 @@ plateaus). - Backend for the computation of the persistence diagram. - The progressive and approximate approaches only allow the computation of saddle-extremum pairs on regular grids. + Backend for the computation of the integral lines. + - the 'OneSkeleton' backend follows the flow along the edges of the mesh. This backend supports MPI computation. +- the 'Numerical' backend computes integral lines following the piecewise constant gradient of each simplex (i.e., it is going through the simplices) +- the 'Discrete' backend computes a discrete integral line (a.k.a. v-path), following the discrete Morse theory model. From 603e2805614f6c3d78c5a1e228bd6eaf27a3f322 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Wed, 27 May 2026 08:50:35 +0200 Subject: [PATCH 04/46] [il-ext] mpi run check --- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 0b80c54707..e403b478ef 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -225,52 +225,56 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkDataArray *inputOffsets = this->GetOrderArray( domain, 0, triangulation, false, 1, ForceInputOffsetScalarField); -#ifndef TTK_ENABLE_MPI + bool isRunningWithMPI = false; + +#ifdef TTK_ENABLE_MPI + isRunningWithMPI = ttk::isRunningWithMPI(); +#endif std::vector idSpareStorage{}; ttk::SimplexId *identifiers = this->GetIdentifierArrayPtr( ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, idSpareStorage); - if(BackEnd == BACKEND::NUMERICAL){ - printMsg("Selected numerical backend"); - return 1; - } - else if(BackEnd == BACKEND::DISCRETE){ - printMsg("Selected discrete backend"); + if(!isRunningWithMPI){ - ttk::vp::VPath vpath; - vpath.setDebugLevel(debugLevel_); - vpath.setThreadNumber(threadNumber_); + if(BackEnd == BACKEND::NUMERICAL){ + printMsg("Selected numerical backend"); + return 1; + } + else if(BackEnd == BACKEND::DISCRETE){ + printMsg("Selected discrete backend"); - std::vector outputPath; + ttk::vp::VPath vpath; + vpath.setDebugLevel(debugLevel_); + vpath.setThreadNumber(threadNumber_); - // TODO - // double-check ttkDiscreteGradient for initialization + std::vector outputPath; - vpath.execute(outputPath); + // TODO + // double-check ttkDiscreteGradient for initialization - // TODO - // double check ttkMorseSmaleComplex for vpath2geometry + vpath.execute(outputPath); - // this->setVertexNumber(numberOfPointsInDomain); - // this->setSeedNumber(numberOfPointsInSeeds); - // this->setDirection(Direction); - // this->setInputScalarField(inputScalars->GetVoidPointer(0)); - // this->setInputOffsets(ttkUtils::GetPointer(inputOffsets)); - // this->setVertexIdentifierScalarField(&inputIdentifiers); - // this->setOutputIntegralLines(&integralLines); - // this->preconditionTriangulation(triangulation); + // TODO + // double check ttkMorseSmaleComplex for vpath2geometry - return 1; - } -#endif + // this->setVertexNumber(numberOfPointsInDomain); + // this->setSeedNumber(numberOfPointsInSeeds); + // this->setDirection(Direction); + // this->setInputScalarField(inputScalars->GetVoidPointer(0)); + // this->setInputOffsets(ttkUtils::GetPointer(inputOffsets)); + // this->setVertexIdentifierScalarField(&inputIdentifiers); + // this->setOutputIntegralLines(&integralLines); + // this->preconditionTriangulation(triangulation); -#ifdef TTK_ENABLE_MPI - if(BackEnd != BACKEND::ONESKELETON){ - printWrn("Distributed run, defaulting to `OneSkeleton` backend."); + return 1; + } + } + else{ + if(BackEnd != BACKEND::ONESKELETON) + printWrn("Distributed run, defaulting to the `OneSkeleton` backend."); } -#endif const ttk::SimplexId numberOfPointsInDomain = domain->GetNumberOfPoints(); this->setVertexNumber(numberOfPointsInDomain); From cd1733a29297bf4df15d46f17d618cd8b45ffd50 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Wed, 27 May 2026 09:24:34 +0200 Subject: [PATCH 05/46] [il-ext] setting up dcg --- core/base/vpath/VPath.h | 6 ++++++ core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 6da19e61f1..25e9654ccb 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -43,6 +43,11 @@ namespace ttk { int execute(std::vector &output, const bool &isForward = true); + inline void preconditionTriangulation(AbstractTriangulation *triangulation){ + + // see dms precondition + } + /** * @brief Computes the integral line starting at the vertex of global id * seedIdentifier. @@ -59,6 +64,7 @@ namespace ttk { protected: + dcg::DiscreteGradient dcg_{}; }; } // namespace vp } // namespace ttk diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 0b80c54707..7efa3c53ae 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -232,16 +232,16 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, idSpareStorage); - if(BackEnd == BACKEND::NUMERICAL){ + if(BackEnd == BACKEND::NUMERICAL) { printMsg("Selected numerical backend"); return 1; - } - else if(BackEnd == BACKEND::DISCRETE){ + } else if(BackEnd == BACKEND::DISCRETE) { printMsg("Selected discrete backend"); ttk::vp::VPath vpath; vpath.setDebugLevel(debugLevel_); vpath.setThreadNumber(threadNumber_); + vpath.preconditionTriangulation(TTK_TRIANGULATION_INTERNAL); std::vector outputPath; @@ -267,7 +267,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), #endif #ifdef TTK_ENABLE_MPI - if(BackEnd != BACKEND::ONESKELETON){ + if(BackEnd != BACKEND::ONESKELETON) { printWrn("Distributed run, defaulting to `OneSkeleton` backend."); } #endif From fe1eb513e00b07095e575c8844093ca4d96929ae Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Wed, 27 May 2026 10:30:35 +0200 Subject: [PATCH 06/46] [il-ext] setup discrete gradient (fetch & compute) --- core/base/vpath/VPath.cpp | 6 --- core/base/vpath/VPath.h | 37 ++++++++++++++++++- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 34 ++++++++++++++--- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/core/base/vpath/VPath.cpp b/core/base/vpath/VPath.cpp index af5c53e441..f248400427 100644 --- a/core/base/vpath/VPath.cpp +++ b/core/base/vpath/VPath.cpp @@ -10,9 +10,3 @@ VPath::VPath(){ VPath::~VPath() = default; -int VPath::execute(vector &output, const bool &isForward){ - - printMsg("Computing VPath..."); - - return 0; -} diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 25e9654ccb..e1ae7f5af2 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -34,18 +34,35 @@ namespace ttk { // template // int execute(triangulationType *triangulation); - /* + /** * @brief Extract a vpath. * * @param output Vector storing the output vpath. * @param isForward Forward or backward vpath (default: forward). */ - int execute(std::vector &output, + template + int execute( + const triangulationType *triangulation, + const std::vector &seeds, + std::vector &output, const bool &isForward = true); + /** + * @brief Triangulation preconditioning. + */ inline void preconditionTriangulation(AbstractTriangulation *triangulation){ // see dms precondition + dcg_.preconditionTriangulation(triangulation); + } + + inline void setInputOffsets(const SimplexId *const offsets) { + this->dcg_.setInputOffsets(offsets); + } + + inline void setInputScalarField(const void *const scalars, + const size_t &mTime){ + this->dcg_.setInputScalarField(scalars, mTime); } /** @@ -68,3 +85,19 @@ namespace ttk { }; } // namespace vp } // namespace ttk + +template +int ttk::vp::VPath::execute( + const triangulationType *triangulation, + const std::vector &input, + std::vector &output, const bool &isForward){ + + // fetching discrete gradient (or computing it) + dcg_.setDebugLevel(debugLevel_); + dcg_.setThreadNumber(threadNumber_); + dcg_.buildGradient(*triangulation, false, nullptr); + + printMsg("Computing VPath..."); + + return 0; +} diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index e403b478ef..39881891cd 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -239,22 +239,44 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), if(!isRunningWithMPI){ if(BackEnd == BACKEND::NUMERICAL){ - printMsg("Selected numerical backend"); + printMsg("Selected `numerical` backend."); return 1; } else if(BackEnd == BACKEND::DISCRETE){ - printMsg("Selected discrete backend"); + printMsg("Selected `discrete` backend."); ttk::vp::VPath vpath; + vpath.setDebugLevel(debugLevel_); vpath.setThreadNumber(threadNumber_); - std::vector outputPath; + // setup the mesh + vpath.preconditionTriangulation(triangulation); - // TODO - // double-check ttkDiscreteGradient for initialization + // setup the data + vpath.setInputScalarField(inputScalars->GetVoidPointer(0), + inputScalars->GetMTime()); + vpath.setInputOffsets( + static_cast(ttkUtils::GetVoidPointer(inputOffsets))); + + std::vector seedCells(seeds->GetNumberOfPoints()); + +#ifdef TTK_ENABLE_OPENMP +#pragma omp parallel for num_threads(threadNumber_) +#endif + for(int i = 0; i < (int) seedCells.size(); i++){ + seedCells[i].dim_ = 0; + seedCells[i].id_ = identifiers[i]; + } + + + std::vector outputPath; - vpath.execute(outputPath); + int status{}; + ttkTemplateMacro(triangulation->getType(), + status = vpath.execute( + static_cast(triangulation->getData()), + seedCells, outputPath)); // TODO // double check ttkMorseSmaleComplex for vpath2geometry From ac711abda56519f7c3058c5fb2a0baa6c0b2bb1c Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Wed, 27 May 2026 11:09:52 +0200 Subject: [PATCH 07/46] [il-ext] timing and warnings --- .../DiscreteGradient_Template.h | 3 ++ core/base/vpath/VPath.h | 32 ++++++++++++++++--- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 2 +- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 25dbd7b7c1..01e4755215 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1549,6 +1549,9 @@ int DiscreteGradient::getDescendingPath( } while(connectedEdgeId != -1); } + else{ + printWrn("Descending path not implemented!"); + } return 0; } diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index e1ae7f5af2..c737b9bfdd 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -44,7 +44,7 @@ namespace ttk { int execute( const triangulationType *triangulation, const std::vector &seeds, - std::vector &output, + std::vector> &output, const bool &isForward = true); /** @@ -89,15 +89,37 @@ namespace ttk { template int ttk::vp::VPath::execute( const triangulationType *triangulation, - const std::vector &input, - std::vector &output, const bool &isForward){ + const std::vector &seeds, + std::vector> &output, const bool &isForward){ - // fetching discrete gradient (or computing it) + // fetching discrete gradient (or pre-computing it) dcg_.setDebugLevel(debugLevel_); dcg_.setThreadNumber(threadNumber_); dcg_.buildGradient(*triangulation, false, nullptr); - printMsg("Computing VPath..."); + Timer t; + + output.resize(seeds.size()); + +#ifdef TTK_ENABLE_OPENMP +#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) +#endif + for(int i = 0; i < (int) seeds.size(); i++){ + if(isForward){ + dcg_.getDescendingPath(seeds[i], output[i], *triangulation); + printMsg(" - Seed-" + + std::to_string(seeds[i].dim_) + " #" + + std::to_string(seeds[i].id_) + + ": " + + std::to_string(output[i].size()) + " item(s)."); + } + else{ + printErr("TODO!"); + } + } + + printMsg("Computed " + std::to_string(output.size()) + " v-path(s)", 1, + t.getElapsedTime(), threadNumber_); return 0; } diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 39881891cd..5b46231f88 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -270,7 +270,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), } - std::vector outputPath; + std::vector> outputPath; int status{}; ttkTemplateMacro(triangulation->getType(), From 8b1d2d89ea8bceeceb2d04ea0058b6ae42640edd Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Thu, 28 May 2026 12:20:22 +0200 Subject: [PATCH 08/46] [il-ext] vpath comments --- core/base/vpath/VPath.h | 29 +++++++++++++++---- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 11 ++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index c737b9bfdd..7be29729c5 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -45,7 +45,7 @@ namespace ttk { const triangulationType *triangulation, const std::vector &seeds, std::vector> &output, - const bool &isForward = true); + const bool &isForward = false); /** * @brief Triangulation preconditioning. @@ -101,17 +101,34 @@ int ttk::vp::VPath::execute( output.resize(seeds.size()); + /* + * NOTE: + * when considering seeds of non-zero dimension, mutliple v-paths may exist + * for a given seed. + * + * TODO: + * modify the output + * consider a pair> where SimplexId encodes the + * identifiers of the v-path going through that cell (for the given seed). + */ + #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) #endif for(int i = 0; i < (int) seeds.size(); i++){ - if(isForward){ + if(!isForward){ dcg_.getDescendingPath(seeds[i], output[i], *triangulation); - printMsg(" - Seed-" - + std::to_string(seeds[i].dim_) + " #" + +#ifdef TTK_ENABLE_OPENMP +#pragma omp critical +#endif + printMsg(" - Seed-#" + std::to_string(seeds[i].id_) - + ": " - + std::to_string(output[i].size()) + " item(s)."); + + " (dim: " + + std::to_string(seeds[i].dim_) + + "): " + + std::to_string(output[i].size()) + " item(s).", + debug::Priority::DETAIL); } else{ printErr("TODO!"); diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 5b46231f88..c90acecd2d 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -276,7 +276,16 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), ttkTemplateMacro(triangulation->getType(), status = vpath.execute( static_cast(triangulation->getData()), - seedCells, outputPath)); + seedCells, outputPath, + // isForward? + Direction == 0)); + + vtkNew pointCoords{}; + + /* NOTE: + * get the barycenter of a cell: triangulation->getCellIncenter() + * see ttkMorseSmaleComplex.cpp:305 + */ // TODO // double check ttkMorseSmaleComplex for vpath2geometry From e7f2ee0148531195194ed2c16494e82a87ee6e50 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 28 May 2026 13:38:18 +0200 Subject: [PATCH 09/46] [il-ext] vpath point set setup --- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index c90acecd2d..548ff09e68 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -280,7 +281,30 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), // isForward? Direction == 0)); + int pointNumber{0}; + for(auto &path : outputPath){ + pointNumber += path.size(); + } + vtkNew pointCoords{}; + vtkNew seedIds{}; + + pointCoords->SetNumberOfComponents(3); + pointCoords->SetNumberOfTuples(pointNumber); + int pointId = 0; + for(auto &path : outputPath){ + for(auto &c : path){ + float point[3]; + triangulation->getCellIncenter(c.id_, c.dim_, point); + pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); + pointId++; + } + } + + vtkNew pointSet{}; + pointSet->SetData(pointCoords); + output->SetPoints(pointSet); + /* NOTE: * get the barycenter of a cell: triangulation->getCellIncenter() From 65f501bf71532c8cf01704945cad1b04e9fdd927 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Thu, 28 May 2026 15:20:55 +0200 Subject: [PATCH 10/46] [il-ext] visualized output points --- core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 548ff09e68..800b973c3d 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -304,6 +304,8 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkNew pointSet{}; pointSet->SetData(pointCoords); output->SetPoints(pointSet); + printMsg("VTK output: " + + std::to_string(pointSet->GetNumberOfPoints()) + " point(s)"); /* NOTE: From f0c295f44d5a72f9f9d4f6265deeeac796385a90 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sun, 31 May 2026 09:05:44 +0200 Subject: [PATCH 11/46] [il-ext] vpath output geometry --- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 800b973c3d..c9ff317287 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -281,49 +281,67 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), // isForward? Direction == 0)); + if(status) + return status; + int pointNumber{0}; for(auto &path : outputPath){ pointNumber += path.size(); } + vtkNew outputPathGeometry; + vtkNew pointCoords{}; - vtkNew seedIds{}; + vtkNew vertexSeedId{}; + vtkNew cellSeedId{}; + vtkNew outputMaskField{}; pointCoords->SetNumberOfComponents(3); pointCoords->SetNumberOfTuples(pointNumber); + + vertexSeedId->SetNumberOfComponents(1); + vertexSeedId->SetNumberOfTuples(pointNumber); + vertexSeedId->SetName("SeedId"); + + outputMaskField->SetNumberOfComponents(1); + outputMaskField->SetNumberOfTuples(pointNumber); + outputMaskField->SetName(ttk::MaskScalarFieldName); + + cellSeedId->SetName("SeedId"); + int pointId = 0; + int pathId = 0; for(auto &path : outputPath){ for(auto &c : path){ float point[3]; triangulation->getCellIncenter(c.id_, c.dim_, point); pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); + vertexSeedId->SetTuple1(pointId, (int) seedCells[pathId].id_); + if((!pointId)||(pointId == pointNumber - 1)){ + outputMaskField->SetTuple1(pointId, 0); + } + else{ + outputMaskField->SetTuple1(pointId, 1); + } pointId++; + + if(pointId > 1){ + vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; + outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); + cellSeedId->InsertNextValue((int) seedCells[pathId].id_); + } } + pathId++; } vtkNew pointSet{}; pointSet->SetData(pointCoords); - output->SetPoints(pointSet); - printMsg("VTK output: " - + std::to_string(pointSet->GetNumberOfPoints()) + " point(s)"); - - - /* NOTE: - * get the barycenter of a cell: triangulation->getCellIncenter() - * see ttkMorseSmaleComplex.cpp:305 - */ - - // TODO - // double check ttkMorseSmaleComplex for vpath2geometry - - // this->setVertexNumber(numberOfPointsInDomain); - // this->setSeedNumber(numberOfPointsInSeeds); - // this->setDirection(Direction); - // this->setInputScalarField(inputScalars->GetVoidPointer(0)); - // this->setInputOffsets(ttkUtils::GetPointer(inputOffsets)); - // this->setVertexIdentifierScalarField(&inputIdentifiers); - // this->setOutputIntegralLines(&integralLines); - // this->preconditionTriangulation(triangulation); + outputPathGeometry->SetPoints(pointSet); + outputPathGeometry->GetPointData()->AddArray(vertexSeedId); + outputPathGeometry->GetPointData()->AddArray(outputMaskField); + outputPathGeometry->GetCellData()->AddArray(cellSeedId); + + output->ShallowCopy(outputPathGeometry); return 1; } From 288b81c2cbf3871f9f674aa914a78ffe8f284b52 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sun, 31 May 2026 09:16:26 +0200 Subject: [PATCH 12/46] [il-ext] multiple vpath geometries --- core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index c9ff317287..02a2edef3d 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -301,17 +301,21 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vertexSeedId->SetNumberOfComponents(1); vertexSeedId->SetNumberOfTuples(pointNumber); - vertexSeedId->SetName("SeedId"); + vertexSeedId->SetName("SeedIdentifier"); outputMaskField->SetNumberOfComponents(1); outputMaskField->SetNumberOfTuples(pointNumber); outputMaskField->SetName(ttk::MaskScalarFieldName); - cellSeedId->SetName("SeedId"); + cellSeedId->SetName("SeedIdentifier"); int pointId = 0; int pathId = 0; + int pathPointId = 0; for(auto &path : outputPath){ + + pathPointId = 0; + for(auto &c : path){ float point[3]; triangulation->getCellIncenter(c.id_, c.dim_, point); @@ -324,8 +328,9 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), outputMaskField->SetTuple1(pointId, 1); } pointId++; + pathPointId++; - if(pointId > 1){ + if(pathPointId > 1){ vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); cellSeedId->InsertNextValue((int) seedCells[pathId].id_); From aac12cbfbdcbb0492aa3c1b952a122c4db420f3e Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Mon, 1 Jun 2026 17:38:17 +0200 Subject: [PATCH 13/46] [il-ext] working on forks --- core/base/discreteGradient/DiscreteGradient.h | 8 ++ .../DiscreteGradient_Template.h | 114 +++++++++++++++++- core/base/vpath/VPath.h | 24 ++-- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 9 ++ 4 files changed, 143 insertions(+), 12 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient.h b/core/base/discreteGradient/DiscreteGradient.h index bf653879d1..08bd30bd47 100644 --- a/core/base/discreteGradient/DiscreteGradient.h +++ b/core/base/discreteGradient/DiscreteGradient.h @@ -436,6 +436,14 @@ user in the gradient. std::vector &vpath, const triangulationType &triangulation) const; + /** + * Return all VPath terminating at the given cell. + */ + template + int getDescendingPaths(const Cell &cell, + std::vector > &vpaths, + const triangulationType &triangulation) const; + /** * Return the VPath terminating at the given 2-saddle restricted to the 2-separatrice of the 1-saddle. diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 01e4755215..70c5600e57 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1550,7 +1550,110 @@ int DiscreteGradient::getDescendingPath( } while(connectedEdgeId != -1); } else{ - printWrn("Descending path not implemented!"); + printWrn("Descending path not implemented for this simplex dimension!"); + } + + return 0; +} + +template +int DiscreteGradient::getDescendingPaths( + const Cell &cell, + std::vector > &vpaths, + const triangulationType &triangulation) const { + + // NOTE: see claude "V-paths extraction from TTK simplices" + + int pathId = vpaths.size(); + vpaths.resize(pathId + 1); + + if(cell.dim_ == 0) { + // assume that cellId is a vertex + SimplexId currentId = cell.id_; + SimplexId connectedEdgeId; + do { + // add a vertex + const Cell vertex(0, currentId); + vpaths[pathId].push_back(vertex); + + if(isCellCritical(vertex) +#ifdef TTK_ENABLE_MPI + || triangulation.getVertexRank(currentId) != ttk::MPIrank_ +#endif + ) { + break; + } + + connectedEdgeId = getPairedCell(vertex, triangulation); + if(connectedEdgeId == -1) { + break; + } + + // add an edge + const Cell edge(1, connectedEdgeId); + vpaths[pathId].push_back(edge); + + if(isCellCritical(edge)) { + break; + } + + for(int i = 0; i < 2; ++i) { + SimplexId vertexId; + triangulation.getEdgeVertex(connectedEdgeId, i, vertexId); + + if(vertexId != currentId) { + currentId = vertexId; + break; + } + } + + } while(connectedEdgeId != -1); + } + else if(cell.dim_ == 1){ + // assume that cellId is an edge + SimplexId currentId = cell.id_; + SimplexId connectedTriangleId; + do { + // add an edge + const Cell edge(1, currentId); + vpaths[pathId].push_back(edge); + + if(isCellCritical(edge) +#ifdef TTK_ENABLE_MPI + || triangulation.getEdgeRank(currentId) != ttk::MPIrank_ +#endif + ) { + break; + } + + connectedTriangleId = getPairedCell(edge, triangulation); + if(connectedTriangleId == -1) { + break; + } + + // add a triangle + const Cell triangle(2, connectedTriangleId); + vpaths[pathId].push_back(triangle); + + if(isCellCritical(triangle)) { + break; + } + + for(int i = 0; i < 3; ++i) { + SimplexId edgeId; + triangulation.getTriangleEdge(connectedTriangleId, i, edgeId); + + if(edgeId != currentId) { + // TODO + // handle forks (multiple valid edgeId, not necessarily the first one) + currentId = edgeId; + break; + } + } + }while(connectedTriangleId != -1); + } + else{ + printWrn("Descending path not implemented for this simplex dimension!"); } return 0; @@ -1723,6 +1826,9 @@ int DiscreteGradient::getAscendingPath(const Cell &cell, // stop at convergence caused by boundary effect } while(currentId != oldId); } + else{ + printWrn("Ascending path not implemented for this simplex dimension!"); + } } else if(dimensionality_ == 3) { if(cell.dim_ == 3) { // assume that cellId is a tetra @@ -1784,6 +1890,12 @@ int DiscreteGradient::getAscendingPath(const Cell &cell, // stop at convergence caused by boundary effect } while(currentId != oldId); } + else{ + printWrn("Ascending path not implemented for this simplex dimension!"); + } + } + else{ + printWrn("Ascending path not implemented for this input dimension!"); } return 0; diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 7be29729c5..729fa226cd 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -118,21 +118,23 @@ int ttk::vp::VPath::execute( for(int i = 0; i < (int) seeds.size(); i++){ if(!isForward){ dcg_.getDescendingPath(seeds[i], output[i], *triangulation); + } + else{ + dcg_.getAscendingPath(seeds[i], output[i], *triangulation); + } #ifdef TTK_ENABLE_OPENMP #pragma omp critical #endif - printMsg(" - Seed-#" - + std::to_string(seeds[i].id_) - + " (dim: " - + std::to_string(seeds[i].dim_) - + "): " - + std::to_string(output[i].size()) + " item(s).", - debug::Priority::DETAIL); - } - else{ - printErr("TODO!"); - } + printMsg(" - Seed-#" + + std::to_string(seeds[i].id_) + + " (dim: " + + std::to_string(seeds[i].dim_) + + ", f: " + + std::to_string(isForward) + + "): " + + std::to_string(output[i].size()) + " item(s).", + debug::Priority::DETAIL); } printMsg("Computed " + std::to_string(output.size()) + " v-path(s)", 1, diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 02a2edef3d..0fc5a3fc59 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -262,6 +262,15 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), std::vector seedCells(seeds->GetNumberOfPoints()); + printf("%d cells in the seed input\n", + seeds->GetNumberOfCells()); + + /* + * TODO + * the seeds should not be retrieved from the points but from the cells. + * then, it'd be transparent (vertex or edge or triangle or tetrahedron). + */ + #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) #endif From 6b709bea371669fd2d7a056bb02c9ddc4d13f4e3 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Tue, 2 Jun 2026 14:53:54 +0200 Subject: [PATCH 14/46] [il-ext] simplex seed (vtk layer) --- core/base/discreteGradient/DiscreteGradient.h | 2 +- .../DiscreteGradient_Template.h | 28 +++++-- core/base/vpath/VPath.h | 12 +-- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 74 +++++++++---------- paraview/xmls/IntegralLines.xml | 4 +- 5 files changed, 66 insertions(+), 54 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient.h b/core/base/discreteGradient/DiscreteGradient.h index 08bd30bd47..883bac2be9 100644 --- a/core/base/discreteGradient/DiscreteGradient.h +++ b/core/base/discreteGradient/DiscreteGradient.h @@ -440,7 +440,7 @@ user in the gradient. * Return all VPath terminating at the given cell. */ template - int getDescendingPaths(const Cell &cell, + int getAllDescendingPaths(const Cell &cell, std::vector > &vpaths, const triangulationType &triangulation) const; diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 70c5600e57..2cd10ce134 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1557,7 +1557,7 @@ int DiscreteGradient::getDescendingPath( } template -int DiscreteGradient::getDescendingPaths( +int DiscreteGradient::getAllDescendingPaths( const Cell &cell, std::vector > &vpaths, const triangulationType &triangulation) const { @@ -1609,7 +1609,7 @@ int DiscreteGradient::getDescendingPaths( } while(connectedEdgeId != -1); } - else if(cell.dim_ == 1){ +/* else if(cell.dim_ == 1){ // assume that cellId is an edge SimplexId currentId = cell.id_; SimplexId connectedTriangleId; @@ -1643,15 +1643,29 @@ int DiscreteGradient::getDescendingPaths( SimplexId edgeId; triangulation.getTriangleEdge(connectedTriangleId, i, edgeId); + int nextTriangleId = -1; if(edgeId != currentId) { - // TODO - // handle forks (multiple valid edgeId, not necessarily the first one) - currentId = edgeId; - break; + + // we need to only consider edges paired with triangles + const Cell edgeOutlet(1, edgeId); + + if(isCellCritical(edgeOutlet)){ + // this is a valid outlet + currentId = edgeId; + break; + } + + nextTriangleId = getPairedCell(edgeOutlet, triangulation); + if(nextTriangleId != -1){ + // TODO + // handle forks (multiple valid edgeId, not necessarily the first one) + currentId = edgeId; + break; + } } } }while(connectedTriangleId != -1); - } + }*/ else{ printWrn("Descending path not implemented for this simplex dimension!"); } diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 729fa226cd..76397efc27 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -37,14 +37,15 @@ namespace ttk { /** * @brief Extract a vpath. * - * @param output Vector storing the output vpath. + * @param output Vector storing the output vpaths (1 entry per seed, + * with possibly multiple v-path per seed). * @param isForward Forward or backward vpath (default: forward). */ template int execute( const triangulationType *triangulation, const std::vector &seeds, - std::vector> &output, + std::vector>> &output, const bool &isForward = false); /** @@ -90,7 +91,8 @@ template int ttk::vp::VPath::execute( const triangulationType *triangulation, const std::vector &seeds, - std::vector> &output, const bool &isForward){ + std::vector>> &output, + const bool &isForward){ // fetching discrete gradient (or pre-computing it) dcg_.setDebugLevel(debugLevel_); @@ -117,10 +119,10 @@ int ttk::vp::VPath::execute( #endif for(int i = 0; i < (int) seeds.size(); i++){ if(!isForward){ - dcg_.getDescendingPath(seeds[i], output[i], *triangulation); + dcg_.getAllDescendingPaths(seeds[i], output[i], *triangulation); } else{ - dcg_.getAscendingPath(seeds[i], output[i], *triangulation); + //dcg_.getAscendingPath(seeds[i], output[i], *triangulation); } #ifdef TTK_ENABLE_OPENMP diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 0fc5a3fc59..3289566244 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -260,33 +260,24 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vpath.setInputOffsets( static_cast(ttkUtils::GetVoidPointer(inputOffsets))); - std::vector seedCells(seeds->GetNumberOfPoints()); - - printf("%d cells in the seed input\n", - seeds->GetNumberOfCells()); - - /* - * TODO - * the seeds should not be retrieved from the points but from the cells. - * then, it'd be transparent (vertex or edge or triangle or tetrahedron). - */ + std::vector seedCells(seeds->GetNumberOfCells()); #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) #endif for(int i = 0; i < (int) seedCells.size(); i++){ - seedCells[i].dim_ = 0; + vtkCell *cell = seeds->GetCell(i); + seedCells[i].dim_ = cell->GetCellDimension(); seedCells[i].id_ = identifiers[i]; } - - std::vector> outputPath; + std::vector>> outputPaths; int status{}; ttkTemplateMacro(triangulation->getType(), status = vpath.execute( static_cast(triangulation->getData()), - seedCells, outputPath, + seedCells, outputPaths, // isForward? Direction == 0)); @@ -294,8 +285,10 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), return status; int pointNumber{0}; - for(auto &path : outputPath){ - pointNumber += path.size(); + for(auto &seedPaths : outputPaths){ + for(auto &path : seedPaths){ + pointNumber += path.size(); + } } vtkNew outputPathGeometry; @@ -321,31 +314,34 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), int pointId = 0; int pathId = 0; int pathPointId = 0; - for(auto &path : outputPath){ - - pathPointId = 0; - - for(auto &c : path){ - float point[3]; - triangulation->getCellIncenter(c.id_, c.dim_, point); - pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); - vertexSeedId->SetTuple1(pointId, (int) seedCells[pathId].id_); - if((!pointId)||(pointId == pointNumber - 1)){ - outputMaskField->SetTuple1(pointId, 0); - } - else{ - outputMaskField->SetTuple1(pointId, 1); - } - pointId++; - pathPointId++; - - if(pathPointId > 1){ - vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; - outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); - cellSeedId->InsertNextValue((int) seedCells[pathId].id_); + for(auto &seedPaths : outputPaths){ + + for(auto &path : seedPaths){ + + pathPointId = 0; + + for(auto &c : path){ + float point[3]; + triangulation->getCellIncenter(c.id_, c.dim_, point); + pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); + vertexSeedId->SetTuple1(pointId, (int) seedCells[pathId].id_); + if((!pointId)||(pointId == pointNumber - 1)){ + outputMaskField->SetTuple1(pointId, 0); + } + else{ + outputMaskField->SetTuple1(pointId, 1); + } + pointId++; + pathPointId++; + + if(pathPointId > 1){ + vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; + outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); + cellSeedId->InsertNextValue((int) seedCells[pathId].id_); + } } + pathId++; } - pathId++; } vtkNew pointSet{}; diff --git a/paraview/xmls/IntegralLines.xml b/paraview/xmls/IntegralLines.xml index 754c18499c..875b271cc7 100644 --- a/paraview/xmls/IntegralLines.xml +++ b/paraview/xmls/IntegralLines.xml @@ -110,7 +110,7 @@ The sources are specified with a vtkPointSet, containing the simplices from whic - Select the vertex identifier scalar field in the sources. + Select the seed identifier scalar field in the sources. From 278f3724d7860945e516148e7a3551706707b39a Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Tue, 2 Jun 2026 16:55:58 +0200 Subject: [PATCH 15/46] [il-ext] vpath arbitrary dim, with forking --- .../DiscreteGradient_Template.h | 149 ++++++++++++++++-- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 14 +- 2 files changed, 146 insertions(+), 17 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 2cd10ce134..a252d25fcc 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1548,8 +1548,7 @@ int DiscreteGradient::getDescendingPath( } } while(connectedEdgeId != -1); - } - else{ + } else { printWrn("Descending path not implemented for this simplex dimension!"); } @@ -1558,6 +1557,133 @@ int DiscreteGradient::getDescendingPath( template int DiscreteGradient::getAllDescendingPaths( + const Cell &cell, + std::vector> &vpaths, + const triangulationType &triangulation) const { + + const int startDim = cell.dim_; + const int startId = cell.id_; + +#ifndef TTK_ENABLE_KAMIKAZE + // Validate dimension + const int maxDim = triangulation.getDimensionality(); + if(startDim < 0 || startDim > maxDim) { + return -1; // invalid dimension + } +#endif + + using VPath = std::vector; + + // Each stack frame carries the current partial path and the current simplex. + // We use DFS to enumerate all paths (branching is possible at each step). + struct Frame { + VPath partialPath; + Cell current; + }; + + std::stack stack; + + // Bootstrap: push the starting simplex onto the stack + { + Frame f; + f.current = cell; + f.partialPath.push_back(cell); + stack.push(std::move(f)); + } + + while(!stack.empty()) { + Frame frame = std::move(stack.top()); + stack.pop(); + + const Cell &curr = frame.current; + const int dim = curr.dim_; + const SimplexId id = curr.id_; + + // --- Step 1: follow the gradient arrow out of `curr` --- + // gradient.getPairedCell(dim, id) returns the id of the paired + // (dim+1)-simplex if curr is paired, or -1 if curr is critical. + const SimplexId pairedId = getPairedCell(curr, triangulation); + + if(pairedId == -1) { + // curr is a critical simplex: this path has terminated. + vpaths.push_back(frame.partialPath); + continue; + } + + // The gradient arrow takes us to a (dim+1)-simplex + const int pairedDim = dim + 1; + Cell paired; + paired.dim_ = pairedDim; + paired.id_ = pairedId; + + // Append the paired simplex to the path + frame.partialPath.push_back(paired); + + // --- Step 2: enumerate all facets of `paired` of dimension `dim` --- + // The discrete gradient arrow *entering* `paired` came from `curr`. + // We continue the path by following gradient arrows out of the OTHER + // facets of `paired` (i.e., cofacets of `paired` in dimension dim + // that are themselves paired to a simplex of dimension dim+1, + // or terminate if critical). + // + // Standard discrete Morse theory: we look at all dim-faces of `paired`, + // exclude `curr` itself, and for each remaining face that is paired + // (i.e., its gradient arrow points to some (dim+1)-simplex, not back + // to `paired`), we spawn a new path branch. + + SimplexId numFacets = 0; + if(pairedDim == 1) { + numFacets = 2; + } else if(pairedDim == 2) { + numFacets = 3; + } else if(pairedDim == 3) { + numFacets = 4; + } + + bool anyBranch = false; + + for(SimplexId f = 0; f < numFacets; ++f) { + SimplexId facetId = -1; + + if(pairedDim == 1) { + triangulation.getEdgeVertex(pairedId, f, facetId); + } else if(pairedDim == 2) { + triangulation.getTriangleEdge(pairedId, f, facetId); + } else if(pairedDim == 3) { + triangulation.getCellTriangle(pairedId, f, facetId); + } + + if(facetId == -1) + continue; + + // Skip the facet we just came from + if(facetId == id) + continue; + + // This facet is a dim-simplex; start a new branch of the V-path from it + Cell nextSimplex; + nextSimplex.dim_ = dim; + nextSimplex.id_ = facetId; + + Frame newFrame; + newFrame.partialPath = frame.partialPath; // copy current path + newFrame.partialPath.push_back(nextSimplex); + newFrame.current = nextSimplex; + stack.push(std::move(newFrame)); + anyBranch = true; + } + + // If no other facet was found (degenerate case), terminate the path here + if(!anyBranch) { + vpaths.push_back(frame.partialPath); + } + } + + return 0; // success +} + +/*template +int DiscreteGradient::getAllDescendingPathsOld( const Cell &cell, std::vector > &vpaths, const triangulationType &triangulation) const { @@ -1608,7 +1734,7 @@ int DiscreteGradient::getAllDescendingPaths( } } while(connectedEdgeId != -1); - } + }*/ /* else if(cell.dim_ == 1){ // assume that cellId is an edge SimplexId currentId = cell.id_; @@ -1658,20 +1784,20 @@ int DiscreteGradient::getAllDescendingPaths( nextTriangleId = getPairedCell(edgeOutlet, triangulation); if(nextTriangleId != -1){ // TODO - // handle forks (multiple valid edgeId, not necessarily the first one) - currentId = edgeId; - break; + // handle forks (multiple valid edgeId, not necessarily the first +one) currentId = edgeId; break; } } } }while(connectedTriangleId != -1); }*/ +/* else{ printWrn("Descending path not implemented for this simplex dimension!"); } return 0; -} +}*/ template bool DiscreteGradient::getDescendingPathThroughWall( @@ -1839,8 +1965,7 @@ int DiscreteGradient::getAscendingPath(const Cell &cell, // stop at convergence caused by boundary effect } while(currentId != oldId); - } - else{ + } else { printWrn("Ascending path not implemented for this simplex dimension!"); } } else if(dimensionality_ == 3) { @@ -1903,12 +2028,10 @@ int DiscreteGradient::getAscendingPath(const Cell &cell, // stop at convergence caused by boundary effect } while(currentId != oldId); - } - else{ + } else { printWrn("Ascending path not implemented for this simplex dimension!"); } - } - else{ + } else { printWrn("Ascending path not implemented for this input dimension!"); } diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 3289566244..34ff62ba0d 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -296,6 +296,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkNew pointCoords{}; vtkNew vertexSeedId{}; vtkNew cellSeedId{}; + vtkNew cellForkId{}; vtkNew outputMaskField{}; pointCoords->SetNumberOfComponents(3); @@ -310,12 +311,14 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), outputMaskField->SetName(ttk::MaskScalarFieldName); cellSeedId->SetName("SeedIdentifier"); + cellForkId->SetName("ForkIdentifier"); int pointId = 0; - int pathId = 0; + int localSeedId = 0; int pathPointId = 0; for(auto &seedPaths : outputPaths){ + int forkId = 0; for(auto &path : seedPaths){ pathPointId = 0; @@ -324,7 +327,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), float point[3]; triangulation->getCellIncenter(c.id_, c.dim_, point); pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); - vertexSeedId->SetTuple1(pointId, (int) seedCells[pathId].id_); + vertexSeedId->SetTuple1(pointId, (int) seedCells[localSeedId].id_); if((!pointId)||(pointId == pointNumber - 1)){ outputMaskField->SetTuple1(pointId, 0); } @@ -337,11 +340,13 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), if(pathPointId > 1){ vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); - cellSeedId->InsertNextValue((int) seedCells[pathId].id_); + cellSeedId->InsertNextValue((int) seedCells[localSeedId].id_); + cellForkId->InsertNextValue((int) forkId); } } - pathId++; + forkId++; } + localSeedId++; } vtkNew pointSet{}; @@ -350,6 +355,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), outputPathGeometry->GetPointData()->AddArray(vertexSeedId); outputPathGeometry->GetPointData()->AddArray(outputMaskField); outputPathGeometry->GetCellData()->AddArray(cellSeedId); + outputPathGeometry->GetCellData()->AddArray(cellForkId); output->ShallowCopy(outputPathGeometry); From b1603226b5c651a5e028a96536cb17270e51be9a Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Tue, 2 Jun 2026 17:26:29 +0200 Subject: [PATCH 16/46] [il-ext] added extra vpath fields --- core/base/vpath/VPath.h | 3 ++- core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 14 ++++++++++++++ paraview/xmls/IntegralLines.xml | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 76397efc27..e09e7dfb8c 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -139,7 +139,8 @@ int ttk::vp::VPath::execute( debug::Priority::DETAIL); } - printMsg("Computed " + std::to_string(output.size()) + " v-path(s)", 1, + printMsg("Computed v-path(s) from " + + std::to_string(output.size()) + " seed(s)", 1, t.getElapsedTime(), threadNumber_); return 0; diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 34ff62ba0d..658befc31a 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -297,6 +297,8 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkNew vertexSeedId{}; vtkNew cellSeedId{}; vtkNew cellForkId{}; + vtkNew vertexSimplexId{}; + vtkNew vertexSimplexDimension{}; vtkNew outputMaskField{}; pointCoords->SetNumberOfComponents(3); @@ -306,6 +308,14 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vertexSeedId->SetNumberOfTuples(pointNumber); vertexSeedId->SetName("SeedIdentifier"); + vertexSimplexId->SetNumberOfComponents(1); + vertexSimplexId->SetNumberOfTuples(pointNumber); + vertexSimplexId->SetName("SimplexIdentifier"); + + vertexSimplexDimension->SetNumberOfComponents(1); + vertexSimplexDimension->SetNumberOfTuples(pointNumber); + vertexSimplexDimension->SetName("SimplexDimension"); + outputMaskField->SetNumberOfComponents(1); outputMaskField->SetNumberOfTuples(pointNumber); outputMaskField->SetName(ttk::MaskScalarFieldName); @@ -328,6 +338,8 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), triangulation->getCellIncenter(c.id_, c.dim_, point); pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); vertexSeedId->SetTuple1(pointId, (int) seedCells[localSeedId].id_); + vertexSimplexId->SetTuple1(pointId, (int) c.id_); + vertexSimplexDimension->SetTuple1(pointId, (int) c.dim_); if((!pointId)||(pointId == pointNumber - 1)){ outputMaskField->SetTuple1(pointId, 0); } @@ -354,6 +366,8 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), outputPathGeometry->SetPoints(pointSet); outputPathGeometry->GetPointData()->AddArray(vertexSeedId); outputPathGeometry->GetPointData()->AddArray(outputMaskField); + outputPathGeometry->GetPointData()->AddArray(vertexSimplexId); + outputPathGeometry->GetPointData()->AddArray(vertexSimplexDimension); outputPathGeometry->GetCellData()->AddArray(cellSeedId); outputPathGeometry->GetCellData()->AddArray(cellForkId); diff --git a/paraview/xmls/IntegralLines.xml b/paraview/xmls/IntegralLines.xml index 875b271cc7..19b93cf4e5 100644 --- a/paraview/xmls/IntegralLines.xml +++ b/paraview/xmls/IntegralLines.xml @@ -205,6 +205,9 @@ plateaus). default_values="0" panel_visibility="advanced"> + + + Enables forking when the integral line comes accross a saddle vertex. In that case, it will spawn as many new integral lines as there are From a388156818d79f0d776a4484112e227b4cde35b6 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Tue, 2 Jun 2026 17:46:00 +0200 Subject: [PATCH 17/46] [il-ext] vpath cleanup --- .../DiscreteGradient_Template.h | 120 ------------------ core/base/vpath/VPath.h | 7 +- 2 files changed, 1 insertion(+), 126 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index a252d25fcc..4a5cedc7e2 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1561,9 +1561,6 @@ int DiscreteGradient::getAllDescendingPaths( std::vector> &vpaths, const triangulationType &triangulation) const { - const int startDim = cell.dim_; - const int startId = cell.id_; - #ifndef TTK_ENABLE_KAMIKAZE // Validate dimension const int maxDim = triangulation.getDimensionality(); @@ -1682,123 +1679,6 @@ int DiscreteGradient::getAllDescendingPaths( return 0; // success } -/*template -int DiscreteGradient::getAllDescendingPathsOld( - const Cell &cell, - std::vector > &vpaths, - const triangulationType &triangulation) const { - - // NOTE: see claude "V-paths extraction from TTK simplices" - - int pathId = vpaths.size(); - vpaths.resize(pathId + 1); - - if(cell.dim_ == 0) { - // assume that cellId is a vertex - SimplexId currentId = cell.id_; - SimplexId connectedEdgeId; - do { - // add a vertex - const Cell vertex(0, currentId); - vpaths[pathId].push_back(vertex); - - if(isCellCritical(vertex) -#ifdef TTK_ENABLE_MPI - || triangulation.getVertexRank(currentId) != ttk::MPIrank_ -#endif - ) { - break; - } - - connectedEdgeId = getPairedCell(vertex, triangulation); - if(connectedEdgeId == -1) { - break; - } - - // add an edge - const Cell edge(1, connectedEdgeId); - vpaths[pathId].push_back(edge); - - if(isCellCritical(edge)) { - break; - } - - for(int i = 0; i < 2; ++i) { - SimplexId vertexId; - triangulation.getEdgeVertex(connectedEdgeId, i, vertexId); - - if(vertexId != currentId) { - currentId = vertexId; - break; - } - } - - } while(connectedEdgeId != -1); - }*/ -/* else if(cell.dim_ == 1){ - // assume that cellId is an edge - SimplexId currentId = cell.id_; - SimplexId connectedTriangleId; - do { - // add an edge - const Cell edge(1, currentId); - vpaths[pathId].push_back(edge); - - if(isCellCritical(edge) -#ifdef TTK_ENABLE_MPI - || triangulation.getEdgeRank(currentId) != ttk::MPIrank_ -#endif - ) { - break; - } - - connectedTriangleId = getPairedCell(edge, triangulation); - if(connectedTriangleId == -1) { - break; - } - - // add a triangle - const Cell triangle(2, connectedTriangleId); - vpaths[pathId].push_back(triangle); - - if(isCellCritical(triangle)) { - break; - } - - for(int i = 0; i < 3; ++i) { - SimplexId edgeId; - triangulation.getTriangleEdge(connectedTriangleId, i, edgeId); - - int nextTriangleId = -1; - if(edgeId != currentId) { - - // we need to only consider edges paired with triangles - const Cell edgeOutlet(1, edgeId); - - if(isCellCritical(edgeOutlet)){ - // this is a valid outlet - currentId = edgeId; - break; - } - - nextTriangleId = getPairedCell(edgeOutlet, triangulation); - if(nextTriangleId != -1){ - // TODO - // handle forks (multiple valid edgeId, not necessarily the first -one) currentId = edgeId; break; - } - } - } - }while(connectedTriangleId != -1); - }*/ -/* - else{ - printWrn("Descending path not implemented for this simplex dimension!"); - } - - return 0; -}*/ - template bool DiscreteGradient::getDescendingPathThroughWall( const Cell &saddle2, diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index e09e7dfb8c..188f23c932 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -107,11 +107,6 @@ int ttk::vp::VPath::execute( * NOTE: * when considering seeds of non-zero dimension, mutliple v-paths may exist * for a given seed. - * - * TODO: - * modify the output - * consider a pair> where SimplexId encodes the - * identifiers of the v-path going through that cell (for the given seed). */ #ifdef TTK_ENABLE_OPENMP @@ -135,7 +130,7 @@ int ttk::vp::VPath::execute( + ", f: " + std::to_string(isForward) + "): " - + std::to_string(output[i].size()) + " item(s).", + + std::to_string(output[i].size()) + " path(s).", debug::Priority::DETAIL); } From c5af6f25a4418a49000a5b052f3bef23c8d2200d Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Wed, 3 Jun 2026 16:44:51 +0200 Subject: [PATCH 18/46] [il-ext] vpath refactor --- core/base/discreteGradient/DiscreteGradient.h | 8 ++ .../DiscreteGradient_Template.h | 81 ++++++++++--------- core/base/vpath/VPath.h | 2 +- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient.h b/core/base/discreteGradient/DiscreteGradient.h index 883bac2be9..e898966323 100644 --- a/core/base/discreteGradient/DiscreteGradient.h +++ b/core/base/discreteGradient/DiscreteGradient.h @@ -428,6 +428,14 @@ user in the gradient. const triangulationType &triangulation, const bool enableCycleDetector = false) const; + /** + * Return all VPath coming from the given cell. + */ + template + int getAllAscendingPaths(const Cell &cell, + std::vector > &vpaths, + const triangulationType &triangulation) const; + /** * Return the VPath terminating at the given cell. */ diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 4a5cedc7e2..12f5e2a07e 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1561,70 +1561,61 @@ int DiscreteGradient::getAllDescendingPaths( std::vector> &vpaths, const triangulationType &triangulation) const { -#ifndef TTK_ENABLE_KAMIKAZE - // Validate dimension - const int maxDim = triangulation.getDimensionality(); - if(startDim < 0 || startDim > maxDim) { - return -1; // invalid dimension - } -#endif + vpaths.clear(); using VPath = std::vector; - // Each stack frame carries the current partial path and the current simplex. + // Each stack entry carries the current partial path and the current simplex. // We use DFS to enumerate all paths (branching is possible at each step). - struct Frame { - VPath partialPath; - Cell current; + struct StackEntry { + VPath partialPath_; + Cell currentCell_; }; - std::stack stack; + std::stack stack; // Bootstrap: push the starting simplex onto the stack { - Frame f; - f.current = cell; - f.partialPath.push_back(cell); - stack.push(std::move(f)); + StackEntry stackEntry; + stackEntry.currentCell_ = cell; + stackEntry.partialPath_.push_back(cell); + stack.push(std::move(stackEntry)); } while(!stack.empty()) { - Frame frame = std::move(stack.top()); + + StackEntry stackEntry = std::move(stack.top()); stack.pop(); - const Cell &curr = frame.current; - const int dim = curr.dim_; - const SimplexId id = curr.id_; + const Cell ¤tCell = stackEntry.currentCell_; - // --- Step 1: follow the gradient arrow out of `curr` --- - // gradient.getPairedCell(dim, id) returns the id of the paired - // (dim+1)-simplex if curr is paired, or -1 if curr is critical. - const SimplexId pairedId = getPairedCell(curr, triangulation); + // 1. Follow the gradient arrow out of `currentCell` + const SimplexId pairedId = getPairedCell(currentCell, triangulation); if(pairedId == -1) { - // curr is a critical simplex: this path has terminated. - vpaths.push_back(frame.partialPath); + // currentCell is a critical simplex: this path has terminated. + vpaths.push_back(stackEntry.partialPath_); continue; } // The gradient arrow takes us to a (dim+1)-simplex - const int pairedDim = dim + 1; + const int pairedDim = currentCell.dim_ + 1; Cell paired; paired.dim_ = pairedDim; paired.id_ = pairedId; // Append the paired simplex to the path - frame.partialPath.push_back(paired); + stackEntry.partialPath_.push_back(paired); - // --- Step 2: enumerate all facets of `paired` of dimension `dim` --- - // The discrete gradient arrow *entering* `paired` came from `curr`. + // 2. Enumerate all facets of `paired` of dimension `dim` + // The discrete gradient arrow *entering* `paired` came from `currentCell`. // We continue the path by following gradient arrows out of the OTHER // facets of `paired` (i.e., cofacets of `paired` in dimension dim // that are themselves paired to a simplex of dimension dim+1, // or terminate if critical). // // Standard discrete Morse theory: we look at all dim-faces of `paired`, - // exclude `curr` itself, and for each remaining face that is paired + // exclude `currentCell` itself, and for each remaining face that is paired // (i.e., its gradient arrow points to some (dim+1)-simplex, not back // to `paired`), we spawn a new path branch. @@ -1654,29 +1645,30 @@ int DiscreteGradient::getAllDescendingPaths( continue; // Skip the facet we just came from - if(facetId == id) + if(facetId == currentCell.id_) continue; // This facet is a dim-simplex; start a new branch of the V-path from it Cell nextSimplex; - nextSimplex.dim_ = dim; + nextSimplex.dim_ = currentCell.dim_; nextSimplex.id_ = facetId; - Frame newFrame; - newFrame.partialPath = frame.partialPath; // copy current path - newFrame.partialPath.push_back(nextSimplex); - newFrame.current = nextSimplex; - stack.push(std::move(newFrame)); + StackEntry newStackEntry; + // copy currentCellentCell_ path + newStackEntry.partialPath_ = stackEntry.partialPath_; + newStackEntry.partialPath_.push_back(nextSimplex); + newStackEntry.currentCell_ = nextSimplex; + stack.push(std::move(newStackEntry)); anyBranch = true; } // If no other facet was found (degenerate case), terminate the path here if(!anyBranch) { - vpaths.push_back(frame.partialPath); + vpaths.push_back(stackEntry.partialPath_); } } - return 0; // success + return 0; } template @@ -1918,6 +1910,15 @@ int DiscreteGradient::getAscendingPath(const Cell &cell, return 0; } +template + int DiscreteGradient::getAllAscendingPaths(const Cell &cell, + std::vector > &vpaths, + const triangulationType &triangulation) const{ + + + return 0; +} + template bool DiscreteGradient::getAscendingPathThroughWall( const Cell &saddle1, diff --git a/core/base/vpath/VPath.h b/core/base/vpath/VPath.h index 188f23c932..d2f5243b42 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpath/VPath.h @@ -117,7 +117,7 @@ int ttk::vp::VPath::execute( dcg_.getAllDescendingPaths(seeds[i], output[i], *triangulation); } else{ - //dcg_.getAscendingPath(seeds[i], output[i], *triangulation); + dcg_.getAllAscendingPaths(seeds[i], output[i], *triangulation); } #ifdef TTK_ENABLE_OPENMP From 5938f4fe35318e5b6a66c4ba3045fd4b52e96c23 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Fri, 5 Jun 2026 17:32:45 +0200 Subject: [PATCH 19/46] [il-ext] all backward v-paths from a simplex --- .../DiscreteGradient_Template.h | 349 +++++++++++++++++- 1 file changed, 347 insertions(+), 2 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 12f5e2a07e..d0c21ac959 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1563,12 +1563,12 @@ int DiscreteGradient::getAllDescendingPaths( vpaths.clear(); - using VPath = std::vector; + using vPath = std::vector; // Each stack entry carries the current partial path and the current simplex. // We use DFS to enumerate all paths (branching is possible at each step). struct StackEntry { - VPath partialPath_; + vPath partialPath_; Cell currentCell_; }; @@ -1915,10 +1915,355 @@ template std::vector > &vpaths, const triangulationType &triangulation) const{ + vpaths.clear(); + + using vPath = std::vector; + + struct StackEntry { + vPath partialPath_; + Cell currentCell_; + }; + + std::stack stack; + + { + StackEntry stackEntry; + stackEntry.currentCell_ = cell; + stackEntry.partialPath_.push_back(cell); + stack.push(std::move(stackEntry)); + } + + while(!stack.empty()) { + + StackEntry stackEntry = std::move(stack.top()); + stack.pop(); + + printf("popping edge %d\n", + stackEntry.currentCell_.id_); + + const Cell ¤tCell = stackEntry.currentCell_; + const SimplexId pairedCofacetId = getPairedCell(currentCell, triangulation); + + if(isCellCritical(currentCell)){ + // currentCell is a critical simplex: this path has terminated. + // the simplex has already been added to the stack path + vpaths.push_back(stackEntry.partialPath_); + continue; + } + + if(currentCell.dim_ != cell.dim_) + continue; + + // check all cofacets + int cofacetNumber = -1; + + switch(currentCell.dim_){ + case 1: + cofacetNumber = triangulation.getEdgeTriangleNumber(currentCell.id_); + break; + case 2: + cofacetNumber = triangulation.getTriangleStarNumber(currentCell.id_); + break; + default: + cofacetNumber = triangulation.getVertexEdgeNumber(currentCell.id_); + break; + } + + bool hasBranched = false; + + for(int i = 0; i < cofacetNumber; i++){ + int cofacetId = -1; + switch(currentCell.dim_){ + case 1: + triangulation.getEdgeTriangle(currentCell.id_, i, cofacetId); + break; + case 2: + triangulation.getTriangleStar(currentCell.id_, i, cofacetId); + break; + default: + triangulation.getVertexEdge(currentCell.id_, i, cofacetId); + break; + } + if(cofacetId != pairedCofacetId){ + + printf(" going for triangle %d\n", cofacetId); + + // we don't want to go down the v-path, we want to go backwards + Cell cofacet; + cofacet.dim_ = currentCell.dim_ + 1; + cofacet.id_ = cofacetId; + + stackEntry.partialPath_.push_back(cofacet); + + StackEntry newStackEntry; + newStackEntry.partialPath_ = stackEntry.partialPath_; + newStackEntry.currentCell_ = cofacet; + + // now find the simplex we came from + int simplexNumber = -1; + + simplexNumber = cofacet.dim_ + 1; + + for(int j = 0; j < simplexNumber; j++){ + SimplexId simplexId = -1; + switch(cofacet.dim_){ + case 1: + triangulation.getEdgeVertex(cofacet.id_, j, simplexId); + break; + case 2: + triangulation.getTriangleEdge(cofacet.id_, j, simplexId); + break; + default: + triangulation.getCellTriangle(cofacet.id_, j, simplexId); + break; + } + + Cell simplex; + simplex.id_ = simplexId; + simplex.dim_ = cofacet.dim_ - 1; + const SimplexId simplexPair = getPairedCell(simplex, triangulation); + + if(isCellCritical(simplex)){ + printf(" edge %d is critical\n", simplex.id_); + } + + if(simplexPair == cofacet.id_){ + printf(" edge %d was paired to our triangle (%d)\n", + simplex.id_, simplexPair); + } + + if((simplexPair == cofacet.id_)||(isCellCritical(simplex))){ + // we found the simplex that was paired the cofacet + // or a critical simplex + newStackEntry.partialPath_.push_back(simplex); + newStackEntry.currentCell_ = simplex; + hasBranched = true; + } + } + + stack.push(std::move(newStackEntry)); + } + + if(!hasBranched){ + vpaths.push_back(stackEntry.partialPath_); + } + } + } return 0; } +/* +template + int DiscreteGradient::getAllAscendingPaths(const Cell &cell, + std::vector > &vpaths, + const triangulationType &triangulation) const{ + + using VPath = std::vector; + + vpaths.clear(); + + Cell target = cell; + + const int d = target.dim_; // dimension of the target simplex + + // ----------------------------------------------------------------------- + // Helper: given a (d)-simplex `facet`, walk backward along the gradient + // and collect every complete V-path that arrives at `facet`. + // We use an explicit stack to avoid recursion on large meshes. + // + // Stack entry: (partial path so far, current frontier facet of dim d) + // ----------------------------------------------------------------------- + using StackEntry = std::pair; + + // Collect cofacets of a d-cell (returns cells of dimension d+1) + auto getCofacets = [&](const Cell &localCell, std::vector &cofacets) + { + cofacets.clear(); + const SimplexId nCofacets = [&]() -> SimplexId { + switch(localCell.dim_) { + case 0: return triangulation.getVertexEdgeNumber(localCell.id_); + case 1: return triangulation.getEdgeTriangleNumber(localCell.id_); + case 2: return triangulation.getTriangleStarNumber(localCell.id_); + default: return 0; + } + }(); + + + + for(SimplexId i = 0; i < nCofacets; ++i) { + SimplexId cofacetId = -1; + switch(localCell.dim_) { + case 0: triangulation.getVertexEdge(localCell.id_, i, cofacetId); break; + case 1: triangulation.getEdgeTriangle(localCell.id_, i, cofacetId); break; + case 2: triangulation.getTriangleStar(localCell.id_, i, cofacetId); break; + default: break; + } + if(cofacetId != -1) + cofacets.emplace_back(localCell.dim_ + 1, cofacetId); + } + }; + + // ----------------------------------------------------------------------- + // Seed: iterate over every cofacet C of `target` (dim d+1). + // If gradient pairs C → target, then target is reachable from C. + // We initialise one stack entry per such cofacet. + // ----------------------------------------------------------------------- + std::vector targetCofacets; + getCofacets(target, targetCofacets); + + printMsg("cell #" + std::to_string(target.id_) + + " d=" + std::to_string(target.dim_) + + " has " + std::to_string(targetCofacets.size()) + + " cofacet(s)"); + + std::stack stack; + + for(const Cell &cofacet : targetCofacets) { + // Check whether the gradient arrow of `cofacet` points to `target` + + printMsg(" Considering cofacet #" + std::to_string(cofacet.id_) + + "," + std::to_string(cofacet.dim_)); + Cell pairedFacet{}; + const SimplexId pairedFacetId = getPairedCell(cofacet, triangulation, true); + printMsg(" paired edgeId: #" + std::to_string(pairedFacetId)); + if(pairedFacetId == -1) + continue; // cofacet is unpaired (critical) — it does not yield a path to target this way + + pairedFacet.dim_ = cofacet.dim_ - 1; + pairedFacet.id_ = pairedFacetId; + + if(pairedFacet.dim_ != target.dim_ || pairedFacet.id_ == target.id_) + continue; // arrow points elsewhere + + printMsg(" -> start a path on triangle #" + + std::to_string(cofacet.id_)); + // Seed a new partial path: [cofacet, target] + // We will prepend cells as we walk backward, so store in reverse for now. + VPath partialPath = {cofacet, target}; + stack.push({partialPath, cofacet}); + } + + // ----------------------------------------------------------------------- + // Backward traversal + // ----------------------------------------------------------------------- + std::vector cofacetsBuf; + + while(!stack.empty()) { + auto [path, currentHighCell] = stack.top(); + stack.pop(); + + // `currentHighCell` has dimension d+1. + // We need all (d+1)-simplices S' such that gradient[S'] points to a + // facet F' of S', and S' in turn is a cofacet of F' which is itself + // a cofacet of some lower cell — i.e. we look one step further back. + // + // Concretely: the *source* of the arrow into currentHighCell is the + // unique facet F such that gradient[currentHighCell] = F (already + // stored as target or the last facet pushed). To go *further back* + // we need all (d+1)-simplices whose gradient arrow lands on some facet + // that has currentHighCell as a cofacet. This is a two-step look-up: + // (a) Facets of currentHighCell (dimension d) + // (b) For each such facet F, cofacets of F (dimension d+1) = {S'} + // (c) Keep S' where getPairedCell(S') == F + + // Collect facets of currentHighCell + const SimplexId nFacets = [&]() -> SimplexId { + switch(currentHighCell.dim_) { + case 1: return triangulation.getEdgeStarNumber(currentHighCell.id_); // wrong — use facet API below + default: break; + } + // Use dimension-appropriate facet count + switch(currentHighCell.dim_) { + case 1: return 2; // edge has 2 vertices + case 2: return 3; // triangle has 3 edges + case 3: return 4; // tet has 4 triangles + default: return 0; + } + }(); + + auto getFacetId = [&](const Cell &highCell, SimplexId i, SimplexId &facetId) { + facetId = -1; + switch(highCell.dim_) { + case 1: triangulation.getEdgeVertex(highCell.id_, i, facetId); break; + case 2: triangulation.getTriangleEdge(highCell.id_, i, facetId); break; + case 3: triangulation.getCellTriangle(highCell.id_, i, facetId); break; + default: break; + } + }; + + bool extended = false; + + for(SimplexId fi = 0; fi < nFacets; ++fi) { + SimplexId facetId = -1; + getFacetId(currentHighCell, fi, facetId); + if(facetId == -1) continue; + + printMsg(" considering edge #" + + std::to_string(facetId)); + + Cell facetCell{d, facetId}; + + // Skip the facet that the current arrow already points to + // (that is `path.back()`, the cell we already came from) + if(facetId == path.back().id_ || d != path.back().dim_) + continue; + + // For each cofacet S' of facetCell (dim d+1), check if gradient[S'] == facetCell + getCofacets(facetCell, cofacetsBuf); + + printMsg(" -> " + std::to_string(cofacetsBuf.size()) + " triangle(s)"); + + for(const Cell &candidate : cofacetsBuf) { + + printMsg(" |-> considering triangle #" + + std::to_string(candidate.id_)); + + if(candidate.id_ == currentHighCell.id_) continue; // don't go back + + const SimplexId pairedCofacetId = getPairedCell(facetCell, triangulation); + + // we only continue if the considered simplex is paired with the cofacet + // we're coming from + if(pairedCofacetId != currentHighCell.id_) continue; + + Cell paired{}; + const SimplexId pairedId = getPairedCell(candidate, triangulation, true); + if(pairedId == -1) continue; + + paired.id_ = pairedId; + paired.dim_ = candidate.dim_ - 1; + + printMsg(" is paired with edge " + std::to_string(pairedId)); + + if(paired.dim_ == d && paired.id_ == facetId) { + // Found a predecessor: candidate → facetCell → currentHighCell + VPath newPath = path; + // Prepend: candidate then facetCell (we are walking backward) + newPath.insert(newPath.begin(), facetCell); + newPath.insert(newPath.begin(), candidate); + + stack.push({newPath, candidate}); + extended = true; + + if(stack.size() == 10) + return 0; + } + } + } + + if(!extended) { + // No further predecessor: `currentHighCell` is a critical (d+1)-cell. + // The path is complete. Reverse so it reads source → … → target. + VPath completePath = path; + std::reverse(completePath.begin(), completePath.end()); + vpaths.push_back(std::move(completePath)); + } + } + + return 0; +}*/ + template bool DiscreteGradient::getAscendingPathThroughWall( const Cell &saddle1, From 96169e7e1d4ce4a72e5b6ee4419f68cd14db3d24 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Fri, 5 Jun 2026 17:56:17 +0200 Subject: [PATCH 20/46] [il-ext] backward vpath bug --- .../DiscreteGradient_Template.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index d0c21ac959..9039d888a7 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1969,7 +1969,7 @@ template break; } - bool hasBranched = false; + bool hasProgressed = false; for(int i = 0; i < cofacetNumber; i++){ int cofacetId = -1; @@ -1993,10 +1993,9 @@ template cofacet.dim_ = currentCell.dim_ + 1; cofacet.id_ = cofacetId; - stackEntry.partialPath_.push_back(cofacet); - StackEntry newStackEntry; newStackEntry.partialPath_ = stackEntry.partialPath_; + newStackEntry.partialPath_.push_back(cofacet); newStackEntry.currentCell_ = cofacet; // now find the simplex we came from @@ -2037,17 +2036,17 @@ template // or a critical simplex newStackEntry.partialPath_.push_back(simplex); newStackEntry.currentCell_ = simplex; - hasBranched = true; + stack.push(std::move(newStackEntry)); + hasProgressed = true; } } - - stack.push(std::move(newStackEntry)); - } - - if(!hasBranched){ - vpaths.push_back(stackEntry.partialPath_); } } + if(!hasProgressed){ + // example: boundary edge paired with its interior cofacet, we stop the + // backward vpath here. + vpaths.push_back(stackEntry.partialPath_); + } } return 0; From d94c25a20b5487834f8aa947fa7411933dbac45c Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Fri, 5 Jun 2026 19:08:42 +0200 Subject: [PATCH 21/46] [il-ext] notes on discrete gradient --- .../DiscreteGradient_Template.h | 216 +----------------- 1 file changed, 5 insertions(+), 211 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 9039d888a7..14c9e0fd1c 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1915,6 +1915,11 @@ template std::vector > &vpaths, const triangulationType &triangulation) const{ + /* + * NOTE + * Looks good in 2D. Needs further tests in 3D. + */ + vpaths.clear(); using vPath = std::vector; @@ -2052,217 +2057,6 @@ template return 0; } -/* -template - int DiscreteGradient::getAllAscendingPaths(const Cell &cell, - std::vector > &vpaths, - const triangulationType &triangulation) const{ - - using VPath = std::vector; - - vpaths.clear(); - - Cell target = cell; - - const int d = target.dim_; // dimension of the target simplex - - // ----------------------------------------------------------------------- - // Helper: given a (d)-simplex `facet`, walk backward along the gradient - // and collect every complete V-path that arrives at `facet`. - // We use an explicit stack to avoid recursion on large meshes. - // - // Stack entry: (partial path so far, current frontier facet of dim d) - // ----------------------------------------------------------------------- - using StackEntry = std::pair; - - // Collect cofacets of a d-cell (returns cells of dimension d+1) - auto getCofacets = [&](const Cell &localCell, std::vector &cofacets) - { - cofacets.clear(); - const SimplexId nCofacets = [&]() -> SimplexId { - switch(localCell.dim_) { - case 0: return triangulation.getVertexEdgeNumber(localCell.id_); - case 1: return triangulation.getEdgeTriangleNumber(localCell.id_); - case 2: return triangulation.getTriangleStarNumber(localCell.id_); - default: return 0; - } - }(); - - - - for(SimplexId i = 0; i < nCofacets; ++i) { - SimplexId cofacetId = -1; - switch(localCell.dim_) { - case 0: triangulation.getVertexEdge(localCell.id_, i, cofacetId); break; - case 1: triangulation.getEdgeTriangle(localCell.id_, i, cofacetId); break; - case 2: triangulation.getTriangleStar(localCell.id_, i, cofacetId); break; - default: break; - } - if(cofacetId != -1) - cofacets.emplace_back(localCell.dim_ + 1, cofacetId); - } - }; - - // ----------------------------------------------------------------------- - // Seed: iterate over every cofacet C of `target` (dim d+1). - // If gradient pairs C → target, then target is reachable from C. - // We initialise one stack entry per such cofacet. - // ----------------------------------------------------------------------- - std::vector targetCofacets; - getCofacets(target, targetCofacets); - - printMsg("cell #" + std::to_string(target.id_) - + " d=" + std::to_string(target.dim_) - + " has " + std::to_string(targetCofacets.size()) - + " cofacet(s)"); - - std::stack stack; - - for(const Cell &cofacet : targetCofacets) { - // Check whether the gradient arrow of `cofacet` points to `target` - - printMsg(" Considering cofacet #" + std::to_string(cofacet.id_) - + "," + std::to_string(cofacet.dim_)); - Cell pairedFacet{}; - const SimplexId pairedFacetId = getPairedCell(cofacet, triangulation, true); - printMsg(" paired edgeId: #" + std::to_string(pairedFacetId)); - if(pairedFacetId == -1) - continue; // cofacet is unpaired (critical) — it does not yield a path to target this way - - pairedFacet.dim_ = cofacet.dim_ - 1; - pairedFacet.id_ = pairedFacetId; - - if(pairedFacet.dim_ != target.dim_ || pairedFacet.id_ == target.id_) - continue; // arrow points elsewhere - - printMsg(" -> start a path on triangle #" - + std::to_string(cofacet.id_)); - // Seed a new partial path: [cofacet, target] - // We will prepend cells as we walk backward, so store in reverse for now. - VPath partialPath = {cofacet, target}; - stack.push({partialPath, cofacet}); - } - - // ----------------------------------------------------------------------- - // Backward traversal - // ----------------------------------------------------------------------- - std::vector cofacetsBuf; - - while(!stack.empty()) { - auto [path, currentHighCell] = stack.top(); - stack.pop(); - - // `currentHighCell` has dimension d+1. - // We need all (d+1)-simplices S' such that gradient[S'] points to a - // facet F' of S', and S' in turn is a cofacet of F' which is itself - // a cofacet of some lower cell — i.e. we look one step further back. - // - // Concretely: the *source* of the arrow into currentHighCell is the - // unique facet F such that gradient[currentHighCell] = F (already - // stored as target or the last facet pushed). To go *further back* - // we need all (d+1)-simplices whose gradient arrow lands on some facet - // that has currentHighCell as a cofacet. This is a two-step look-up: - // (a) Facets of currentHighCell (dimension d) - // (b) For each such facet F, cofacets of F (dimension d+1) = {S'} - // (c) Keep S' where getPairedCell(S') == F - - // Collect facets of currentHighCell - const SimplexId nFacets = [&]() -> SimplexId { - switch(currentHighCell.dim_) { - case 1: return triangulation.getEdgeStarNumber(currentHighCell.id_); // wrong — use facet API below - default: break; - } - // Use dimension-appropriate facet count - switch(currentHighCell.dim_) { - case 1: return 2; // edge has 2 vertices - case 2: return 3; // triangle has 3 edges - case 3: return 4; // tet has 4 triangles - default: return 0; - } - }(); - - auto getFacetId = [&](const Cell &highCell, SimplexId i, SimplexId &facetId) { - facetId = -1; - switch(highCell.dim_) { - case 1: triangulation.getEdgeVertex(highCell.id_, i, facetId); break; - case 2: triangulation.getTriangleEdge(highCell.id_, i, facetId); break; - case 3: triangulation.getCellTriangle(highCell.id_, i, facetId); break; - default: break; - } - }; - - bool extended = false; - - for(SimplexId fi = 0; fi < nFacets; ++fi) { - SimplexId facetId = -1; - getFacetId(currentHighCell, fi, facetId); - if(facetId == -1) continue; - - printMsg(" considering edge #" - + std::to_string(facetId)); - - Cell facetCell{d, facetId}; - - // Skip the facet that the current arrow already points to - // (that is `path.back()`, the cell we already came from) - if(facetId == path.back().id_ || d != path.back().dim_) - continue; - - // For each cofacet S' of facetCell (dim d+1), check if gradient[S'] == facetCell - getCofacets(facetCell, cofacetsBuf); - - printMsg(" -> " + std::to_string(cofacetsBuf.size()) + " triangle(s)"); - - for(const Cell &candidate : cofacetsBuf) { - - printMsg(" |-> considering triangle #" + - std::to_string(candidate.id_)); - - if(candidate.id_ == currentHighCell.id_) continue; // don't go back - - const SimplexId pairedCofacetId = getPairedCell(facetCell, triangulation); - - // we only continue if the considered simplex is paired with the cofacet - // we're coming from - if(pairedCofacetId != currentHighCell.id_) continue; - - Cell paired{}; - const SimplexId pairedId = getPairedCell(candidate, triangulation, true); - if(pairedId == -1) continue; - - paired.id_ = pairedId; - paired.dim_ = candidate.dim_ - 1; - - printMsg(" is paired with edge " + std::to_string(pairedId)); - - if(paired.dim_ == d && paired.id_ == facetId) { - // Found a predecessor: candidate → facetCell → currentHighCell - VPath newPath = path; - // Prepend: candidate then facetCell (we are walking backward) - newPath.insert(newPath.begin(), facetCell); - newPath.insert(newPath.begin(), candidate); - - stack.push({newPath, candidate}); - extended = true; - - if(stack.size() == 10) - return 0; - } - } - } - - if(!extended) { - // No further predecessor: `currentHighCell` is a critical (d+1)-cell. - // The path is complete. Reverse so it reads source → … → target. - VPath completePath = path; - std::reverse(completePath.begin(), completePath.end()); - vpaths.push_back(std::move(completePath)); - } - } - - return 0; -}*/ - template bool DiscreteGradient::getAscendingPathThroughWall( const Cell &saddle1, From 4a81d7d2a1ff159e1dace99d72b5b83d7a93bf39 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Fri, 5 Jun 2026 19:13:49 +0200 Subject: [PATCH 22/46] [il-ext] vpath notes --- core/base/discreteGradient/DiscreteGradient_Template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 14c9e0fd1c..56808e6b5c 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1917,7 +1917,7 @@ template /* * NOTE - * Looks good in 2D. Needs further tests in 3D. + * Looks good in 2D (needs tests for vertices). Needs further tests in 3D. */ vpaths.clear(); From dfb64d0b2e9d02ff189819d930e1b237716b8ea0 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 6 Jun 2026 16:42:16 +0200 Subject: [PATCH 23/46] [il-ext] all ascending vpaths --- .../DiscreteGradient_Template.h | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 56808e6b5c..0eee7e40d2 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1915,11 +1915,6 @@ template std::vector > &vpaths, const triangulationType &triangulation) const{ - /* - * NOTE - * Looks good in 2D (needs tests for vertices). Needs further tests in 3D. - */ - vpaths.clear(); using vPath = std::vector; @@ -1943,13 +1938,11 @@ template StackEntry stackEntry = std::move(stack.top()); stack.pop(); - printf("popping edge %d\n", - stackEntry.currentCell_.id_); - const Cell ¤tCell = stackEntry.currentCell_; const SimplexId pairedCofacetId = getPairedCell(currentCell, triangulation); - if(isCellCritical(currentCell)){ + + if((currentCell.id_ != cell.id_)&&(isCellCritical(currentCell))){ // currentCell is a critical simplex: this path has terminated. // the simplex has already been added to the stack path vpaths.push_back(stackEntry.partialPath_); @@ -1991,8 +1984,6 @@ template } if(cofacetId != pairedCofacetId){ - printf(" going for triangle %d\n", cofacetId); - // we don't want to go down the v-path, we want to go backwards Cell cofacet; cofacet.dim_ = currentCell.dim_ + 1; @@ -2027,18 +2018,13 @@ template simplex.dim_ = cofacet.dim_ - 1; const SimplexId simplexPair = getPairedCell(simplex, triangulation); - if(isCellCritical(simplex)){ - printf(" edge %d is critical\n", simplex.id_); - } - - if(simplexPair == cofacet.id_){ - printf(" edge %d was paired to our triangle (%d)\n", - simplex.id_, simplexPair); - } - - if((simplexPair == cofacet.id_)||(isCellCritical(simplex))){ - // we found the simplex that was paired the cofacet - // or a critical simplex + if(isCellCritical(simplex)) { + // always terminate here — don't continue the path through a critical cell + newStackEntry.partialPath_.push_back(simplex); + vpaths.push_back(newStackEntry.partialPath_); + hasProgressed = true; // prevent the fallback push too + // do NOT push to stack + } else if(simplexPair == cofacet.id_) { newStackEntry.partialPath_.push_back(simplex); newStackEntry.currentCell_ = simplex; stack.push(std::move(newStackEntry)); From 38fccd9fd8af22031c0d0e8b6c8f2ae41efc9379 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sun, 7 Jun 2026 10:29:00 +0200 Subject: [PATCH 24/46] [il-ext] setting up numerical comp --- .../numericalIntegralLines/CMakeLists.txt | 9 ++ .../NumericalIntegralLines.cpp | 12 +++ .../NumericalIntegralLines.h | 82 +++++++++++++++++++ core/base/vpath/VPath.cpp | 12 --- core/base/{vpath => vpaths}/CMakeLists.txt | 6 +- core/base/vpaths/VPaths.cpp | 12 +++ core/base/{vpath/VPath.h => vpaths/VPaths.h} | 30 ++----- core/vtk/ttkIntegralLines/ttk.module | 3 +- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 17 ++-- core/vtk/ttkIntegralLines/ttkIntegralLines.h | 2 +- 10 files changed, 139 insertions(+), 46 deletions(-) create mode 100644 core/base/numericalIntegralLines/CMakeLists.txt create mode 100644 core/base/numericalIntegralLines/NumericalIntegralLines.cpp create mode 100644 core/base/numericalIntegralLines/NumericalIntegralLines.h delete mode 100644 core/base/vpath/VPath.cpp rename core/base/{vpath => vpaths}/CMakeLists.txt (61%) create mode 100644 core/base/vpaths/VPaths.cpp rename core/base/{vpath/VPath.h => vpaths/VPaths.h} (78%) diff --git a/core/base/numericalIntegralLines/CMakeLists.txt b/core/base/numericalIntegralLines/CMakeLists.txt new file mode 100644 index 0000000000..90a520a0c6 --- /dev/null +++ b/core/base/numericalIntegralLines/CMakeLists.txt @@ -0,0 +1,9 @@ +ttk_add_base_library(numericalIntegralLines + SOURCES + NumericalIntegralLines.cpp + HEADERS + NumericalIntegralLines.h + DEPENDS + geometry + triangulation + ) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.cpp b/core/base/numericalIntegralLines/NumericalIntegralLines.cpp new file mode 100644 index 0000000000..eccf0724ab --- /dev/null +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.cpp @@ -0,0 +1,12 @@ +#include + +using namespace std; +using namespace ttk; +using namespace vp; + +NumericalIntegralLines::NumericalIntegralLines(){ + this->setDebugMsgPrefix("NumericalIntegralLines"); +} + +NumericalIntegralLines::~NumericalIntegralLines() = default; + diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h new file mode 100644 index 0000000000..432d4cdad9 --- /dev/null +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -0,0 +1,82 @@ +/// \ingroup base +/// \class ttk::NumericalIntegralLines +/// \author Julien Tierny +/// \date May 2026 +/// \date NumericalIntegralLines extractor wrapping the DiscreteGradient class. +/// +/// \brief TTK convenience class wrapping the DiscreteGradient class for +/// the easy extraction of vpaths. +/// +/// Given a simplexId and dimension, this class returns a descending (or +/// ascending) vpath started in the given input simplex. +/// +/// \sa NumericalIntegralLines.cpp %for an alternative integral line backend. +/// \sa DiscreteGradient.cpp %for the core mechanisms. +/// \sa ttkNumericalIntegralLines.cpp %for a usage example. +/// + +#pragma once + +// base code includes +#include +// std includes + +namespace ttk { + namespace vp { + + class NumericalIntegralLines : virtual public Debug { + + public: + NumericalIntegralLines(); + ~NumericalIntegralLines() override; + + // template + // int execute(triangulationType *triangulation); + + /** + * @brief Extract a vpath. + * + * @param output Vector storing the output vpaths (1 entry per seed, + * with possibly multiple v-path per seed). + * @param isForward Forward or backward vpath (default: forward). + */ + template + int execute( + const triangulationType *triangulation, + const bool &isForward = false); + + /** + * @brief Triangulation preconditioning. + */ + inline void preconditionTriangulation(AbstractTriangulation *triangulation){ + + // see dms precondition + } + + inline void setInputOffsets(const SimplexId *const offsets) { + } + + inline void setInputScalarField(const void *const scalars, + const size_t &mTime){ + } + + protected: + }; + } // namespace vp +} // namespace ttk + +template +int ttk::vp::NumericalIntegralLines::execute( + const triangulationType *triangulation, + const bool &isForward){ + + Timer t; + + printMsg("Computed numerical integral line(s) from " + // + std::to_string(output.size()) + // + " seed(s)" + , 1, + t.getElapsedTime(), threadNumber_); + + return 0; +} diff --git a/core/base/vpath/VPath.cpp b/core/base/vpath/VPath.cpp deleted file mode 100644 index f248400427..0000000000 --- a/core/base/vpath/VPath.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -using namespace std; -using namespace ttk; -using namespace vp; - -VPath::VPath(){ - this->setDebugMsgPrefix("VPath"); -} - -VPath::~VPath() = default; - diff --git a/core/base/vpath/CMakeLists.txt b/core/base/vpaths/CMakeLists.txt similarity index 61% rename from core/base/vpath/CMakeLists.txt rename to core/base/vpaths/CMakeLists.txt index 06e07934ec..f63bf59778 100644 --- a/core/base/vpath/CMakeLists.txt +++ b/core/base/vpaths/CMakeLists.txt @@ -1,8 +1,8 @@ -ttk_add_base_library(vPath +ttk_add_base_library(vPaths SOURCES - VPath.cpp + VPaths.cpp HEADERS - VPath.h + VPaths.h DEPENDS discreteGradient geometry diff --git a/core/base/vpaths/VPaths.cpp b/core/base/vpaths/VPaths.cpp new file mode 100644 index 0000000000..c2f3a90cc6 --- /dev/null +++ b/core/base/vpaths/VPaths.cpp @@ -0,0 +1,12 @@ +#include + +using namespace std; +using namespace ttk; +using namespace vp; + +VPaths::VPaths(){ + this->setDebugMsgPrefix("VPaths"); +} + +VPaths::~VPaths() = default; + diff --git a/core/base/vpath/VPath.h b/core/base/vpaths/VPaths.h similarity index 78% rename from core/base/vpath/VPath.h rename to core/base/vpaths/VPaths.h index d2f5243b42..2a1ee7ad8e 100644 --- a/core/base/vpath/VPath.h +++ b/core/base/vpaths/VPaths.h @@ -1,8 +1,8 @@ /// \ingroup base -/// \class ttk::VPath +/// \class ttk::VPaths /// \author Julien Tierny /// \date May 2026 -/// \date VPath extractor wrapping the DiscreteGradient class. +/// \date VPaths extractor wrapping the DiscreteGradient class. /// /// \brief TTK convenience class wrapping the DiscreteGradient class for /// the easy extraction of vpaths. @@ -10,9 +10,9 @@ /// Given a simplexId and dimension, this class returns a descending (or /// ascending) vpath started in the given input simplex. /// -/// \sa VPath.cpp %for an alternative integral line backend. +/// \sa VPaths.cpp %for an alternative integral line backend. /// \sa DiscreteGradient.cpp %for the core mechanisms. -/// \sa ttkVPath.cpp %for a usage example. +/// \sa ttkVPaths.cpp %for a usage example. /// #pragma once @@ -25,11 +25,11 @@ namespace ttk { namespace vp { - class VPath : virtual public Debug { + class VPaths : virtual public Debug { public: - VPath(); - ~VPath() override; + VPaths(); + ~VPaths() override; // template // int execute(triangulationType *triangulation); @@ -66,20 +66,6 @@ namespace ttk { this->dcg_.setInputScalarField(scalars, mTime); } - /** - * @brief Computes the integral line starting at the vertex of global id - * seedIdentifier. - * - * @tparam triangulationType - * @param triangulation - * @param integralLine integral line to compute - * @param offsets Order array of the scalar array - */ - // template - // void computeIntegralLine(const triangulationType *triangulation, - // ttk::intgl::IntegralLine *integralLine, - // const ttk::SimplexId *offsets) const; - protected: dcg::DiscreteGradient dcg_{}; @@ -88,7 +74,7 @@ namespace ttk { } // namespace ttk template -int ttk::vp::VPath::execute( +int ttk::vp::VPaths::execute( const triangulationType *triangulation, const std::vector &seeds, std::vector>> &output, diff --git a/core/vtk/ttkIntegralLines/ttk.module b/core/vtk/ttkIntegralLines/ttk.module index b6ce63c0df..b50b6e3731 100644 --- a/core/vtk/ttkIntegralLines/ttk.module +++ b/core/vtk/ttkIntegralLines/ttk.module @@ -6,5 +6,6 @@ HEADERS ttkIntegralLines.h DEPENDS integralLines - vPath + numericalIntegralLines + vPaths ttkAlgorithm diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 658befc31a..e2100c3ebd 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -246,18 +246,18 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), else if(BackEnd == BACKEND::DISCRETE){ printMsg("Selected `discrete` backend."); - ttk::vp::VPath vpath; + ttk::vp::VPaths vpaths; - vpath.setDebugLevel(debugLevel_); - vpath.setThreadNumber(threadNumber_); + vpaths.setDebugLevel(debugLevel_); + vpaths.setThreadNumber(threadNumber_); // setup the mesh - vpath.preconditionTriangulation(triangulation); + vpaths.preconditionTriangulation(triangulation); // setup the data - vpath.setInputScalarField(inputScalars->GetVoidPointer(0), + vpaths.setInputScalarField(inputScalars->GetVoidPointer(0), inputScalars->GetMTime()); - vpath.setInputOffsets( + vpaths.setInputOffsets( static_cast(ttkUtils::GetVoidPointer(inputOffsets))); std::vector seedCells(seeds->GetNumberOfCells()); @@ -275,7 +275,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), int status{}; ttkTemplateMacro(triangulation->getType(), - status = vpath.execute( + status = vpaths.execute( static_cast(triangulation->getData()), seedCells, outputPaths, // isForward? @@ -291,6 +291,9 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), } } + // TODO + // add v-path length (i.e., number of simplices) + vtkNew outputPathGeometry; vtkNew pointCoords{}; diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.h b/core/vtk/ttkIntegralLines/ttkIntegralLines.h index dc24c7a5fb..84306a5f4f 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.h +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.h @@ -70,7 +70,7 @@ // ttk code includes #include -#include +#include #include #include From 544f46b05f0ad990dd0b2da472591182c0b7e46d Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sun, 7 Jun 2026 18:04:57 +0200 Subject: [PATCH 25/46] [il-ext] added vpath length --- core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index e2100c3ebd..1360359ab8 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -291,9 +291,6 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), } } - // TODO - // add v-path length (i.e., number of simplices) - vtkNew outputPathGeometry; vtkNew pointCoords{}; @@ -302,6 +299,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkNew cellForkId{}; vtkNew vertexSimplexId{}; vtkNew vertexSimplexDimension{}; + vtkNew cellSimplexNumber{}; vtkNew outputMaskField{}; pointCoords->SetNumberOfComponents(3); @@ -325,6 +323,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), cellSeedId->SetName("SeedIdentifier"); cellForkId->SetName("ForkIdentifier"); + cellSimplexNumber->SetName("SimplexNumber"); int pointId = 0; int localSeedId = 0; @@ -336,6 +335,8 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), pathPointId = 0; + int simplexNumber = path.size(); + for(auto &c : path){ float point[3]; triangulation->getCellIncenter(c.id_, c.dim_, point); @@ -357,6 +358,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); cellSeedId->InsertNextValue((int) seedCells[localSeedId].id_); cellForkId->InsertNextValue((int) forkId); + cellSimplexNumber->InsertNextValue((simplexNumber)); } } forkId++; @@ -373,6 +375,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), outputPathGeometry->GetPointData()->AddArray(vertexSimplexDimension); outputPathGeometry->GetCellData()->AddArray(cellSeedId); outputPathGeometry->GetCellData()->AddArray(cellForkId); + outputPathGeometry->GetCellData()->AddArray(cellSimplexNumber); output->ShallowCopy(outputPathGeometry); From edc1288a414ba49b9290f1e9605deec901529519 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Tue, 9 Jun 2026 12:14:40 +0200 Subject: [PATCH 26/46] [il-ext] setting up numerical integral lines --- .../NumericalIntegralLines.cpp | 2 +- .../NumericalIntegralLines.h | 95 +++++++++++++++---- core/base/vpaths/VPaths.h | 2 +- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 38 ++++++++ core/vtk/ttkIntegralLines/ttkIntegralLines.h | 1 + 5 files changed, 117 insertions(+), 21 deletions(-) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.cpp b/core/base/numericalIntegralLines/NumericalIntegralLines.cpp index eccf0724ab..95d7acda47 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.cpp +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.cpp @@ -2,7 +2,7 @@ using namespace std; using namespace ttk; -using namespace vp; +using namespace nil; NumericalIntegralLines::NumericalIntegralLines(){ this->setDebugMsgPrefix("NumericalIntegralLines"); diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index 432d4cdad9..f85c41f04a 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -22,7 +22,7 @@ // std includes namespace ttk { - namespace vp { + namespace nil { class NumericalIntegralLines : virtual public Debug { @@ -34,47 +34,104 @@ namespace ttk { // int execute(triangulationType *triangulation); /** - * @brief Extract a vpath. + * @brief Compute a single numerical integral line. + * + * @param seed (SimplexId, dimension) + * @param barycentricWeights Weights for the input seed. + * @param output Output integral line (vector of 3D points). + * @param isForawrd Forward or backward line (default: forward). + */ + template + int computeIntegralLine(const triangulationType *triangulation, + const std::pair &seed, + const std::array &barycentricWeights, + std::vector> &output, + const bool &isForward = false); + + /** + * @brief Compute numerical integral lines. * * @param output Vector storing the output vpaths (1 entry per seed, * with possibly multiple v-path per seed). * @param isForward Forward or backward vpath (default: forward). */ - template - int execute( - const triangulationType *triangulation, + template + int execute(const triangulationType *triangulation, + const std::vector> &seeds, + std::vector>> &output, const bool &isForward = false); /** * @brief Triangulation preconditioning. */ inline void preconditionTriangulation(AbstractTriangulation *triangulation){ - - // see dms precondition - } - - inline void setInputOffsets(const SimplexId *const offsets) { + // precondition simplex2face + // precondition face2cofacets } - inline void setInputScalarField(const void *const scalars, - const size_t &mTime){ + inline void setInputScalarField(const void *const scalars){ + scalars_ = scalars; } protected: + int maximumIterationNumber_{1000000000}; + const void *scalars_; }; - } // namespace vp + } // namespace nil } // namespace ttk -template -int ttk::vp::NumericalIntegralLines::execute( - const triangulationType *triangulation, - const bool &isForward){ +template + int ttk::nil::NumericalIntegralLines::computeIntegralLine( + const triangulationType *triangulation, + const std::pair &seed, + const std::array &barycentricWeights, + std::vector> &output, + const bool &isForward){ + + + for(int i = 0; i < (int) maximumIterationNumber_; i++){ + + } + + return 0; +} + +template +int ttk::nil::NumericalIntegralLines::execute(const triangulationType *triangulation, + const std::vector> &seeds, + std::vector>> &output, + const bool &isForward){ Timer t; + output.resize(seeds.size()); + + const std::array barycentricWeights{1/3, 1/3, 1/3}; + +#ifdef TTK_ENABLE_OPENMP +#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) +#endif + for(int i = 0; i < (int) seeds.size(); i++){ + computeIntegralLine( + triangulation, seeds[i], barycentricWeights, output[i], isForward); + +#ifdef TTK_ENABLE_OPENMP +#pragma omp critical +#endif + printMsg(" - Seed-#" + + std::to_string(seeds[i].first) + + " (dim: " + + std::to_string(seeds[i].second) + + ", f: " + + std::to_string(isForward) + + "): " + + std::to_string(output[i].size()) + " point(s).", + debug::Priority::DETAIL); + } + printMsg("Computed numerical integral line(s) from " - // + std::to_string(output.size()) - // + " seed(s)" + + std::to_string(output.size()) + + " seed(s)" , 1, t.getElapsedTime(), threadNumber_); diff --git a/core/base/vpaths/VPaths.h b/core/base/vpaths/VPaths.h index 2a1ee7ad8e..a5f23077c0 100644 --- a/core/base/vpaths/VPaths.h +++ b/core/base/vpaths/VPaths.h @@ -35,7 +35,7 @@ namespace ttk { // int execute(triangulationType *triangulation); /** - * @brief Extract a vpath. + * @brief Extract vpaths. * * @param output Vector storing the output vpaths (1 entry per seed, * with possibly multiple v-path per seed). diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 1360359ab8..3faa779852 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -241,6 +241,44 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), if(BackEnd == BACKEND::NUMERICAL){ printMsg("Selected `numerical` backend."); + + ttk::nil::NumericalIntegralLines num; + + num.setDebugLevel(debugLevel_); + num.setThreadNumber(threadNumber_); + + // setup the mesh + num.preconditionTriangulation(triangulation); + + // setup the data + num.setInputScalarField(inputScalars->GetVoidPointer(0)); + + // setup the seeds (simplexId, dimension) + std::vector > seedCells(seeds->GetNumberOfCells()); + +#ifdef TTK_ENABLE_OPENMP +#pragma omp parallel for num_threads(threadNumber_) +#endif + for(int i = 0; i < (int) seedCells.size(); i++){ + vtkCell *cell = seeds->GetCell(i); + seedCells[i].first = identifiers[i]; + seedCells[i].second = cell->GetCellDimension(); + } + + std::vector>> outputPaths; + + int status{}; + ttkVtkTemplateMacro(inputScalars->GetDataType(), + triangulation->getType(), + (status = num.execute( + static_cast(triangulation->getData()), + seedCells, outputPaths, + // isForward? + Direction == 0))); + + if(status) + return status; + return 1; } else if(BackEnd == BACKEND::DISCRETE){ diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.h b/core/vtk/ttkIntegralLines/ttkIntegralLines.h index 84306a5f4f..89acf78808 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.h +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.h @@ -70,6 +70,7 @@ // ttk code includes #include +#include #include #include #include From c26324cc49bd71010cae9e68b6bab9133b8f29af Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 11 Jun 2026 17:33:23 +0200 Subject: [PATCH 27/46] [il-ext] setting up numerical integration --- .../NumericalIntegralLines.h | 62 ++++++++++++++++--- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 2 +- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index f85c41f04a..90a07e64f4 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -24,14 +24,21 @@ namespace ttk { namespace nil { + struct PathPoint{ + SimplexId simplexId_; + int simplexDimension_; + std::vector barycentricWeights_; + }; + class NumericalIntegralLines : virtual public Debug { public: NumericalIntegralLines(); ~NumericalIntegralLines() override; - // template - // int execute(triangulationType *triangulation); + template + int computeEndPoint(const triangulationType *triangulation, + const PathPoint &start, PathPoint &end); /** * @brief Compute a single numerical integral line. @@ -44,10 +51,15 @@ namespace ttk { template int computeIntegralLine(const triangulationType *triangulation, const std::pair &seed, - const std::array &barycentricWeights, - std::vector> &output, + const std::vector &barycentricWeights, + std::vector &output, const bool &isForward = false); + template + int computeNumericalGradient(const triangulationType *triangulation, + const int &simplexDimension, const int &simplexId, + std::vector &gradient); + /** * @brief Compute numerical integral lines. * @@ -58,7 +70,7 @@ namespace ttk { template int execute(const triangulationType *triangulation, const std::vector> &seeds, - std::vector>> &output, + std::vector> &output, const bool &isForward = false); /** @@ -80,38 +92,68 @@ namespace ttk { } // namespace nil } // namespace ttk +template + int ttk::nil::NumericalIntegralLines::computeEndPoint( + const triangulationType *triangulation, + const ttk::nil::PathPoint &start, ttk::nil::PathPoint &end){ + + std::vector gradient(3); + + computeNumericalGradient( + triangulation, start.simplexDimension_, start.simplexId_, gradient); + + return 0; +} + template int ttk::nil::NumericalIntegralLines::computeIntegralLine( const triangulationType *triangulation, const std::pair &seed, - const std::array &barycentricWeights, - std::vector> &output, + const std::vector &startBarycentricWeights, + std::vector &output, const bool &isForward){ + output.clear(); + + PathPoint startPoint, endPoint; + + startPoint.simplexId_ = seed.first; + startPoint.simplexDimension_ = seed.second; + startPoint.barycentricWeights_ = startBarycentricWeights; for(int i = 0; i < (int) maximumIterationNumber_; i++){ + computeEndPoint(triangulation, startPoint, endPoint); } return 0; } +template + int ttk::nil::NumericalIntegralLines::computeNumericalGradient( + const triangulationType *triangulation, + const int &simplexDimension, const int &simplexId, + std::vector &gradient){ + + return 0; +} + template int ttk::nil::NumericalIntegralLines::execute(const triangulationType *triangulation, const std::vector> &seeds, - std::vector>> &output, + std::vector> &output, const bool &isForward){ Timer t; output.resize(seeds.size()); - const std::array barycentricWeights{1/3, 1/3, 1/3}; - #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) #endif for(int i = 0; i < (int) seeds.size(); i++){ + std::vector + barycentricWeights(seeds[i].second + 1, 1/(seeds[i].second + 1)); computeIntegralLine( triangulation, seeds[i], barycentricWeights, output[i], isForward); diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 3faa779852..72bf4f84cc 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -265,7 +265,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), seedCells[i].second = cell->GetCellDimension(); } - std::vector>> outputPaths; + std::vector> outputPaths; int status{}; ttkVtkTemplateMacro(inputScalars->GetDataType(), From 2c530fe639366fc296a8a640dc2fa1b44ec0e800 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 11 Jun 2026 18:32:24 +0200 Subject: [PATCH 28/46] [il-ext] numerical gradient computation --- .../NumericalIntegralLines.h | 140 +++++++++++++++++- 1 file changed, 132 insertions(+), 8 deletions(-) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index 90a07e64f4..ce98da6941 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -38,7 +38,7 @@ namespace ttk { template int computeEndPoint(const triangulationType *triangulation, - const PathPoint &start, PathPoint &end); + const PathPoint &start, PathPoint &end) const; /** * @brief Compute a single numerical integral line. @@ -53,12 +53,12 @@ namespace ttk { const std::pair &seed, const std::vector &barycentricWeights, std::vector &output, - const bool &isForward = false); + const bool &isForward = false) const; template int computeNumericalGradient(const triangulationType *triangulation, const int &simplexDimension, const int &simplexId, - std::vector &gradient); + std::vector &gradient) const; /** * @brief Compute numerical integral lines. @@ -71,7 +71,12 @@ namespace ttk { int execute(const triangulationType *triangulation, const std::vector> &seeds, std::vector> &output, - const bool &isForward = false); + const bool &isForward = false) const; + + template + int getVertexIdentifiers(const triangulationType *triangulation, + const int &simplexDimension, const int &simplexId, + std::vector vertexIdentifiers) const; /** * @brief Triangulation preconditioning. @@ -95,7 +100,7 @@ namespace ttk { template int ttk::nil::NumericalIntegralLines::computeEndPoint( const triangulationType *triangulation, - const ttk::nil::PathPoint &start, ttk::nil::PathPoint &end){ + const ttk::nil::PathPoint &start, ttk::nil::PathPoint &end) const{ std::vector gradient(3); @@ -111,7 +116,7 @@ template const std::pair &seed, const std::vector &startBarycentricWeights, std::vector &output, - const bool &isForward){ + const bool &isForward) const{ output.clear(); @@ -129,11 +134,94 @@ template return 0; } +// TODO +// move that function to the geometry class + template int ttk::nil::NumericalIntegralLines::computeNumericalGradient( const triangulationType *triangulation, const int &simplexDimension, const int &simplexId, - std::vector &gradient){ + std::vector &gradient) const{ + + gradient = {0, 0, 0}; + + if(!simplexDimension) + return -1; + + std::vector vertexIdentifiers; + + getVertexIdentifiers(triangulation, simplexDimension, simplexId, vertexIdentifiers); + + const int vertexNumber = vertexIdentifiers.size(); + + std::vector> vertexPoints(vertexNumber); + std::vector vertexScalars(vertexNumber); + + for(int i = 0; i < (int) vertexNumber; i++){ + triangulation->getVertexPoint(vertexIdentifiers[i], + vertexPoints[i][0], vertexPoints[i][1], vertexPoints[i][2]); + vertexScalars[i] = ((dataType *) scalars_)[vertexIdentifiers[i]]; + } + + // build edge vectors and corresponding differences, wrt v0 + std::vector> edgeVectors(simplexDimension); + std::vector edgeDifferences(simplexDimension); + + for(int i = 0; i < simplexDimension; i++) { + for(int c = 0; c < 3; c++) + edgeVectors[i][c] = vertexPoints[i + 1][c] - vertexPoints[0][c]; + edgeDifferences[i] = vertexScalars[i + 1] - vertexScalars[0]; + } + + // Gram matrix gramMatrix[i][j] = edgeVectors[i] . edgeVectors[j] + // (simplexDimension x simplexDimension) + std::vector> + gramMatrix(simplexDimension, std::vector(simplexDimension, 0)); + + for(int i = 0; i < simplexDimension; i++) + for(int j = 0; j < simplexDimension; j++) + gramMatrix[i][j] = ttk::Geometry::dotProduct( + edgeVectors[i].data(), edgeVectors[j].data()); + + // Gaussian elimintation + std::vector> + augmentedMatrix(simplexDimension, std::vector(simplexDimension + 1)); + for(int i = 0; i < simplexDimension; ++i) { + for(int j = 0; j < simplexDimension; ++j) + augmentedMatrix[i][j] = gramMatrix[i][j]; + augmentedMatrix[i][simplexDimension] = edgeDifferences[i]; + } + + for(int col = 0; col < simplexDimension; col++) { + // Partial pivot + int pivot = col; + for(int row = col + 1; row < simplexDimension; row++) + if(std::abs(augmentedMatrix[row][col]) > + std::abs(augmentedMatrix[pivot][col])) + pivot = row; + std::swap(augmentedMatrix[col], augmentedMatrix[pivot]); + + const float diagVal = augmentedMatrix[col][col]; + if(std::abs(diagVal) < powf(10, -FLT_DIG)) + return -2; + + for(int row = 0; row < simplexDimension; row++) { + if(row == col) + continue; + const float factor = augmentedMatrix[row][col] / diagVal; + for(int j = col; j <= simplexDimension; ++j) + augmentedMatrix[row][j] -= factor * augmentedMatrix[col][j]; + } + } + + std::vector alpha(simplexDimension); + for(int i = 0; i < simplexDimension; i++) + alpha[i] = augmentedMatrix[i][simplexDimension] / augmentedMatrix[i][i]; + + // reconstruct the 3D gradient + for(int i = 0; i < simplexDimension; i++) + for(int c = 0; c < 3; c++) + gradient[c] += alpha[i] * edgeVectors[i][c]; return 0; } @@ -142,7 +230,7 @@ template int ttk::nil::NumericalIntegralLines::execute(const triangulationType *triangulation, const std::vector> &seeds, std::vector> &output, - const bool &isForward){ + const bool &isForward) const{ Timer t; @@ -179,3 +267,39 @@ int ttk::nil::NumericalIntegralLines::execute(const triangulationType *triangula return 0; } + +template + int ttk::nil::NumericalIntegralLines::getVertexIdentifiers( + const triangulationType *triangulation, + const int &simplexDimension, const int &simplexId, + std::vector vertexIdentifiers) const{ + + switch(simplexDimension){ + case 0: + vertexIdentifiers = {simplexId}; + break; + case 1: + vertexIdentifiers.resize(2); + triangulation->getEdgeVertex(simplexId, 0, vertexIdentifiers[0]); + triangulation->getEdgeVertex(simplexId, 1, vertexIdentifiers[1]); + break; + case 2: + vertexIdentifiers.resize(3); + triangulation->getTriangleVertex(simplexId, 0, vertexIdentifiers[0]); + triangulation->getTriangleVertex(simplexId, 1, vertexIdentifiers[1]); + triangulation->getTriangleVertex(simplexId, 2, vertexIdentifiers[2]); + break; + case 3: + vertexIdentifiers.resize(4); + triangulation->getCellVertex(simplexId, 0, vertexIdentifiers[0]); + triangulation->getCellVertex(simplexId, 1, vertexIdentifiers[1]); + triangulation->getCellVertex(simplexId, 2, vertexIdentifiers[2]); + triangulation->getCellVertex(simplexId, 3, vertexIdentifiers[3]); + break; + default: + return -1; + break; + } + + return 0; +} From 3cd4a0ba6640800f284b9d889424e102b5bddaf4 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 11 Jun 2026 18:58:50 +0200 Subject: [PATCH 29/46] [il-ext] comment removal --- core/base/numericalIntegralLines/NumericalIntegralLines.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index ce98da6941..ed8c1c7f61 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -107,6 +107,8 @@ template computeNumericalGradient( triangulation, start.simplexDimension_, start.simplexId_, gradient); + + return 0; } @@ -174,7 +176,6 @@ template } // Gram matrix gramMatrix[i][j] = edgeVectors[i] . edgeVectors[j] - // (simplexDimension x simplexDimension) std::vector> gramMatrix(simplexDimension, std::vector(simplexDimension, 0)); From 74180e9059d28c7985367af8d80fc6481b9e5d80 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Mon, 7 Sep 2026 09:35:16 +0200 Subject: [PATCH 30/46] [nil] merges, drafting numerical integration --- core/base/common/welcomeMsg.inl | 6 +- .../DepthImageBasedGeometryApproximation.h | 12 +- core/base/discreteGradient/DiscreteGradient.h | 8 +- .../DiscreteGradient_Template.h | 29 +- .../DiscreteMorseSandwich.cpp | 7 +- .../DiscreteMorseSandwich.h | 51 +- .../DiscreteMorseSandwichMPI.cpp | 7 +- .../DiscreteMorseSandwichMPI.h | 75 +- .../discreteVectorField/DiscreteVectorField.h | 4 +- .../DistanceMatrixDistortion.cpp | 5 +- core/base/ftmTree/FTMTree_CT_Template.h | 86 +- .../ImplicitTriangulation.h | 22 +- core/base/integralLines/IntegralLines.h | 4 +- .../LowestCommonAncestor.cpp | 2 +- .../BranchMappingDistance.h | 50 +- .../mergeTreeClustering/MergeTreeClustering.h | 2 +- .../mergeTreeClustering/MergeTreeDistance.h | 4 +- .../NumericalIntegralLines.cpp | 3 +- .../NumericalIntegralLines.h | 992 ++++++++++++++++-- .../PeriodicImplicitTriangulation.h | 15 +- .../RegularGridTriangulation.cpp | 8 +- .../RegularGridTriangulation.h | 16 +- .../FastRipsPersistenceDiagram2.cpp | 4 +- .../TopologicalCompression.cpp | 7 +- core/base/triangulation/Triangulation.cpp | 6 +- .../VectorSimplification.cpp | 7 +- .../VectorSimplification.h | 51 +- core/base/vpaths/VPaths.cpp | 3 +- core/base/vpaths/VPaths.h | 42 +- .../ttkImportEmbeddingFromTable.cpp | 6 +- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 73 +- core/vtk/ttkIntegralLines/ttkIntegralLines.h | 2 +- 32 files changed, 1212 insertions(+), 397 deletions(-) diff --git a/core/base/common/welcomeMsg.inl b/core/base/common/welcomeMsg.inl index 109916832e..4ed3e2b1e4 100644 --- a/core/base/common/welcomeMsg.inl +++ b/core/base/common/welcomeMsg.inl @@ -12,7 +12,8 @@ printMsg( debug::LineMode::NEW, stream); printMsg(debug::output::BOLD - + "|_ _|_ _| |/ / / /__\\ \\ |___ \\ / _ \\___ \\ / /_" + + "|_ _|_ _| |/ / / /__\\ \\ |___ \\ / _ " + "\\___ \\ / /_" + debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, @@ -32,7 +33,8 @@ printMsg( debug::LineMode::NEW, stream); printMsg(debug::output::BOLD - + " |_| |_| |_|\\_\\ | |\\___| | |_____|\\___/_____|\\___/" + + " |_| |_| |_|\\_\\ | |\\___| | " + "|_____|\\___/_____|\\___/" + debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, diff --git a/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h b/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h index 2c881db4e7..082f934f70 100644 --- a/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h +++ b/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h @@ -253,16 +253,16 @@ int ttk::DepthImageBasedGeometryApproximation::execute( triangleDistortions[triangleDistortionOffset++] = isNaN(i0Depth) || isNaN(i2Depth) || isNaN(i1Depth) ? myNan - : std::max( - absDiff(i0Depth, i1Depth), - std::max(absDiff(i1Depth, i2Depth), absDiff(i0Depth, i2Depth))); + : std::max(absDiff(i0Depth, i1Depth), + std::max(absDiff(i1Depth, i2Depth), + absDiff(i0Depth, i2Depth))); triangleDistortions[triangleDistortionOffset++] = isNaN(i1Depth) || isNaN(i2Depth) || isNaN(i3Depth) ? myNan - : std::max( - absDiff(i1Depth, i3Depth), - std::max(absDiff(i3Depth, i2Depth), absDiff(i2Depth, i1Depth))); + : std::max(absDiff(i1Depth, i3Depth), + std::max(absDiff(i3Depth, i2Depth), + absDiff(i2Depth, i1Depth))); } } } diff --git a/core/base/discreteGradient/DiscreteGradient.h b/core/base/discreteGradient/DiscreteGradient.h index e898966323..0fe3984748 100644 --- a/core/base/discreteGradient/DiscreteGradient.h +++ b/core/base/discreteGradient/DiscreteGradient.h @@ -433,8 +433,8 @@ user in the gradient. */ template int getAllAscendingPaths(const Cell &cell, - std::vector > &vpaths, - const triangulationType &triangulation) const; + std::vector> &vpaths, + const triangulationType &triangulation) const; /** * Return the VPath terminating at the given cell. @@ -449,8 +449,8 @@ user in the gradient. */ template int getAllDescendingPaths(const Cell &cell, - std::vector > &vpaths, - const triangulationType &triangulation) const; + std::vector> &vpaths, + const triangulationType &triangulation) const; /** * Return the VPath terminating at the given 2-saddle restricted to the diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 0eee7e40d2..1c2148f773 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1911,9 +1911,10 @@ int DiscreteGradient::getAscendingPath(const Cell &cell, } template - int DiscreteGradient::getAllAscendingPaths(const Cell &cell, - std::vector > &vpaths, - const triangulationType &triangulation) const{ +int DiscreteGradient::getAllAscendingPaths( + const Cell &cell, + std::vector> &vpaths, + const triangulationType &triangulation) const { vpaths.clear(); @@ -1941,8 +1942,7 @@ template const Cell ¤tCell = stackEntry.currentCell_; const SimplexId pairedCofacetId = getPairedCell(currentCell, triangulation); - - if((currentCell.id_ != cell.id_)&&(isCellCritical(currentCell))){ + if((currentCell.id_ != cell.id_) && (isCellCritical(currentCell))) { // currentCell is a critical simplex: this path has terminated. // the simplex has already been added to the stack path vpaths.push_back(stackEntry.partialPath_); @@ -1955,7 +1955,7 @@ template // check all cofacets int cofacetNumber = -1; - switch(currentCell.dim_){ + switch(currentCell.dim_) { case 1: cofacetNumber = triangulation.getEdgeTriangleNumber(currentCell.id_); break; @@ -1969,9 +1969,9 @@ template bool hasProgressed = false; - for(int i = 0; i < cofacetNumber; i++){ + for(int i = 0; i < cofacetNumber; i++) { int cofacetId = -1; - switch(currentCell.dim_){ + switch(currentCell.dim_) { case 1: triangulation.getEdgeTriangle(currentCell.id_, i, cofacetId); break; @@ -1982,7 +1982,7 @@ template triangulation.getVertexEdge(currentCell.id_, i, cofacetId); break; } - if(cofacetId != pairedCofacetId){ + if(cofacetId != pairedCofacetId) { // we don't want to go down the v-path, we want to go backwards Cell cofacet; @@ -1999,9 +1999,9 @@ template simplexNumber = cofacet.dim_ + 1; - for(int j = 0; j < simplexNumber; j++){ + for(int j = 0; j < simplexNumber; j++) { SimplexId simplexId = -1; - switch(cofacet.dim_){ + switch(cofacet.dim_) { case 1: triangulation.getEdgeVertex(cofacet.id_, j, simplexId); break; @@ -2019,10 +2019,11 @@ template const SimplexId simplexPair = getPairedCell(simplex, triangulation); if(isCellCritical(simplex)) { - // always terminate here — don't continue the path through a critical cell + // always terminate here — don't continue the path through a + // critical cell newStackEntry.partialPath_.push_back(simplex); vpaths.push_back(newStackEntry.partialPath_); - hasProgressed = true; // prevent the fallback push too + hasProgressed = true; // prevent the fallback push too // do NOT push to stack } else if(simplexPair == cofacet.id_) { newStackEntry.partialPath_.push_back(simplex); @@ -2033,7 +2034,7 @@ template } } } - if(!hasProgressed){ + if(!hasProgressed) { // example: boundary edge paired with its interior cofacet, we stop the // backward vpath here. vpaths.push_back(stackEntry.partialPath_); diff --git a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp index ed0499fb2b..f136add1f4 100644 --- a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp +++ b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp @@ -131,9 +131,10 @@ void ttk::DiscreteMorseSandwich::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const PersistencePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if( - pairs.begin(), pairs.end(), - [](const PersistencePair &a) { return a.type == 1; }) + std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), + [](const PersistencePair &a) { + return a.type == 1; + }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h index 93a5584c1b..a0370575e5 100644 --- a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h +++ b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h @@ -699,31 +699,32 @@ void ttk::DiscreteMorseSandwich::getMaxSaddlePairs( const auto dim = this->dg_.getDimensionality(); auto saddle2ToMaxima - = dim == 3 - ? getSaddle2ToMaxima( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getTriangleStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getTriangleStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isTriangleOnBoundary(a); - }, - triangulation) - : getSaddle2ToMaxima( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getEdgeStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getEdgeStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isEdgeOnBoundary(a); - }, - triangulation); + = dim == 3 ? getSaddle2ToMaxima( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getTriangleStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getTriangleStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isTriangleOnBoundary(a); + }, + triangulation) + : getSaddle2ToMaxima( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getEdgeStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getEdgeStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isEdgeOnBoundary(a); + }, + triangulation); Timer tmseq{}; diff --git a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp index afb7fbdb83..da2c9fc218 100644 --- a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp +++ b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp @@ -31,9 +31,10 @@ void ttk::DiscreteMorseSandwichMPI::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const PersistencePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if( - pairs.begin(), pairs.end(), - [](const PersistencePair &a) { return a.type == 1; }) + std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), + [](const PersistencePair &a) { + return a.type == 1; + }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h index 038e912a0f..436a8eeb4d 100644 --- a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h +++ b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h @@ -2197,8 +2197,8 @@ int ttk::DiscreteMorseSandwichMPI::getSaddle1ToMinima( }; ttk::SimplexId elementNumber = 0; // follow vpaths from 1-saddles to minima -#pragma omp parallel shared(extremaLocks, saddleAtomic) reduction(+: elementNumber) \ - num_threads(localThreadNumber) +#pragma omp parallel shared(extremaLocks, saddleAtomic) \ + reduction(+ : elementNumber) num_threads(localThreadNumber) { int threadNumber = omp_get_thread_num(); #pragma omp for schedule(static) @@ -2428,7 +2428,8 @@ void ttk::DiscreteMorseSandwichMPI::getSaddle2ToMaxima( ttk::SimplexId totalFinishedElement{0}; ttk::SimplexId totalElement{0}; #ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for num_threads(localThreadNumber) reduction(+:totalFinishedElement) +#pragma omp parallel for num_threads(localThreadNumber) \ + reduction(+ : totalFinishedElement) #endif for(size_t i = 0; i < criticalSaddles.size(); ++i) { totalFinishedElement += getFaceStarNumber(criticalSaddles[i]); @@ -2519,8 +2520,8 @@ void ttk::DiscreteMorseSandwichMPI::getSaddle2ToMaxima( }; // follow vpaths from 2-saddles to maxima char saddleLocalId; -#pragma omp parallel shared(extremaLocks, saddleAtomic) reduction(+: elementNumber) \ - num_threads(localThreadNumber) +#pragma omp parallel shared(extremaLocks, saddleAtomic) \ + reduction(+ : elementNumber) num_threads(localThreadNumber) { int threadNumber = omp_get_thread_num(); #pragma omp for schedule(static) @@ -2867,9 +2868,11 @@ void ttk::DiscreteMorseSandwichMPI::getMinSaddlePairs( if(criticalExtremasNumber > 0) { // extracts the global min -#pragma omp declare reduction(get_min : std::pair :omp_out = omp_out.second < omp_in.second ? omp_out : omp_in) -#pragma omp parallel for reduction(get_min \ - : localMin) num_threads(localThreadNumber) +#pragma omp declare reduction( \ + get_min : std::pair : omp_out \ + = omp_out.second < omp_in.second ? omp_out : omp_in) +#pragma omp parallel for reduction(get_min : localMin) \ + num_threads(localThreadNumber) for(ttk::SimplexId i = 0; i < criticalExtremasNumber; i++) { if(offsets[criticalExtremas[i]] < localMin.second) { localMin.first = criticalExtremas[i]; @@ -2925,9 +2928,10 @@ void ttk::DiscreteMorseSandwichMPI::getMinSaddlePairs( MPI_IN_PLACE, &totalNumberOfPairs, 1, MPI_SimplexId, MPI_SUM, MPIcomm); globalToLocalSaddle.reserve(criticalEdgesNumber); -#pragma omp declare reduction (merge : std::vector: omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) -#pragma omp parallel for reduction(merge \ - : extremasGid) schedule(static) \ +#pragma omp declare reduction( \ + merge : std::vector : omp_out.insert( \ + omp_out.end(), omp_in.begin(), omp_in.end())) +#pragma omp parallel for reduction(merge : extremasGid) schedule(static) \ shared(saddles) num_threads(localThreadNumber) for(ttk::SimplexId i = 0; i < criticalEdgesNumber; ++i) { auto &mins = saddle1ToMinima[i]; @@ -2954,8 +2958,8 @@ void ttk::DiscreteMorseSandwichMPI::getMinSaddlePairs( extremasGid.size(), std::vector()); std::vector extremaLocks(extremasGid.size(), 0); std::vector> extremas(extremasGid.size(), extremaNode<1>()); -#pragma omp parallel master shared(extremaLocks, extremas, globalMinLid, \ - ghostPresence, saddles, globalMinOffset) \ +#pragma omp parallel master shared(extremaLocks, extremas, globalMinLid, \ + ghostPresence, saddles, globalMinOffset) \ num_threads(localThreadNumber) { #pragma omp task @@ -3204,9 +3208,10 @@ void ttk::DiscreteMorseSandwichMPI::computeMaxSaddlePairs( MPI_Allreduce( MPI_IN_PLACE, &totalNumberOfPairs, 1, MPI_SimplexId, MPI_SUM, MPIcomm); globalToLocalSaddle.reserve(criticalSaddlesNumber); -#pragma omp declare reduction (merge : std::vector: omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) -#pragma omp parallel for reduction(merge \ - : extremasGid) schedule(static) \ +#pragma omp declare reduction( \ + merge : std::vector : omp_out.insert( \ + omp_out.end(), omp_in.begin(), omp_in.end())) +#pragma omp parallel for reduction(merge : extremasGid) schedule(static) \ shared(saddles, saddle2ToMaxima) num_threads(localThreadNumber) for(ttk::SimplexId i = 0; i < criticalSaddlesNumber; ++i) { auto &maxs = saddle2ToMaxima[i]; @@ -3254,7 +3259,7 @@ void ttk::DiscreteMorseSandwichMPI::computeMaxSaddlePairs( std::vector> extremas( extremasGid.size(), extremaNode()); #pragma omp parallel master shared(extremaLocks, extremas, ghostPresence, \ - saddles) num_threads(localThreadNumber) + saddles) num_threads(localThreadNumber) { #pragma omp task { @@ -3409,8 +3414,7 @@ void ttk::DiscreteMorseSandwichMPI::getMaxSaddlePairs( ttk::SimplexId globalMaxOffset{0}; if(criticalExtremasNumber > 0) { // extracts the global max -#pragma omp parallel for reduction(max \ - : globalMaxOffset) \ +#pragma omp parallel for reduction(max : globalMaxOffset) \ num_threads(localThreadNumber) for(ttk::SimplexId i = 0; i < vertexNumber; i++) { if(globalMaxOffset < offsets[i]) { @@ -3422,9 +3426,10 @@ void ttk::DiscreteMorseSandwichMPI::getMaxSaddlePairs( MPI_Allreduce( MPI_IN_PLACE, &globalMaxOffset, 1, MPI_SimplexId, MPI_MAX, MPIcomm); -#pragma omp declare reduction (merge : std::vector : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) -#pragma omp parallel for reduction(merge \ - : localMaxId) \ +#pragma omp declare reduction( \ + merge : std::vector : omp_out.insert( \ + omp_out.end(), omp_in.begin(), omp_in.end())) +#pragma omp parallel for reduction(merge : localMaxId) \ num_threads(localThreadNumber) for(ttk::SimplexId i = 0; i < criticalExtremasNumber; i++) { if(triangulation.getCellRank(criticalExtremas[i]) == ttk::MPIrank_) { @@ -3840,9 +3845,10 @@ void ttk::DiscreteMorseSandwichMPI::extractPairs( ttk::SimplexId saddleNumber = saddleToPairedExtrema.size(); #ifdef TTK_ENABLE_OPENMP -#pragma omp declare reduction (merge : std::vector : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) -#pragma omp parallel for reduction(merge \ - : pairs) schedule(static) \ +#pragma omp declare reduction( \ + merge : std::vector : omp_out.insert( \ + omp_out.end(), omp_in.begin(), omp_in.end())) +#pragma omp parallel for reduction(merge : pairs) schedule(static) \ num_threads(localThreadNumber) #endif for(ttk::SimplexId i = 0; i < saddleNumber; i++) { @@ -3870,7 +3876,8 @@ ttk::SimplexId ttk::DiscreteMorseSandwichMPI::computePairNumbers( ttk::SimplexId saddleNumber = saddleToPairedExtrema.size(); ttk::SimplexId computedSaddleNumber{0}; #ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for reduction(+ : computedSaddleNumber) schedule(static) num_threads(localThreadNumber) +#pragma omp parallel for reduction(+ : computedSaddleNumber) schedule(static) \ + num_threads(localThreadNumber) #endif for(ttk::SimplexId i = 0; i < saddleNumber; i++) { if(saddleToPairedExtrema[i] > -1 && saddles[i].rank_ == ttk::MPIrank_) { @@ -5710,7 +5717,9 @@ void ttk::DiscreteMorseSandwichMPI::getSaddleSaddlePairs( ttk::Timer t_mpi; ttk::startMPITimer(t_mpi, ttk::MPIrank_, ttk::MPIsize_); #endif -#pragma omp declare reduction (merge : std::vector: omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) +#pragma omp declare reduction( \ + merge : std::vector : omp_out.insert( \ + omp_out.end(), omp_in.begin(), omp_in.end())) #pragma omp parallel for reduction(merge : saddles1Gid) schedule(static) for(size_t i = 0; i < critical1Saddles.size(); i++) { const auto s1 = critical1Saddles[i]; @@ -5838,9 +5847,9 @@ void ttk::DiscreteMorseSandwichMPI::getSaddleSaddlePairs( = std::min(saddle2Number + 1, static_cast(10)); ttk::SimplexId taskNum = static_cast(saddle2Number / taskSize) + 1; -#pragma omp parallel num_threads(threadNumber_) shared( \ - onBoundaryThread, s1Locks, s2Locks, s2GlobalBoundaries, s2LocalBoundaries, \ - localEdgeToSaddle1_, saddles2, edgeTrianglePartner) +#pragma omp parallel num_threads(threadNumber_) shared( \ + onBoundaryThread, s1Locks, s2Locks, s2GlobalBoundaries, s2LocalBoundaries, \ + localEdgeToSaddle1_, saddles2, edgeTrianglePartner) { #pragma omp single nowait { @@ -6014,7 +6023,7 @@ void ttk::DiscreteMorseSandwichMPI::getSaddleSaddlePairs( ->second; #pragma omp task firstprivate(lid) \ shared(s2GlobalBoundaries, s2LocalBoundaries, edgeTrianglePartner, s1Locks, \ - s2Locks, saddles2) + s2Locks, saddles2) { ttk::SimplexId lidBlock; ttk::SimplexId lidElement; @@ -6052,7 +6061,9 @@ void ttk::DiscreteMorseSandwichMPI::getSaddleSaddlePairs( Timer tmseq{}; // extract saddle-saddle pairs from computed boundaries -#pragma omp declare reduction (merge : std::vector: omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) +#pragma omp declare reduction( \ + merge : std::vector : omp_out.insert( \ + omp_out.end(), omp_in.begin(), omp_in.end())) #pragma omp parallel for reduction(merge : pairs) schedule(static) for(size_t i = 0; i < edgeTrianglePartner.size(); ++i) { if(edgeTrianglePartner[i] != -1) { diff --git a/core/base/discreteVectorField/DiscreteVectorField.h b/core/base/discreteVectorField/DiscreteVectorField.h index 25d78b87f2..510df06be9 100644 --- a/core/base/discreteVectorField/DiscreteVectorField.h +++ b/core/base/discreteVectorField/DiscreteVectorField.h @@ -60,8 +60,8 @@ namespace ttk { const std::array &lowVerts, const std::array &lowVertWeights, const std::array &faces) - : Cell{dim, id}, lowVerts_{lowVerts}, - lowVertWeights_{lowVertWeights}, faces_{faces} { + : Cell{dim, id}, lowVerts_{lowVerts}, lowVertWeights_{lowVertWeights}, + faces_{faces} { } // ID values for Outward vertices in current Outward star diff --git a/core/base/distanceMatrixDistortion/DistanceMatrixDistortion.cpp b/core/base/distanceMatrixDistortion/DistanceMatrixDistortion.cpp index e5e1fb63ac..e91c515987 100644 --- a/core/base/distanceMatrixDistortion/DistanceMatrixDistortion.cpp +++ b/core/base/distanceMatrixDistortion/DistanceMatrixDistortion.cpp @@ -41,9 +41,8 @@ int ttk::DistanceMatrixDistortion::execute( } #ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for num_threads(this->threadNumber_) reduction(max \ - : maxi) \ - schedule(dynamic) +#pragma omp parallel for num_threads(this->threadNumber_) \ + reduction(max : maxi) schedule(dynamic) #endif // TTK_ENABLE_OPENMP for(size_t i = 0; i < n; i++) { for(size_t j = i + 1; j < n; j++) { diff --git a/core/base/ftmTree/FTMTree_CT_Template.h b/core/base/ftmTree/FTMTree_CT_Template.h index 2ff214b909..fcd883aefd 100644 --- a/core/base/ftmTree/FTMTree_CT_Template.h +++ b/core/base/ftmTree/FTMTree_CT_Template.h @@ -100,61 +100,61 @@ namespace ttk { this->printMsg({"- final number of nodes :", nbNodes}); } } -// clang-format on -// clang format fail to use the right indentation level -// here, but it break the code if not disabled... + // clang-format on + // clang format fail to use the right indentation level + // here, but it break the code if not disabled... -// ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ -template -int FTMTree_CT::leafSearch(const triangulationType *mesh) { - const auto nbScalars = scalars_->size; - const auto chunkSize = getChunkSize(); - const auto chunkNb = getChunkCount(); + template + int FTMTree_CT::leafSearch(const triangulationType *mesh) { + const auto nbScalars = scalars_->size; + const auto chunkSize = getChunkSize(); + const auto chunkNb = getChunkCount(); - // Extrema extract and launch tasks - for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) { + // Extrema extract and launch tasks + for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) { #ifdef TTK_ENABLE_OPENMP4 #pragma omp task firstprivate(chunkId) #endif - { - const SimplexId lowerBound = chunkId * chunkSize; - const SimplexId upperBound - = std::min(nbScalars, (chunkId + 1) * chunkSize); - for(SimplexId v = lowerBound; v < upperBound; ++v) { - const auto &neighNumb = mesh->getVertexNeighborNumber(v); - valence upval = 0; - valence downval = 0; - - for(valence n = 0; n < neighNumb; ++n) { - SimplexId neigh{-1}; - mesh->getVertexNeighbor(v, n, neigh); - if(scalars_->isLower(neigh, v)) { - ++downval; - } else { - ++upval; + { + const SimplexId lowerBound = chunkId * chunkSize; + const SimplexId upperBound + = std::min(nbScalars, (chunkId + 1) * chunkSize); + for(SimplexId v = lowerBound; v < upperBound; ++v) { + const auto &neighNumb = mesh->getVertexNeighborNumber(v); + valence upval = 0; + valence downval = 0; + + for(valence n = 0; n < neighNumb; ++n) { + SimplexId neigh{-1}; + mesh->getVertexNeighbor(v, n, neigh); + if(scalars_->isLower(neigh, v)) { + ++downval; + } else { + ++upval; + } + } + + jt_.setValence(v, downval); + st_.setValence(v, upval); + + if(!downval) { + jt_.makeNode(v); + } + + if(!upval) { + st_.makeNode(v); + } } } - - jt_.setValence(v, downval); - st_.setValence(v, upval); - - if(!downval) { - jt_.makeNode(v); - } - - if(!upval) { - st_.makeNode(v); - } } - } - } #ifdef TTK_ENABLE_OPENMP4 #pragma omp taskwait #endif - return 0; -} + return 0; + } -} // namespace ftm + } // namespace ftm } // namespace ttk diff --git a/core/base/implicitTriangulation/ImplicitTriangulation.h b/core/base/implicitTriangulation/ImplicitTriangulation.h index 2824b66cad..eda8e9be3d 100644 --- a/core/base/implicitTriangulation/ImplicitTriangulation.h +++ b/core/base/implicitTriangulation/ImplicitTriangulation.h @@ -110,29 +110,33 @@ namespace ttk { virtual int getTetrahedronEdge(const SimplexId &tetId, const int &id, - SimplexId &edgeId) const = 0; + SimplexId &edgeId) const + = 0; int getTetrahedronEdges(std::vector> &edges) const; virtual int getTetrahedronTriangle(const SimplexId &tetId, const int &id, - SimplexId &triangleId) const = 0; + SimplexId &triangleId) const + = 0; int getTetrahedronTriangles( std::vector> &triangles) const; virtual int getTetrahedronNeighbor(const SimplexId &tetId, const int &localNeighborId, - SimplexId &neighborId) const = 0; + SimplexId &neighborId) const + = 0; - virtual SimplexId - getTetrahedronNeighborNumber(const SimplexId &tetId) const = 0; + virtual SimplexId getTetrahedronNeighborNumber(const SimplexId &tetId) const + = 0; int getTetrahedronNeighbors(std::vector> &neighbors); virtual int getTetrahedronVertex(const SimplexId &tetId, const int &localVertexId, - SimplexId &vertexId) const = 0; + SimplexId &vertexId) const + = 0; SimplexId getTriangleEdgeNumberInternal( const SimplexId & /*triangleId*/) const override { @@ -155,10 +159,12 @@ namespace ttk { virtual int getTriangleNeighbor(const SimplexId &triangleId, const int &localNeighborId, - SimplexId &neighborId) const = 0; + SimplexId &neighborId) const + = 0; virtual SimplexId - getTriangleNeighborNumber(const SimplexId &triangleId) const = 0; + getTriangleNeighborNumber(const SimplexId &triangleId) const + = 0; int getTriangleNeighbors(std::vector> &neighbors); diff --git a/core/base/integralLines/IntegralLines.h b/core/base/integralLines/IntegralLines.h index 077793af87..c8ef149c76 100644 --- a/core/base/integralLines/IntegralLines.h +++ b/core/base/integralLines/IntegralLines.h @@ -713,8 +713,8 @@ int ttk::IntegralLines::execute(triangulationType *triangulation) { int const taskNumber = (int)seedNumber_ / chunkSize_; #ifdef TTK_ENABLE_OPENMP4 #ifdef TTK_ENABLE_MPI -#pragma omp parallel shared( \ - ttk::intgl::finishedElement_, toSend_, ttk::intgl::addedElement_) \ +#pragma omp parallel shared( \ + ttk::intgl::finishedElement_, toSend_, ttk::intgl::addedElement_) \ num_threads(threadNumber_) { #else diff --git a/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp b/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp index 2fbf81c706..f6798aae04 100644 --- a/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp +++ b/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp @@ -57,7 +57,7 @@ int ttk::LowestCommonAncestor::RMQuery(const int &i, const int &j) const { // Position of the min in the blocs between the bloc of i and j min_pos[1] = ((blocJ - blocI) > 1) ? blocMinimumPosition_[blocMinimumValueRMQ_.query( - blocI + 1, blocJ - 1)] + blocI + 1, blocJ - 1)] : INT_MAX; // Position of the min in the bloc containing the jth case min_pos[2] diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index de3e47c835..ab1e25d4bf 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -336,14 +336,15 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0) { memT[curr1 + l * dim2 + nn2 * dim3 + 0 * dim4] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - curr1, parent1, -1, -1, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - curr1, parent1, -1, -1, tree1, tree2) + curr1, parent1, -1, -1, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2( + curr1, parent1, -1, -1, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - curr1, parent1, -1, -1, tree1, tree2) + curr1, parent1, -1, -1, tree1, tree2) : editCost_Shifting( - curr1, parent1, -1, -1, tree1, tree2); + curr1, parent1, -1, -1, tree1, tree2); } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -378,14 +379,15 @@ namespace ttk { if(tree2->getNumberOfChildren(curr2) == 0) { memT[nn1 + 0 * dim2 + curr2 * dim3 + l * dim4] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - -1, -1, curr2, parent2, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - -1, -1, curr2, parent2, tree1, tree2) + -1, -1, curr2, parent2, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2( + -1, -1, curr2, parent2, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - -1, -1, curr2, parent2, tree1, tree2) + -1, -1, curr2, parent2, tree1, tree2) : editCost_Shifting( - -1, -1, curr2, parent2, tree1, tree2); + -1, -1, curr2, parent2, tree1, tree2); } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -433,15 +435,17 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0 and tree2->getNumberOfChildren(curr2) == 0) { memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] - = this->baseMetric_ == 0 ? editCost_Wasserstein1( - curr1, parent1, curr2, parent2, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - curr1, parent1, curr2, parent2, tree1, tree2) + = this->baseMetric_ == 0 + ? editCost_Wasserstein1( + curr1, parent1, curr2, parent2, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2( + curr1, parent1, curr2, parent2, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - curr1, parent1, curr2, parent2, tree1, tree2) + curr1, parent1, curr2, parent2, tree1, tree2) : editCost_Shifting( - curr1, parent1, curr2, parent2, tree1, tree2); + curr1, parent1, curr2, parent2, tree1, tree2); } //--------------------------------------------------------------------------- // If first tree only has one branch, try all decompositions of @@ -655,12 +659,14 @@ namespace ttk { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; matchedCost[m.first.first] - = this->baseMetric_ == 0 ? editCost_Wasserstein1( - m.first.first, m.first.second, m.second.first, m.second.second, - tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - m.first.first, m.first.second, m.second.first, - m.second.second, tree1, tree2) + = this->baseMetric_ == 0 + ? editCost_Wasserstein1(m.first.first, m.first.second, + m.second.first, + m.second.second, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2(m.first.first, m.first.second, + m.second.first, + m.second.second, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence(m.first.first, m.first.second, m.second.first, diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index c6ec23903f..ecc47705d9 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -288,7 +288,7 @@ namespace ttk { #ifdef TTK_ENABLE_OPENMP4 #pragma omp parallel for schedule(dynamic) \ shared(centroids, centroids2, oldCentroids_, oldCentroids2_) \ - num_threads(this->threadNumber_) if(parallelize_) + num_threads(this->threadNumber_) if(parallelize_) #endif for(unsigned int i = 0; i < centroids.size(); ++i) { std::vector> matching, diff --git a/core/base/mergeTreeClustering/MergeTreeDistance.h b/core/base/mergeTreeClustering/MergeTreeDistance.h index 331d5d0b2a..8cdbb84b81 100644 --- a/core/base/mergeTreeClustering/MergeTreeDistance.h +++ b/core/base/mergeTreeClustering/MergeTreeDistance.h @@ -935,7 +935,7 @@ namespace ttk { #ifdef TTK_ENABLE_OPENMP4 #pragma omp task firstprivate(taskQueue, nodeT) UNTIED() \ shared(treeTable, forestTable, treeBackTable, forestBackTable, \ - treeChildDone, treeNodeDone) if(isTree1) + treeChildDone, treeNodeDone) if(isTree1) { #endif const ftm::FTMTree_MT *treeT = (isTree1) ? tree1 : tree2; @@ -1089,7 +1089,7 @@ namespace ttk { #ifdef TTK_ENABLE_OPENMP4 #pragma omp task firstprivate(nodeT) UNTIED() \ shared(treeTable, forestTable, treeBackTable, forestBackTable, \ - treeChildDone, treeNodeDone) + treeChildDone, treeNodeDone) { #endif while((int)nodeT != -1) { diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.cpp b/core/base/numericalIntegralLines/NumericalIntegralLines.cpp index 95d7acda47..a1119d8682 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.cpp +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.cpp @@ -4,9 +4,8 @@ using namespace std; using namespace ttk; using namespace nil; -NumericalIntegralLines::NumericalIntegralLines(){ +NumericalIntegralLines::NumericalIntegralLines() { this->setDebugMsgPrefix("NumericalIntegralLines"); } NumericalIntegralLines::~NumericalIntegralLines() = default; - diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index ed8c1c7f61..627f1f48c3 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -18,16 +18,31 @@ #pragma once // base code includes +#include #include // std includes +#include +#include +#include +#include namespace ttk { namespace nil { - struct PathPoint{ - SimplexId simplexId_; - int simplexDimension_; - std::vector barycentricWeights_; + struct PathPoint { + SimplexId simplexId_; + int simplexDimension_; + std::vector barycentricWeights_; + }; + + /// Status of an elementary advection step (see doGradientStep()). + enum StepStatus { + /// The advection carries on (possibly in another simplex). + REGULAR_STEP = 0, + /// The advection reached the boundary of the domain. + BOUNDARY_REACHED = 1, + /// The advection reached a maximum (a minimum if backward). + EXTREMUM_REACHED = 2 }; class NumericalIntegralLines : virtual public Debug { @@ -36,10 +51,6 @@ namespace ttk { NumericalIntegralLines(); ~NumericalIntegralLines() override; - template - int computeEndPoint(const triangulationType *triangulation, - const PathPoint &start, PathPoint &end) const; - /** * @brief Compute a single numerical integral line. * @@ -49,16 +60,54 @@ namespace ttk { * @param isForawrd Forward or backward line (default: forward). */ template - int computeIntegralLine(const triangulationType *triangulation, - const std::pair &seed, - const std::vector &barycentricWeights, - std::vector &output, - const bool &isForward = false) const; + int computeIntegralLine(const triangulationType *triangulation, + const std::pair &seed, + const std::vector &barycentricWeights, + std::vector &output, + const bool &isForward = false) const; + /** + * @brief Compute the gradient of the piecewise linear scalar field, + * restricted to the affine hull of the input simplex. + * + * @param simplexDimension Dimension of the input simplex. + * @param simplexId Identifier of the input simplex. + * @param gradient Output 3D gradient vector. + * @param barycentricGradient Optional output expression of the gradient + * in the edge basis (v1 - v0, ... vd - v0) of the simplex. This is also + * the variation of the barycentric weights (but for the first one) + * induced by a displacement along the gradient. + */ template - int computeNumericalGradient(const triangulationType *triangulation, - const int &simplexDimension, const int &simplexId, - std::vector &gradient) const; + int computeNumericalGradient(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + std::vector &gradient, + std::vector *barycentricGradient + = nullptr) const; + + /** + * @brief Elementary step of advection. + * + * Since the gradient of a piecewise linear scalar field is constant + * within a simplex, the integral line is a straight segment there. + * Hence, this step is integrated exactly: the current point is advected + * within its simplex until it reaches its boundary. Then, the simplex in + * which the advection carries on is identified (along with the + * barycentric coordinates of the advected point within it). + * + * @param current Input point (simplex, dimension, barycentric weights). + * @param isForward Forward or backward advection. + * @param next Output point (simplex, dimension, barycentric weights). + * @return StepStatus upon success (negative values otherwise). When the + * advection cannot carry on (boundary of the domain or extremum), the + * output simplex is the input one (with updated barycentric weights). + */ + template + int doGradientStep(const triangulationType *triangulation, + const PathPoint ¤t, + const bool &isForward, + PathPoint &next) const; /** * @brief Compute numerical integral lines. @@ -69,68 +118,309 @@ namespace ttk { */ template int execute(const triangulationType *triangulation, - const std::vector> &seeds, - std::vector> &output, - const bool &isForward = false) const; + const std::vector> &seeds, + std::vector> &output, + const bool &isForward = false) const; + + /** + * @brief Compute the variation of the barycentric weights of a point + * advected within the input simplex, per unit of arc length. + * + * @param slope Optional output slope of the scalar field along the + * (unit) advection direction. + * @return 0 if the advection can be carried on within the simplex + * (negative values otherwise, in particular if the restriction of the + * scalar field to the simplex is uniform). + */ + template + int getBarycentricVelocity(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + const bool &isForward, + std::vector &velocity, + float *slope = nullptr) const; + + /** + * @brief Retrieve the identifier of the face of the input simplex which + * is spanned by the input vertices. + */ + template + int getFaceIdentifier(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + const std::vector &faceVertices, + const int &faceDimension, + SimplexId &faceIdentifier) const; + + /** + * @brief Compute the 3D coordinates of a path point. + */ + template + int getPointCoordinates(const triangulationType *triangulation, + const PathPoint &point, + std::array &coordinates) const; + + /** + * @brief Retrieve the cofaces of the input simplex (i.e. the simplices + * of the star of the input simplex, of higher dimension), as a list of + * (identifier, dimension) pairs. + */ + template + int getCofaces(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + std::vector> &cofaces) const; + + /** + * @brief Retrieve the face of the input simplex which supports the point + * of input barycentric weights (i.e. the face spanned by the vertices of + * non-zero weight). + */ + template + int getSubSimplex(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + const std::vector &barycentricWeights, + PathPoint &subSimplex) const; + + template + int getVertexIdentifiers(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + std::vector &vertexIdentifiers) const; + /** + * @brief Check if the input simplex is on the boundary of the domain. + */ template - int getVertexIdentifiers(const triangulationType *triangulation, - const int &simplexDimension, const int &simplexId, - std::vector vertexIdentifiers) const; + bool isOnDomainBoundary(const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId) const; + + /** + * @brief Check if an advection of input velocity can be carried on + * within a simplex, from a point of input barycentric weights (i.e. the + * advection does not immediately leave the simplex). + */ + static inline bool + isMotionAdmissible(const std::vector &barycentricWeights, + const std::vector &velocity) { + + float maximumVelocity = 0; + for(int i = 0; i < (int)velocity.size(); i++) + if(std::abs(velocity[i]) > maximumVelocity) + maximumVelocity = std::abs(velocity[i]); + + if(!(maximumVelocity > 0)) + return false; + + for(int i = 0; i < (int)barycentricWeights.size(); i++) + if((barycentricWeights[i] <= barycentricEpsilon_) + && (velocity[i] < -relativeEpsilon_ * maximumVelocity)) + // the advection immediately exits through the i-th face + return false; + + return true; + } + + /** + * @brief Express the barycentric weights of a point, given for a + * simplex, in the basis of one of its cofaces. + */ + static inline int + mapBarycentricWeights(const std::vector &sourceVertices, + const std::vector &sourceWeights, + const std::vector &targetVertices, + std::vector &targetWeights) { + + targetWeights.clear(); + targetWeights.resize(targetVertices.size(), 0); + + for(int i = 0; i < (int)sourceVertices.size(); i++) { + bool isFound = false; + for(int j = 0; j < (int)targetVertices.size(); j++) { + if(targetVertices[j] == sourceVertices[i]) { + targetWeights[j] = sourceWeights[i]; + isFound = true; + break; + } + } + if(!isFound) + // the source simplex is not a face of the target one + return -1; + } + + return 0; + } + + static inline int + normalizeBarycentricWeights(std::vector &barycentricWeights) { + + if(barycentricWeights.empty()) + return -1; + + float sum = 0; + for(int i = 0; i < (int)barycentricWeights.size(); i++) { + if(barycentricWeights[i] < 0) + barycentricWeights[i] = 0; + sum += barycentricWeights[i]; + } + + if(!(sum > 0)) { + // degenerated weights: fall back on the barycenter + for(int i = 0; i < (int)barycentricWeights.size(); i++) + barycentricWeights[i] = 1.0 / barycentricWeights.size(); + return -2; + } + + for(int i = 0; i < (int)barycentricWeights.size(); i++) + barycentricWeights[i] /= sum; + + return 0; + } /** * @brief Triangulation preconditioning. */ - inline void preconditionTriangulation(AbstractTriangulation *triangulation){ + inline void + preconditionTriangulation(AbstractTriangulation *triangulation) { + + if(triangulation == nullptr) + return; + // precondition simplex2face + triangulation->preconditionEdges(); + triangulation->preconditionCellEdges(); + // precondition face2cofacets + triangulation->preconditionVertexEdges(); + triangulation->preconditionVertexStars(); + triangulation->preconditionEdgeStars(); + + // precondition boundary + triangulation->preconditionBoundaryVertices(); + triangulation->preconditionBoundaryEdges(); + + if(triangulation->getDimensionality() == 3) { + triangulation->preconditionTriangles(); + triangulation->preconditionTriangleEdges(); + triangulation->preconditionCellTriangles(); + triangulation->preconditionVertexTriangles(); + triangulation->preconditionEdgeTriangles(); + triangulation->preconditionTriangleStars(); + triangulation->preconditionBoundaryTriangles(); + } } - inline void setInputScalarField(const void *const scalars){ + inline void setInputScalarField(const void *const scalars) { scalars_ = scalars; } protected: + /// Below this value, a barycentric weight is considered as null. + static constexpr float barycentricEpsilon_{1e-6}; + /// Relative tolerance used for the null tests on the velocity. + static constexpr float relativeEpsilon_{1e-6}; + int maximumIterationNumber_{1000000000}; - const void *scalars_; + /// Number of consecutive steps without any motion after which the + /// advection is considered as arbitrarily close to an extremum. + int maximumStalledStepNumber_{8}; + const void *scalars_{}; }; } // namespace nil } // namespace ttk template - int ttk::nil::NumericalIntegralLines::computeEndPoint( - const triangulationType *triangulation, - const ttk::nil::PathPoint &start, ttk::nil::PathPoint &end) const{ +int ttk::nil::NumericalIntegralLines::computeIntegralLine( + const triangulationType *triangulation, + const std::pair &seed, + const std::vector &startBarycentricWeights, + std::vector &output, + const bool &isForward) const { - std::vector gradient(3); + output.clear(); - computeNumericalGradient( - triangulation, start.simplexDimension_, start.simplexId_, gradient); +#ifndef TTK_ENABLE_KAMIKAZE + if(triangulation == nullptr) + return -1; + if(scalars_ == nullptr) + return -2; + if((seed.second < 0) || (seed.second > triangulation->getDimensionality())) + return -3; +#endif + PathPoint current; + current.simplexId_ = seed.first; + current.simplexDimension_ = seed.second; + current.barycentricWeights_ = startBarycentricWeights; + if((int)current.barycentricWeights_.size() != seed.second + 1) + // no valid input coordinates: start from the barycenter of the seed + current.barycentricWeights_.assign( + seed.second + 1, 1.0 / (seed.second + 1)); + normalizeBarycentricWeights(current.barycentricWeights_); - return 0; -} + output.push_back(current); -template - int ttk::nil::NumericalIntegralLines::computeIntegralLine( - const triangulationType *triangulation, - const std::pair &seed, - const std::vector &startBarycentricWeights, - std::vector &output, - const bool &isForward) const{ + std::array previousCoordinates{}, currentCoordinates{}; + getPointCoordinates(triangulation, current, previousCoordinates); - output.clear(); + // an advection step may legitimately not move the current point (it can + // simply update the simplex supporting it, for instance when leaving a + // vertex for one of the tetrahedra of its star). however, a point which no + // longer moves is arbitrarily close to an extremum. + int stalledStepNumber = 0; + float pathLength = 0; + + int step = 0, status = REGULAR_STEP; + + for(step = 0; step < maximumIterationNumber_; step++) { - PathPoint startPoint, endPoint; + PathPoint next; - startPoint.simplexId_ = seed.first; - startPoint.simplexDimension_ = seed.second; - startPoint.barycentricWeights_ = startBarycentricWeights; + status = doGradientStep( + triangulation, current, isForward, next); - for(int i = 0; i < (int) maximumIterationNumber_; i++){ + if(status < 0) + return status; - computeEndPoint(triangulation, startPoint, endPoint); + getPointCoordinates(triangulation, next, currentCoordinates); + + const float stepLength = Geometry::distance( + previousCoordinates.data(), currentCoordinates.data()); + + if(stepLength > pathLength * std::numeric_limits::epsilon()) { + output.push_back(next); + pathLength += stepLength; + stalledStepNumber = 0; + } else { + // the point did not move: only update the simplex supporting it + output.back() = next; + stalledStepNumber++; + } + + current = next; + previousCoordinates = currentCoordinates; + + if(status != REGULAR_STEP) + // the advection either left the domain or reached an extremum + break; + + if(stalledStepNumber > maximumStalledStepNumber_) { + // the advection is arbitrarily close to an extremum + status = EXTREMUM_REACHED; + break; + } + } + + if(step == maximumIterationNumber_) { +#ifdef TTK_ENABLE_OPENMP +#pragma omp critical +#endif + printWrn("Maximum iteration number reached for seed-#" + + std::to_string(seed.first) + + " (dim: " + std::to_string(seed.second) + ")."); } return 0; @@ -140,53 +430,70 @@ template // move that function to the geometry class template - int ttk::nil::NumericalIntegralLines::computeNumericalGradient( - const triangulationType *triangulation, - const int &simplexDimension, const int &simplexId, - std::vector &gradient) const{ +int ttk::nil::NumericalIntegralLines::computeNumericalGradient( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + std::vector &gradient, + std::vector *barycentricGradient) const { gradient = {0, 0, 0}; + if(barycentricGradient) + barycentricGradient->assign(simplexDimension, 0); + if(!simplexDimension) return -1; std::vector vertexIdentifiers; - getVertexIdentifiers(triangulation, simplexDimension, simplexId, vertexIdentifiers); + getVertexIdentifiers( + triangulation, simplexDimension, simplexId, vertexIdentifiers); const int vertexNumber = vertexIdentifiers.size(); std::vector> vertexPoints(vertexNumber); std::vector vertexScalars(vertexNumber); - for(int i = 0; i < (int) vertexNumber; i++){ - triangulation->getVertexPoint(vertexIdentifiers[i], - vertexPoints[i][0], vertexPoints[i][1], vertexPoints[i][2]); - vertexScalars[i] = ((dataType *) scalars_)[vertexIdentifiers[i]]; + for(int i = 0; i < (int)vertexNumber; i++) { + triangulation->getVertexPoint(vertexIdentifiers[i], vertexPoints[i][0], + vertexPoints[i][1], vertexPoints[i][2]); + vertexScalars[i] = ((const dataType *)scalars_)[vertexIdentifiers[i]]; } // build edge vectors and corresponding differences, wrt v0 std::vector> edgeVectors(simplexDimension); - std::vector edgeDifferences(simplexDimension); + std::vector edgeDifferences(simplexDimension); for(int i = 0; i < simplexDimension; i++) { for(int c = 0; c < 3; c++) edgeVectors[i][c] = vertexPoints[i + 1][c] - vertexPoints[0][c]; - edgeDifferences[i] = vertexScalars[i + 1] - vertexScalars[0]; + edgeDifferences[i] + = ((float)vertexScalars[i + 1]) - ((float)vertexScalars[0]); } // Gram matrix gramMatrix[i][j] = edgeVectors[i] . edgeVectors[j] - std::vector> - gramMatrix(simplexDimension, std::vector(simplexDimension, 0)); + std::vector> gramMatrix( + simplexDimension, std::vector(simplexDimension, 0)); - for(int i = 0; i < simplexDimension; i++) + float maximumDiagonalEntry = 0; + + for(int i = 0; i < simplexDimension; i++) { for(int j = 0; j < simplexDimension; j++) gramMatrix[i][j] = ttk::Geometry::dotProduct( edgeVectors[i].data(), edgeVectors[j].data()); + if(gramMatrix[i][i] > maximumDiagonalEntry) + maximumDiagonalEntry = gramMatrix[i][i]; + } + + if(!(maximumDiagonalEntry > 0)) + // degenerated simplex + return -2; + // Gaussian elimintation - std::vector> - augmentedMatrix(simplexDimension, std::vector(simplexDimension + 1)); + std::vector> augmentedMatrix( + simplexDimension, std::vector(simplexDimension + 1)); for(int i = 0; i < simplexDimension; ++i) { for(int j = 0; j < simplexDimension; ++j) augmentedMatrix[i][j] = gramMatrix[i][j]; @@ -197,13 +504,14 @@ template // Partial pivot int pivot = col; for(int row = col + 1; row < simplexDimension; row++) - if(std::abs(augmentedMatrix[row][col]) > - std::abs(augmentedMatrix[pivot][col])) + if(std::abs(augmentedMatrix[row][col]) + > std::abs(augmentedMatrix[pivot][col])) pivot = row; std::swap(augmentedMatrix[col], augmentedMatrix[pivot]); const float diagVal = augmentedMatrix[col][col]; - if(std::abs(diagVal) < powf(10, -FLT_DIG)) + if(std::abs(diagVal) < powf(10, -FLT_DIG) * maximumDiagonalEntry) + // degenerated simplex return -2; for(int row = 0; row < simplexDimension; row++) { @@ -224,14 +532,172 @@ template for(int c = 0; c < 3; c++) gradient[c] += alpha[i] * edgeVectors[i][c]; + if(barycentricGradient) + *barycentricGradient = alpha; + return 0; } template -int ttk::nil::NumericalIntegralLines::execute(const triangulationType *triangulation, - const std::vector> &seeds, - std::vector> &output, - const bool &isForward) const{ +int ttk::nil::NumericalIntegralLines::doGradientStep( + const triangulationType *triangulation, + const PathPoint ¤t, + const bool &isForward, + PathPoint &next) const { + + next = current; + + // 1) advection within the current simplex. + // the gradient of a piecewise linear scalar field is constant within a + // simplex. hence, the integral line is a straight segment there, which can + // be integrated exactly: the point is advected until it reaches the boundary + // of the simplex. + std::vector weights = current.barycentricWeights_; + std::vector velocity; + bool hasMoved = false; + + if(getBarycentricVelocity( + triangulation, current.simplexDimension_, current.simplexId_, isForward, + velocity) + == 0) { + + float maximumVelocity = 0; + for(int i = 0; i <= current.simplexDimension_; i++) + if(std::abs(velocity[i]) > maximumVelocity) + maximumVelocity = std::abs(velocity[i]); + + // largest arc length which maintains the point within the simplex + float travelDistance = std::numeric_limits::infinity(); + for(int i = 0; i <= current.simplexDimension_; i++) { + if(velocity[i] < -relativeEpsilon_ * maximumVelocity) { + const float distance = current.barycentricWeights_[i] / (-velocity[i]); + if(distance < travelDistance) + travelDistance = distance; + } + } + + if((travelDistance > 0) + && (travelDistance < std::numeric_limits::infinity())) { + + for(int i = 0; i <= current.simplexDimension_; i++) + weights[i] + = current.barycentricWeights_[i] + travelDistance * velocity[i]; + normalizeBarycentricWeights(weights); + + hasMoved = true; + } + } + + // the advected point is now supported by a face of the current simplex + PathPoint exitPoint; + if(getSubSimplex(triangulation, current.simplexDimension_, current.simplexId_, + weights, exitPoint) + < 0) + return -1; + + // 2) identify the simplex in which the advection carries on. + // the flow is taken over by the coface of the exit face which maximizes the + // slope of the scalar field (the steepest one) among the cofaces which admit + // the advection. note that the gradient restricted to a face of a simplex is + // the projection of the gradient of the simplex: the slope of a coface is + // therefore always larger than (or equal to) that of the exit face. + std::vector> cofaces; + getCofaces( + triangulation, exitPoint.simplexDimension_, exitPoint.simplexId_, cofaces); + + std::vector exitVertices, cofaceVertices; + getVertexIdentifiers(triangulation, exitPoint.simplexDimension_, + exitPoint.simplexId_, exitVertices); + + PathPoint bestPoint; + bestPoint.simplexDimension_ = -1; + float bestSlope = 0; + + for(int i = 0; i < (int)cofaces.size(); i++) { + + PathPoint candidate; + candidate.simplexId_ = cofaces[i].first; + candidate.simplexDimension_ = cofaces[i].second; + + getVertexIdentifiers(triangulation, candidate.simplexDimension_, + candidate.simplexId_, cofaceVertices); + + // express the advected point in the barycentric basis of the coface + if(mapBarycentricWeights(exitVertices, exitPoint.barycentricWeights_, + cofaceVertices, candidate.barycentricWeights_) + < 0) + continue; + + float slope = 0; + if(getBarycentricVelocity( + triangulation, candidate.simplexDimension_, candidate.simplexId_, + isForward, velocity, &slope) + < 0) + continue; + + if(!isMotionAdmissible(candidate.barycentricWeights_, velocity)) + // the advection would immediately leave this coface + continue; + + // steepest slope: along a unit direction, the variation of the scalar + // field is given by the magnitude of the gradient. + // ties (the gradient of the coface is aligned with one of its faces) are + // settled in favor of the coface of highest dimension (i.e. the least + // constrained advection). + if((slope > bestSlope) + || ((slope > bestSlope * (1 - relativeEpsilon_)) + && (candidate.simplexDimension_ > bestPoint.simplexDimension_))) { + bestSlope = slope; + bestPoint = candidate; + } + } + + if(bestPoint.simplexDimension_ >= 0) { + next = bestPoint; + return REGULAR_STEP; + } + + // no coface takes the flow over. + const bool isOnBoundary = isOnDomainBoundary( + triangulation, exitPoint.simplexDimension_, exitPoint.simplexId_); + + if((!isOnBoundary) && (exitPoint.simplexDimension_ > 0) + && ((exitPoint.simplexDimension_ != current.simplexDimension_) + || (exitPoint.simplexId_ != current.simplexId_))) { + + // in the interior of the domain, the flow is then constrained to the exit + // face itself (typically, two cells whose gradients both point towards + // their common face). + if(getBarycentricVelocity( + triangulation, exitPoint.simplexDimension_, exitPoint.simplexId_, + isForward, velocity) + == 0) { + + if(isMotionAdmissible(exitPoint.barycentricWeights_, velocity)) { + next = exitPoint; + return REGULAR_STEP; + } + } + } + + // the advection stops here: report the advected point within the current + // simplex (same simplex, different barycentric weights). + next.simplexId_ = current.simplexId_; + next.simplexDimension_ = current.simplexDimension_; + next.barycentricWeights_ = weights; + + if(hasMoved && isOnBoundary) + return BOUNDARY_REACHED; + + return EXTREMUM_REACHED; +} + +template +int ttk::nil::NumericalIntegralLines::execute( + const triangulationType *triangulation, + const std::vector> &seeds, + std::vector> &output, + const bool &isForward) const { Timer t; @@ -240,63 +706,363 @@ int ttk::nil::NumericalIntegralLines::execute(const triangulationType *triangula #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) #endif - for(int i = 0; i < (int) seeds.size(); i++){ - std::vector - barycentricWeights(seeds[i].second + 1, 1/(seeds[i].second + 1)); + for(int i = 0; i < (int)seeds.size(); i++) { + std::vector barycentricWeights( + seeds[i].second + 1, 1.0 / (seeds[i].second + 1)); computeIntegralLine( triangulation, seeds[i], barycentricWeights, output[i], isForward); #ifdef TTK_ENABLE_OPENMP #pragma omp critical #endif - printMsg(" - Seed-#" - + std::to_string(seeds[i].first) - + " (dim: " - + std::to_string(seeds[i].second) - + ", f: " - + std::to_string(isForward) - + "): " - + std::to_string(output[i].size()) + " point(s).", - debug::Priority::DETAIL); + printMsg(" - Seed-#" + std::to_string(seeds[i].first) + + " (dim: " + std::to_string(seeds[i].second) + + ", f: " + std::to_string(isForward) + + "): " + std::to_string(output[i].size()) + " point(s).", + debug::Priority::DETAIL); + } + + printMsg("Computed from " + std::to_string(output.size()) + " seed(s)", 1, + t.getElapsedTime(), threadNumber_); + + return 0; +} + +template +int ttk::nil::NumericalIntegralLines::getBarycentricVelocity( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + const bool &isForward, + std::vector &velocity, + float *slope) const { + + velocity.clear(); + + if(slope) + *slope = 0; + + if(simplexDimension < 1) + // no motion within a vertex + return -1; + + std::vector gradient, barycentricGradient; + + if(computeNumericalGradient( + triangulation, simplexDimension, simplexId, gradient, + &barycentricGradient) + < 0) + return -2; + + // along the unit advection direction, the variation of the scalar field is + // given by the magnitude of the gradient + const float magnitude = ttk::Geometry::magnitude(gradient.data()); + + if(!(magnitude > 0)) + // uniform scalar field: no motion + return -3; + + if(slope) + *slope = magnitude; + + // unit speed advection (the integration variable is the arc length) + const float scale = (isForward ? 1.0 : -1.0) / magnitude; + + velocity.resize(simplexDimension + 1, 0); + for(int i = 0; i < simplexDimension; i++) { + velocity[i + 1] = scale * barycentricGradient[i]; + // the barycentric weights sum up to 1 + velocity[0] -= scale * barycentricGradient[i]; + } + + return 0; +} + +template +int ttk::nil::NumericalIntegralLines::getFaceIdentifier( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + const std::vector &faceVertices, + const int &faceDimension, + SimplexId &faceIdentifier) const { + + faceIdentifier = -1; + + if(faceDimension == simplexDimension) { + faceIdentifier = simplexId; + return 0; + } + + if(!faceDimension) { + faceIdentifier = faceVertices[0]; + return 0; + } + + const int cellDimension = triangulation->getDimensionality(); + + int faceNumber = 0; + if(faceDimension == 1) { + if(simplexDimension == cellDimension) + faceNumber = triangulation->getCellEdgeNumber(simplexId); + else + // edges of a triangle + faceNumber = 3; + } else if(faceDimension == 2) + // triangles of a tetrahedron + faceNumber = triangulation->getCellTriangleNumber(simplexId); + else + return -1; + + // identify the face of the simplex which spans the input vertices + std::vector candidateVertices; + + for(int i = 0; i < faceNumber; i++) { + + SimplexId candidateId = -1; + + if(faceDimension == 1) { + if(simplexDimension == cellDimension) + triangulation->getCellEdge(simplexId, i, candidateId); + else + triangulation->getTriangleEdge(simplexId, i, candidateId); + } else + triangulation->getCellTriangle(simplexId, i, candidateId); + + getVertexIdentifiers( + triangulation, faceDimension, candidateId, candidateVertices); + + bool isMatching = true; + for(int j = 0; j < (int)faceVertices.size(); j++) { + bool isFound = false; + for(int k = 0; k < (int)candidateVertices.size(); k++) { + if(candidateVertices[k] == faceVertices[j]) { + isFound = true; + break; + } + } + if(!isFound) { + isMatching = false; + break; + } + } + + if(isMatching) { + faceIdentifier = candidateId; + return 0; + } + } + + return -2; +} + +template +int ttk::nil::NumericalIntegralLines::getPointCoordinates( + const triangulationType *triangulation, + const PathPoint &point, + std::array &coordinates) const { + + coordinates = {0, 0, 0}; + + std::vector vertexIdentifiers; + + if(getVertexIdentifiers(triangulation, point.simplexDimension_, + point.simplexId_, vertexIdentifiers) + < 0) + return -1; + + for(int i = 0; i < (int)vertexIdentifiers.size(); i++) { + std::array vertexPoint; + triangulation->getVertexPoint( + vertexIdentifiers[i], vertexPoint[0], vertexPoint[1], vertexPoint[2]); + for(int c = 0; c < 3; c++) + coordinates[c] += point.barycentricWeights_[i] * vertexPoint[c]; + } + + return 0; +} + +template +int ttk::nil::NumericalIntegralLines::getCofaces( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + std::vector> &cofaces) const { + + cofaces.clear(); + + const int cellDimension = triangulation->getDimensionality(); + + if((simplexDimension < 0) || (simplexDimension >= cellDimension)) + // a top dimensional cell has no coface + return -1; + + SimplexId cofaceId = -1; + + if(!simplexDimension) { + // the edges of the star of the vertex + const SimplexId edgeNumber = triangulation->getVertexEdgeNumber(simplexId); + for(SimplexId i = 0; i < edgeNumber; i++) { + triangulation->getVertexEdge(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, 1)); + } + + if(cellDimension == 3) { + // the triangles of the star of the vertex + const SimplexId triangleNumber + = triangulation->getVertexTriangleNumber(simplexId); + for(SimplexId i = 0; i < triangleNumber; i++) { + triangulation->getVertexTriangle(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, 2)); + } + } + + // the cells of the star of the vertex + const SimplexId starNumber = triangulation->getVertexStarNumber(simplexId); + for(SimplexId i = 0; i < starNumber; i++) { + triangulation->getVertexStar(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, cellDimension)); + } + + return 0; } - printMsg("Computed numerical integral line(s) from " - + std::to_string(output.size()) - + " seed(s)" - , 1, - t.getElapsedTime(), threadNumber_); + if(simplexDimension == 1) { + if(cellDimension == 3) { + // the triangles of the star of the edge + const SimplexId triangleNumber + = triangulation->getEdgeTriangleNumber(simplexId); + for(SimplexId i = 0; i < triangleNumber; i++) { + triangulation->getEdgeTriangle(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, 2)); + } + } + + // the cells of the star of the edge + const SimplexId starNumber = triangulation->getEdgeStarNumber(simplexId); + for(SimplexId i = 0; i < starNumber; i++) { + triangulation->getEdgeStar(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, cellDimension)); + } + + return 0; + } + + // the cells of the star of the triangle + const SimplexId starNumber = triangulation->getTriangleStarNumber(simplexId); + for(SimplexId i = 0; i < starNumber; i++) { + triangulation->getTriangleStar(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, cellDimension)); + } return 0; } template - int ttk::nil::NumericalIntegralLines::getVertexIdentifiers( - const triangulationType *triangulation, - const int &simplexDimension, const int &simplexId, - std::vector vertexIdentifiers) const{ +int ttk::nil::NumericalIntegralLines::getSubSimplex( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + const std::vector &barycentricWeights, + PathPoint &subSimplex) const { + + std::vector vertexIdentifiers; + + if(getVertexIdentifiers( + triangulation, simplexDimension, simplexId, vertexIdentifiers) + < 0) + return -1; + + // the point is supported by the face spanned by the vertices of non-zero + // barycentric weight + std::vector faceVertices; + std::vector faceWeights; + + for(int i = 0; i < (int)vertexIdentifiers.size(); i++) { + if(barycentricWeights[i] > barycentricEpsilon_) { + faceVertices.push_back(vertexIdentifiers[i]); + faceWeights.push_back(barycentricWeights[i]); + } + } - switch(simplexDimension){ + if(faceVertices.empty()) { + // degenerated weights: fall back on the closest vertex + int closestVertex = 0; + for(int i = 1; i < (int)vertexIdentifiers.size(); i++) + if(barycentricWeights[i] > barycentricWeights[closestVertex]) + closestVertex = i; + faceVertices = {vertexIdentifiers[closestVertex]}; + faceWeights = {1}; + } + + const int faceDimension = faceVertices.size() - 1; + + if(faceDimension == simplexDimension) { + subSimplex.simplexId_ = simplexId; + subSimplex.simplexDimension_ = simplexDimension; + subSimplex.barycentricWeights_ = barycentricWeights; + normalizeBarycentricWeights(subSimplex.barycentricWeights_); + return 0; + } + + SimplexId faceIdentifier = -1; + + if(getFaceIdentifier(triangulation, simplexDimension, simplexId, faceVertices, + faceDimension, faceIdentifier) + < 0) + return -2; + + subSimplex.simplexId_ = faceIdentifier; + subSimplex.simplexDimension_ = faceDimension; + + // the vertices of the face are not necessarily ordered as in the simplex + std::vector subVertexIdentifiers; + getVertexIdentifiers( + triangulation, faceDimension, faceIdentifier, subVertexIdentifiers); + + if(mapBarycentricWeights(faceVertices, faceWeights, subVertexIdentifiers, + subSimplex.barycentricWeights_) + < 0) + return -3; + + normalizeBarycentricWeights(subSimplex.barycentricWeights_); + + return 0; +} + +template +int ttk::nil::NumericalIntegralLines::getVertexIdentifiers( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId, + std::vector &vertexIdentifiers) const { + + if((simplexDimension < 0) || (simplexDimension > 3)) + return -1; + + vertexIdentifiers.resize(simplexDimension + 1); + + if(simplexDimension == triangulation->getDimensionality()) { + // top dimensional simplex: use the (faster) cell accessors + // (in 2D, triangles are cells) + for(int i = 0; i < simplexDimension + 1; i++) + triangulation->getCellVertex(simplexId, i, vertexIdentifiers[i]); + return 0; + } + + switch(simplexDimension) { case 0: - vertexIdentifiers = {simplexId}; + vertexIdentifiers[0] = simplexId; break; case 1: - vertexIdentifiers.resize(2); triangulation->getEdgeVertex(simplexId, 0, vertexIdentifiers[0]); triangulation->getEdgeVertex(simplexId, 1, vertexIdentifiers[1]); break; case 2: - vertexIdentifiers.resize(3); triangulation->getTriangleVertex(simplexId, 0, vertexIdentifiers[0]); triangulation->getTriangleVertex(simplexId, 1, vertexIdentifiers[1]); triangulation->getTriangleVertex(simplexId, 2, vertexIdentifiers[2]); break; - case 3: - vertexIdentifiers.resize(4); - triangulation->getCellVertex(simplexId, 0, vertexIdentifiers[0]); - triangulation->getCellVertex(simplexId, 1, vertexIdentifiers[1]); - triangulation->getCellVertex(simplexId, 2, vertexIdentifiers[2]); - triangulation->getCellVertex(simplexId, 3, vertexIdentifiers[3]); - break; default: return -1; break; @@ -304,3 +1070,25 @@ template return 0; } + +template +bool ttk::nil::NumericalIntegralLines::isOnDomainBoundary( + const triangulationType *triangulation, + const int &simplexDimension, + const SimplexId &simplexId) const { + + if(simplexDimension == triangulation->getDimensionality()) + // a top dimensional cell is never on the boundary of the domain + return false; + + switch(simplexDimension) { + case 0: + return triangulation->isVertexOnBoundary(simplexId); + case 1: + return triangulation->isEdgeOnBoundary(simplexId); + case 2: + return triangulation->isTriangleOnBoundary(simplexId); + } + + return false; +} diff --git a/core/base/periodicImplicitTriangulation/PeriodicImplicitTriangulation.h b/core/base/periodicImplicitTriangulation/PeriodicImplicitTriangulation.h index d0110a4536..c1f8b71dda 100644 --- a/core/base/periodicImplicitTriangulation/PeriodicImplicitTriangulation.h +++ b/core/base/periodicImplicitTriangulation/PeriodicImplicitTriangulation.h @@ -113,20 +113,23 @@ namespace ttk { virtual int getTetrahedronEdge(const SimplexId &tetId, const int &id, - SimplexId &edgeId) const = 0; + SimplexId &edgeId) const + = 0; int getTetrahedronEdges(std::vector> &edges) const; virtual int getTetrahedronTriangle(const SimplexId &tetId, const int &id, - SimplexId &triangleId) const = 0; + SimplexId &triangleId) const + = 0; int getTetrahedronTriangles( std::vector> &triangles) const; virtual int getTetrahedronNeighbor(const SimplexId &tetId, const int &localNeighborId, - SimplexId &neighborId) const = 0; + SimplexId &neighborId) const + = 0; SimplexId getTetrahedronNeighborNumber(const SimplexId &tetId) const; @@ -134,7 +137,8 @@ namespace ttk { virtual int getTetrahedronVertex(const SimplexId &tetId, const int &localVertexId, - SimplexId &vertexId) const = 0; + SimplexId &vertexId) const + = 0; SimplexId getTriangleEdgeNumberInternal( const SimplexId &ttkNotUsed(triangleId)) const override { @@ -157,7 +161,8 @@ namespace ttk { virtual int getTriangleNeighbor(const SimplexId &triangleId, const int &localNeighborId, - SimplexId &neighborId) const = 0; + SimplexId &neighborId) const + = 0; SimplexId getTriangleNeighborNumber(const SimplexId &triangleId) const; diff --git a/core/base/regularGridTriangulation/RegularGridTriangulation.cpp b/core/base/regularGridTriangulation/RegularGridTriangulation.cpp index e931676a65..26a20f2bb9 100644 --- a/core/base/regularGridTriangulation/RegularGridTriangulation.cpp +++ b/core/base/regularGridTriangulation/RegularGridTriangulation.cpp @@ -424,11 +424,9 @@ int ttk::RegularGridTriangulation::preconditionDistributedVertices() { localBBox_y_max{this->localGridOffset_[1]}, localBBox_z_max{this->localGridOffset_[2]}; #ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for reduction( \ - min \ - : localBBox_x_min, localBBox_y_min, localBBox_z_min) \ - reduction(max \ - : localBBox_x_max, localBBox_y_max, localBBox_z_max) +#pragma omp parallel for reduction( \ + min : localBBox_x_min, localBBox_y_min, localBBox_z_min) \ + reduction(max : localBBox_x_max, localBBox_y_max, localBBox_z_max) #endif for(SimplexId lvid = 0; lvid < nLocVertices; ++lvid) { // only keep non-ghost vertices diff --git a/core/base/regularGridTriangulation/RegularGridTriangulation.h b/core/base/regularGridTriangulation/RegularGridTriangulation.h index 751e4a333a..d0a97c03f5 100644 --- a/core/base/regularGridTriangulation/RegularGridTriangulation.h +++ b/core/base/regularGridTriangulation/RegularGridTriangulation.h @@ -88,16 +88,20 @@ namespace ttk { float spacing_[3]; // virtual void vertexToPosition2d(const SimplexId vertex, - SimplexId p[2]) const = 0; - virtual void vertexToPosition(const SimplexId vertex, - SimplexId p[3]) const = 0; + SimplexId p[2]) const + = 0; + virtual void vertexToPosition(const SimplexId vertex, SimplexId p[3]) const + = 0; virtual void triangleToPosition2d(const SimplexId triangle, - SimplexId p[2]) const = 0; + SimplexId p[2]) const + = 0; virtual void triangleToPosition(const SimplexId triangle, const int k, - SimplexId p[3]) const = 0; + SimplexId p[3]) const + = 0; virtual void tetrahedronToPosition(const SimplexId tetrahedron, - SimplexId p[3]) const = 0; + SimplexId p[3]) const + = 0; SimplexId findEdgeFromVertices(const SimplexId v0, const SimplexId v1) const; diff --git a/core/base/ripsPersistenceDiagram/FastRipsPersistenceDiagram2.cpp b/core/base/ripsPersistenceDiagram/FastRipsPersistenceDiagram2.cpp index 96a4627a55..34c77397a2 100644 --- a/core/base/ripsPersistenceDiagram/FastRipsPersistenceDiagram2.cpp +++ b/core/base/ripsPersistenceDiagram/FastRipsPersistenceDiagram2.cpp @@ -152,8 +152,8 @@ void FastRipsPersistenceDiagram2::computeRips0And1Persistence( e.d)) { // RNG edge critical.push_back(e); rng_.push_back(e); - if constexpr(std::is_same_v || std::is_same_v) + if constexpr(std::is_same_v + || std::is_same_v) ph[1].emplace_back(e.e); } else { // not RNG edge : merge neighboring polygons const int poly1 = UF.find(e.f1); diff --git a/core/base/topologicalCompression/TopologicalCompression.cpp b/core/base/topologicalCompression/TopologicalCompression.cpp index 171d5bb2b1..f71d2455fc 100644 --- a/core/base/topologicalCompression/TopologicalCompression.cpp +++ b/core/base/topologicalCompression/TopologicalCompression.cpp @@ -639,9 +639,10 @@ int ttk::TopologicalCompression::WriteToFile(FILE *fp, numberOfVertices *= (1 + dataExtent[2 * i + 1] - dataExtent[2 * i]); NbVertices = numberOfVertices; - int const totalSize = usePersistence ? ComputeTotalSizeForPersistenceDiagram( - getMapping(), getCriticalConstraints(), zfpOnly, - getNbSegments(), getNbVertices(), zfpTolerance) + int const totalSize = usePersistence + ? ComputeTotalSizeForPersistenceDiagram( + getMapping(), getCriticalConstraints(), zfpOnly, + getNbSegments(), getNbVertices(), zfpTolerance) : useOther ? ComputeTotalSizeForOther() : 0; diff --git a/core/base/triangulation/Triangulation.cpp b/core/base/triangulation/Triangulation.cpp index 617b6c9b94..ebdfc9e612 100644 --- a/core/base/triangulation/Triangulation.cpp +++ b/core/base/triangulation/Triangulation.cpp @@ -43,9 +43,9 @@ Triangulation::Triangulation(const Triangulation &rhs) Triangulation::Triangulation(Triangulation &&rhs) noexcept : AbstractTriangulation( - std::move(*static_cast(&rhs))), - abstractTriangulation_{nullptr}, explicitTriangulation_{std::move( - rhs.explicitTriangulation_)}, + std::move(*static_cast(&rhs))), + abstractTriangulation_{nullptr}, + explicitTriangulation_{std::move(rhs.explicitTriangulation_)}, implicitTriangulation_{std::move(rhs.implicitTriangulation_)}, periodicImplicitTriangulation_{ std::move(rhs.periodicImplicitTriangulation_)}, diff --git a/core/base/vectorSimplification/VectorSimplification.cpp b/core/base/vectorSimplification/VectorSimplification.cpp index 2e181eb45f..5bd12905f1 100644 --- a/core/base/vectorSimplification/VectorSimplification.cpp +++ b/core/base/vectorSimplification/VectorSimplification.cpp @@ -21,9 +21,10 @@ void ttk::VectorSimplification::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const CandidatePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if( - pairs.begin(), pairs.end(), - [](const CandidatePair &a) { return a.type == 1; }) + std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), + [](const CandidatePair &a) { + return a.type == 1; + }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/vectorSimplification/VectorSimplification.h b/core/base/vectorSimplification/VectorSimplification.h index 8987941abc..af7b5a8e5f 100644 --- a/core/base/vectorSimplification/VectorSimplification.h +++ b/core/base/vectorSimplification/VectorSimplification.h @@ -654,31 +654,32 @@ void ttk::VectorSimplification::getAscSaddlePairs( const auto dim = this->dcvf_.getDimensionality(); auto saddle2ToMaxima - = dim == 3 - ? getSaddle2ToAscPair( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getTriangleStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getTriangleStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isTriangleOnBoundary(a); - }, - triangulation, static_cast(0.0)) - : getSaddle2ToAscPair( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getEdgeStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getEdgeStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isEdgeOnBoundary(a); - }, - triangulation, static_cast(0.0)); + = dim == 3 ? getSaddle2ToAscPair( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getTriangleStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getTriangleStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isTriangleOnBoundary(a); + }, + triangulation, static_cast(0.0)) + : getSaddle2ToAscPair( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getEdgeStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getEdgeStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isEdgeOnBoundary(a); + }, + triangulation, static_cast(0.0)); for(size_t i = 0; i < saddle2ToMaxima.size(); ++i) { auto &maxs = saddle2ToMaxima[i]; diff --git a/core/base/vpaths/VPaths.cpp b/core/base/vpaths/VPaths.cpp index c2f3a90cc6..fdde6cc6e1 100644 --- a/core/base/vpaths/VPaths.cpp +++ b/core/base/vpaths/VPaths.cpp @@ -4,9 +4,8 @@ using namespace std; using namespace ttk; using namespace vp; -VPaths::VPaths(){ +VPaths::VPaths() { this->setDebugMsgPrefix("VPaths"); } VPaths::~VPaths() = default; - diff --git a/core/base/vpaths/VPaths.h b/core/base/vpaths/VPaths.h index a5f23077c0..d8c57b1950 100644 --- a/core/base/vpaths/VPaths.h +++ b/core/base/vpaths/VPaths.h @@ -42,16 +42,16 @@ namespace ttk { * @param isForward Forward or backward vpath (default: forward). */ template - int execute( - const triangulationType *triangulation, - const std::vector &seeds, - std::vector>> &output, - const bool &isForward = false); + int execute(const triangulationType *triangulation, + const std::vector &seeds, + std::vector>> &output, + const bool &isForward = false); /** * @brief Triangulation preconditioning. */ - inline void preconditionTriangulation(AbstractTriangulation *triangulation){ + inline void + preconditionTriangulation(AbstractTriangulation *triangulation) { // see dms precondition dcg_.preconditionTriangulation(triangulation); @@ -62,12 +62,11 @@ namespace ttk { } inline void setInputScalarField(const void *const scalars, - const size_t &mTime){ + const size_t &mTime) { this->dcg_.setInputScalarField(scalars, mTime); } protected: - dcg::DiscreteGradient dcg_{}; }; } // namespace vp @@ -78,7 +77,7 @@ int ttk::vp::VPaths::execute( const triangulationType *triangulation, const std::vector &seeds, std::vector>> &output, - const bool &isForward){ + const bool &isForward) { // fetching discrete gradient (or pre-computing it) dcg_.setDebugLevel(debugLevel_); @@ -98,30 +97,25 @@ int ttk::vp::VPaths::execute( #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) #endif - for(int i = 0; i < (int) seeds.size(); i++){ - if(!isForward){ + for(int i = 0; i < (int)seeds.size(); i++) { + if(!isForward) { dcg_.getAllDescendingPaths(seeds[i], output[i], *triangulation); - } - else{ + } else { dcg_.getAllAscendingPaths(seeds[i], output[i], *triangulation); } #ifdef TTK_ENABLE_OPENMP #pragma omp critical #endif - printMsg(" - Seed-#" - + std::to_string(seeds[i].id_) - + " (dim: " - + std::to_string(seeds[i].dim_) - + ", f: " - + std::to_string(isForward) - + "): " - + std::to_string(output[i].size()) + " path(s).", - debug::Priority::DETAIL); + printMsg(" - Seed-#" + std::to_string(seeds[i].id_) + + " (dim: " + std::to_string(seeds[i].dim_) + + ", f: " + std::to_string(isForward) + + "): " + std::to_string(output[i].size()) + " path(s).", + debug::Priority::DETAIL); } - printMsg("Computed v-path(s) from " - + std::to_string(output.size()) + " seed(s)", 1, + printMsg( + "Computed v-path(s) from " + std::to_string(output.size()) + " seed(s)", 1, t.getElapsedTime(), threadNumber_); return 0; diff --git a/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp b/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp index b54e4827d8..964df589a4 100644 --- a/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp +++ b/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp @@ -73,15 +73,15 @@ int ttkImportEmbeddingFromTable::RequestData( vtkDataArray *xarr = XColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(XColumn.data())); + inputTable->GetColumnByName(XColumn.data())); vtkDataArray *yarr = YColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(YColumn.data())); + inputTable->GetColumnByName(YColumn.data())); vtkDataArray *zarr = ZColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(ZColumn.data())); + inputTable->GetColumnByName(ZColumn.data())); if(xarr == nullptr or yarr == nullptr or zarr == nullptr) { printErr("invalid input columns."); diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 72bf4f84cc..14a9b19426 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -237,9 +237,9 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, idSpareStorage); - if(!isRunningWithMPI){ + if(!isRunningWithMPI) { - if(BackEnd == BACKEND::NUMERICAL){ + if(BackEnd == BACKEND::NUMERICAL) { printMsg("Selected `numerical` backend."); ttk::nil::NumericalIntegralLines num; @@ -254,12 +254,13 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), num.setInputScalarField(inputScalars->GetVoidPointer(0)); // setup the seeds (simplexId, dimension) - std::vector > seedCells(seeds->GetNumberOfCells()); + std::vector> seedCells( + seeds->GetNumberOfCells()); #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) #endif - for(int i = 0; i < (int) seedCells.size(); i++){ + for(int i = 0; i < (int)seedCells.size(); i++) { vtkCell *cell = seeds->GetCell(i); seedCells[i].first = identifiers[i]; seedCells[i].second = cell->GetCellDimension(); @@ -268,20 +269,18 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), std::vector> outputPaths; int status{}; - ttkVtkTemplateMacro(inputScalars->GetDataType(), - triangulation->getType(), - (status = num.execute( - static_cast(triangulation->getData()), - seedCells, outputPaths, - // isForward? - Direction == 0))); + ttkVtkTemplateMacro(inputScalars->GetDataType(), triangulation->getType(), + (status = num.execute( + static_cast(triangulation->getData()), + seedCells, outputPaths, + // isForward? + Direction == 0))); if(status) return status; return 1; - } - else if(BackEnd == BACKEND::DISCRETE){ + } else if(BackEnd == BACKEND::DISCRETE) { printMsg("Selected `discrete` backend."); ttk::vp::VPaths vpaths; @@ -293,8 +292,8 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vpaths.preconditionTriangulation(triangulation); // setup the data - vpaths.setInputScalarField(inputScalars->GetVoidPointer(0), - inputScalars->GetMTime()); + vpaths.setInputScalarField( + inputScalars->GetVoidPointer(0), inputScalars->GetMTime()); vpaths.setInputOffsets( static_cast(ttkUtils::GetVoidPointer(inputOffsets))); @@ -303,7 +302,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for num_threads(threadNumber_) #endif - for(int i = 0; i < (int) seedCells.size(); i++){ + for(int i = 0; i < (int)seedCells.size(); i++) { vtkCell *cell = seeds->GetCell(i); seedCells[i].dim_ = cell->GetCellDimension(); seedCells[i].id_ = identifiers[i]; @@ -312,19 +311,19 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), std::vector>> outputPaths; int status{}; - ttkTemplateMacro(triangulation->getType(), - status = vpaths.execute( - static_cast(triangulation->getData()), - seedCells, outputPaths, - // isForward? - Direction == 0)); + ttkTemplateMacro( + triangulation->getType(), + status = vpaths.execute(static_cast(triangulation->getData()), + seedCells, outputPaths, + // isForward? + Direction == 0)); if(status) return status; int pointNumber{0}; - for(auto &seedPaths : outputPaths){ - for(auto &path : seedPaths){ + for(auto &seedPaths : outputPaths) { + for(auto &path : seedPaths) { pointNumber += path.size(); } } @@ -366,36 +365,35 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), int pointId = 0; int localSeedId = 0; int pathPointId = 0; - for(auto &seedPaths : outputPaths){ + for(auto &seedPaths : outputPaths) { int forkId = 0; - for(auto &path : seedPaths){ + for(auto &path : seedPaths) { pathPointId = 0; int simplexNumber = path.size(); - for(auto &c : path){ + for(auto &c : path) { float point[3]; triangulation->getCellIncenter(c.id_, c.dim_, point); pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); - vertexSeedId->SetTuple1(pointId, (int) seedCells[localSeedId].id_); - vertexSimplexId->SetTuple1(pointId, (int) c.id_); - vertexSimplexDimension->SetTuple1(pointId, (int) c.dim_); - if((!pointId)||(pointId == pointNumber - 1)){ + vertexSeedId->SetTuple1(pointId, (int)seedCells[localSeedId].id_); + vertexSimplexId->SetTuple1(pointId, (int)c.id_); + vertexSimplexDimension->SetTuple1(pointId, (int)c.dim_); + if((!pointId) || (pointId == pointNumber - 1)) { outputMaskField->SetTuple1(pointId, 0); - } - else{ + } else { outputMaskField->SetTuple1(pointId, 1); } pointId++; pathPointId++; - if(pathPointId > 1){ + if(pathPointId > 1) { vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); - cellSeedId->InsertNextValue((int) seedCells[localSeedId].id_); - cellForkId->InsertNextValue((int) forkId); + cellSeedId->InsertNextValue((int)seedCells[localSeedId].id_); + cellForkId->InsertNextValue((int)forkId); cellSimplexNumber->InsertNextValue((simplexNumber)); } } @@ -419,8 +417,7 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), return 1; } - } - else{ + } else { if(BackEnd != BACKEND::ONESKELETON) printWrn("Distributed run, defaulting to the `OneSkeleton` backend."); } diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.h b/core/vtk/ttkIntegralLines/ttkIntegralLines.h index 89acf78808..60b710cd59 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.h +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.h @@ -85,7 +85,7 @@ class TTKINTEGRALLINES_EXPORT ttkIntegralLines : public ttkAlgorithm, vtkTypeMacro(ttkIntegralLines, ttkAlgorithm); - enum class BACKEND{ + enum class BACKEND { ONESKELETON = 0, NUMERICAL = 1, DISCRETE = 2, From 50d2e1a50707308a2ec975708f02be092acd28e8 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Mon, 7 Sep 2026 09:45:21 +0200 Subject: [PATCH 31/46] [nil] 1D specials --- .../NumericalIntegralLines.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index 627f1f48c3..95a2b971df 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -299,7 +299,9 @@ namespace ttk { // precondition boundary triangulation->preconditionBoundaryVertices(); - triangulation->preconditionBoundaryEdges(); + if(triangulation->getDimensionality() > 1) + // in 1D, edges are cells (and the boundary is made of vertices) + triangulation->preconditionBoundaryEdges(); if(triangulation->getDimensionality() == 3) { triangulation->preconditionTriangles(); @@ -900,11 +902,15 @@ int ttk::nil::NumericalIntegralLines::getCofaces( SimplexId cofaceId = -1; if(!simplexDimension) { - // the edges of the star of the vertex - const SimplexId edgeNumber = triangulation->getVertexEdgeNumber(simplexId); - for(SimplexId i = 0; i < edgeNumber; i++) { - triangulation->getVertexEdge(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, 1)); + if(cellDimension > 1) { + // the edges of the star of the vertex + // (in 1D, edges are cells: they are collected below) + const SimplexId edgeNumber + = triangulation->getVertexEdgeNumber(simplexId); + for(SimplexId i = 0; i < edgeNumber; i++) { + triangulation->getVertexEdge(simplexId, i, cofaceId); + cofaces.push_back(std::make_pair(cofaceId, 1)); + } } if(cellDimension == 3) { From 28ee472896a680616bd54aee2cc201aaf73dbe72 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Mon, 7 Sep 2026 10:05:46 +0200 Subject: [PATCH 32/46] [nil] filling output data structure --- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 14a9b19426..010ed0999c 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -279,6 +279,102 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), if(status) return status; + int pointNumber{0}; + for(auto &path : outputPaths) { + pointNumber += path.size(); + } + + vtkNew outputPathGeometry; + + vtkNew pointCoords{}; + vtkNew vertexSeedId{}; + vtkNew cellSeedId{}; + vtkNew vertexSimplexId{}; + vtkNew vertexSimplexDimension{}; + vtkNew cellSimplexNumber{}; + vtkNew vertexDistanceFromSeed{}; + vtkNew outputMaskField{}; + + pointCoords->SetNumberOfComponents(3); + pointCoords->SetNumberOfTuples(pointNumber); + + vertexSeedId->SetNumberOfComponents(1); + vertexSeedId->SetNumberOfTuples(pointNumber); + vertexSeedId->SetName("SeedIdentifier"); + + vertexSimplexId->SetNumberOfComponents(1); + vertexSimplexId->SetNumberOfTuples(pointNumber); + vertexSimplexId->SetName("SimplexIdentifier"); + + vertexSimplexDimension->SetNumberOfComponents(1); + vertexSimplexDimension->SetNumberOfTuples(pointNumber); + vertexSimplexDimension->SetName("SimplexDimension"); + + vertexDistanceFromSeed->SetNumberOfComponents(1); + vertexDistanceFromSeed->SetNumberOfTuples(pointNumber); + vertexDistanceFromSeed->SetName("DistanceFromSeed"); + + outputMaskField->SetNumberOfComponents(1); + outputMaskField->SetNumberOfTuples(pointNumber); + outputMaskField->SetName(ttk::MaskScalarFieldName); + + cellSeedId->SetName("SeedIdentifier"); + cellSimplexNumber->SetName("SimplexNumber"); + + int pointId = 0; + for(int i = 0; i < (int)outputPaths.size(); i++) { + + const int simplexNumber = outputPaths[i].size(); + double distanceFromSeed = 0; + std::array point{}, previousPoint{}; + + for(int j = 0; j < simplexNumber; j++) { + + const ttk::nil::PathPoint &pathPoint = outputPaths[i][j]; + + // the path points are expressed by their barycentric coordinates + // within their simplex + num.getPointCoordinates(triangulation, pathPoint, point); + + if(j) + distanceFromSeed + += ttk::Geometry::distance(previousPoint.data(), point.data()); + + pointCoords->SetTuple3(pointId, point[0], point[1], point[2]); + vertexSeedId->SetTuple1(pointId, (int)seedCells[i].first); + vertexSimplexId->SetTuple1(pointId, (int)pathPoint.simplexId_); + vertexSimplexDimension->SetTuple1( + pointId, pathPoint.simplexDimension_); + vertexDistanceFromSeed->SetTuple1(pointId, distanceFromSeed); + // mask out the extremities of the integral line + outputMaskField->SetTuple1( + pointId, ((!j) || (j == simplexNumber - 1)) ? 0 : 1); + pointId++; + + if(j) { + vtkIdType edgeIds[2] = {pointId - 2, pointId - 1}; + outputPathGeometry->InsertNextCell(VTK_LINE, 2, edgeIds); + cellSeedId->InsertNextValue((int)seedCells[i].first); + cellSimplexNumber->InsertNextValue(simplexNumber); + } + + previousPoint = point; + } + } + + vtkNew pointSet{}; + pointSet->SetData(pointCoords); + outputPathGeometry->SetPoints(pointSet); + outputPathGeometry->GetPointData()->AddArray(vertexSeedId); + outputPathGeometry->GetPointData()->AddArray(outputMaskField); + outputPathGeometry->GetPointData()->AddArray(vertexSimplexId); + outputPathGeometry->GetPointData()->AddArray(vertexSimplexDimension); + outputPathGeometry->GetPointData()->AddArray(vertexDistanceFromSeed); + outputPathGeometry->GetCellData()->AddArray(cellSeedId); + outputPathGeometry->GetCellData()->AddArray(cellSimplexNumber); + + output->ShallowCopy(outputPathGeometry); + return 1; } else if(BackEnd == BACKEND::DISCRETE) { printMsg("Selected `discrete` backend."); From 0cb4b6b38bf1d60a79d11ea5965df53db232ec47 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Mon, 7 Sep 2026 10:49:44 +0200 Subject: [PATCH 33/46] [nil] move bary norm to geom --- core/base/geometry/Geometry.cpp | 30 ++++++++++++++++ core/base/geometry/Geometry.h | 10 ++++++ .../NumericalIntegralLines.h | 34 +++---------------- .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 3 ++ 4 files changed, 47 insertions(+), 30 deletions(-) diff --git a/core/base/geometry/Geometry.cpp b/core/base/geometry/Geometry.cpp index eaa1e6dd1c..2dd1e719ce 100644 --- a/core/base/geometry/Geometry.cpp +++ b/core/base/geometry/Geometry.cpp @@ -534,6 +534,34 @@ T Geometry::magnitude(const T *o, const T *d) { return sqrt(mag); } +template +int Geometry::normalizeBarycentricWeights(std::vector &baryCentrics) { + + if(baryCentrics.empty()) + return -1; + + T sum = 0; + + for(size_t i = 0; i < baryCentrics.size(); i++) { + // clamp the negative weights induced by numerical inaccuracies + if(baryCentrics[i] < 0) + baryCentrics[i] = 0; + sum += baryCentrics[i]; + } + + if(!(sum > 0)) { + // degenerated weights: fall back on the barycenter + for(size_t i = 0; i < baryCentrics.size(); i++) + baryCentrics[i] = 1.0 / baryCentrics.size(); + return -2; + } + + for(size_t i = 0; i < baryCentrics.size(); i++) + baryCentrics[i] /= sum; + + return 0; +} + template void Geometry::projectOnTrianglePlane(const T *p, const T *a, @@ -885,6 +913,8 @@ void Geometry::transposeMatrix(const std::vector> &a, template TYPE Geometry::magnitudeFlatten( \ std::vector> const &); \ template TYPE Geometry::magnitude(TYPE const *, TYPE const *); \ + template int Geometry::normalizeBarycentricWeights( \ + std::vector &); \ template void Geometry::projectOnTrianglePlane( \ TYPE const *, TYPE const *, TYPE const *, TYPE *); \ template void Geometry::projectOnEdge( \ diff --git a/core/base/geometry/Geometry.h b/core/base/geometry/Geometry.h index 346630536d..125f63b9df 100644 --- a/core/base/geometry/Geometry.h +++ b/core/base/geometry/Geometry.h @@ -377,6 +377,16 @@ namespace ttk { template T magnitude(const T *o, const T *d); + /// Normalize a list of barycentric weights: the negative weights + /// (induced by numerical inaccuracies) are clamped to zero and the + /// remaining ones are re-scaled, such that they sum up to one. + /// \param baryCentrics Input/output barycentric weights. + /// \return Returns 0 upon success, negative values otherwise (in + /// particular, -2 if the input weights are degenerated, in which case the + /// output weights are those of the barycenter). + template + int normalizeBarycentricWeights(std::vector &baryCentrics); + /// Compute the integer power of a floating-point value /// (std::pow is optimised for floating-point exponents) template diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index 95a2b971df..6ee0e11e13 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -253,32 +253,6 @@ namespace ttk { return 0; } - static inline int - normalizeBarycentricWeights(std::vector &barycentricWeights) { - - if(barycentricWeights.empty()) - return -1; - - float sum = 0; - for(int i = 0; i < (int)barycentricWeights.size(); i++) { - if(barycentricWeights[i] < 0) - barycentricWeights[i] = 0; - sum += barycentricWeights[i]; - } - - if(!(sum > 0)) { - // degenerated weights: fall back on the barycenter - for(int i = 0; i < (int)barycentricWeights.size(); i++) - barycentricWeights[i] = 1.0 / barycentricWeights.size(); - return -2; - } - - for(int i = 0; i < (int)barycentricWeights.size(); i++) - barycentricWeights[i] /= sum; - - return 0; - } - /** * @brief Triangulation preconditioning. */ @@ -361,7 +335,7 @@ int ttk::nil::NumericalIntegralLines::computeIntegralLine( // no valid input coordinates: start from the barycenter of the seed current.barycentricWeights_.assign( seed.second + 1, 1.0 / (seed.second + 1)); - normalizeBarycentricWeights(current.barycentricWeights_); + ttk::Geometry::normalizeBarycentricWeights(current.barycentricWeights_); output.push_back(current); @@ -584,7 +558,7 @@ int ttk::nil::NumericalIntegralLines::doGradientStep( for(int i = 0; i <= current.simplexDimension_; i++) weights[i] = current.barycentricWeights_[i] + travelDistance * velocity[i]; - normalizeBarycentricWeights(weights); + ttk::Geometry::normalizeBarycentricWeights(weights); hasMoved = true; } @@ -1007,7 +981,7 @@ int ttk::nil::NumericalIntegralLines::getSubSimplex( subSimplex.simplexId_ = simplexId; subSimplex.simplexDimension_ = simplexDimension; subSimplex.barycentricWeights_ = barycentricWeights; - normalizeBarycentricWeights(subSimplex.barycentricWeights_); + ttk::Geometry::normalizeBarycentricWeights(subSimplex.barycentricWeights_); return 0; } @@ -1031,7 +1005,7 @@ int ttk::nil::NumericalIntegralLines::getSubSimplex( < 0) return -3; - normalizeBarycentricWeights(subSimplex.barycentricWeights_); + ttk::Geometry::normalizeBarycentricWeights(subSimplex.barycentricWeights_); return 0; } diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 010ed0999c..c60f65d875 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -402,6 +402,9 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkCell *cell = seeds->GetCell(i); seedCells[i].dim_ = cell->GetCellDimension(); seedCells[i].id_ = identifiers[i]; + + printf("cell: %d (d=%d)\n", + seedCells[i].id_, seedCells[i].dim_); } std::vector>> outputPaths; From ebcb5822b5ed850b2c388e9ef02f1b31e4df33c9 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Mon, 7 Sep 2026 11:15:30 +0200 Subject: [PATCH 34/46] [nil] improved gui seed selection --- core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 3 --- .../vtk/ttkTriangulationRequest/ttkTriangulationRequest.cpp | 6 ++++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index c60f65d875..010ed0999c 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -402,9 +402,6 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vtkCell *cell = seeds->GetCell(i); seedCells[i].dim_ = cell->GetCellDimension(); seedCells[i].id_ = identifiers[i]; - - printf("cell: %d (d=%d)\n", - seedCells[i].id_, seedCells[i].dim_); } std::vector>> outputPaths; diff --git a/core/vtk/ttkTriangulationRequest/ttkTriangulationRequest.cpp b/core/vtk/ttkTriangulationRequest/ttkTriangulationRequest.cpp index 8f141bd02e..18b49b66a5 100644 --- a/core/vtk/ttkTriangulationRequest/ttkTriangulationRequest.cpp +++ b/core/vtk/ttkTriangulationRequest/ttkTriangulationRequest.cpp @@ -260,7 +260,8 @@ int ttkTriangulationRequest::RequestData(vtkInformation *ttkNotUsed(request), case SIMPLEX::VERTEX: { const auto vid = addVertex(si); cells->InsertNextCell(VTK_VERTEX, 1, &vid); - cellIds->InsertNextTuple1(vid); + // report the identifier of the vertex (not that of the point) + cellIds->InsertNextTuple1(si); cellDims->InsertNextTuple1(0); } break; @@ -493,7 +494,8 @@ int ttkTriangulationRequest::RequestData(vtkInformation *ttkNotUsed(request), if(triangulation->isVertexOnBoundary(v)) { const auto vid = addVertex(v); cells->InsertNextCell(VTK_VERTEX, 1, &vid); - cellIds->InsertNextTuple1(vid); + // report the identifier of the vertex (not that of the point) + cellIds->InsertNextTuple1(v); cellDims->InsertNextTuple1(0); } } From aa744b4c8dd1893606af3d0d6042604077ac3263 Mon Sep 17 00:00:00 2001 From: Julien Tierny Date: Mon, 7 Sep 2026 11:26:16 +0200 Subject: [PATCH 35/46] [nil] warning removal --- core/vtk/ttkIntegralLines/ttkIntegralLines.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index 010ed0999c..ab5f9011f0 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -574,11 +574,11 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), } numberOfPointsInSeeds = inputIdentifiers.size(); } else { - std::vector idSpareStorage{}; + std::vector lIdSpareStorage{}; ttk::SimplexId *inputIdentifierGlobalId; inputIdentifierGlobalId = this->GetIdentifierArrayPtr( ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, - idSpareStorage); + lIdSpareStorage); ttk::SimplexId localId = 0; for(int i = 0; i < numberOfPointsInSeeds; i++) { localId = triangulation->getVertexLocalId(inputIdentifierGlobalId[i]); @@ -595,11 +595,11 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), this->setGlobalElementCounter(numberOfPointsInSeeds); inputIdentifiers.resize(numberOfPointsInSeeds); totalSeeds = numberOfPointsInSeeds; - std::vector idSpareStorage{}; + std::vector lIdSpareStorage{}; ttk::SimplexId *inputIdentifierGlobalId; inputIdentifierGlobalId = this->GetIdentifierArrayPtr( ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds, - idSpareStorage); + lIdSpareStorage); for(int i = 0; i < numberOfPointsInSeeds; i++) { inputIdentifiers.at(i) = triangulation->getVertexLocalId(inputIdentifierGlobalId[i]); From 163ee198849747fb5376505b439efc05bcaf7231 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Mon, 7 Sep 2026 17:31:35 +0200 Subject: [PATCH 36/46] [nil] fix on discrete gradient forward vpath --- .../DiscreteGradient_Template.h | 8 ++++ .../vtk/ttkIntegralLines/ttkIntegralLines.cpp | 48 +++++++++++++------ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 1c2148f773..8231884557 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1952,6 +1952,14 @@ int DiscreteGradient::getAllAscendingPaths( if(currentCell.dim_ != cell.dim_) continue; + if(currentCell.dim_ >= dimensionality_) { + // currentCell is a maximal simplex: it admits no cofacet at all (in + // particular, the star of a triangle is only defined in 3D). the + // ascending path terminates here. + vpaths.push_back(stackEntry.partialPath_); + continue; + } + // check all cofacets int cofacetNumber = -1; diff --git a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp index ab5f9011f0..79177e41f5 100644 --- a/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp +++ b/core/vtk/ttkIntegralLines/ttkIntegralLines.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -258,12 +259,21 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), seeds->GetNumberOfCells()); #ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for num_threads(threadNumber_) +#pragma omp parallel num_threads(threadNumber_) #endif - for(int i = 0; i < (int)seedCells.size(); i++) { - vtkCell *cell = seeds->GetCell(i); - seedCells[i].first = identifiers[i]; - seedCells[i].second = cell->GetCellDimension(); + { + // GetCell(vtkIdType) returns a shared internal cell object: only the + // vtkGenericCell overload is thread-safe. + vtkNew cell{}; + +#ifdef TTK_ENABLE_OPENMP +#pragma omp for +#endif + for(int i = 0; i < (int)seedCells.size(); i++) { + seeds->GetCell(i, cell); + seedCells[i].first = identifiers[i]; + seedCells[i].second = cell->GetCellDimension(); + } } std::vector> outputPaths; @@ -396,12 +406,21 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), std::vector seedCells(seeds->GetNumberOfCells()); #ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for num_threads(threadNumber_) +#pragma omp parallel num_threads(threadNumber_) #endif - for(int i = 0; i < (int)seedCells.size(); i++) { - vtkCell *cell = seeds->GetCell(i); - seedCells[i].dim_ = cell->GetCellDimension(); - seedCells[i].id_ = identifiers[i]; + { + // GetCell(vtkIdType) returns a shared internal cell object: only the + // vtkGenericCell overload is thread-safe. + vtkNew cell{}; + +#ifdef TTK_ENABLE_OPENMP +#pragma omp for +#endif + for(int i = 0; i < (int)seedCells.size(); i++) { + seeds->GetCell(i, cell); + seedCells[i].dim_ = cell->GetCellDimension(); + seedCells[i].id_ = identifiers[i]; + } } std::vector>> outputPaths; @@ -477,11 +496,10 @@ int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request), vertexSeedId->SetTuple1(pointId, (int)seedCells[localSeedId].id_); vertexSimplexId->SetTuple1(pointId, (int)c.id_); vertexSimplexDimension->SetTuple1(pointId, (int)c.dim_); - if((!pointId) || (pointId == pointNumber - 1)) { - outputMaskField->SetTuple1(pointId, 0); - } else { - outputMaskField->SetTuple1(pointId, 1); - } + // mask out the extremities of the integral line + outputMaskField->SetTuple1( + pointId, + ((!pathPointId) || (pathPointId == simplexNumber - 1)) ? 0 : 1); pointId++; pathPointId++; From 50b8cedba6e7829043d63f151f3b14cf7d06a51c Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Tue, 8 Sep 2026 16:39:47 +0200 Subject: [PATCH 37/46] [nil] edge seed fix --- .../NumericalIntegralLines.h | 171 ++++++++++++------ 1 file changed, 112 insertions(+), 59 deletions(-) diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index 6ee0e11e13..90304766bb 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -140,6 +140,29 @@ namespace ttk { std::vector &velocity, float *slope = nullptr) const; + /** + * @brief Identify the simplex which takes the flow over at the input + * point. + * + * The flow is taken over by the coface of the input simplex which + * maximizes the slope of the scalar field (the steepest one) among the + * cofaces which admit the advection. Note that the gradient restricted + * to a face of a simplex is the projection of the gradient of the + * simplex: the slope of a coface is therefore always larger than (or + * equal to) that of its faces. + * + * @param point Input point (simplex, dimension, barycentric weights). + * @param isForward Forward or backward advection. + * @param next Output point (same location, expressed in the coface). + * @return 0 if a coface takes the flow over (negative values otherwise, + * in which case \p next is left untouched). + */ + template + int getFlowSimplex(const triangulationType *triangulation, + const PathPoint &point, + const bool &isForward, + PathPoint &next) const; + /** * @brief Retrieve the identifier of the face of the input simplex which * is spanned by the input vertices. @@ -337,6 +360,19 @@ int ttk::nil::NumericalIntegralLines::computeIntegralLine( seed.second + 1, 1.0 / (seed.second + 1)); ttk::Geometry::normalizeBarycentricWeights(current.barycentricWeights_); + // the seed simplex is where the integral line starts, not necessarily the + // simplex within which the advection takes place. generically, a point in + // the interior of a face is immediately advected within one of its cofaces + // (for instance, the mid-point of an edge is taken over by one of the + // triangles of its star). hand the flow over right away: this does not move + // the point, it only re-expresses it in the coface. if no coface admits the + // advection, the seed simplex constrains the flow and is kept as is. + PathPoint flowPoint; + if(getFlowSimplex( + triangulation, current, isForward, flowPoint) + == 0) + current = flowPoint; + output.push_back(current); std::array previousCoordinates{}, currentCoordinates{}; @@ -572,66 +608,10 @@ int ttk::nil::NumericalIntegralLines::doGradientStep( return -1; // 2) identify the simplex in which the advection carries on. - // the flow is taken over by the coface of the exit face which maximizes the - // slope of the scalar field (the steepest one) among the cofaces which admit - // the advection. note that the gradient restricted to a face of a simplex is - // the projection of the gradient of the simplex: the slope of a coface is - // therefore always larger than (or equal to) that of the exit face. - std::vector> cofaces; - getCofaces( - triangulation, exitPoint.simplexDimension_, exitPoint.simplexId_, cofaces); - - std::vector exitVertices, cofaceVertices; - getVertexIdentifiers(triangulation, exitPoint.simplexDimension_, - exitPoint.simplexId_, exitVertices); - - PathPoint bestPoint; - bestPoint.simplexDimension_ = -1; - float bestSlope = 0; - - for(int i = 0; i < (int)cofaces.size(); i++) { - - PathPoint candidate; - candidate.simplexId_ = cofaces[i].first; - candidate.simplexDimension_ = cofaces[i].second; - - getVertexIdentifiers(triangulation, candidate.simplexDimension_, - candidate.simplexId_, cofaceVertices); - - // express the advected point in the barycentric basis of the coface - if(mapBarycentricWeights(exitVertices, exitPoint.barycentricWeights_, - cofaceVertices, candidate.barycentricWeights_) - < 0) - continue; - - float slope = 0; - if(getBarycentricVelocity( - triangulation, candidate.simplexDimension_, candidate.simplexId_, - isForward, velocity, &slope) - < 0) - continue; - - if(!isMotionAdmissible(candidate.barycentricWeights_, velocity)) - // the advection would immediately leave this coface - continue; - - // steepest slope: along a unit direction, the variation of the scalar - // field is given by the magnitude of the gradient. - // ties (the gradient of the coface is aligned with one of its faces) are - // settled in favor of the coface of highest dimension (i.e. the least - // constrained advection). - if((slope > bestSlope) - || ((slope > bestSlope * (1 - relativeEpsilon_)) - && (candidate.simplexDimension_ > bestPoint.simplexDimension_))) { - bestSlope = slope; - bestPoint = candidate; - } - } - - if(bestPoint.simplexDimension_ >= 0) { - next = bestPoint; + if(getFlowSimplex( + triangulation, exitPoint, isForward, next) + == 0) return REGULAR_STEP; - } // no coface takes the flow over. const bool isOnBoundary = isOnDomainBoundary( @@ -754,6 +734,79 @@ int ttk::nil::NumericalIntegralLines::getBarycentricVelocity( return 0; } +template +int ttk::nil::NumericalIntegralLines::getFlowSimplex( + const triangulationType *triangulation, + const PathPoint &point, + const bool &isForward, + PathPoint &next) const { + + // the flow is taken over by the coface of the input simplex which maximizes + // the slope of the scalar field (the steepest one) among the cofaces which + // admit the advection. note that the gradient restricted to a face of a + // simplex is the projection of the gradient of the simplex: the slope of a + // coface is therefore always larger than (or equal to) that of its faces. + std::vector> cofaces; + getCofaces(triangulation, point.simplexDimension_, point.simplexId_, cofaces); + + std::vector pointVertices, cofaceVertices; + getVertexIdentifiers( + triangulation, point.simplexDimension_, point.simplexId_, pointVertices); + + std::vector velocity; + + PathPoint bestPoint; + bestPoint.simplexDimension_ = -1; + float bestSlope = 0; + + for(int i = 0; i < (int)cofaces.size(); i++) { + + PathPoint candidate; + candidate.simplexId_ = cofaces[i].first; + candidate.simplexDimension_ = cofaces[i].second; + + getVertexIdentifiers(triangulation, candidate.simplexDimension_, + candidate.simplexId_, cofaceVertices); + + // express the advected point in the barycentric basis of the coface + if(mapBarycentricWeights(pointVertices, point.barycentricWeights_, + cofaceVertices, candidate.barycentricWeights_) + < 0) + continue; + + float slope = 0; + if(getBarycentricVelocity( + triangulation, candidate.simplexDimension_, candidate.simplexId_, + isForward, velocity, &slope) + < 0) + continue; + + if(!isMotionAdmissible(candidate.barycentricWeights_, velocity)) + // the advection would immediately leave this coface + continue; + + // steepest slope: along a unit direction, the variation of the scalar + // field is given by the magnitude of the gradient. + // ties (the gradient of the coface is aligned with one of its faces) are + // settled in favor of the coface of highest dimension (i.e. the least + // constrained advection). + if((slope > bestSlope) + || ((slope > bestSlope * (1 - relativeEpsilon_)) + && (candidate.simplexDimension_ > bestPoint.simplexDimension_))) { + bestSlope = slope; + bestPoint = candidate; + } + } + + if(bestPoint.simplexDimension_ < 0) + // no coface takes the flow over + return -1; + + next = bestPoint; + + return 0; +} + template int ttk::nil::NumericalIntegralLines::getFaceIdentifier( const triangulationType *triangulation, From d2d8660809166240172be1386d0d24ec84ddbe00 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 10 Sep 2026 14:57:30 +0200 Subject: [PATCH 38/46] [il-ext] clang-format17 --- .../DepthImageBasedGeometryApproximation.h | 12 +-- .../DiscreteMorseSandwich.cpp | 7 +- .../DiscreteMorseSandwich.h | 51 ++++++----- .../DiscreteMorseSandwichMPI.cpp | 7 +- core/base/ftmTree/FTMTree_CT_Template.h | 86 +++++++++---------- .../LowestCommonAncestor.cpp | 2 +- .../BranchMappingDistance.h | 50 +++++------ .../TopologicalCompression.cpp | 7 +- core/base/triangulation/Triangulation.cpp | 2 +- .../VectorSimplification.cpp | 7 +- .../VectorSimplification.h | 51 ++++++----- .../ttkImportEmbeddingFromTable.cpp | 6 +- 12 files changed, 138 insertions(+), 150 deletions(-) diff --git a/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h b/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h index 082f934f70..2c881db4e7 100644 --- a/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h +++ b/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h @@ -253,16 +253,16 @@ int ttk::DepthImageBasedGeometryApproximation::execute( triangleDistortions[triangleDistortionOffset++] = isNaN(i0Depth) || isNaN(i2Depth) || isNaN(i1Depth) ? myNan - : std::max(absDiff(i0Depth, i1Depth), - std::max(absDiff(i1Depth, i2Depth), - absDiff(i0Depth, i2Depth))); + : std::max( + absDiff(i0Depth, i1Depth), + std::max(absDiff(i1Depth, i2Depth), absDiff(i0Depth, i2Depth))); triangleDistortions[triangleDistortionOffset++] = isNaN(i1Depth) || isNaN(i2Depth) || isNaN(i3Depth) ? myNan - : std::max(absDiff(i1Depth, i3Depth), - std::max(absDiff(i3Depth, i2Depth), - absDiff(i2Depth, i1Depth))); + : std::max( + absDiff(i1Depth, i3Depth), + std::max(absDiff(i3Depth, i2Depth), absDiff(i2Depth, i1Depth))); } } } diff --git a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp index f136add1f4..ed0499fb2b 100644 --- a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp +++ b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp @@ -131,10 +131,9 @@ void ttk::DiscreteMorseSandwich::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const PersistencePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), - [](const PersistencePair &a) { - return a.type == 1; - }) + std::to_string(dim == 3 ? std::count_if( + pairs.begin(), pairs.end(), + [](const PersistencePair &a) { return a.type == 1; }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h index a0370575e5..93a5584c1b 100644 --- a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h +++ b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h @@ -699,32 +699,31 @@ void ttk::DiscreteMorseSandwich::getMaxSaddlePairs( const auto dim = this->dg_.getDimensionality(); auto saddle2ToMaxima - = dim == 3 ? getSaddle2ToMaxima( - criticalSaddles, - [&triangulation]( - const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getTriangleStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getTriangleStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isTriangleOnBoundary(a); - }, - triangulation) - : getSaddle2ToMaxima( - criticalSaddles, - [&triangulation]( - const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getEdgeStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getEdgeStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isEdgeOnBoundary(a); - }, - triangulation); + = dim == 3 + ? getSaddle2ToMaxima( + criticalSaddles, + [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getTriangleStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getTriangleStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isTriangleOnBoundary(a); + }, + triangulation) + : getSaddle2ToMaxima( + criticalSaddles, + [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getEdgeStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getEdgeStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isEdgeOnBoundary(a); + }, + triangulation); Timer tmseq{}; diff --git a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp index da2c9fc218..afb7fbdb83 100644 --- a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp +++ b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp @@ -31,10 +31,9 @@ void ttk::DiscreteMorseSandwichMPI::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const PersistencePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), - [](const PersistencePair &a) { - return a.type == 1; - }) + std::to_string(dim == 3 ? std::count_if( + pairs.begin(), pairs.end(), + [](const PersistencePair &a) { return a.type == 1; }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/ftmTree/FTMTree_CT_Template.h b/core/base/ftmTree/FTMTree_CT_Template.h index fcd883aefd..2ff214b909 100644 --- a/core/base/ftmTree/FTMTree_CT_Template.h +++ b/core/base/ftmTree/FTMTree_CT_Template.h @@ -100,61 +100,61 @@ namespace ttk { this->printMsg({"- final number of nodes :", nbNodes}); } } - // clang-format on - // clang format fail to use the right indentation level - // here, but it break the code if not disabled... +// clang-format on +// clang format fail to use the right indentation level +// here, but it break the code if not disabled... - // ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ - template - int FTMTree_CT::leafSearch(const triangulationType *mesh) { - const auto nbScalars = scalars_->size; - const auto chunkSize = getChunkSize(); - const auto chunkNb = getChunkCount(); +template +int FTMTree_CT::leafSearch(const triangulationType *mesh) { + const auto nbScalars = scalars_->size; + const auto chunkSize = getChunkSize(); + const auto chunkNb = getChunkCount(); - // Extrema extract and launch tasks - for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) { + // Extrema extract and launch tasks + for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) { #ifdef TTK_ENABLE_OPENMP4 #pragma omp task firstprivate(chunkId) #endif - { - const SimplexId lowerBound = chunkId * chunkSize; - const SimplexId upperBound - = std::min(nbScalars, (chunkId + 1) * chunkSize); - for(SimplexId v = lowerBound; v < upperBound; ++v) { - const auto &neighNumb = mesh->getVertexNeighborNumber(v); - valence upval = 0; - valence downval = 0; - - for(valence n = 0; n < neighNumb; ++n) { - SimplexId neigh{-1}; - mesh->getVertexNeighbor(v, n, neigh); - if(scalars_->isLower(neigh, v)) { - ++downval; - } else { - ++upval; - } - } - - jt_.setValence(v, downval); - st_.setValence(v, upval); - - if(!downval) { - jt_.makeNode(v); - } - - if(!upval) { - st_.makeNode(v); - } + { + const SimplexId lowerBound = chunkId * chunkSize; + const SimplexId upperBound + = std::min(nbScalars, (chunkId + 1) * chunkSize); + for(SimplexId v = lowerBound; v < upperBound; ++v) { + const auto &neighNumb = mesh->getVertexNeighborNumber(v); + valence upval = 0; + valence downval = 0; + + for(valence n = 0; n < neighNumb; ++n) { + SimplexId neigh{-1}; + mesh->getVertexNeighbor(v, n, neigh); + if(scalars_->isLower(neigh, v)) { + ++downval; + } else { + ++upval; } } + + jt_.setValence(v, downval); + st_.setValence(v, upval); + + if(!downval) { + jt_.makeNode(v); + } + + if(!upval) { + st_.makeNode(v); + } } + } + } #ifdef TTK_ENABLE_OPENMP4 #pragma omp taskwait #endif - return 0; - } + return 0; +} - } // namespace ftm +} // namespace ftm } // namespace ttk diff --git a/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp b/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp index f6798aae04..2fbf81c706 100644 --- a/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp +++ b/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp @@ -57,7 +57,7 @@ int ttk::LowestCommonAncestor::RMQuery(const int &i, const int &j) const { // Position of the min in the blocs between the bloc of i and j min_pos[1] = ((blocJ - blocI) > 1) ? blocMinimumPosition_[blocMinimumValueRMQ_.query( - blocI + 1, blocJ - 1)] + blocI + 1, blocJ - 1)] : INT_MAX; // Position of the min in the bloc containing the jth case min_pos[2] diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index ab1e25d4bf..de3e47c835 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -336,15 +336,14 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0) { memT[curr1 + l * dim2 + nn2 * dim3 + 0 * dim4] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - curr1, parent1, -1, -1, tree1, tree2) - : this->baseMetric_ == 1 - ? editCost_Wasserstein2( - curr1, parent1, -1, -1, tree1, tree2) + curr1, parent1, -1, -1, tree1, tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + curr1, parent1, -1, -1, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - curr1, parent1, -1, -1, tree1, tree2) + curr1, parent1, -1, -1, tree1, tree2) : editCost_Shifting( - curr1, parent1, -1, -1, tree1, tree2); + curr1, parent1, -1, -1, tree1, tree2); } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -379,15 +378,14 @@ namespace ttk { if(tree2->getNumberOfChildren(curr2) == 0) { memT[nn1 + 0 * dim2 + curr2 * dim3 + l * dim4] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - -1, -1, curr2, parent2, tree1, tree2) - : this->baseMetric_ == 1 - ? editCost_Wasserstein2( - -1, -1, curr2, parent2, tree1, tree2) + -1, -1, curr2, parent2, tree1, tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + -1, -1, curr2, parent2, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - -1, -1, curr2, parent2, tree1, tree2) + -1, -1, curr2, parent2, tree1, tree2) : editCost_Shifting( - -1, -1, curr2, parent2, tree1, tree2); + -1, -1, curr2, parent2, tree1, tree2); } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -435,17 +433,15 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0 and tree2->getNumberOfChildren(curr2) == 0) { memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] - = this->baseMetric_ == 0 - ? editCost_Wasserstein1( - curr1, parent1, curr2, parent2, tree1, tree2) - : this->baseMetric_ == 1 - ? editCost_Wasserstein2( - curr1, parent1, curr2, parent2, tree1, tree2) + = this->baseMetric_ == 0 ? editCost_Wasserstein1( + curr1, parent1, curr2, parent2, tree1, tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + curr1, parent1, curr2, parent2, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - curr1, parent1, curr2, parent2, tree1, tree2) + curr1, parent1, curr2, parent2, tree1, tree2) : editCost_Shifting( - curr1, parent1, curr2, parent2, tree1, tree2); + curr1, parent1, curr2, parent2, tree1, tree2); } //--------------------------------------------------------------------------- // If first tree only has one branch, try all decompositions of @@ -659,14 +655,12 @@ namespace ttk { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; matchedCost[m.first.first] - = this->baseMetric_ == 0 - ? editCost_Wasserstein1(m.first.first, m.first.second, - m.second.first, - m.second.second, tree1, tree2) - : this->baseMetric_ == 1 - ? editCost_Wasserstein2(m.first.first, m.first.second, - m.second.first, - m.second.second, tree1, tree2) + = this->baseMetric_ == 0 ? editCost_Wasserstein1( + m.first.first, m.first.second, m.second.first, m.second.second, + tree1, tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + m.first.first, m.first.second, m.second.first, + m.second.second, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence(m.first.first, m.first.second, m.second.first, diff --git a/core/base/topologicalCompression/TopologicalCompression.cpp b/core/base/topologicalCompression/TopologicalCompression.cpp index f71d2455fc..171d5bb2b1 100644 --- a/core/base/topologicalCompression/TopologicalCompression.cpp +++ b/core/base/topologicalCompression/TopologicalCompression.cpp @@ -639,10 +639,9 @@ int ttk::TopologicalCompression::WriteToFile(FILE *fp, numberOfVertices *= (1 + dataExtent[2 * i + 1] - dataExtent[2 * i]); NbVertices = numberOfVertices; - int const totalSize = usePersistence - ? ComputeTotalSizeForPersistenceDiagram( - getMapping(), getCriticalConstraints(), zfpOnly, - getNbSegments(), getNbVertices(), zfpTolerance) + int const totalSize = usePersistence ? ComputeTotalSizeForPersistenceDiagram( + getMapping(), getCriticalConstraints(), zfpOnly, + getNbSegments(), getNbVertices(), zfpTolerance) : useOther ? ComputeTotalSizeForOther() : 0; diff --git a/core/base/triangulation/Triangulation.cpp b/core/base/triangulation/Triangulation.cpp index ebdfc9e612..af453bbe44 100644 --- a/core/base/triangulation/Triangulation.cpp +++ b/core/base/triangulation/Triangulation.cpp @@ -43,7 +43,7 @@ Triangulation::Triangulation(const Triangulation &rhs) Triangulation::Triangulation(Triangulation &&rhs) noexcept : AbstractTriangulation( - std::move(*static_cast(&rhs))), + std::move(*static_cast(&rhs))), abstractTriangulation_{nullptr}, explicitTriangulation_{std::move(rhs.explicitTriangulation_)}, implicitTriangulation_{std::move(rhs.implicitTriangulation_)}, diff --git a/core/base/vectorSimplification/VectorSimplification.cpp b/core/base/vectorSimplification/VectorSimplification.cpp index 5bd12905f1..2e181eb45f 100644 --- a/core/base/vectorSimplification/VectorSimplification.cpp +++ b/core/base/vectorSimplification/VectorSimplification.cpp @@ -21,10 +21,9 @@ void ttk::VectorSimplification::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const CandidatePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), - [](const CandidatePair &a) { - return a.type == 1; - }) + std::to_string(dim == 3 ? std::count_if( + pairs.begin(), pairs.end(), + [](const CandidatePair &a) { return a.type == 1; }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/vectorSimplification/VectorSimplification.h b/core/base/vectorSimplification/VectorSimplification.h index af7b5a8e5f..8987941abc 100644 --- a/core/base/vectorSimplification/VectorSimplification.h +++ b/core/base/vectorSimplification/VectorSimplification.h @@ -654,32 +654,31 @@ void ttk::VectorSimplification::getAscSaddlePairs( const auto dim = this->dcvf_.getDimensionality(); auto saddle2ToMaxima - = dim == 3 ? getSaddle2ToAscPair( - criticalSaddles, - [&triangulation]( - const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getTriangleStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getTriangleStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isTriangleOnBoundary(a); - }, - triangulation, static_cast(0.0)) - : getSaddle2ToAscPair( - criticalSaddles, - [&triangulation]( - const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getEdgeStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getEdgeStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isEdgeOnBoundary(a); - }, - triangulation, static_cast(0.0)); + = dim == 3 + ? getSaddle2ToAscPair( + criticalSaddles, + [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getTriangleStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getTriangleStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isTriangleOnBoundary(a); + }, + triangulation, static_cast(0.0)) + : getSaddle2ToAscPair( + criticalSaddles, + [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getEdgeStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getEdgeStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isEdgeOnBoundary(a); + }, + triangulation, static_cast(0.0)); for(size_t i = 0; i < saddle2ToMaxima.size(); ++i) { auto &maxs = saddle2ToMaxima[i]; diff --git a/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp b/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp index 964df589a4..b54e4827d8 100644 --- a/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp +++ b/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp @@ -73,15 +73,15 @@ int ttkImportEmbeddingFromTable::RequestData( vtkDataArray *xarr = XColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(XColumn.data())); + inputTable->GetColumnByName(XColumn.data())); vtkDataArray *yarr = YColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(YColumn.data())); + inputTable->GetColumnByName(YColumn.data())); vtkDataArray *zarr = ZColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(ZColumn.data())); + inputTable->GetColumnByName(ZColumn.data())); if(xarr == nullptr or yarr == nullptr or zarr == nullptr) { printErr("invalid input columns."); From 56f3262dd54ffc8d11e203f744f55f1334357b04 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 10 Sep 2026 15:11:12 +0200 Subject: [PATCH 39/46] [il-ext] upgrading ubuntu for clang-format tests --- .github/workflows/check.yml | 10 ++--- .../ContinuousScatterPlot.h | 2 +- core/base/contourTree/ContourTree.cpp | 44 ++++++++++++++----- .../geoPHUtils.h | 8 ++-- .../DiscreteMorseSandwichMPI.h | 4 +- core/base/ftmTree/FTMAtomicVector.h | 4 +- core/base/ftmTree/FTMTree_CT_Template.h | 4 +- core/base/ftmTree/FTMTree_MT.cpp | 4 +- core/base/ftrGraph/FTRGraphPrivate_Template.h | 24 +++++++--- .../MandatoryCriticalPoints.cpp | 8 +++- .../MandatoryCriticalPoints.h | 8 +++- .../mergeTreeClustering/MergeTreeClustering.h | 2 +- .../persistenceDiagram/PersistenceDiagram.h | 5 +-- .../planarGraphLayout/PlanarGraphLayout.h | 4 +- .../ttkContourAroundPoint.cpp | 2 +- .../ttkContourTreeAlignment.cpp | 4 +- ...ttkMergeTreePrincipalGeodesicsDecoding.cpp | 2 +- 17 files changed, 96 insertions(+), 43 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 2b06e9fad7..e9ce97a6c9 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -15,7 +15,7 @@ jobs: # Check source formatting # # ----------------------- # check-formatting: - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 steps: - uses: actions/checkout@v4 @@ -68,7 +68,7 @@ jobs: # Code lint job # # ------------- # lint-code: - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 strategy: matrix: config: @@ -109,7 +109,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-22.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-26.04.deb - name: Install ParaView .deb run: | @@ -159,7 +159,7 @@ jobs: # Check compiler warnings # # ----------------------- # check-warnings: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 strategy: matrix: kamikaze: [KAMIKAZE=TRUE, KAMIKAZE=FALSE] @@ -201,7 +201,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-24.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-26.04.deb - name: Install ParaView .deb run: | diff --git a/core/base/continuousScatterPlot/ContinuousScatterPlot.h b/core/base/continuousScatterPlot/ContinuousScatterPlot.h index 626b1f05e6..536373acee 100644 --- a/core/base/continuousScatterPlot/ContinuousScatterPlot.h +++ b/core/base/continuousScatterPlot/ContinuousScatterPlot.h @@ -499,7 +499,7 @@ int ttk::ContinuousScatterPlot::execute( if(v < 0.0 or (u + v) > 1.0) continue; - // triangle/ray intersection below + // triangle/ray intersection below #ifdef TTK_ENABLE_OPENMP #pragma omp atomic update #endif diff --git a/core/base/contourTree/ContourTree.cpp b/core/base/contourTree/ContourTree.cpp index 4cb9c2ceeb..5a8dc2c118 100644 --- a/core/base/contourTree/ContourTree.cpp +++ b/core/base/contourTree/ContourTree.cpp @@ -2704,17 +2704,23 @@ int ContourTree::computeSkeleton(unsigned int arcResolution) { #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { SubLevelSetTree::computeSkeleton(arcResolution); } + { + SubLevelSetTree::computeSkeleton(arcResolution); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { mergeTree_.computeSkeleton(arcResolution); } + { + mergeTree_.computeSkeleton(arcResolution); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { splitTree_.computeSkeleton(arcResolution); } + { + splitTree_.computeSkeleton(arcResolution); + } } return 0; @@ -2728,17 +2734,23 @@ int ContourTree::smoothSkeleton(unsigned int skeletonSmoothing) { #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { SubLevelSetTree::smoothSkeleton(skeletonSmoothing); } + { + SubLevelSetTree::smoothSkeleton(skeletonSmoothing); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { mergeTree_.smoothSkeleton(skeletonSmoothing); } + { + mergeTree_.smoothSkeleton(skeletonSmoothing); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { splitTree_.smoothSkeleton(skeletonSmoothing); } + { + splitTree_.smoothSkeleton(skeletonSmoothing); + } } return 0; @@ -2752,17 +2764,23 @@ int ContourTree::clearSkeleton() { #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { SubLevelSetTree::clearSkeleton(); } + { + SubLevelSetTree::clearSkeleton(); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { mergeTree_.clearSkeleton(); } + { + mergeTree_.clearSkeleton(); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { splitTree_.clearSkeleton(); } + { + splitTree_.clearSkeleton(); + } } return 0; @@ -2893,12 +2911,16 @@ int ContourTree::simplify(const double &simplificationThreshold, #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { mergeTree_.simplify(simplificationThreshold, metric); } + { + mergeTree_.simplify(simplificationThreshold, metric); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { splitTree_.simplify(simplificationThreshold, metric); } + { + splitTree_.simplify(simplificationThreshold, metric); + } } return 0; diff --git a/core/base/delaunayRipsPersistenceDiagram/geoPHUtils.h b/core/base/delaunayRipsPersistenceDiagram/geoPHUtils.h index e8ca5202e9..87fe37be92 100644 --- a/core/base/delaunayRipsPersistenceDiagram/geoPHUtils.h +++ b/core/base/delaunayRipsPersistenceDiagram/geoPHUtils.h @@ -3,7 +3,7 @@ #include #include -#if((BOOST_VERSION / 100) % 1000) >= 81 +#if ((BOOST_VERSION / 100) % 1000) >= 81 #include #include #else @@ -11,7 +11,7 @@ #include #endif -#if((BOOST_VERSION / 100) % 1000) >= 84 +#if ((BOOST_VERSION / 100) % 1000) >= 84 #include #define TTK_CONCURRENT_HASHTABLE_AVAILABLE #endif @@ -47,7 +47,7 @@ namespace ttk::gph { template using PointCloud = std::vector>; -#if((BOOST_VERSION / 100) % 1000) >= 81 +#if ((BOOST_VERSION / 100) % 1000) >= 81 template using HashMap = boost::unordered_flat_map; template @@ -59,7 +59,7 @@ namespace ttk::gph { using HashSet = boost::unordered_set; #endif -#if((BOOST_VERSION / 100) % 1000) >= 84 +#if ((BOOST_VERSION / 100) % 1000) >= 84 template using ConcurrentHashMap = boost::concurrent_flat_map; #endif diff --git a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h index 436a8eeb4d..14d8d6cd9b 100644 --- a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h +++ b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.h @@ -2768,7 +2768,9 @@ void ttk::DiscreteMorseSandwichMPI::unpackGhostPresence( // Add the entry to the map if(lid == -1 || getSimplexRank(lid) != ttk::MPIrank_) { #pragma omp critical - { localGhostPresenceMap[vp.extremaId_] = ghost; } + { + localGhostPresenceMap[vp.extremaId_] = ghost; + } } else { lid = localTriangToLocalVectExtrema.find(lid)->second; extremaLocks[lid].lock(); diff --git a/core/base/ftmTree/FTMAtomicVector.h b/core/base/ftmTree/FTMAtomicVector.h index 80477a73a3..59e7df268d 100644 --- a/core/base/ftmTree/FTMAtomicVector.h +++ b/core/base/ftmTree/FTMAtomicVector.h @@ -69,7 +69,9 @@ namespace ttk { // WARNING: In parallel we do not want to make reserve as it can lead // to data race, we should not enter here #pragma omp critical(AtomicUFReserve) - { std::vector::resize(newSize, defaultValue); } + { + std::vector::resize(newSize, defaultValue); + } } else #endif diff --git a/core/base/ftmTree/FTMTree_CT_Template.h b/core/base/ftmTree/FTMTree_CT_Template.h index fcd883aefd..11c0d372bb 100644 --- a/core/base/ftmTree/FTMTree_CT_Template.h +++ b/core/base/ftmTree/FTMTree_CT_Template.h @@ -24,7 +24,9 @@ namespace ttk { #ifdef TTK_ENABLE_OPENMP4 #pragma omp single nowait #endif - { leafSearch(mesh); } + { + leafSearch(mesh); + } } printTime(precomputeTime, "leafSearch", 3); } diff --git a/core/base/ftmTree/FTMTree_MT.cpp b/core/base/ftmTree/FTMTree_MT.cpp index 4a3b355799..db7d8a3dd8 100644 --- a/core/base/ftmTree/FTMTree_MT.cpp +++ b/core/base/ftmTree/FTMTree_MT.cpp @@ -918,7 +918,9 @@ vector FTMTree_MT::sortedNodes(const bool para) { #ifdef TTK_ENABLE_OPENMP #pragma omp single #endif - { std::sort(sortedNodes.begin(), sortedNodes.end(), indirect_sort); } + { + std::sort(sortedNodes.begin(), sortedNodes.end(), indirect_sort); + } } return sortedNodes; diff --git a/core/base/ftrGraph/FTRGraphPrivate_Template.h b/core/base/ftrGraph/FTRGraphPrivate_Template.h index a117c8b0bd..2eeba2f0f8 100644 --- a/core/base/ftrGraph/FTRGraphPrivate_Template.h +++ b/core/base/ftrGraph/FTRGraphPrivate_Template.h @@ -38,7 +38,9 @@ void ttk::ftr::FTRGraph::growthFromSeed( --nbProp_; } #pragma omp critical(stats) - { curTime = sweepStart_.getElapsedTime(); } + { + curTime = sweepStart_.getElapsedTime(); + } propTimes_[curProp - 1] = curTime; } #endif @@ -72,7 +74,9 @@ void ttk::ftr::FTRGraph::growthFromSeed( --nbProp_; } #pragma omp critical(stats) - { curTime = sweepStart_.getElapsedTime(); } + { + curTime = sweepStart_.getElapsedTime(); + } propTimes_[curProp - 1] = curTime; } #endif @@ -214,7 +218,9 @@ void ttk::ftr::FTRGraph::growthFromSeed( --nbProp_; } #pragma omp critical(stats) - { curTime = sweepStart_.getElapsedTime(); } + { + curTime = sweepStart_.getElapsedTime(); + } propTimes_[curProp - 1] = curTime; } #endif @@ -244,7 +250,9 @@ void ttk::ftr::FTRGraph::growthFromSeed( --nbProp_; } #pragma omp critical(stats) - { curTime = sweepStart_.getElapsedTime(); } + { + curTime = sweepStart_.getElapsedTime(); + } propTimes_[curProp - 1] = curTime; } #endif @@ -336,7 +344,9 @@ void ttk::ftr::FTRGraph::growthFromSeed( --nbProp_; } #pragma omp critical(stats) - { curTime = sweepStart_.getElapsedTime(); } + { + curTime = sweepStart_.getElapsedTime(); + } propTimes_[curProp - 1] = curTime; } #endif @@ -382,7 +392,9 @@ void ttk::ftr::FTRGraph::growthFromSeed( --nbProp_; } #pragma omp critical(stats) - { curTime = sweepStart_.getElapsedTime(); } + { + curTime = sweepStart_.getElapsedTime(); + } propTimes_[curProp - 1] = curTime; } #endif diff --git a/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.cpp b/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.cpp index b9ce20b458..b6ebaef4ab 100644 --- a/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.cpp +++ b/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.cpp @@ -1016,11 +1016,15 @@ int MandatoryCriticalPoints::enumerateMandatorySaddles( #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { upperLca.preprocess(); } + { + upperLca.preprocess(); + } #ifdef TTK_ENABLE_OPENMP #pragma omp section #endif - { lowerLca.preprocess(); } + { + lowerLca.preprocess(); + } } // Link lists for each thread diff --git a/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.h b/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.h index 5ef92d0448..8d3b5c5cc6 100644 --- a/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.h +++ b/core/base/mandatoryCriticalPoints/MandatoryCriticalPoints.h @@ -1021,13 +1021,17 @@ int ttk::MandatoryCriticalPoints::buildSubTrees( #ifdef TTK_ENABLE_OPENMP #pragma omp critical #endif - { lowerMinimumList_.push_back(i); } + { + lowerMinimumList_.push_back(i); + } } if(isUpperMax) { #ifdef TTK_ENABLE_OPENMP #pragma omp critical #endif - { upperMaximumList_.push_back(i); } + { + upperMaximumList_.push_back(i); + } } } diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index ecc47705d9..ccacb10eeb 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -341,7 +341,7 @@ namespace ttk { for(unsigned int i = 0; i < trees.size(); ++i) identified[i] = (upperBound_[i] <= centroidScore[bestCentroid_[i]]); - // Step 3 + // Step 3 #ifdef TTK_ENABLE_OPENMP4 #pragma omp parallel for schedule(dynamic) shared(centroids, centroids2) \ num_threads(this->threadNumber_) if(parallelize_) diff --git a/core/base/persistenceDiagram/PersistenceDiagram.h b/core/base/persistenceDiagram/PersistenceDiagram.h index 8508647398..65e2e80d7e 100644 --- a/core/base/persistenceDiagram/PersistenceDiagram.h +++ b/core/base/persistenceDiagram/PersistenceDiagram.h @@ -934,9 +934,8 @@ int ttk::PersistenceDiagram::executeDiscreteMorseSandwichMPI( && triangulation->getSimplexRank(lid, simplexType) == ttk::MPIrank_) { // Add the relevant data - struct dataResponse res { - .lid_ = element.lid_, .isBirth_ = element.isBirth_ - }; + struct dataResponse res{ + .lid_ = element.lid_, .isBirth_ = element.isBirth_}; ttk::SimplexId vLid = dmsMPI_.getCellGreaterVertex( Cell{element.dim_ + (1 - element.isBirth_), lid}, *triangulation); res.vertexGid_ = triangulation->getVertexGlobalId(vLid); diff --git a/core/base/planarGraphLayout/PlanarGraphLayout.h b/core/base/planarGraphLayout/PlanarGraphLayout.h index 55053adb33..c6b1ddd921 100644 --- a/core/base/planarGraphLayout/PlanarGraphLayout.h +++ b/core/base/planarGraphLayout/PlanarGraphLayout.h @@ -263,7 +263,9 @@ int ttk::PlanarGraphLayout::computeDotString( // --------------------------------------------------------------------------- // Build Dot String - { dotString = headString + nodeString + edgeString + rankString + "}"; } + { + dotString = headString + nodeString + edgeString + rankString + "}"; + } // Print Status this->printMsg("Generating DOT string", 1, t.getElapsedTime()); diff --git a/core/vtk/ttkContourAroundPoint/ttkContourAroundPoint.cpp b/core/vtk/ttkContourAroundPoint/ttkContourAroundPoint.cpp index 5db49f2145..6d36843366 100644 --- a/core/vtk/ttkContourAroundPoint/ttkContourAroundPoint.cpp +++ b/core/vtk/ttkContourAroundPoint/ttkContourAroundPoint.cpp @@ -122,7 +122,7 @@ bool ttkContourAroundPoint::preprocessPts(vtkUnstructuredGrid *nodes, if(!scalarBuf || !codeBuf) return false; - // ---- Cell data ---- // + // ---- Cell data ---- // #ifndef NDEBUG // each arc should of course be defined by exactly two vertices auto cells = arcs->GetCells(); diff --git a/core/vtk/ttkContourTreeAlignment/ttkContourTreeAlignment.cpp b/core/vtk/ttkContourTreeAlignment/ttkContourTreeAlignment.cpp index d76d664d63..d7453acee1 100644 --- a/core/vtk/ttkContourTreeAlignment/ttkContourTreeAlignment.cpp +++ b/core/vtk/ttkContourTreeAlignment/ttkContourTreeAlignment.cpp @@ -50,7 +50,9 @@ int ttkContourTreeAlignment::RequestData(vtkInformation *ttkNotUsed(request), //================================================================================================================== // Print status - { this->printMsg("RequestData"); } + { + this->printMsg("RequestData"); + } //================================================================================================================== // Prepare input diff --git a/core/vtk/ttkMergeTreePrincipalGeodesicsDecoding/ttkMergeTreePrincipalGeodesicsDecoding.cpp b/core/vtk/ttkMergeTreePrincipalGeodesicsDecoding/ttkMergeTreePrincipalGeodesicsDecoding.cpp index 474cc6f4aa..a7d80a59d3 100644 --- a/core/vtk/ttkMergeTreePrincipalGeodesicsDecoding/ttkMergeTreePrincipalGeodesicsDecoding.cpp +++ b/core/vtk/ttkMergeTreePrincipalGeodesicsDecoding/ttkMergeTreePrincipalGeodesicsDecoding.cpp @@ -499,7 +499,7 @@ int ttkMergeTreePrincipalGeodesicsDecoding::runOutput( and (inputMTrees.empty() or baryMatchings_.empty())) printWrn("Please provide input trees and correlation matrix to transfer " "input trees information."); - // TODO fix if an interpolation is empty + // TODO fix if an interpolation is empty #ifdef TTK_ENABLE_OPENMP #pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_) #endif From 6d0a280921bdd82c2adc4e32b5c74f19d8f92fe8 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 10 Sep 2026 15:22:12 +0200 Subject: [PATCH 40/46] [il-ext] clang-format 21 --- .../DepthImageBasedGeometryApproximation.h | 12 +-- .../DiscreteMorseSandwich.cpp | 7 +- .../DiscreteMorseSandwich.h | 51 +++++------ .../DiscreteMorseSandwichMPI.cpp | 7 +- core/base/ftmTree/FTMTree_CT_Template.h | 86 +++++++++---------- .../LowestCommonAncestor.cpp | 2 +- .../BranchMappingDistance.h | 50 ++++++----- .../TopologicalCompression.cpp | 7 +- core/base/triangulation/Triangulation.cpp | 2 +- .../VectorSimplification.cpp | 7 +- .../VectorSimplification.h | 51 +++++------ .../ttkImportEmbeddingFromTable.cpp | 6 +- .../ttkMergeTreeVisualization.h | 2 +- 13 files changed, 151 insertions(+), 139 deletions(-) diff --git a/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h b/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h index 2c881db4e7..082f934f70 100644 --- a/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h +++ b/core/base/depthImageBasedGeometryApproximation/DepthImageBasedGeometryApproximation.h @@ -253,16 +253,16 @@ int ttk::DepthImageBasedGeometryApproximation::execute( triangleDistortions[triangleDistortionOffset++] = isNaN(i0Depth) || isNaN(i2Depth) || isNaN(i1Depth) ? myNan - : std::max( - absDiff(i0Depth, i1Depth), - std::max(absDiff(i1Depth, i2Depth), absDiff(i0Depth, i2Depth))); + : std::max(absDiff(i0Depth, i1Depth), + std::max(absDiff(i1Depth, i2Depth), + absDiff(i0Depth, i2Depth))); triangleDistortions[triangleDistortionOffset++] = isNaN(i1Depth) || isNaN(i2Depth) || isNaN(i3Depth) ? myNan - : std::max( - absDiff(i1Depth, i3Depth), - std::max(absDiff(i3Depth, i2Depth), absDiff(i2Depth, i1Depth))); + : std::max(absDiff(i1Depth, i3Depth), + std::max(absDiff(i3Depth, i2Depth), + absDiff(i2Depth, i1Depth))); } } } diff --git a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp index ed0499fb2b..f136add1f4 100644 --- a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp +++ b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.cpp @@ -131,9 +131,10 @@ void ttk::DiscreteMorseSandwich::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const PersistencePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if( - pairs.begin(), pairs.end(), - [](const PersistencePair &a) { return a.type == 1; }) + std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), + [](const PersistencePair &a) { + return a.type == 1; + }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h index 93a5584c1b..a0370575e5 100644 --- a/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h +++ b/core/base/discreteMorseSandwich/DiscreteMorseSandwich.h @@ -699,31 +699,32 @@ void ttk::DiscreteMorseSandwich::getMaxSaddlePairs( const auto dim = this->dg_.getDimensionality(); auto saddle2ToMaxima - = dim == 3 - ? getSaddle2ToMaxima( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getTriangleStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getTriangleStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isTriangleOnBoundary(a); - }, - triangulation) - : getSaddle2ToMaxima( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getEdgeStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getEdgeStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isEdgeOnBoundary(a); - }, - triangulation); + = dim == 3 ? getSaddle2ToMaxima( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getTriangleStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getTriangleStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isTriangleOnBoundary(a); + }, + triangulation) + : getSaddle2ToMaxima( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getEdgeStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getEdgeStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isEdgeOnBoundary(a); + }, + triangulation); Timer tmseq{}; diff --git a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp index afb7fbdb83..da2c9fc218 100644 --- a/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp +++ b/core/base/discreteMorseSandwichMPI/DiscreteMorseSandwichMPI.cpp @@ -31,9 +31,10 @@ void ttk::DiscreteMorseSandwichMPI::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const PersistencePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if( - pairs.begin(), pairs.end(), - [](const PersistencePair &a) { return a.type == 1; }) + std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), + [](const PersistencePair &a) { + return a.type == 1; + }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/ftmTree/FTMTree_CT_Template.h b/core/base/ftmTree/FTMTree_CT_Template.h index 41dc2261e3..11c0d372bb 100644 --- a/core/base/ftmTree/FTMTree_CT_Template.h +++ b/core/base/ftmTree/FTMTree_CT_Template.h @@ -102,61 +102,61 @@ namespace ttk { this->printMsg({"- final number of nodes :", nbNodes}); } } -// clang-format on -// clang format fail to use the right indentation level -// here, but it break the code if not disabled... + // clang-format on + // clang format fail to use the right indentation level + // here, but it break the code if not disabled... -// ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ -template -int FTMTree_CT::leafSearch(const triangulationType *mesh) { - const auto nbScalars = scalars_->size; - const auto chunkSize = getChunkSize(); - const auto chunkNb = getChunkCount(); + template + int FTMTree_CT::leafSearch(const triangulationType *mesh) { + const auto nbScalars = scalars_->size; + const auto chunkSize = getChunkSize(); + const auto chunkNb = getChunkCount(); - // Extrema extract and launch tasks - for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) { + // Extrema extract and launch tasks + for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) { #ifdef TTK_ENABLE_OPENMP4 #pragma omp task firstprivate(chunkId) #endif - { - const SimplexId lowerBound = chunkId * chunkSize; - const SimplexId upperBound - = std::min(nbScalars, (chunkId + 1) * chunkSize); - for(SimplexId v = lowerBound; v < upperBound; ++v) { - const auto &neighNumb = mesh->getVertexNeighborNumber(v); - valence upval = 0; - valence downval = 0; - - for(valence n = 0; n < neighNumb; ++n) { - SimplexId neigh{-1}; - mesh->getVertexNeighbor(v, n, neigh); - if(scalars_->isLower(neigh, v)) { - ++downval; - } else { - ++upval; + { + const SimplexId lowerBound = chunkId * chunkSize; + const SimplexId upperBound + = std::min(nbScalars, (chunkId + 1) * chunkSize); + for(SimplexId v = lowerBound; v < upperBound; ++v) { + const auto &neighNumb = mesh->getVertexNeighborNumber(v); + valence upval = 0; + valence downval = 0; + + for(valence n = 0; n < neighNumb; ++n) { + SimplexId neigh{-1}; + mesh->getVertexNeighbor(v, n, neigh); + if(scalars_->isLower(neigh, v)) { + ++downval; + } else { + ++upval; + } + } + + jt_.setValence(v, downval); + st_.setValence(v, upval); + + if(!downval) { + jt_.makeNode(v); + } + + if(!upval) { + st_.makeNode(v); + } } } - - jt_.setValence(v, downval); - st_.setValence(v, upval); - - if(!downval) { - jt_.makeNode(v); - } - - if(!upval) { - st_.makeNode(v); - } } - } - } #ifdef TTK_ENABLE_OPENMP4 #pragma omp taskwait #endif - return 0; -} + return 0; + } -} // namespace ftm + } // namespace ftm } // namespace ttk diff --git a/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp b/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp index 2fbf81c706..f6798aae04 100644 --- a/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp +++ b/core/base/lowestCommonAncestor/LowestCommonAncestor.cpp @@ -57,7 +57,7 @@ int ttk::LowestCommonAncestor::RMQuery(const int &i, const int &j) const { // Position of the min in the blocs between the bloc of i and j min_pos[1] = ((blocJ - blocI) > 1) ? blocMinimumPosition_[blocMinimumValueRMQ_.query( - blocI + 1, blocJ - 1)] + blocI + 1, blocJ - 1)] : INT_MAX; // Position of the min in the bloc containing the jth case min_pos[2] diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index de3e47c835..ab1e25d4bf 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -336,14 +336,15 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0) { memT[curr1 + l * dim2 + nn2 * dim3 + 0 * dim4] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - curr1, parent1, -1, -1, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - curr1, parent1, -1, -1, tree1, tree2) + curr1, parent1, -1, -1, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2( + curr1, parent1, -1, -1, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - curr1, parent1, -1, -1, tree1, tree2) + curr1, parent1, -1, -1, tree1, tree2) : editCost_Shifting( - curr1, parent1, -1, -1, tree1, tree2); + curr1, parent1, -1, -1, tree1, tree2); } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -378,14 +379,15 @@ namespace ttk { if(tree2->getNumberOfChildren(curr2) == 0) { memT[nn1 + 0 * dim2 + curr2 * dim3 + l * dim4] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - -1, -1, curr2, parent2, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - -1, -1, curr2, parent2, tree1, tree2) + -1, -1, curr2, parent2, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2( + -1, -1, curr2, parent2, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - -1, -1, curr2, parent2, tree1, tree2) + -1, -1, curr2, parent2, tree1, tree2) : editCost_Shifting( - -1, -1, curr2, parent2, tree1, tree2); + -1, -1, curr2, parent2, tree1, tree2); } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -433,15 +435,17 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0 and tree2->getNumberOfChildren(curr2) == 0) { memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] - = this->baseMetric_ == 0 ? editCost_Wasserstein1( - curr1, parent1, curr2, parent2, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - curr1, parent1, curr2, parent2, tree1, tree2) + = this->baseMetric_ == 0 + ? editCost_Wasserstein1( + curr1, parent1, curr2, parent2, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2( + curr1, parent1, curr2, parent2, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence( - curr1, parent1, curr2, parent2, tree1, tree2) + curr1, parent1, curr2, parent2, tree1, tree2) : editCost_Shifting( - curr1, parent1, curr2, parent2, tree1, tree2); + curr1, parent1, curr2, parent2, tree1, tree2); } //--------------------------------------------------------------------------- // If first tree only has one branch, try all decompositions of @@ -655,12 +659,14 @@ namespace ttk { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; matchedCost[m.first.first] - = this->baseMetric_ == 0 ? editCost_Wasserstein1( - m.first.first, m.first.second, m.second.first, m.second.second, - tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - m.first.first, m.first.second, m.second.first, - m.second.second, tree1, tree2) + = this->baseMetric_ == 0 + ? editCost_Wasserstein1(m.first.first, m.first.second, + m.second.first, + m.second.second, tree1, tree2) + : this->baseMetric_ == 1 + ? editCost_Wasserstein2(m.first.first, m.first.second, + m.second.first, + m.second.second, tree1, tree2) : this->baseMetric_ == 2 ? editCost_Persistence(m.first.first, m.first.second, m.second.first, diff --git a/core/base/topologicalCompression/TopologicalCompression.cpp b/core/base/topologicalCompression/TopologicalCompression.cpp index 171d5bb2b1..f71d2455fc 100644 --- a/core/base/topologicalCompression/TopologicalCompression.cpp +++ b/core/base/topologicalCompression/TopologicalCompression.cpp @@ -639,9 +639,10 @@ int ttk::TopologicalCompression::WriteToFile(FILE *fp, numberOfVertices *= (1 + dataExtent[2 * i + 1] - dataExtent[2 * i]); NbVertices = numberOfVertices; - int const totalSize = usePersistence ? ComputeTotalSizeForPersistenceDiagram( - getMapping(), getCriticalConstraints(), zfpOnly, - getNbSegments(), getNbVertices(), zfpTolerance) + int const totalSize = usePersistence + ? ComputeTotalSizeForPersistenceDiagram( + getMapping(), getCriticalConstraints(), zfpOnly, + getNbSegments(), getNbVertices(), zfpTolerance) : useOther ? ComputeTotalSizeForOther() : 0; diff --git a/core/base/triangulation/Triangulation.cpp b/core/base/triangulation/Triangulation.cpp index af453bbe44..ebdfc9e612 100644 --- a/core/base/triangulation/Triangulation.cpp +++ b/core/base/triangulation/Triangulation.cpp @@ -43,7 +43,7 @@ Triangulation::Triangulation(const Triangulation &rhs) Triangulation::Triangulation(Triangulation &&rhs) noexcept : AbstractTriangulation( - std::move(*static_cast(&rhs))), + std::move(*static_cast(&rhs))), abstractTriangulation_{nullptr}, explicitTriangulation_{std::move(rhs.explicitTriangulation_)}, implicitTriangulation_{std::move(rhs.implicitTriangulation_)}, diff --git a/core/base/vectorSimplification/VectorSimplification.cpp b/core/base/vectorSimplification/VectorSimplification.cpp index 2e181eb45f..5bd12905f1 100644 --- a/core/base/vectorSimplification/VectorSimplification.cpp +++ b/core/base/vectorSimplification/VectorSimplification.cpp @@ -21,9 +21,10 @@ void ttk::VectorSimplification::displayStats( std::count_if(pairs.begin(), pairs.end(), [](const CandidatePair &a) { return a.type == 0; }))}, {" #Saddle-saddle pairs", - std::to_string(dim == 3 ? std::count_if( - pairs.begin(), pairs.end(), - [](const CandidatePair &a) { return a.type == 1; }) + std::to_string(dim == 3 ? std::count_if(pairs.begin(), pairs.end(), + [](const CandidatePair &a) { + return a.type == 1; + }) : 0)}, {" #Saddle-max pairs", std::to_string(std::count_if( diff --git a/core/base/vectorSimplification/VectorSimplification.h b/core/base/vectorSimplification/VectorSimplification.h index 8987941abc..af7b5a8e5f 100644 --- a/core/base/vectorSimplification/VectorSimplification.h +++ b/core/base/vectorSimplification/VectorSimplification.h @@ -654,31 +654,32 @@ void ttk::VectorSimplification::getAscSaddlePairs( const auto dim = this->dcvf_.getDimensionality(); auto saddle2ToMaxima - = dim == 3 - ? getSaddle2ToAscPair( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getTriangleStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getTriangleStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isTriangleOnBoundary(a); - }, - triangulation, static_cast(0.0)) - : getSaddle2ToAscPair( - criticalSaddles, - [&triangulation](const SimplexId a, const SimplexId i, SimplexId &r) { - return triangulation.getEdgeStar(a, i, r); - }, - [&triangulation](const SimplexId a) { - return triangulation.getEdgeStarNumber(a); - }, - [&triangulation](const SimplexId a) { - return triangulation.isEdgeOnBoundary(a); - }, - triangulation, static_cast(0.0)); + = dim == 3 ? getSaddle2ToAscPair( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getTriangleStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getTriangleStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isTriangleOnBoundary(a); + }, + triangulation, static_cast(0.0)) + : getSaddle2ToAscPair( + criticalSaddles, + [&triangulation]( + const SimplexId a, const SimplexId i, SimplexId &r) { + return triangulation.getEdgeStar(a, i, r); + }, + [&triangulation](const SimplexId a) { + return triangulation.getEdgeStarNumber(a); + }, + [&triangulation](const SimplexId a) { + return triangulation.isEdgeOnBoundary(a); + }, + triangulation, static_cast(0.0)); for(size_t i = 0; i < saddle2ToMaxima.size(); ++i) { auto &maxs = saddle2ToMaxima[i]; diff --git a/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp b/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp index b54e4827d8..964df589a4 100644 --- a/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp +++ b/core/vtk/ttkImportEmbeddingFromTable/ttkImportEmbeddingFromTable.cpp @@ -73,15 +73,15 @@ int ttkImportEmbeddingFromTable::RequestData( vtkDataArray *xarr = XColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(XColumn.data())); + inputTable->GetColumnByName(XColumn.data())); vtkDataArray *yarr = YColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(YColumn.data())); + inputTable->GetColumnByName(YColumn.data())); vtkDataArray *zarr = ZColumn.empty() ? nullptr : vtkDataArray::SafeDownCast( - inputTable->GetColumnByName(ZColumn.data())); + inputTable->GetColumnByName(ZColumn.data())); if(xarr == nullptr or yarr == nullptr or zarr == nullptr) { printErr("invalid input columns."); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 0c4b9adee0..83b47eeed7 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -1281,7 +1281,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // Insert point // -------------- auto getPoint - = [&](vtkUnstructuredGrid *vtu, int pointID, double(&point)[3]) { + = [&](vtkUnstructuredGrid *vtu, int pointID, double (&point)[3]) { if(not vtu) return; if(not isPersistenceDiagram or convertedToDiagram) { From 0eb304946953a7b6c3695873641f53aca249f67a Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 10 Sep 2026 17:04:27 +0200 Subject: [PATCH 41/46] [il-ext] downgrading to ubuntu 24 for warnings --- .github/workflows/check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index e9ce97a6c9..76f64fbaf4 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -68,7 +68,7 @@ jobs: # Code lint job # # ------------- # lint-code: - runs-on: ubuntu-26.04 + runs-on: ubuntu-24.04 strategy: matrix: config: @@ -109,7 +109,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-26.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-24.04.deb - name: Install ParaView .deb run: | @@ -159,7 +159,7 @@ jobs: # Check compiler warnings # # ----------------------- # check-warnings: - runs-on: ubuntu-26.04 + runs-on: ubuntu-24.04 strategy: matrix: kamikaze: [KAMIKAZE=TRUE, KAMIKAZE=FALSE] @@ -201,7 +201,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-26.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-24.04.deb - name: Install ParaView .deb run: | From fa9a4ee143f6c085410f4f038aa5a911873e078c Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Thu, 10 Sep 2026 17:36:40 +0200 Subject: [PATCH 42/46] [il-ext] ci checks downgrade ubuntu 22 --- .github/workflows/check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 76f64fbaf4..281496bd6e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -68,7 +68,7 @@ jobs: # Code lint job # # ------------- # lint-code: - runs-on: ubuntu-24.04 + runs-on: ubuntu-22.04 strategy: matrix: config: @@ -109,7 +109,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-24.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-22.04.deb - name: Install ParaView .deb run: | @@ -159,7 +159,7 @@ jobs: # Check compiler warnings # # ----------------------- # check-warnings: - runs-on: ubuntu-24.04 + runs-on: ubuntu-22.04 strategy: matrix: kamikaze: [KAMIKAZE=TRUE, KAMIKAZE=FALSE] @@ -201,7 +201,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-24.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-22.04.deb - name: Install ParaView .deb run: | From 1ab4c12c319169d79c759e151556966239706791 Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 12 Sep 2026 08:53:55 +0200 Subject: [PATCH 43/46] [il-ext] rev compiler check ci --- .github/workflows/check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 281496bd6e..88d8e30e45 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -159,7 +159,7 @@ jobs: # Check compiler warnings # # ----------------------- # check-warnings: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: kamikaze: [KAMIKAZE=TRUE, KAMIKAZE=FALSE] @@ -201,7 +201,7 @@ jobs: - name: Fetch TTK-ParaView headless Debian package run: | wget -O ttk-paraview-headless.deb \ - https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-22.04.deb + https://github.com/${{ env.PV_REPO }}/releases/download/${{ env.PV_TAG }}/ttk-paraview-headless-ubuntu-24.04.deb - name: Install ParaView .deb run: | From dbbd425d06a2e3f91b5375bd83a186ec3768131c Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 12 Sep 2026 09:10:00 +0200 Subject: [PATCH 44/46] [il-ext] fixing warnings in 64bits --- core/base/discreteGradient/DiscreteGradient_Template.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index 8231884557..ef6ff4f2a4 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1961,7 +1961,7 @@ int DiscreteGradient::getAllAscendingPaths( } // check all cofacets - int cofacetNumber = -1; + SimplexId cofacetNumber = -1; switch(currentCell.dim_) { case 1: @@ -1977,8 +1977,8 @@ int DiscreteGradient::getAllAscendingPaths( bool hasProgressed = false; - for(int i = 0; i < cofacetNumber; i++) { - int cofacetId = -1; + for(SimplexId i = 0; i < cofacetNumber; i++) { + SimplexId cofacetId = -1; switch(currentCell.dim_) { case 1: triangulation.getEdgeTriangle(currentCell.id_, i, cofacetId); From 4e83f27b68e6d397622cf478d87fc509bc64ad3d Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 12 Sep 2026 09:44:56 +0200 Subject: [PATCH 45/46] [il-ext] lint fixes --- .../discreteGradient/DiscreteGradient_Template.h | 15 +++++++++------ .../NumericalIntegralLines.h | 12 ++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/base/discreteGradient/DiscreteGradient_Template.h b/core/base/discreteGradient/DiscreteGradient_Template.h index ef6ff4f2a4..57553fb3b0 100644 --- a/core/base/discreteGradient/DiscreteGradient_Template.h +++ b/core/base/discreteGradient/DiscreteGradient_Template.h @@ -1997,10 +1997,10 @@ int DiscreteGradient::getAllAscendingPaths( cofacet.dim_ = currentCell.dim_ + 1; cofacet.id_ = cofacetId; - StackEntry newStackEntry; - newStackEntry.partialPath_ = stackEntry.partialPath_; - newStackEntry.partialPath_.push_back(cofacet); - newStackEntry.currentCell_ = cofacet; + // the path shared by all the branches below (one per face of the + // cofacet): each branch extends its own copy of it + std::vector cofacetPath = stackEntry.partialPath_; + cofacetPath.push_back(cofacet); // now find the simplex we came from int simplexNumber = -1; @@ -2029,11 +2029,14 @@ int DiscreteGradient::getAllAscendingPaths( if(isCellCritical(simplex)) { // always terminate here — don't continue the path through a // critical cell - newStackEntry.partialPath_.push_back(simplex); - vpaths.push_back(newStackEntry.partialPath_); + std::vector criticalPath = cofacetPath; + criticalPath.push_back(simplex); + vpaths.push_back(std::move(criticalPath)); hasProgressed = true; // prevent the fallback push too // do NOT push to stack } else if(simplexPair == cofacet.id_) { + StackEntry newStackEntry; + newStackEntry.partialPath_ = cofacetPath; newStackEntry.partialPath_.push_back(simplex); newStackEntry.currentCell_ = simplex; stack.push(std::move(newStackEntry)); diff --git a/core/base/numericalIntegralLines/NumericalIntegralLines.h b/core/base/numericalIntegralLines/NumericalIntegralLines.h index 90304766bb..8dd25d4f52 100644 --- a/core/base/numericalIntegralLines/NumericalIntegralLines.h +++ b/core/base/numericalIntegralLines/NumericalIntegralLines.h @@ -936,7 +936,7 @@ int ttk::nil::NumericalIntegralLines::getCofaces( = triangulation->getVertexEdgeNumber(simplexId); for(SimplexId i = 0; i < edgeNumber; i++) { triangulation->getVertexEdge(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, 1)); + cofaces.emplace_back(cofaceId, 1); } } @@ -946,7 +946,7 @@ int ttk::nil::NumericalIntegralLines::getCofaces( = triangulation->getVertexTriangleNumber(simplexId); for(SimplexId i = 0; i < triangleNumber; i++) { triangulation->getVertexTriangle(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, 2)); + cofaces.emplace_back(cofaceId, 2); } } @@ -954,7 +954,7 @@ int ttk::nil::NumericalIntegralLines::getCofaces( const SimplexId starNumber = triangulation->getVertexStarNumber(simplexId); for(SimplexId i = 0; i < starNumber; i++) { triangulation->getVertexStar(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, cellDimension)); + cofaces.emplace_back(cofaceId, cellDimension); } return 0; @@ -967,7 +967,7 @@ int ttk::nil::NumericalIntegralLines::getCofaces( = triangulation->getEdgeTriangleNumber(simplexId); for(SimplexId i = 0; i < triangleNumber; i++) { triangulation->getEdgeTriangle(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, 2)); + cofaces.emplace_back(cofaceId, 2); } } @@ -975,7 +975,7 @@ int ttk::nil::NumericalIntegralLines::getCofaces( const SimplexId starNumber = triangulation->getEdgeStarNumber(simplexId); for(SimplexId i = 0; i < starNumber; i++) { triangulation->getEdgeStar(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, cellDimension)); + cofaces.emplace_back(cofaceId, cellDimension); } return 0; @@ -985,7 +985,7 @@ int ttk::nil::NumericalIntegralLines::getCofaces( const SimplexId starNumber = triangulation->getTriangleStarNumber(simplexId); for(SimplexId i = 0; i < starNumber; i++) { triangulation->getTriangleStar(simplexId, i, cofaceId); - cofaces.push_back(std::make_pair(cofaceId, cellDimension)); + cofaces.emplace_back(cofaceId, cellDimension); } return 0; From cf6c56edfa770d42a5c5d3c308734181a851aa5b Mon Sep 17 00:00:00 2001 From: Julien J Tierny Date: Sat, 12 Sep 2026 10:05:34 +0200 Subject: [PATCH 46/46] [il-ext] windows fix --- core/base/{vpaths => vPaths}/CMakeLists.txt | 0 core/base/{vpaths => vPaths}/VPaths.cpp | 0 core/base/{vpaths => vPaths}/VPaths.h | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename core/base/{vpaths => vPaths}/CMakeLists.txt (100%) rename core/base/{vpaths => vPaths}/VPaths.cpp (100%) rename core/base/{vpaths => vPaths}/VPaths.h (100%) diff --git a/core/base/vpaths/CMakeLists.txt b/core/base/vPaths/CMakeLists.txt similarity index 100% rename from core/base/vpaths/CMakeLists.txt rename to core/base/vPaths/CMakeLists.txt diff --git a/core/base/vpaths/VPaths.cpp b/core/base/vPaths/VPaths.cpp similarity index 100% rename from core/base/vpaths/VPaths.cpp rename to core/base/vPaths/VPaths.cpp diff --git a/core/base/vpaths/VPaths.h b/core/base/vPaths/VPaths.h similarity index 100% rename from core/base/vpaths/VPaths.h rename to core/base/vPaths/VPaths.h