TTK
Loading...
Searching...
No Matches
ttkMergeTreePrincipalGeodesics.cpp
Go to the documentation of this file.
3#include <ttkMergeTreeUtils.h>
4
5#include <vtkInformation.h>
6
7#include <vtkDataArray.h>
8#include <vtkDataSet.h>
9#include <vtkDoubleArray.h>
10#include <vtkObjectFactory.h>
11#include <vtkPointData.h>
12#include <vtkSmartPointer.h>
13#include <vtkTable.h>
14
15#include <ttkUtils.h>
16
17// A VTK macro that enables the instantiation of this class via ::New()
18// You do not have to modify this
20
34 this->SetNumberOfInputPorts(2);
35 this->SetNumberOfOutputPorts(4);
36}
37
46 int port, vtkInformation *info) {
47 if(port == 0)
48 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
49 else if(port == 1) {
50 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
51 info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
52 } else
53 return 0;
54 return 1;
55}
56
73 int port, vtkInformation *info) {
74 if(port == 0) {
75 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
76 } else if(port == 1 or port == 2 or port == 3) {
77 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable");
78 } else {
79 return 0;
80 }
81 return 1;
82}
83
98 vtkInformation *ttkNotUsed(request),
99 vtkInformationVector **inputVector,
100 vtkInformationVector *outputVector) {
101 // ------------------------------------------------------------------------------------
102 // --- Get input object from input vector
103 // ------------------------------------------------------------------------------------
104 auto blocks = vtkMultiBlockDataSet::GetData(inputVector[0], 0);
105 auto blocks2 = vtkMultiBlockDataSet::GetData(inputVector[1], 0);
106
107 // ------------------------------------------------------------------------------------
108 // --- Load blocks
109 // ------------------------------------------------------------------------------------
110 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> inputTrees, inputTrees2;
111 ttk::ftm::loadBlocks(inputTrees, blocks);
112 ttk::ftm::loadBlocks(inputTrees2, blocks2);
113
114 // ------------------------------------------------------------------------------------
115 // If we have already computed once but the input has changed
116 if((treesNodes.size() != 0 and inputTrees[0]->GetBlock(0) != treesNodes[0])
117 or (treesNodes2.size() != inputTrees2.size()))
118 resetDataVisualization();
119
120 // Parameters
122 if(not normalizedWasserstein_) {
123 oldEpsilonTree1 = epsilonTree1_;
124 epsilonTree1_ = 100;
125 } else
126 epsilonTree1_ = oldEpsilonTree1;
128 printMsg("Computation with normalized Wasserstein.");
129 else
130 printMsg("Computation without normalized Wasserstein.");
131
132 return run<float>(outputVector, inputTrees, inputTrees2);
133}
134
135template <class dataType>
137 vtkInformationVector *outputVector,
138 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees,
139 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees2) {
140 if(not isDataVisualizationFilled())
141 runCompute<dataType>(outputVector, inputTrees, inputTrees2);
142 runOutput<dataType>(outputVector, inputTrees, inputTrees2);
143 return 1;
144}
145
146template <class dataType>
148 vtkInformationVector *ttkNotUsed(outputVector),
149 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees,
150 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees2) {
151 // ------------------------------------------------------------------------------------
152 // --- Construct trees
153 // ------------------------------------------------------------------------------------
154 std::vector<ttk::ftm::MergeTree<dataType>> intermediateMTrees,
155 intermediateMTrees2;
156
157 bool const useSecondPairsType = (mixtureCoefficient_ == 0);
159 inputTrees, intermediateMTrees, treesNodes, treesArcs, treesSegmentation,
160 useSecondPairsType, DiagramPairTypes);
161 // If merge trees are provided in input and normalization is not asked
166 = (intermediateMTrees[0].tree.template isJoinTree<dataType>() ? 1 : 0);
167 }
169 or (mixtureCoefficient_ != 0 and mixtureCoefficient_ != 1)) {
170 auto &inputTrees2ToUse
171 = (not isPersistenceDiagram_ ? inputTrees2 : inputTrees);
173 inputTrees2ToUse, intermediateMTrees2, treesNodes2, treesArcs2,
174 treesSegmentation2, !useSecondPairsType, DiagramPairTypes);
175 }
177
178 const int numInputs = intermediateMTrees.size();
179 const int numInputs2 = intermediateMTrees2.size();
180 setDataVisualization(numInputs, numInputs2);
181
182 // ------------------------------------------------------------------------------------
183 // --- Call base
184 // ------------------------------------------------------------------------------------
185 execute<dataType>(intermediateMTrees, intermediateMTrees2);
186
188 intermediateMTrees, intermediateDTrees);
189
190 return 1;
191}
192
193template <class dataType>
196 int blockId,
197 vtkMultiBlockDataSet *output_barycenter) {
198 vtkSmartPointer<vtkUnstructuredGrid> const vtkOutputNodeBary
200 vtkSmartPointer<vtkUnstructuredGrid> const vtkOutputArcBary
202
203 ttkMergeTreeVisualization visuMakerBary;
204 visuMakerBary.setShiftMode(2); // Line
205 visuMakerBary.setVtkOutputNode(vtkOutputNodeBary);
207 visuMakerBary.setVtkOutputArc(vtkOutputArcBary);
208 else {
209 visuMakerBary.setVtkOutputArc(vtkOutputNodeBary);
211 visuMakerBary.setIsPDSadMax(blockId);
212 else
213 visuMakerBary.setIsPDSadMax(mixtureCoefficient_ == 0);
214 visuMakerBary.setPlanarLayout(true);
215 }
216 visuMakerBary.setDebugLevel(this->debugLevel_);
217 visuMakerBary.setOutputTreeNodeId(true);
220 visuMakerBary.makeTreesOutput<dataType>(&(barycenter.tree));
221
222 // Construct multiblock
223 if(not isPersistenceDiagram_) {
224 vtkMultiBlockDataSet::SafeDownCast(output_barycenter->GetBlock(0))
225 ->SetBlock(blockId, vtkOutputNodeBary);
226 vtkMultiBlockDataSet::SafeDownCast(output_barycenter->GetBlock(1))
227 ->SetBlock(blockId, vtkOutputArcBary);
228 } else
229 output_barycenter->SetBlock(blockId, vtkOutputNodeBary);
230}
231
232template <class dataType>
234 vtkInformationVector *outputVector,
235 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees,
236 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> &inputTrees2) {
237 // ------------------------------------------------------------------------------------
238 // --- Create output
239 // ------------------------------------------------------------------------------------
240 auto output_barycenter = vtkMultiBlockDataSet::GetData(outputVector, 0);
241 auto output_coef = vtkTable::GetData(outputVector, 1);
242 auto output_geodVector = vtkTable::GetData(outputVector, 2);
243 auto output_corrMatrix = vtkTable::GetData(outputVector, 3);
244
245 // ------------------------------------------
246 // --- Barycenter
247 // ------------------------------------------
248 auto noBlockBary
249 = 1
251 or (mixtureCoefficient_ != 0 and mixtureCoefficient_ != 1));
252 output_barycenter->SetNumberOfBlocks(noBlockBary);
253 if(not isPersistenceDiagram_) {
254 vtkSmartPointer<vtkMultiBlockDataSet> const vtkBlockNodes
258 int const noBlock = (inputTrees2.size() == 0 ? 1 : 2);
259 vtkBlockNodes->SetNumberOfBlocks(noBlock);
260 vtkBlockArcs->SetNumberOfBlocks(noBlock);
261 output_barycenter->SetBlock(0, vtkBlockNodes);
262 output_barycenter->SetBlock(1, vtkBlockArcs);
263 }
264
266 mergeTreeDoubleToTemplate(barycenter_, barycenterT);
267 makeBarycenterOutput<dataType>(barycenterT, 0, output_barycenter);
268
269 if(inputTrees2.size() != 0
271 and mixtureCoefficient_ != 1)) {
273 mergeTreeDoubleToTemplate(barycenterInput2_, barycenter2T);
274 makeBarycenterOutput<dataType>(barycenter2T, 1, output_barycenter);
275 }
276
277 // ------------------------------------------
278 // --- Coefficients
279 // ------------------------------------------
280 std::vector<std::vector<std::vector<double>> *> allTs{&allTs_, &allScaledTs_};
281
282 vtkNew<vtkIntArray> treeIDArray{};
283 treeIDArray->SetName("TreeID");
284 treeIDArray->SetNumberOfTuples(inputTrees.size());
285 for(unsigned int i = 0; i < inputTrees.size(); ++i) {
286 treeIDArray->SetTuple1(i, i);
287 }
288 output_coef->AddColumn(treeIDArray);
289
290 for(unsigned int t = 0; t < 2; ++t) {
291 for(unsigned int i = 0; i < (*allTs[t]).size(); ++i) {
292 vtkNew<vtkDoubleArray> tArray{};
293 auto size = (*allTs[t]).size();
294 std::string const name
295 = (t == 0 ? ttk::axa::getTableCoefficientName(size, i)
297 tArray->SetName(name.c_str());
298 tArray->SetNumberOfTuples(inputTrees.size());
299 for(unsigned int j = 0; j < (*allTs[t])[i].size(); ++j)
300 tArray->SetTuple1(j, (*allTs[t])[i][j]);
301 output_coef->AddColumn(tArray);
302 }
303 }
304
305 // Copy Field Data
306 // - aggregate input field data
307 for(unsigned int b = 0; b < inputTrees[0]->GetNumberOfBlocks(); ++b) {
308 vtkNew<vtkFieldData> fd{};
309 fd->CopyStructure(inputTrees[0]->GetBlock(b)->GetFieldData());
310 fd->SetNumberOfTuples(inputTrees.size());
311 for(size_t i = 0; i < inputTrees.size(); ++i) {
312 fd->SetTuple(i, 0, inputTrees[i]->GetBlock(b)->GetFieldData());
313 }
314
315 // - copy input field data to output row data
316 for(int i = 0; i < fd->GetNumberOfArrays(); ++i) {
317 auto array = fd->GetAbstractArray(i);
318 array->SetName(array->GetName());
319 output_coef->AddColumn(array);
320 }
321 }
322
323 // Field Data Input Parameters
324 std::vector<std::string> paramNames;
325 getParamNames(paramNames);
326 for(auto paramName : paramNames) {
327 vtkNew<vtkDoubleArray> array{};
328 array->SetName(paramName.c_str());
329 array->InsertNextTuple1(getParamValueFromName(paramName));
330 output_coef->GetFieldData()->AddArray(array);
331 }
332 vtkNew<vtkIntArray> diagramPairTypesArray{};
333 diagramPairTypesArray->SetName("DiagramPairTypes");
334 diagramPairTypesArray->InsertNextTuple1(DiagramPairTypes);
335 output_coef->GetFieldData()->AddArray(diagramPairTypesArray);
336
337 // ------------------------------------------
338 // --- Geodesics Vectors
339 // ------------------------------------------
340 std::vector<std::vector<std::vector<std::vector<double>>> *> vectors{
341 &vS_, &v2s_};
342 unsigned int maxSize = vS_[0].size();
343 if(inputTrees2.size() != 0
345 and mixtureCoefficient_ != 1)) {
346 vectors = {&vS_, &v2s_, &trees2Vs_, &trees2V2s_};
347 maxSize = std::max(vS_[0].size(), trees2Vs_[0].size());
348 }
349 for(unsigned int v = 0; v < vectors.size(); ++v) {
350 auto vector = vectors[v];
351 for(unsigned int i = 0; i < (*vector).size(); ++i)
352 for(unsigned int k = 0; k < 2; ++k) {
353 vtkNew<vtkDoubleArray> vectorArray{};
354 bool const isSecondInput = (v >= 2);
355 std::string const name = ttk::axa::getTableVectorName(
356 (*vector).size(), i, v % 2, k, isSecondInput);
357 vectorArray->SetName(name.c_str());
358 vectorArray->SetNumberOfTuples(maxSize);
359 for(unsigned int j = 0; j < (*vector)[i].size(); ++j)
360 vectorArray->SetTuple1(j, (*vector)[i][j][k]);
361 for(unsigned int j = (*vector)[i].size(); j < maxSize; ++j)
362 vectorArray->SetTuple1(j, std::nan(""));
363 output_geodVector->AddColumn(vectorArray);
364 }
365 }
366
367 // ------------------------------------------
368 // --- Correlation Matrix
369 // ------------------------------------------
370 // TODO manage second input
371 // Correlation coefficients
372 unsigned int const noCols = branchesCorrelationMatrix_[0].size();
373 unsigned int const noRows = branchesCorrelationMatrix_.size();
374 for(unsigned int j = 0; j < noCols; ++j) {
375 vtkNew<vtkDoubleArray> corrArray{}, persArray{};
376 std::string const name = ttk::axa::getTableCorrelationName(noCols, j);
377 corrArray->SetName(name.c_str());
378 corrArray->SetNumberOfTuples(noRows);
379 std::string const name2 = ttk::axa::getTableCorrelationPersName(noCols, j);
380 persArray->SetName(name2.c_str());
381 persArray->SetNumberOfTuples(noRows);
382 for(unsigned int i = 0; i < noRows; ++i) {
383 corrArray->SetTuple1(i, branchesCorrelationMatrix_[i][j]);
384 persArray->SetTuple1(i, persCorrelationMatrix_[i][j]);
385 }
386 output_corrMatrix->AddColumn(corrArray);
387 output_corrMatrix->AddColumn(persArray);
388 }
389
390 // Tree matching
391 std::vector<std::vector<ttk::ftm::idNode>> matchingMatrix;
393 barycenter_, intermediateDTrees, baryMatchings_, matchingMatrix);
395 for(unsigned int j = 0; j < inputTrees.size(); ++j)
396 matchingMatrix[barycenter_.tree.getNode(barycenter_.tree.getRoot())
397 ->getOrigin()][j]
398 = intermediateDTrees[j]
399 .tree.getNode(intermediateDTrees[j].tree.getRoot())
400 ->getOrigin();
401 for(unsigned int j = 0; j < inputTrees.size(); ++j) {
402 vtkNew<vtkIntArray> corrArray{};
403 std::string const name = ttk::axa::getTableTreeName(inputTrees.size(), j);
404 corrArray->SetName(name.c_str());
405 corrArray->SetNumberOfTuples(noRows);
406 for(unsigned int i = 0; i < noRows; ++i)
407 corrArray->SetTuple1(i, (int)matchingMatrix[i][j]);
408 output_corrMatrix->AddColumn(corrArray);
409 }
410
411 // Barycenter node id
412 vtkNew<vtkIntArray> baryNodeId{};
413 baryNodeId->SetName("BaryNodeId");
414 baryNodeId->SetNumberOfTuples(noRows);
415 for(unsigned int i = 0; i < noRows; ++i)
416 baryNodeId->SetTuple1(i, i);
417 output_corrMatrix->AddColumn(baryNodeId);
418
419 // Barycenter node isLeaf
420 vtkNew<vtkIntArray> baryNodeIsLeaf{};
421 baryNodeIsLeaf->SetName("BaryNodeIsLeaf");
422 baryNodeIsLeaf->SetNumberOfTuples(noRows);
423 for(unsigned int i = 0; i < noRows; ++i)
424 baryNodeIsLeaf->SetTuple1(i, barycenter_.tree.isLeaf(i));
425 output_corrMatrix->AddColumn(baryNodeIsLeaf);
426
427 // Barycenter node persistence
428 vtkNew<vtkDoubleArray> baryNodePers{};
429 baryNodePers->SetName("BaryNodePers");
430 baryNodePers->SetNumberOfTuples(noRows);
431 for(unsigned int i = 0; i < noRows; ++i) {
432 auto nodePers = barycenter_.tree.template getNodePersistence<double>(i);
433 baryNodePers->SetTuple1(i, nodePers);
434 }
435 output_corrMatrix->AddColumn(baryNodePers);
436
437 // Trees persistence order
438 std::vector<std::vector<int>> treesOrder(intermediateDTrees.size());
439 for(unsigned int i = 0; i < intermediateDTrees.size(); ++i) {
440 treesOrder[i].resize(intermediateDTrees[i].tree.getNumberOfNodes());
441 std::vector<std::tuple<ttk::ftm::idNode, ttk::ftm::idNode, double>> pairs;
442 intermediateDTrees[i].tree.template getPersistencePairsFromTree<double>(
443 pairs, false);
444 for(unsigned int j = 0; j < pairs.size(); ++j) {
445 int const index = pairs.size() - 1 - j;
446 treesOrder[i][std::get<0>(pairs[j])] = index;
447 treesOrder[i][std::get<1>(pairs[j])] = index;
448 }
449 }
450
451 vtkNew<vtkDoubleArray> treesPersOrder{};
452 treesPersOrder->SetName("TreesPersOrder");
453 treesPersOrder->SetNumberOfTuples(noRows);
454 for(unsigned int i = 0; i < noRows; ++i) {
455 int minIndex = std::numeric_limits<int>::max();
456 for(unsigned int j = 0; j < intermediateDTrees.size(); ++j) {
457 if(int(matchingMatrix[i][j]) != -1)
458 minIndex = std::min(minIndex, treesOrder[j][matchingMatrix[i][j]]);
459 }
460 treesPersOrder->SetTuple1(i, minIndex);
461 }
462 output_corrMatrix->AddColumn(treesPersOrder);
463
464 return 1;
465}
#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 ttk::MergeTreePrincipalGeodesics module.
void makeBarycenterOutput(ttk::ftm::MergeTree< dataType > &barycenter, int blockId, vtkMultiBlockDataSet *output_barycenter)
int runCompute(vtkInformationVector *outputVector, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees2)
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int runOutput(vtkInformationVector *outputVector, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees2)
int FillOutputPortInformation(int port, vtkInformation *info) override
int run(vtkInformationVector *outputVector, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees2)
int FillInputPortInformation(int port, vtkInformation *info) override
void makeTreesOutput(FTMTree_MT *tree1)
void setConvertedToDiagram(bool converted)
void setVtkOutputArc(vtkUnstructuredGrid *vtkArc)
void setVtkOutputNode(vtkUnstructuredGrid *vtkNode)
int debugLevel_
Definition Debug.h:379
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
void getParamNames(std::vector< std::string > &paramNames)
double getParamValueFromName(std::string &paramName)
std::vector< std::vector< std::vector< double > > > v2s_
std::vector< std::vector< std::vector< double > > > trees2V2s_
std::vector< std::vector< std::vector< double > > > vS_
std::vector< std::vector< double > > allTs_
std::vector< std::vector< double > > branchesCorrelationMatrix_
std::vector< std::vector< double > > persCorrelationMatrix_
std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > baryMatchings_
std::vector< std::vector< std::vector< double > > > trees2Vs_
std::vector< std::vector< double > > allScaledTs_
void execute(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< ftm::MergeTree< dataType > > &trees2)
void getMatchingMatrix(const ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< ftm::idNode > > &matchingMatrix)
std::string getTableCoefficientNormName(int noAxes, int axeNum)
std::string getTableCorrelationPersName(int noAxes, int axeNum)
std::string getTableVectorName(int noAxes, int axeNum, int vId, int vComp, bool isSecondInput)
std::string getTableTreeName(int noTrees, int treeNum)
std::string getTableCoefficientName(int noAxes, int axeNum)
std::string getTableCorrelationName(int noAxes, int axeNum)
bool constructTrees(std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, std::vector< MergeTree< dataType > > &intermediateTrees, std::vector< vtkUnstructuredGrid * > &treesNodes, std::vector< vtkUnstructuredGrid * > &treesArcs, std::vector< vtkDataSet * > &treesSegmentation, const std::vector< bool > &useSecondPairsTypeVec, int diagramPairTypes=0)
void loadBlocks(std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, vtkMultiBlockDataSet *blocks)
void mergeTreesTemplateToDouble(std::vector< MergeTree< dataType > > &mts, std::vector< MergeTree< double > > &newMts)
ftm::FTMTree_MT tree
Definition FTMTree_MT.h:906
vtkStandardNewMacro(ttkMergeTreePrincipalGeodesics)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)