100 vtkInformationVector **inputVector,
101 vtkInformationVector *outputVector) {
105 auto blockBary = vtkMultiBlockDataSet::GetData(inputVector[0], 0);
106 auto tableCoefficients = vtkTable::GetData(inputVector[1], 0);
107 auto tableVectors = vtkTable::GetData(inputVector[2], 0);
108 auto tableCorrelation = vtkTable::GetData(inputVector[3], 0);
109 auto blockInputTrees = vtkMultiBlockDataSet::GetData(inputVector[4], 0);
114 std::vector<vtkSmartPointer<vtkMultiBlockDataSet>> inputBary, inputTrees;
119 if((baryTreeNodes.size() != 0
120 and inputBary[0]->GetBlock(0) != baryTreeNodes[0])
122 and
int(
allTs_[0].size()) != tableCoefficients->GetNumberOfRows())
123 or tableCoefficientsMTime != tableCoefficients->GetMTime()
124 or tableVectorsMTime != tableVectors->GetMTime()
126 and tableCorrelationMTime != tableCorrelation->GetMTime())
128 and blockInputTreesMTime != blockInputTrees->GetMTime())) {
129 resetDataVisualization();
131 tableCoefficientsMTime = tableCoefficients->GetMTime();
132 tableVectorsMTime = tableVectors->GetMTime();
134 tableCorrelationMTime = tableCorrelation->GetMTime();
136 blockInputTreesMTime = blockInputTrees->GetMTime();
139 printMsg(
"Load parameters from field data.");
140 std::vector<std::string> paramNames;
142 for(
auto paramName : paramNames) {
143 auto array = tableCoefficients->GetFieldData()->GetArray(paramName.c_str());
145 double const value = array->GetTuple1(0);
148 printMsg(
" - " + paramName +
" was not found in the field data.");
153 printMsg(
"Computation with normalized Wasserstein.");
155 printMsg(
"Computation without normalized Wasserstein.");
160 auto tableVNoCols = tableVectors->GetNumberOfColumns() / inputBary.size();
161 unsigned int const numberOfGeodesics = tableVNoCols / 4;
162 auto numberOfInputs = tableCoefficients->GetNumberOfRows();
164 auto baryNoNodes = tableVectors->GetNumberOfRows();
165 auto baryNoNodes2 = baryNoNodes;
166 if(inputBary.size() > 1) {
167 for(
unsigned int i = 0; i < 2; ++i) {
168 auto &baryNoNodesT = (i == 0 ? baryNoNodes : baryNoNodes2);
170 std::isnan(tableVectors
172 numberOfGeodesics, 0, 0, 0, (i == 1))
174 ->GetVariantValue(baryNoNodesT - 1)
184 std::vector<std::string> nonFieldDataNames{
"TreeID"};
185 allTs_.resize(numberOfGeodesics, std::vector<double>(numberOfInputs, 0.0));
186 for(
unsigned int i = 0; i < numberOfGeodesics; ++i)
187 for(
unsigned int j = 0; j < numberOfInputs; ++j) {
188 std::string
const name
190 allTs_[i][j] = tableCoefficients->GetColumnByName(name.c_str())
193 nonFieldDataNames.push_back(name);
194 std::string
const normName
196 nonFieldDataNames.push_back(normName);
201 vtkNew<vtkFieldData> fd{};
202 for(
int i = 0; i < tableCoefficients->GetNumberOfColumns(); ++i) {
203 std::string
const name{tableCoefficients->GetColumnName(i)};
204 if(std::count(nonFieldDataNames.begin(), nonFieldDataNames.end(), name)
206 auto array = tableCoefficients->GetColumn(i);
207 array->SetName(name.c_str());
211 inputFieldData = vtkFieldData::New();
212 inputFieldData->ShallowCopy(fd);
217 pVS_.resize(numberOfGeodesics, std::vector<double *>(2));
219 if(inputBary.size() > 1) {
220 pTrees2Vs_.resize(numberOfGeodesics, std::vector<double *>(2));
223 for(
unsigned int h = 0; h < inputBary.size(); ++h) {
226 bool const secondInput = (h == 1);
227 for(
unsigned int i = 0; i < numberOfGeodesics; ++i) {
228 for(
unsigned int k = 0; k < 2; ++k) {
230 numberOfGeodesics, i, 0, k, secondInput);
232 numberOfGeodesics, i, 1, k, secondInput);
233 pVS[i][k] = ttkUtils::GetPointer<double>(vtkDataArray::SafeDownCast(
234 tableVectors->GetColumnByName(name1.c_str())));
235 pV2s[i][k] = ttkUtils::GetPointer<double>(vtkDataArray::SafeDownCast(
236 tableVectors->GetColumnByName(name2.c_str())));
246 if(tableCorrelation) {
250 auto tableCorrNoRows = tableCorrelation->GetNumberOfRows();
251 auto baryNodeIdArray = tableCorrelation->GetColumnByName(
"BaryNodeId");
253 for(
unsigned int j = 0; j < numberOfGeodesics; ++j) {
254 std::string
const name
256 std::string
const name2
259 = ttkUtils::GetPointer<double>(vtkDataArray::SafeDownCast(
260 tableCorrelation->GetColumnByName(name.c_str())));
262 = ttkUtils::GetPointer<double>(vtkDataArray::SafeDownCast(
263 tableCorrelation->GetColumnByName(name2.c_str())));
269 for(
unsigned int i = 0; i < numberOfInputs; ++i) {
271 auto array = tableCorrelation->GetColumnByName(name.c_str());
274 for(
unsigned int j = 0; j < tableCorrNoRows; ++j) {
275 auto baryNodeId = baryNodeIdArray->GetVariantValue(j).ToInt();
277 baryNodeId, array->GetVariantValue(j).ToDouble(), 0.0);
289 return run<float>(outputVector, inputBary, inputTrees);
305 vtkInformationVector *
ttkNotUsed(outputVector),
313 const int numTrees = inputTrees.size();
315 setDataVisualization(numTrees);
317 std::vector<ttk::ftm::MergeTree<dataType>> baryDTree, inputDTrees;
319 std::vector<bool> useSadMaxPairsVec{
false,
true};
321 useSadMaxPairsVec.erase(useSadMaxPairsVec.begin());
322 ttk::ftm::constructTrees<dataType>(inputBary, baryDTree, baryTreeNodes,
323 baryTreeArcs, baryTreeSegmentation,
327 or (ReconstructInputTrees
329 bool const useSadMaxPairs
331 bool const isInputPD = ttk::ftm::constructTrees<dataType>(
332 inputTrees, inputDTrees, inputTreesNodes, inputTreesArcs,
333 inputTreesSegmentation, useSadMaxPairs);
341 std::string
const preFix{(processFirstInput ?
"" :
"Second Input ")};
342 auto &baryToUse = (processFirstInput ? baryDTree[0] : baryDTree[1]);
347 printMsg(
"Compute Geodesics Distance...");
348 computeGeodesicsDistance<dataType>(baryDTree);
352 if(OutputInputTrees) {
355 processInputTrees<dataType>(inputDTrees);
359 if(ReconstructInputTrees) {
361 printMsg(
"Reconstruct " + preFix +
"Input Trees...");
362 std::vector<ttk::ftm::MergeTree<dataType>> reconstructedTreesT;
363 reconstruction<dataType>(baryToUse, inputDTrees, reconstructedTreesT,
364 reconstructionErrors, recInputMatchings,
365 recBaryMatchings, !processFirstInput);
366 ttk::ftm::mergeTreesTemplateToDouble<dataType>(
367 reconstructedTreesT, reconstructedTrees);
369 reconstructedTrees.clear();
372 if(ConstructGeodesicsTrees) {
374 printMsg(
"Construct Geodesics Trees...");
375 std::vector<std::vector<ttk::ftm::MergeTree<dataType>>> geodesicsTreesT;
376 constructGeodesicsTrees<dataType>(
377 baryToUse, geodesicsTreesT, !processFirstInput);
378 ttk::ftm::mergeTreesTemplateToDouble<dataType>(
379 geodesicsTreesT, geodesicsTrees);
381 geodesicsTrees.clear();
384 if(ConstructEllipses) {
386 printMsg(
"Construct Ellipses Trees...");
387 std::vector<ttk::ftm::MergeTree<dataType>> geodesicsEllipsesT;
388 constructGeodesicsEllipses<dataType>(
389 baryToUse, geodesicsEllipsesT, !processFirstInput);
390 ttk::ftm::mergeTreesTemplateToDouble<dataType>(
391 geodesicsEllipsesT, geodesicsEllipses);
393 geodesicsEllipses.clear();
396 if(ConstructRectangle) {
398 printMsg(
"Construct Rectangle Trees...");
399 std::vector<ttk::ftm::MergeTree<dataType>> geodesicsRectangleT;
400 constructGeodesicsRectangle<dataType>(
401 baryToUse, geodesicsRectangleT, RectangleMultiplier, !processFirstInput);
402 ttk::ftm::mergeTreesTemplateToDouble<dataType>(
403 geodesicsRectangleT, geodesicsRectangle);
405 geodesicsRectangle.clear();
408 if(ConstructSurface) {
410 printMsg(
"Construct " + preFix +
"Surface Trees...");
411 std::vector<ttk::ftm::MergeTree<dataType>> geodesicsSurfaceT;
412 constructGeodesicsSurface<dataType>(
413 baryToUse, geodesicsSurfaceT, !processFirstInput);
414 ttk::ftm::mergeTreesTemplateToDouble<dataType>(
415 geodesicsSurfaceT, geodesicsSurface);
417 geodesicsSurface.clear();
419 ttk::ftm::mergeTreesTemplateToDouble<dataType>(baryDTree, baryMTree);
420 ttk::ftm::mergeTreesTemplateToDouble<dataType>(inputDTrees, inputMTrees);
427 vtkInformationVector *outputVector,
435 auto output = vtkMultiBlockDataSet::GetData(outputVector, 0);
437 unsigned int const noInput = (OutputInputTrees ? inputTrees.size() : 0);
438 unsigned int const noReconst = reconstructedTrees.size();
439 unsigned int const noBary = (OutputBarycenter ? 1 : 0);
440 unsigned int const noGeod
441 = geodesicsTrees.size()
442 * (geodesicsTrees.size() == 0 ? 0 : geodesicsTrees[0].size());
443 unsigned int const noEllipses = geodesicsEllipses.size();
444 unsigned int const noRectangle = geodesicsRectangle.size();
445 unsigned int const noSurface = geodesicsSurface.size();
447 printMsg(
"noInput = " + std::to_string(noInput));
448 printMsg(
"noReconst = " + std::to_string(noReconst));
449 printMsg(
"noBary = " + std::to_string(noBary));
450 printMsg(
"noGeod = " + std::to_string(noGeod));
451 printMsg(
"noEllipses = " + std::to_string(noEllipses));
452 printMsg(
"noRectangle = " + std::to_string(noRectangle));
453 printMsg(
"noSurface = " + std::to_string(noSurface));
455 std::vector<unsigned int> allNo{
456 noInput, noReconst, noBary, noGeod, noEllipses, noRectangle, noSurface};
457 std::vector<unsigned int> steps(allNo.size());
458 for(
unsigned int i = 0; i < allNo.size(); ++i)
459 steps[i] = (i == 0 ? 0 : steps[i - 1]) + allNo[i];
461 unsigned int const noTreesTotal = steps[steps.size() - 1];
463 unsigned int const noBlocks
465 output->SetNumberOfBlocks(noBlocks);
468 vtkBlockNodes->SetNumberOfBlocks(noTreesTotal);
469 output->SetBlock(0, vtkBlockNodes);
473 vtkBlockArcs->SetNumberOfBlocks(noTreesTotal);
474 output->SetBlock(1, vtkBlockArcs);
476 if(OutputInputTreesSegmentation) {
479 vtkBlockSegs->SetNumberOfBlocks(noTreesTotal);
483 int const geodesicsTreesOffset = std::max((
int)geodesicsTrees.size() - 1, 0);
488 std::vector<std::vector<ttk::ftm::idNode>> matchingMatrix;
490 getMatchingMatrix<double>(
495 printWrn(
"Please provide input trees and correlation matrix to transfer "
496 "input trees information.");
498#ifdef TTK_ENABLE_OPENMP
499#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
501 for(
unsigned int i = 0; i < noTreesTotal; ++i) {
505 std::vector<double> ts;
509 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(inputMTrees[index], mt);
512 }
else if(i < steps[1]) {
514 index = i - steps[0];
515 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
516 reconstructedTrees[index], mt);
519 }
else if(i < steps[2]) {
521 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(baryMTree[0], mt);
523 std::array<double, 2> middle;
528 }
else if(i < steps[3]) {
530 index = i - steps[2];
531 int const i0 = index / geodesicsTrees[0].size();
532 int const i1 = index % geodesicsTrees[0].size();
533 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(geodesicsTrees[i0][i1], mt);
536 }
else if(i < steps[4]) {
538 index = i - steps[3];
539 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
540 geodesicsEllipses[index], mt);
541 treeType = 3 + geodesicsTreesOffset;
543 }
else if(i < steps[5]) {
545 index = i - steps[4];
546 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
547 geodesicsRectangle[index], mt);
548 treeType = 4 + geodesicsTreesOffset;
550 }
else if(i < steps[6]) {
552 index = i - steps[5];
553 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
554 geodesicsSurface[index], mt);
555 treeType = 5 + geodesicsTreesOffset;
559 bool const isInputTree = (i < steps[0]);
560 bool const isInputTreeAndGotMesh
561 = (isInputTree and inputTrees[i]->GetNumberOfBlocks() >= 3);
562 bool const isReconstructedTree = (i >= steps[0] and i < steps[1]);
563 bool const isInputOrReconstructedTree
564 = (isInputTree or isReconstructedTree);
579 for(
unsigned int n = 0; n <
vSize_; ++n) {
580 if((
int)matchingMatrix[n][i] != -1) {
595 for(
unsigned int n = 0; n <
vSize_; ++n) {
596 if((
int)matchingMatrix[n][i] != -1) {
597 baryNodeID[matchingMatrix[n][i]] = n;
598 baryNodePers[matchingMatrix[n][i]]
599 = baryMTree[0].tree.template getNodePersistence<double>(n);
602 std::string nameBaryNodePers{
"BaryNodePers"};
604 std::string nameBaryNodeId{
"BaryNodeId"};
615 if(isInputTreeAndGotMesh and OutputInputTreesSegmentation) {
626 if(isReconstructedTree) {
629 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(baryMTree[0], baryMT);
630 std::vector<ttk::ftm::idNode> matchingVector;
632 mt, baryMT, recBaryMatchings[index], matchingVector);
634 for(
unsigned int n = 0; n <
vSize_; ++n) {
635 auto match = matchingVector[n];
637 baryNodeID[match] = n;
639 std::string nameBaryNodeId{
"BaryNodeId"};
645 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
646 inputMTrees[index], inputMT);
647 std::vector<ttk::ftm::idNode> matchingVector;
649 mt, inputMT, recInputMatchings[index], matchingVector);
651 for(
unsigned int n = 0; n <
vSize_; ++n) {
652 auto match = matchingMatrix[n][index];
653 if((
int)match != -1) {
654 match = matchingVector[match];
656 baryNodeID[match] = n;
659 std::string nameBaryNodeId{
"BaryNodeId"};
679 if(noReconst != 0 or noInput != 0) {
680 vtkNew<vtkFieldData> fd{};
681 if(isInputOrReconstructedTree)
682 fd->DeepCopy(inputFieldData);
684 fd->CopyStructure(inputFieldData);
685 for(
int a = 0; a < inputFieldData->GetNumberOfArrays(); ++a) {
686 auto array = fd->GetAbstractArray(a);
687 array->SetNumberOfTuples(1);
688 if(isInputOrReconstructedTree) {
689 vtkNew<vtkIdList> id;
690 id->InsertNextId(i % (noInput == 0 ? noReconst : noInput));
691 inputFieldData->GetAbstractArray(a)->GetTuples(
id, array);
693 auto downArray = vtkDataArray::SafeDownCast(array);
695 downArray->SetTuple1(0, std::nan(
""));
698 vtkOutputNode->GetFieldData()->ShallowCopy(fd);
702 vtkNew<vtkIntArray> treeTypeArray{};
703 treeTypeArray->SetName(
"TreeType");
704 treeTypeArray->InsertNextTuple1(treeType);
705 vtkOutputNode->GetFieldData()->AddArray(treeTypeArray);
707 vtkNew<vtkIntArray> treeIDArray{};
708 treeIDArray->SetName(
"TreeID");
709 treeIDArray->InsertNextTuple1(i);
710 vtkOutputNode->GetFieldData()->AddArray(treeIDArray);
712 for(
unsigned int j = 0; j < ts.size(); ++j) {
713 vtkNew<vtkDoubleArray> tArray{};
715 tArray->SetName(name.c_str());
716 tArray->InsertNextTuple1(ts[j]);
717 vtkOutputNode->GetFieldData()->AddArray(tArray);
719 vtkNew<vtkDoubleArray> scaledTArray{};
720 std::string
const name2
722 scaledTArray->SetName(name2.c_str());
724 vtkOutputNode->GetFieldData()->AddArray(scaledTArray);
727 bool const isSurfaceTree = (treeType == 5 + geodesicsTreesOffset);
728 vtkNew<vtkIntArray> isSurfaceArray{};
729 isSurfaceArray->SetName(
"isSurface");
730 isSurfaceArray->InsertNextTuple1(isSurfaceTree);
731 vtkOutputNode->GetFieldData()->AddArray(isSurfaceArray);
733 vtkNew<vtkIntArray> isBoundaryArray{};
734 isBoundaryArray->SetName(
"isBoundary");
735 isBoundaryArray->InsertNextTuple1(isBoundary);
736 vtkOutputNode->GetFieldData()->AddArray(isBoundaryArray);
738 vtkNew<vtkIntArray> BoundaryIDArray{};
739 BoundaryIDArray->SetName(
"BoundaryID");
740 BoundaryIDArray->InsertNextTuple1(boundaryID);
741 vtkOutputNode->GetFieldData()->AddArray(BoundaryIDArray);
743 vtkNew<vtkDoubleArray> reconstructionErrorArray{};
744 reconstructionErrorArray->SetName(
"ReconstructionError");
745 auto err = (isReconstructedTree and reconstructionErrors.size() != 0
746 ? reconstructionErrors[index]
748 reconstructionErrorArray->InsertNextTuple1(err);
749 vtkOutputNode->GetFieldData()->AddArray(reconstructionErrorArray);
752 vtkMultiBlockDataSet::SafeDownCast(output->GetBlock(0))
753 ->SetBlock(i, vtkOutputNode);
755 vtkMultiBlockDataSet::SafeDownCast(output->GetBlock(1))
756 ->SetBlock(i, vtkOutputArc);
757 if(OutputInputTreesSegmentation)
758 vtkMultiBlockDataSet::SafeDownCast(
760 ->SetBlock(i, vtkOutputSegmentation);
764 std::vector<std::string> paramNames;
766 for(
auto paramName : paramNames) {
767 vtkNew<vtkDoubleArray> array{};
768 array->SetName(paramName.c_str());
770 output->GetFieldData()->AddArray(array);