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 useSadMaxPairs = (mixtureCoefficient_ == 0);
158 isPersistenceDiagram_ = ttk::ftm::constructTrees<dataType>(
159 inputTrees, intermediateMTrees, treesNodes, treesArcs, treesSegmentation,
160 useSadMaxPairs);
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);
172 ttk::ftm::constructTrees<dataType>(inputTrees2ToUse, intermediateMTrees2,
173 treesNodes2, treesArcs2,
174 treesSegmentation2, !useSadMaxPairs);
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
187 ttk::ftm::mergeTreesTemplateToDouble<dataType>(
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
333 // ------------------------------------------
334 // --- Geodesics Vectors
335 // ------------------------------------------
336 std::vector<std::vector<std::vector<std::vector<double>>> *> vectors{
337 &vS_, &v2s_};
338 unsigned int maxSize = vS_[0].size();
339 if(inputTrees2.size() != 0
341 and mixtureCoefficient_ != 1)) {
342 vectors = {&vS_, &v2s_, &trees2Vs_, &trees2V2s_};
343 maxSize = std::max(vS_[0].size(), trees2Vs_[0].size());
344 }
345 for(unsigned int v = 0; v < vectors.size(); ++v) {
346 auto vector = vectors[v];
347 for(unsigned int i = 0; i < (*vector).size(); ++i)
348 for(unsigned int k = 0; k < 2; ++k) {
349 vtkNew<vtkDoubleArray> vectorArray{};
350 bool const isSecondInput = (v >= 2);
351 std::string const name = ttk::axa::getTableVectorName(
352 (*vector).size(), i, v % 2, k, isSecondInput);
353 vectorArray->SetName(name.c_str());
354 vectorArray->SetNumberOfTuples(maxSize);
355 for(unsigned int j = 0; j < (*vector)[i].size(); ++j)
356 vectorArray->SetTuple1(j, (*vector)[i][j][k]);
357 for(unsigned int j = (*vector)[i].size(); j < maxSize; ++j)
358 vectorArray->SetTuple1(j, std::nan(""));
359 output_geodVector->AddColumn(vectorArray);
360 }
361 }
362
363 // ------------------------------------------
364 // --- Correlation Matrix
365 // ------------------------------------------
366 // TODO manage second input
367 // Correlation coefficients
368 unsigned int const noCols = branchesCorrelationMatrix_[0].size();
369 unsigned int const noRows = branchesCorrelationMatrix_.size();
370 for(unsigned int j = 0; j < noCols; ++j) {
371 vtkNew<vtkDoubleArray> corrArray{}, persArray{};
372 std::string const name = ttk::axa::getTableCorrelationName(noCols, j);
373 corrArray->SetName(name.c_str());
374 corrArray->SetNumberOfTuples(noRows);
375 std::string const name2 = ttk::axa::getTableCorrelationPersName(noCols, j);
376 persArray->SetName(name2.c_str());
377 persArray->SetNumberOfTuples(noRows);
378 for(unsigned int i = 0; i < noRows; ++i) {
379 corrArray->SetTuple1(i, branchesCorrelationMatrix_[i][j]);
380 persArray->SetTuple1(i, persCorrelationMatrix_[i][j]);
381 }
382 output_corrMatrix->AddColumn(corrArray);
383 output_corrMatrix->AddColumn(persArray);
384 }
385
386 // Tree matching
387 std::vector<std::vector<ttk::ftm::idNode>> matchingMatrix;
389 barycenter_, intermediateDTrees, baryMatchings_, matchingMatrix);
391 for(unsigned int j = 0; j < inputTrees.size(); ++j)
393 ->getOrigin()][j]
394 = intermediateDTrees[j]
395 .tree.getNode(intermediateDTrees[j].tree.getRoot())
396 ->getOrigin();
397 for(unsigned int j = 0; j < inputTrees.size(); ++j) {
398 vtkNew<vtkIntArray> corrArray{};
399 std::string const name = ttk::axa::getTableTreeName(inputTrees.size(), j);
400 corrArray->SetName(name.c_str());
401 corrArray->SetNumberOfTuples(noRows);
402 for(unsigned int i = 0; i < noRows; ++i)
403 corrArray->SetTuple1(i, (int)matchingMatrix[i][j]);
404 output_corrMatrix->AddColumn(corrArray);
405 }
406
407 // Barycenter node id
408 vtkNew<vtkIntArray> baryNodeId{};
409 baryNodeId->SetName("BaryNodeId");
410 baryNodeId->SetNumberOfTuples(noRows);
411 for(unsigned int i = 0; i < noRows; ++i)
412 baryNodeId->SetTuple1(i, i);
413 output_corrMatrix->AddColumn(baryNodeId);
414
415 // Barycenter node isLeaf
416 vtkNew<vtkIntArray> baryNodeIsLeaf{};
417 baryNodeIsLeaf->SetName("BaryNodeIsLeaf");
418 baryNodeIsLeaf->SetNumberOfTuples(noRows);
419 for(unsigned int i = 0; i < noRows; ++i)
420 baryNodeIsLeaf->SetTuple1(i, barycenter_.tree.isLeaf(i));
421 output_corrMatrix->AddColumn(baryNodeIsLeaf);
422
423 // Barycenter node persistence
424 vtkNew<vtkDoubleArray> baryNodePers{};
425 baryNodePers->SetName("BaryNodePers");
426 baryNodePers->SetNumberOfTuples(noRows);
427 for(unsigned int i = 0; i < noRows; ++i) {
428 auto nodePers = barycenter_.tree.template getNodePersistence<double>(i);
429 baryNodePers->SetTuple1(i, nodePers);
430 }
431 output_corrMatrix->AddColumn(baryNodePers);
432
433 // Trees persistence order
434 std::vector<std::vector<int>> treesOrder(intermediateDTrees.size());
435 for(unsigned int i = 0; i < intermediateDTrees.size(); ++i) {
436 treesOrder[i].resize(intermediateDTrees[i].tree.getNumberOfNodes());
437 std::vector<std::tuple<ttk::ftm::idNode, ttk::ftm::idNode, double>> pairs;
438 intermediateDTrees[i].tree.template getPersistencePairsFromTree<double>(
439 pairs, false);
440 for(unsigned int j = 0; j < pairs.size(); ++j) {
441 int const index = pairs.size() - 1 - j;
442 treesOrder[i][std::get<0>(pairs[j])] = index;
443 treesOrder[i][std::get<1>(pairs[j])] = index;
444 }
445 }
446
447 vtkNew<vtkDoubleArray> treesPersOrder{};
448 treesPersOrder->SetName("TreesPersOrder");
449 treesPersOrder->SetNumberOfTuples(noRows);
450 for(unsigned int i = 0; i < noRows; ++i) {
451 int minIndex = std::numeric_limits<int>::max();
452 for(unsigned int j = 0; j < intermediateDTrees.size(); ++j) {
453 if(int(matchingMatrix[i][j]) != -1)
454 minIndex = std::min(minIndex, treesOrder[j][matchingMatrix[i][j]]);
455 }
456 treesPersOrder->SetTuple1(i, minIndex);
457 }
458 output_corrMatrix->AddColumn(treesPersOrder);
459
460 return 1;
461}
#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 getMatchingMatrix(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)
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_
bool isLeaf(idNode nodeId)
Node * getNode(idNode nodeId)
Definition FTMTree_MT.h:393
SimplexId getOrigin() const
Definition FTMNode.h:64
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)
void loadBlocks(std::vector< vtkSmartPointer< vtkMultiBlockDataSet > > &inputTrees, vtkMultiBlockDataSet *blocks)
ftm::FTMTree_MT tree
Definition FTMTree_MT.h:903
vtkStandardNewMacro(ttkMergeTreePrincipalGeodesics)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)