TTK
Loading...
Searching...
No Matches
ttkBottleneckDistance.cpp
Go to the documentation of this file.
3#include <ttkUtils.h>
4
5#include <vtkDoubleArray.h>
6#include <vtkFloatArray.h>
7#include <vtkInformation.h>
8#include <vtkIntArray.h>
9#include <vtkMultiBlockDataSet.h>
10#include <vtkPointData.h>
11#include <vtkUnstructuredGrid.h>
12
14
16 SetNumberOfInputPorts(1);
17 SetNumberOfOutputPorts(2);
18}
19
21 vtkInformation *info) {
22 if(port == 0) {
23 info->Set(ttkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
24 return 1;
25 }
26 return 0;
27}
28
30 vtkInformation *info) {
31 if(port == 0) {
32 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
33 return 1;
34 } else if(port == 1) {
35 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
36 return 1;
37 }
38 return 0;
39}
40
41static int generateMatchings(vtkUnstructuredGrid *const outputCT3,
42 const ttk::DiagramType &diagram1,
43 const ttk::DiagramType &diagram2,
44 const std::vector<ttk::MatchingType> &matchings,
45 const std::array<double, 3> &distances,
46 const double globalDist,
47 const double spacing,
48 const bool isBottleneck,
49 const bool is2D0,
50 const bool is2D1) {
51
52 vtkNew<vtkUnstructuredGrid> vtu{};
53
54 vtkNew<vtkPoints> points{};
55 points->SetNumberOfPoints(2 * matchings.size());
56 vtu->SetPoints(points);
57
58 vtkNew<vtkDoubleArray> costs{};
59 costs->SetName("Cost");
60 costs->SetNumberOfComponents(1);
61 costs->SetNumberOfTuples(matchings.size());
62 vtu->GetCellData()->AddArray(costs);
63
64 vtkNew<vtkIntArray> matchingIds{};
65 matchingIds->SetName("MatchingIdentifier");
66 matchingIds->SetNumberOfComponents(1);
67 matchingIds->SetNumberOfTuples(matchings.size());
68 vtu->GetCellData()->AddArray(matchingIds);
69
70 // Build matchings.
71 for(size_t i = 0; i < matchings.size(); ++i) {
72 const auto &t = matchings[i];
73 const auto n1 = std::get<0>(t);
74 const auto n2 = std::get<1>(t);
75
76 const auto &pair0 = diagram1[n1];
77 const auto &pair1 = diagram2[n2];
78
79 const auto pairPoint = [](const ttk::PersistencePair &pair, const bool is2D,
80 const double zval) -> std::array<double, 3> {
81 if(is2D) {
82 return {pair.birth.sfValue, pair.death.sfValue, zval};
83 } else {
84 return {
85 pair.death.coords[0], pair.death.coords[1], pair.death.coords[2]};
86 }
87 };
88
89 const auto p0 = pairPoint(pair0, is2D0, -spacing / 2.0);
90 points->SetPoint(2 * i + 0, p0.data());
91 const auto p1 = pairPoint(pair1, is2D1, spacing / 2.0);
92 points->SetPoint(2 * i + 1, p1.data());
93
94 std::array<vtkIdType, 2> ids{
95 2 * static_cast<vtkIdType>(i) + 0,
96 2 * static_cast<vtkIdType>(i) + 1,
97 };
98 vtu->InsertNextCell(VTK_LINE, 2, ids.data());
99
100 costs->SetTuple1(i, std::get<2>(t));
101 matchingIds->SetTuple1(i, i);
102 }
103
104 // add distance results to output_matchings FieldData
105 vtkNew<vtkDoubleArray> minSad{};
106 minSad->SetName("MinSaddleCost");
107 minSad->SetNumberOfTuples(1);
108 minSad->SetTuple1(0, distances[0]);
109
110 vtkNew<vtkDoubleArray> sadSad{};
111 sadSad->SetName("SaddleSaddleCost");
112 sadSad->SetNumberOfTuples(1);
113 sadSad->SetTuple1(0, distances[1]);
114
115 vtkNew<vtkDoubleArray> sadMax{};
116 sadMax->SetName("SaddleMaxCost");
117 sadMax->SetNumberOfTuples(1);
118 sadMax->SetTuple1(0, distances[2]);
119
120 vtkNew<vtkDoubleArray> wass{};
121 wass->SetName(isBottleneck ? "BottleneckDistance" : "WassersteinDistance");
122 wass->SetNumberOfTuples(1);
123 wass->SetTuple1(0, globalDist);
124
125 vtu->GetFieldData()->AddArray(minSad);
126 vtu->GetFieldData()->AddArray(sadSad);
127 vtu->GetFieldData()->AddArray(sadMax);
128 vtu->GetFieldData()->AddArray(wass);
129
130 outputCT3->ShallowCopy(vtu);
131
132 return 1;
133}
134
136 vtkInformationVector **inputVector,
137 vtkInformationVector *outputVector) {
138
139 auto outputDiagrams = vtkMultiBlockDataSet::GetData(outputVector, 0);
140 auto outputMatchings = vtkUnstructuredGrid::GetData(outputVector, 1);
141
142 auto blocks = vtkMultiBlockDataSet::GetData(inputVector[0]);
143 std::vector<vtkUnstructuredGrid *> inputDiags{};
144
145 if(blocks == nullptr) {
146 this->printErr("No input diagrams");
147 return 0;
148 }
149
150 for(size_t i = 0; i < blocks->GetNumberOfBlocks(); ++i) {
151 const auto diag = vtkUnstructuredGrid::SafeDownCast(blocks->GetBlock(i));
152 if(diag != nullptr) {
153 inputDiags.emplace_back(diag);
154 }
155 }
156
157 if(inputDiags.size() < 2) {
158 this->printErr("Less than two input diagrams");
159 return 0;
160 }
161 if(inputDiags.size() > 2) {
162 this->printWrn("More than two input diagrams: "
163 + std::to_string(inputDiags.size()));
164 }
165
166 const auto coords0 = vtkFloatArray::SafeDownCast(
167 inputDiags[0]->GetPointData()->GetArray("Coordinates"));
168 const auto coords1 = vtkFloatArray::SafeDownCast(
169 inputDiags[1]->GetPointData()->GetArray("Coordinates"));
170
171 const bool is2D0 = coords0 != nullptr;
172 const bool is2D1 = coords1 != nullptr;
173
174 // Call package
175 int status = 0;
176
177 ttk::DiagramType diagram0{}, diagram1{};
178 std::vector<ttk::MatchingType> matchings{};
179
180 status = VTUToDiagram(diagram0, inputDiags[0], *this);
181 if(status < 0) {
182 this->printErr("Could not extract diagram from first input data-set");
183 return 0;
184 }
185
186 status = VTUToDiagram(diagram1, inputDiags[1], *this);
187 if(status < 0) {
188 this->printErr("Could not extract diagram from second input data-set");
189 return 0;
190 }
191
192 // Exec.
193 status = this->execute(diagram0, diagram1, matchings);
194 if(status != 0) {
195 this->printErr("Base layer failed with error status "
196 + std::to_string(status));
197 return 0;
198 }
199
200 // Generate matchings
201 if(this->UseOutputMatching) {
202 status = generateMatchings(outputMatchings, diagram0, diagram1, matchings,
203 this->costs_, this->distance_, this->Spacing,
204 this->WassersteinMetric == "inf", is2D0, is2D1);
205
206 if(status != 1) {
207 this->printErr("Could not compute matchings");
208 return 0;
209 }
210 }
211
212 // Translate diagrams
213 vtkNew<vtkUnstructuredGrid> vtu0{}, vtu1{};
214 if(this->UseGeometricSpacing) {
215 vtu0->ShallowCopy(inputDiags[0]);
216 ResetDiagramPosition(vtu0, *this);
217 TranslateDiagram(vtu0, {0, 0, -this->Spacing});
218 vtu1->ShallowCopy(inputDiags[1]);
219 ResetDiagramPosition(vtu1, *this);
220 TranslateDiagram(vtu1, {0, 0, this->Spacing});
221 } else {
222 vtu0->ShallowCopy(inputDiags[0]);
223 vtu1->ShallowCopy(inputDiags[1]);
224 }
225
226 // Add matchings infos on diagrams
227 status = augmentDiagrams(matchings, vtu0, vtu1);
228 if(status != 1) {
229 this->printErr("Could not augment diagrams");
230 return 0;
231 }
232
233 // Set output.
234 outputDiagrams->SetNumberOfBlocks(2);
235 outputDiagrams->SetBlock(0, vtu0);
236 outputDiagrams->SetBlock(1, vtu1);
237
238 return 1;
239}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition: BaseClass.h:47
TTK VTK-filter that wraps the bottleneckDistance processing package.
int FillOutputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillInputPortInformation(int port, vtkInformation *info) override
int execute(const ttk::DiagramType &diag0, const ttk::DiagramType &diag1, std::vector< MatchingType > &matchings)
std::array< double, 3 > costs_
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:159
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:149
std::vector< PersistencePair > DiagramType
Persistence Diagram type as a vector of Persistence pairs.
std::array< float, 3 > coords
ttk::CriticalVertex birth
ttk::CriticalVertex death
int augmentDiagrams(const std::vector< ttk::MatchingType > &matchings, vtkUnstructuredGrid *const vtu0, vtkUnstructuredGrid *const vtu1)
vtkStandardNewMacro(ttkBottleneckDistance)
int TranslateDiagram(vtkUnstructuredGrid *const diagram, const std::array< double, 3 > &trans)
Translate a diagram to a new position.
int VTUToDiagram(ttk::DiagramType &diagram, vtkUnstructuredGrid *vtu, const ttk::Debug &dbg)
Converts a Persistence Diagram in the VTK Unstructured Grid format (as generated by the ttkPersistenc...
int ResetDiagramPosition(vtkUnstructuredGrid *const diagram, const ttk::Debug &dbg)
Translate back a canonical diagram into its original position.