1#include <vtkCellData.h>
3#include <vtkDoubleArray.h>
4#include <vtkFloatArray.h>
5#include <vtkIdTypeArray.h>
6#include <vtkInformation.h>
8#include <vtkPointData.h>
9#include <vtkSmartPointer.h>
19 SetNumberOfInputPorts(1);
20 SetNumberOfOutputPorts(3);
24 int port, vtkInformation *info) {
26 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(),
"vtkDataSet");
33 int port, vtkInformation *info) {
35 info->Set(vtkDataObject::DATA_TYPE_NAME(),
"vtkUnstructuredGrid");
37 }
else if(port == 1) {
40 }
else if(port == 2) {
41 info->Set(vtkDataObject::DATA_TYPE_NAME(),
"vtkUnstructuredGrid");
47template <
typename scalarType,
typename triangulationType>
48int ttkPersistenceDiagramApproximation::dispatch(
49 vtkUnstructuredGrid *outputCTPersistenceDiagram,
50 vtkUnstructuredGrid *outputBounds,
51 vtkDataArray *
const inputScalarsArray,
52 const scalarType *
const inputScalars,
53 scalarType *outputScalars,
54 SimplexId *outputOffsets,
55 int *outputMonotonyOffsets,
56 const SimplexId *
const inputOrder,
57 const triangulationType *triangulation) {
60 std::vector<ttk::PersistencePair> CTDiagram{};
64 double *range = inputScalarsArray->GetRange(0);
70 if(!std::is_same<ttk::ImplicitWithPreconditions, triangulationType>::value
71 && !std::is_same<ttk::ImplicitNoPreconditions, triangulationType>::value) {
72 this->
printErr(
"Explicit, Compact or Periodic triangulation detected.");
73 this->
printErr(
"Approximation only works on regular grids.");
82 this->
printMsg(
"Complete", 1.0, tm.getElapsedTime(), this->threadNumber_);
94 this->
printErr(
"PersistenceDiagram::execute() error code : "
95 + std::to_string(status));
100 vtkNew<vtkUnstructuredGrid>
const vtu{};
102 triangulation->getDimensionality(), this->ShowInsideDomain);
104 outputCTPersistenceDiagram->ShallowCopy(vtu);
107 drawBottleneckBounds(outputBounds, CTDiagram, inputScalarsArray,
108 outputScalars, inputScalars, triangulation);
116 vtkInformationVector **inputVector,
117 vtkInformationVector *outputVector) {
119 vtkDataSet *input = vtkDataSet::GetData(inputVector[0]);
120 vtkUnstructuredGrid *outputCTPersistenceDiagram
121 = vtkUnstructuredGrid::GetData(outputVector, 0);
122 vtkDataSet *outputField = vtkDataSet::GetData(outputVector, 1);
123 vtkUnstructuredGrid *outputBounds
124 = vtkUnstructuredGrid::GetData(outputVector, 2);
127#ifndef TTK_ENABLE_KAMIKAZE
129 this->
printErr(
"Wrong triangulation");
136 vtkDataArray *inputScalars = this->GetInputArrayToProcess(0, inputVector);
137#ifndef TTK_ENABLE_KAMIKAZE
139 this->
printErr(
"Wrong input scalars");
145 input, 0, triangulation,
false, 1, ForceInputOffsetScalarField);
147#ifndef TTK_ENABLE_KAMIKAZE
149 this->
printErr(
"Wrong input offsets");
152 if(offsetField->GetDataType() != VTK_INT
153 and offsetField->GetDataType() != VTK_ID_TYPE) {
154 this->
printErr(
"Input offset field type not supported");
159 vtkNew<ttkSimplexIdTypeArray> outputOffsets{};
160 outputOffsets->SetNumberOfComponents(1);
161 outputOffsets->SetNumberOfTuples(inputScalars->GetNumberOfTuples());
162 outputOffsets->SetName(
"outputOffsets");
164 vtkNew<vtkIntArray> outputMonotonyOffsets{};
165 outputMonotonyOffsets->SetNumberOfComponents(1);
166 outputMonotonyOffsets->SetNumberOfTuples(inputScalars->GetNumberOfTuples());
167 outputMonotonyOffsets->SetName(
"outputMonotonyffsets");
168 outputMonotonyOffsets->FillComponent(0, 0);
172 outputScalars->SetNumberOfComponents(1);
173 outputScalars->SetNumberOfTuples(inputScalars->GetNumberOfTuples());
174 outputScalars->DeepCopy(inputScalars);
176 std::stringstream ss;
177 ss << inputScalars->GetName() <<
"_Approximated";
178 outputScalars->SetName(ss.str().c_str());
182 inputScalars->GetDataType(), triangulation->
getType(),
183 status = this->dispatch(
184 outputCTPersistenceDiagram, outputBounds, inputScalars,
190 static_cast<TTK_TT *
>(triangulation->
getData())));
193 outputCTPersistenceDiagram->GetFieldData()->ShallowCopy(
194 input->GetFieldData());
197 outputField->ShallowCopy(input);
198 outputField->GetPointData()->AddArray(outputScalars);
199 outputField->GetPointData()->AddArray(outputOffsets);
200 outputField->GetPointData()->AddArray(outputMonotonyOffsets);
202 printWrn(
"The exact Persistence Diagram was computed");
203 printWrn(
"Other outputs are empty");
209template <
typename scalarType,
typename triangulationType>
210int ttkPersistenceDiagramApproximation::drawBottleneckBounds(
211 vtkUnstructuredGrid *outputBounds,
212 const std::vector<ttk::PersistencePair> &diagram,
213 vtkDataArray *inputScalarsArray,
214 const scalarType *
const outputScalars,
215 const scalarType *
const inputScalars,
216 const triangulationType *triangulation)
const {
218 if(diagram.empty()) {
222 vtkNew<vtkUnstructuredGrid> bounds{};
223 double *range = inputScalarsArray->GetRange(0);
224 double const delta = (range[1] - range[0]) *
Epsilon;
228 vtkNew<ttkSimplexIdTypeArray> BirthId{};
229 BirthId->SetNumberOfComponents(1);
230 BirthId->SetName(
"BirthId");
231 vtkNew<ttkSimplexIdTypeArray> DeathId{};
232 DeathId->SetNumberOfComponents(1);
233 DeathId->SetName(
"DeathId");
235 vtkNew<ttkSimplexIdTypeArray> pairIdentifierScalars{};
236 pairIdentifierScalars->SetNumberOfComponents(1);
237 pairIdentifierScalars->SetName(
"PairIdentifier");
239 vtkNew<vtkDoubleArray> persistenceScalars{};
240 persistenceScalars->SetNumberOfComponents(1);
241 persistenceScalars->SetName(
"Persistence");
243 vtkNew<vtkIntArray> unfolded{};
244 unfolded->SetNumberOfComponents(1);
245 unfolded->SetName(
"TrueValues");
247 vtkNew<vtkIntArray> extremumIndexScalars{};
248 extremumIndexScalars->SetNumberOfComponents(1);
249 extremumIndexScalars->SetName(
"PairType");
253 const ttk::SimplexId maxIndex = triangulation->getCellVertexNumber(0) - 2;
255 vtkNew<vtkPoints> points{};
257 for(
size_t i = 0; i < diagram.size(); ++i) {
258 const auto a = diagram[i].birth.id;
259 const auto b = diagram[i].death.id;
261 const auto sa = outputScalars[a];
262 const auto sb = outputScalars[b];
263 if(sb - sa >= 2 * delta) {
264 vtkIdType
const p0 = points->InsertNextPoint(sa - delta, sb - delta, 0);
265 vtkIdType
const p1 = points->InsertNextPoint(sa + delta, sb - delta, 0);
266 vtkIdType
const p2 = points->InsertNextPoint(sa - delta, sb + delta, 0);
267 vtkIdType
const p3 = points->InsertNextPoint(sa + delta, sb + delta, 0);
269 vtkNew<vtkIdList> quad{};
270 quad->InsertNextId(p0);
271 quad->InsertNextId(p1);
272 quad->InsertNextId(p3);
273 quad->InsertNextId(p2);
274 bounds->InsertNextCell(VTK_QUAD, quad);
276 pairIdentifierScalars->InsertNextTuple1(i);
277 BirthId->InsertNextTuple1(a);
278 DeathId->InsertNextTuple1(b);
279 persistenceScalars->InsertNextTuple1(sb - sa);
281 extremumIndexScalars->InsertNextTuple1(-1);
283 const auto type = diagram[i].dim;
285 extremumIndexScalars->InsertNextTuple1(minIndex);
286 }
else if(type == 1) {
287 extremumIndexScalars->InsertNextTuple1(saddleSaddleIndex);
288 }
else if(type == 2) {
289 extremumIndexScalars->InsertNextTuple1(maxIndex);
292 if((abs((
double)(outputScalars[a] - inputScalars[a])) > 1e-6)
293 or (abs((
double)(outputScalars[b] - inputScalars[b])) > 1e-6)) {
294 unfolded->InsertNextTuple1(0);
296 unfolded->InsertNextTuple1(1);
304 const auto s0 = inputScalars[diagram[0].birth.id];
305 const auto s2 = inputScalars[diagram[0].death.id];
306 auto s1 = inputScalars[diagram.back().birth.id];
307 s1 = s1 > s2 / 2 ? s1 : s2 / 2;
308 vtkIdType
const p0 = points->InsertNextPoint(s0, s0, 0);
309 vtkIdType
const p1 = points->InsertNextPoint(s0, s0 + 2 * delta, 0);
310 vtkIdType
const p2 = points->InsertNextPoint(s1, s1, 0);
311 vtkIdType
const p3 = points->InsertNextPoint(s1, s1 + 2 * delta, 0);
313 vtkNew<vtkIdList> quad{};
314 quad->InsertNextId(p0);
315 quad->InsertNextId(p1);
316 quad->InsertNextId(p3);
317 quad->InsertNextId(p2);
318 bounds->InsertNextCell(VTK_QUAD, quad);
319 pairIdentifierScalars->InsertNextTuple1(-1);
320 BirthId->InsertNextTuple1(-1);
321 DeathId->InsertNextTuple1(-1);
322 persistenceScalars->InsertNextTuple1(
Epsilon);
323 extremumIndexScalars->InsertNextTuple1(-1);
324 unfolded->InsertNextTuple1(-1);
327 bounds->SetPoints(points);
329 bounds->GetCellData()->AddArray(BirthId);
330 bounds->GetCellData()->AddArray(DeathId);
331 bounds->GetCellData()->AddArray(persistenceScalars);
332 bounds->GetCellData()->AddArray(pairIdentifierScalars);
333 bounds->GetCellData()->AddArray(extremumIndexScalars);
334 bounds->GetCellData()->AddArray(unfolded);
336 outputBounds->ShallowCopy(bounds);
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
static vtkInformationIntegerKey * SAME_DATA_TYPE_AS_INPUT_PORT()
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, ttk::Triangulation *triangulation, const bool getGlobalOrder=false, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
TTK VTK-filter for the computation of an approximation of a persistence diagram.
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillOutputPortInformation(int port, vtkInformation *info) override
ttkPersistenceDiagramApproximation()
int FillInputPortInformation(int port, vtkInformation *info) override
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
void setOutputMonotonyOffsets(void *data)
void sortPersistenceDiagram(std::vector< PersistencePair > &diagram, const SimplexId *const offsets) const
void preconditionTriangulation(AbstractTriangulation *triangulation)
void setDeltaApproximate(double data)
void setOutputScalars(void *data)
void setOutputOffsets(void *data)
void augmentPersistenceDiagram(std::vector< PersistencePair > &persistencePairs, const scalarType *const scalars, const triangulationType *triangulation)
Complete a ttk::DiagramType instance with scalar field values (useful for persistence) and 3D coordin...
int executeApproximateTopology(std::vector< PersistencePair > &CTDiagram, const scalarType *inputScalars, const triangulationType *triangulation)
Triangulation is a class that provides time and memory efficient traversal methods on triangulations ...
AbstractTriangulation * getData()
Triangulation::Type getType() const
int SimplexId
Identifier type for simplices of any dimension.
#define ttkVtkTemplateMacro(dataType, triangulationType, call)
vtkStandardNewMacro(ttkPersistenceDiagramApproximation)
int DiagramToVTU(vtkUnstructuredGrid *vtu, const ttk::DiagramType &diagram, vtkDataArray *const inputScalars, const ttk::Debug &dbg, const int dim, const bool embedInDomain)
Converts a Persistence Diagram in the ttk::DiagramType format to the VTK Unstructured Grid format (as...
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)