Skip to content

Commit 211c852

Browse files
committed
Using GetBranchByVolume Filter
Handling multiple domains
1 parent e504a28 commit 211c852

File tree

3 files changed

+243
-49
lines changed

3 files changed

+243
-49
lines changed

src/libs/vtkh/filters/ContourTree.cpp

Lines changed: 228 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,85 @@
33
#include <vtkh/filters/Recenter.hpp>
44

55
// vtkm includes
6-
#include <vtkm/cont/DeviceAdapter.h>
7-
#include <vtkm/cont/Storage.h>
8-
#include <vtkm/internal/Configure.h>
6+
#include <vtkm/filter/scalar_topology/ContourTreeUniformDistributed.h>
7+
#include <vtkm/filter/scalar_topology/DistributedBranchDecompositionFilter.h>
8+
#include <vtkm/filter/scalar_topology/SelectTopVolumeContoursFilter.h>
9+
#include <vtkm/filter/scalar_topology/worklet/branch_decomposition/HierarchicalVolumetricBranchDecomposer.h>
910
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/PrintVectors.h>
1011
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ProcessContourTree.h>
11-
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/processcontourtree/Branch.h>
12-
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/processcontourtree/PiecewiseLinearFunction.h>
12+
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
13+
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/HierarchicalContourTree.h>
14+
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/TreeCompiler.h>
1315

1416
#include <vtkh/filters/GhostStripper.hpp>
1517

1618
#include <fstream>
1719

1820
namespace caugmented_ns = vtkm::worklet::contourtree_augmented;
1921

22+
#ifdef DEBUG
23+
void SaveToBDEM(const vtkm::cont::DataSet& ds,
24+
const std::string& fieldname,
25+
const std::string& filename)
26+
{
27+
std::cout << "Saving block to " << filename << std::endl;
28+
vtkm::Id3 blockSize;
29+
vtkm::Id3 globalSize;
30+
vtkm::Id3 pointIndexStart;
31+
vtkm::cont::CastAndCall(ds.GetCellSet(),
32+
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
33+
blockSize,
34+
globalSize,
35+
pointIndexStart);
36+
std::ofstream os(filename, std::ios::binary);
37+
os << "#GLOBAL_EXTENTS " << globalSize[1] << " " << globalSize[0];
38+
if (globalSize[2] > 1)
39+
{
40+
os << " " << globalSize[2];
41+
}
42+
os << std::endl;
43+
os << "#OFFSET " << pointIndexStart[1] << " " << pointIndexStart[0];
44+
if (globalSize[2] > 1)
45+
{
46+
os << " " << pointIndexStart[2];
47+
}
48+
os << std::endl;
49+
os << blockSize[1] << " " << blockSize[0];
50+
if (globalSize[2] > 1)
51+
{
52+
os << " " << blockSize[2];
53+
}
54+
os << std::endl;
55+
try
56+
{
57+
auto dataArray =
58+
ds.GetField(fieldname).GetData().AsArrayHandle<vtkm::cont::ArrayHandleBasic<vtkm::Float32>>();
59+
os.write(reinterpret_cast<const char*>(dataArray.GetReadPointer()),
60+
dataArray.GetNumberOfValues() * sizeof(vtkm::Float32));
61+
}
62+
catch (vtkm::cont::ErrorBadType& e)
63+
{
64+
std::cerr << "Error: Cannot get as ArrayHandleBasic<vtkm::Float32>: " << e.GetMessage()
65+
<< std::endl;
66+
}
67+
}
68+
69+
void SaveToBDEM(const vtkm::cont::PartitionedDataSet& pds,
70+
const std::string& fieldname,
71+
const std::string& basefilename,
72+
int rank,
73+
int blocksPerRank)
74+
{
75+
for (vtkm::Id i = 0; i < pds.GetNumberOfPartitions(); ++i)
76+
{
77+
std::string filename = basefilename + '_' + std::to_string(rank*blocksPerRank+i) + ".bdem";
78+
std::cout << "Saving partition " << i << " to " << filename << std::endl;
79+
SaveToBDEM(pds.GetPartition(i), fieldname, filename);
80+
}
81+
}
82+
#endif
83+
84+
#ifdef VTKH_PARALLEL
2085
static void ShiftLogicalOriginToZero(vtkm::cont::PartitionedDataSet& pds)
2186
{
2287
// Shift the logical origin (minimum of LocalPointIndexStart) to zero
@@ -118,7 +183,6 @@ static void ComputeGlobalPointSize(vtkm::cont::PartitionedDataSet& pds)
118183
}
119184
}
120185

121-
#ifdef VTKH_PARALLEL
122186
#include <mpi.h>
123187

124188
// This is from VTK-m diy mpi_cast.hpp. Need the make_DIY_MPI_Comm
@@ -198,14 +262,52 @@ void ContourTree::PostExecute()
198262
Filter::PostExecute();
199263
}
200264

265+
struct TopVolumeBranchSaddleIsoValueFunctor
266+
{
267+
vtkm::Id nSelectedBranches;
268+
std::vector<vtkm::Float64> dbranches;
269+
270+
public:
271+
272+
TopVolumeBranchSaddleIsoValueFunctor(vtkm::Id nSelectedBranches) : nSelectedBranches(nSelectedBranches) {
273+
}
274+
void operator()(const vtkm::cont::ArrayHandle<vtkm::Float32> &arr)
275+
{
276+
auto topVolBranchSaddleIsoValue = arr.ReadPortal();
277+
278+
for (vtkm::Id branch = 0; branch < nSelectedBranches; ++branch) {
279+
dbranches.push_back(topVolBranchSaddleIsoValue.Get(branch));
280+
}
281+
}
282+
283+
void operator()(const vtkm::cont::ArrayHandle<vtkm::Float64> &arr)
284+
{
285+
auto topVolBranchSaddleIsoValue = arr.ReadPortal();
286+
287+
for (vtkm::Id branch = 0; branch < nSelectedBranches; ++branch) {
288+
dbranches.push_back(topVolBranchSaddleIsoValue.Get(branch));
289+
}
290+
}
291+
template <typename T>
292+
void operator()(const T&)
293+
{
294+
throw vtkm::cont::ErrorBadValue("TopVolumeBranchSaddleIsoValueFunctor Expected Float32 or Float64!");
295+
}
296+
297+
vtkm::Float64 Get(vtkm::Id branch)
298+
{
299+
return dbranches[branch];
300+
}
301+
};
302+
201303
struct AnalyzerFunctor
202304
{
203-
vtkm::filter::scalar_topology::ContourTreeAugmented& filter;
305+
vtkm::filter::scalar_topology::ContourTreeAugmented* filter;
204306
vtkh::ContourTree& contourTree;
205307
bool dataFieldIsSorted;
206308

207309
public:
208-
AnalyzerFunctor(vtkh::ContourTree& contourTree, vtkm::filter::scalar_topology::ContourTreeAugmented& filter): contourTree(contourTree), filter(filter) {
310+
AnalyzerFunctor(vtkh::ContourTree& contourTree, vtkm::filter::scalar_topology::ContourTreeAugmented* filter): contourTree(contourTree), filter(filter) {
209311
}
210312

211313
void SetDataFieldIsSorted(bool dataFieldIsSorted) {
@@ -214,12 +316,12 @@ struct AnalyzerFunctor
214316

215317
void operator()(const vtkm::cont::ArrayHandle<vtkm::Float32> &arr) const
216318
{
217-
contourTree.analysis<vtkm::Float32>(filter, dataFieldIsSorted, arr);
319+
contourTree.analysis<vtkm::Float32>(*filter, dataFieldIsSorted, arr);
218320
}
219321

220322
void operator()(const vtkm::cont::ArrayHandle<vtkm::Float64> &arr) const
221323
{
222-
contourTree.analysis<vtkm::Float64>(filter, dataFieldIsSorted, arr);
324+
contourTree.analysis<vtkm::Float64>(*filter, dataFieldIsSorted, arr);
223325
}
224326

225327
template <typename T>
@@ -343,10 +445,77 @@ template<typename DataValueType> void ContourTree::analysis(vtkm::filter::scalar
343445
}
344446
}
345447

448+
void ContourTree::distributed_analysis(const vtkm::cont::PartitionedDataSet& result, int mpi_rank) {
449+
vtkm::filter::scalar_topology::DistributedBranchDecompositionFilter bd_filter;
450+
auto bd_result = bd_filter.Execute(result);
451+
452+
#if 0
453+
for (vtkm::Id ds_no = 0; ds_no < result.GetNumberOfPartitions(); ++ds_no)
454+
{
455+
auto ds = bd_result.GetPartition(ds_no);
456+
std::string branchDecompositionFileName = std::string("BranchDecomposition_Rank_") +
457+
std::to_string(static_cast<int>(mpi_rank)) + std::string("_Block_") +
458+
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
459+
460+
std::ofstream treeStream(branchDecompositionFileName.c_str());
461+
treeStream
462+
<< vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::PrintBranches(ds);
463+
}
464+
#endif
465+
466+
vtkm::filter::scalar_topology::SelectTopVolumeContoursFilter tp_filter;
467+
vtkm::Id numBranches = m_levels;
468+
469+
tp_filter.SetSavedBranches(numBranches);
470+
bd_result = tp_filter.Execute(bd_result);
471+
472+
for (vtkm::Id ds_no = 0; ds_no < result.GetNumberOfPartitions(); ++ds_no)
473+
{
474+
auto ds = bd_result.GetPartition(ds_no);
475+
auto topVolBranchGRId = ds.GetField("TopVolumeBranchGlobalRegularIds")
476+
.GetData()
477+
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
478+
.ReadPortal();
479+
480+
auto topVolBranchSaddleEpsilon = ds.GetField("TopVolumeBranchSaddleEpsilon")
481+
.GetData()
482+
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
483+
.ReadPortal();
484+
485+
vtkm::Id nSelectedBranches = topVolBranchGRId.GetNumberOfValues();
486+
487+
TopVolumeBranchSaddleIsoValueFunctor iso_functor(nSelectedBranches);
488+
489+
vtkm::cont::CastAndCall(ds.GetField("TopVolumeBranchSaddleIsoValue").GetData(), iso_functor);
490+
491+
492+
vtkm::Float32 eps = 0.00001;
493+
494+
for (vtkm::Id branch = 0; branch < nSelectedBranches; ++branch)
495+
{
496+
m_iso_values[branch] = iso_functor.Get(branch) + (eps * topVolBranchSaddleEpsilon.Get(branch));
497+
}
498+
499+
break;
500+
}
501+
502+
std::sort(m_iso_values.begin(), m_iso_values.end());
503+
}
504+
346505
void ContourTree::DoExecute()
506+
{
347507
{
508+
#ifdef VTKH_PARALLEL
509+
int mpi_rank = 0;
510+
511+
MPI_Comm mpi_comm = MPI_Comm_f2c(vtkh::GetMPICommHandle());
512+
vtkm::cont::EnvironmentTracker::SetCommunicator(vtkmdiy::mpi::communicator(vtkmdiy::mpi::make_DIY_MPI_Comm(mpi_comm)));
513+
514+
MPI_Comm_rank(mpi_comm, &mpi_rank);
515+
#endif
516+
}
517+
348518
vtkh::DataSet *old_input = this->m_input;
349-
const int before_num_domains = this->m_input->GetNumberOfDomains();
350519

351520
// make sure we have a node-centered field
352521
bool valid_field = false;
@@ -388,7 +557,6 @@ void ContourTree::DoExecute()
388557
this->m_output = new DataSet();
389558

390559
const int num_domains = this->m_input->GetNumberOfDomains();
391-
assert(num_domains == 1);
392560

393561
#ifndef VTKH_PARALLEL
394562
vtkm::cont::DataSet inDataSet;
@@ -409,68 +577,85 @@ void ContourTree::DoExecute()
409577

410578
vtkm::cont::PartitionedDataSet inDataSet;
411579

412-
vtkm::Id domain_id;
413-
vtkm::cont::DataSet dom;
580+
for (int i = 0; i < num_domains; ++i)
581+
{
582+
vtkm::Id domain_id;
583+
vtkm::cont::DataSet dom;
414584

415-
this->m_input->GetDomain(0, dom, domain_id);
416-
inDataSet.AppendPartition(dom);
585+
this->m_input->GetDomain(i, dom, domain_id);
586+
inDataSet.AppendPartition(dom);
587+
this->m_output->AddDomain(dom, domain_id);
588+
}
417589

590+
#ifdef DEBUG
418591
if( mpi_size != 1 )
419592
{
420593
std::ostringstream ostr;
421594
ostr << "rank: " << mpi_rank
422595
<< " coord system range: " << dom.GetCoordinateSystem(0).GetRange() << std::endl;
423596
std::cout << ostr.str();
424597
}
425-
#ifdef DEBUG
426598
#endif
427599
#endif // VTKH_PARALLEL
428600

601+
vtkm::filter::Filter *filterField;
602+
603+
#ifndef VTKH_PARALLEL
429604
bool useMarchingCubes = false;
430605
// Compute the fully augmented contour tree.
431606
// This should always be true for now in order for the isovalue selection to work.
432607
bool computeRegularStructure = true;
433608

434609
//Convert the mesh of values into contour tree, pairs of vertex ids
435610
vtkm::filter::scalar_topology::ContourTreeAugmented filter(useMarchingCubes, computeRegularStructure);
436-
437-
filter.SetActiveField(m_field_name);
438-
439-
#ifdef VTKH_PARALLEL
611+
#else // VTKH_PARALLEL
612+
// TODO SET VTKM to do vtkm::cont::LogLovel::Info
613+
// vtkm::filter::scalar_topology::ContourTreeUniformDistributed filter(vtkm::cont::LogLevel::Info, vtkm::cont::LogLevel::Info);
614+
vtkm::filter::scalar_topology::ContourTreeUniformDistributed filter;
615+
vtkm::filter::scalar_topology::ContourTreeAugmented aug_filter(false, true);
616+
617+
if (mpi_size == 1) {
618+
filterField = &aug_filter;
619+
} else {
620+
filter.SetUseBoundaryExtremaOnly(true);
621+
filter.SetUseMarchingCubes(false);
622+
filter.SetAugmentHierarchicalTree(true);
440623
ShiftLogicalOriginToZero(inDataSet);
441624
ComputeGlobalPointSize(inDataSet);
625+
filterField = &filter;
626+
}
627+
442628
#endif // VTKH_PARALLEL
443629

444-
auto result = filter.Execute(inDataSet);
630+
filterField->SetActiveField(m_field_name);
445631

446-
m_iso_values.resize(m_levels);
632+
#ifdef DEBUG
633+
SaveToBDEM(inDataSet, m_field_name, "debug-ascent", mpi_rank, num_domains);
634+
#endif
447635

448-
if (mpi_rank == 0) {
449-
AnalyzerFunctor analyzerFunctor(*this, filter);
636+
auto result = filterField->Execute(inDataSet);
637+
638+
m_iso_values.resize(m_levels);
450639

451640
#ifndef VTKH_PARALLEL
641+
if (mpi_rank == 0) {
642+
AnalyzerFunctor analyzerFunctor(*this, &filter);
452643
analyzerFunctor.SetDataFieldIsSorted(false);
453644
vtkm::cont::CastAndCall(inDataSet.GetField(m_field_name).GetData(), analyzerFunctor);
645+
} // mpi_rank == 0
454646
#else
455-
if(mpi_size == 1)
456-
{
457-
analyzerFunctor.SetDataFieldIsSorted(false);
458-
vtkm::cont::CastAndCall(inDataSet.GetPartitions()[0].GetField(m_field_name).GetData(), analyzerFunctor);
459-
} else {
460-
analyzerFunctor.SetDataFieldIsSorted(true);
461-
462-
/*
463-
if( result.GetPartitions()[0].GetNumberOfFields() > 1 ) {
464-
vtkm::cont::CastAndCall(result.GetPartitions()[0].GetField("values").GetData(), analyzerFunctor);
465-
} else {
466-
vtkm::cont::CastAndCall(result.GetPartitions()[0].GetField(0).GetData(), analyzerFunctor);
467-
}*/
468-
469-
// TODO TO BE REVISITED. Tested with: srun -n 8 ./t_vtk-h_contour_tree_par
470-
vtkm::cont::CastAndCall(result.GetPartitions()[0].GetField("resultData").GetData(), analyzerFunctor);
471-
}
647+
if (mpi_size > 1)
648+
{ // BranchDecomposition
649+
distributed_analysis(result, mpi_rank);
650+
}
651+
else
652+
{
653+
AnalyzerFunctor analyzerFunctor(*this, (vtkm::filter::scalar_topology::ContourTreeAugmented *) filterField);
654+
655+
analyzerFunctor.SetDataFieldIsSorted(false);
656+
vtkm::cont::CastAndCall(inDataSet.GetPartitions()[0].GetField(m_field_name).GetData(), analyzerFunctor);
657+
}
472658
#endif // VTKH_PARALLEL
473-
} // mpi_rank == 0
474659

475660
#ifdef VTKH_PARALLEL
476661
MPI_Bcast(&m_iso_values[0], m_levels, MPI_DOUBLE, 0, mpi_comm);

src/libs/vtkh/filters/ContourTree.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ContourTree : public Filter
2727
private:
2828
friend class AnalyzerFunctor;
2929
template<typename DataValueType> void analysis(vtkm::filter::scalar_topology::ContourTreeAugmented& filter, bool dataFieldIsSorted, const vtkm::cont::UnknownArrayHandle& arr);
30+
void distributed_analysis(const vtkm::cont::PartitionedDataSet& result, int rank);
3031

3132
std::string m_field_name;
3233
int m_levels;

0 commit comments

Comments
 (0)