2020-06-12 17:50:01 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
|
|
|
//
|
|
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) 2018, The Regents of the University of California, through
|
|
|
|
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
|
|
|
|
// from the U.S. Dept. of Energy). All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
// are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// (1) Redistributions of source code must retain the above copyright notice, this
|
|
|
|
// list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// (2) Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// (3) Neither the name of the University of California, Lawrence Berkeley National
|
|
|
|
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
|
|
|
|
// used to endorse or promote products derived from this software without
|
|
|
|
// specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
|
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
|
|
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
|
|
//=============================================================================
|
|
|
|
//
|
|
|
|
// This code is an extension of the algorithm presented in the paper:
|
|
|
|
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
|
|
|
|
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
|
|
|
|
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
|
|
|
|
// (LDAV), October 2016, Baltimore, Maryland.
|
|
|
|
//
|
|
|
|
// The PPP2 algorithm and software were jointly developed by
|
|
|
|
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
|
|
|
|
// Oliver Ruebel (LBNL)
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
#ifndef vtk_m_filter_ContourTreeUniformDistributed_hxx
|
|
|
|
#define vtk_m_filter_ContourTreeUniformDistributed_hxx
|
|
|
|
|
|
|
|
// vtkm includes
|
|
|
|
#include <vtkm/cont/Timer.h>
|
|
|
|
|
|
|
|
// single-node augmented contour tree includes
|
|
|
|
#include <vtkm/filter/ContourTreeUniformDistributed.h>
|
|
|
|
#include <vtkm/worklet/ContourTreeUniformAugmented.h>
|
2020-09-15 17:57:20 +00:00
|
|
|
#include <vtkm/worklet/contourtree_augmented/DataSetMesh.h>
|
2020-09-17 12:42:41 +00:00
|
|
|
#include <vtkm/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
|
2020-09-15 17:57:20 +00:00
|
|
|
#include <vtkm/worklet/contourtree_augmented/meshtypes/mesh_boundary/MeshBoundaryContourTreeMesh.h>
|
2020-06-12 17:50:01 +00:00
|
|
|
|
|
|
|
// distributed contour tree includes
|
2020-09-15 17:57:20 +00:00
|
|
|
#include <vtkm/worklet/contourtree_distributed/BoundaryTree.h>
|
|
|
|
#include <vtkm/worklet/contourtree_distributed/BoundaryTreeMaker.h>
|
|
|
|
#include <vtkm/worklet/contourtree_distributed/ComputeDistributedContourTreeFunctor.h>
|
|
|
|
#include <vtkm/worklet/contourtree_distributed/DistributedContourTreeBlockData.h>
|
|
|
|
#include <vtkm/worklet/contourtree_distributed/HierarchicalContourTree.h>
|
|
|
|
#include <vtkm/worklet/contourtree_distributed/InteriorForest.h>
|
|
|
|
#include <vtkm/worklet/contourtree_distributed/PrintGraph.h>
|
2020-06-12 17:50:01 +00:00
|
|
|
#include <vtkm/worklet/contourtree_distributed/SpatialDecomposition.h>
|
2020-09-15 17:57:20 +00:00
|
|
|
#include <vtkm/worklet/contourtree_distributed/TreeGrafter.h>
|
2020-06-12 17:50:01 +00:00
|
|
|
|
|
|
|
// DIY includes
|
|
|
|
// clang-format off
|
|
|
|
VTKM_THIRDPARTY_PRE_INCLUDE
|
|
|
|
#include <vtkm/thirdparty/diy/Configure.h>
|
|
|
|
#include <vtkm/thirdparty/diy/diy.h>
|
|
|
|
VTKM_THIRDPARTY_POST_INCLUDE
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace filter
|
|
|
|
{
|
2020-10-28 00:40:41 +00:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Helper structs needed to support approbriate type discovery as part
|
|
|
|
// of pre- and post-execute
|
|
|
|
//-----------------------------------------------------------------------------
|
2020-06-12 17:50:01 +00:00
|
|
|
namespace contourtree_distributed_detail
|
|
|
|
{
|
2020-09-15 17:57:20 +00:00
|
|
|
struct ComputeLocalTree
|
|
|
|
{
|
|
|
|
template <typename T, typename Storage, typename DerivedPolicy>
|
|
|
|
void operator()(const vtkm::cont::ArrayHandle<T, Storage>& field,
|
|
|
|
ContourTreeUniformDistributed* self,
|
|
|
|
const vtkm::Id blockIndex,
|
|
|
|
const vtkm::cont::DataSet& inputData,
|
|
|
|
const vtkm::filter::FieldMetadata& fieldMeta,
|
|
|
|
vtkm::filter::PolicyBase<DerivedPolicy> policy)
|
|
|
|
{
|
|
|
|
self->ComputeLocalTree(blockIndex, inputData, field, fieldMeta, policy);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
//----Helper struct to call DoPostExecute. This is used to be able to
|
|
|
|
// wrap the PostExecute work in a functor so that we can use VTK-M's
|
|
|
|
// vtkm::cont::CastAndCall to infer the FieldType template parameters
|
|
|
|
struct PostExecuteCaller
|
|
|
|
{
|
|
|
|
template <typename T, typename S, typename DerivedPolicy>
|
|
|
|
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, S>&,
|
|
|
|
ContourTreeUniformDistributed* self,
|
|
|
|
const vtkm::cont::PartitionedDataSet& input,
|
|
|
|
vtkm::cont::PartitionedDataSet& output,
|
|
|
|
const vtkm::filter::FieldMetadata& fieldMeta,
|
|
|
|
vtkm::filter::PolicyBase<DerivedPolicy> policy) const
|
|
|
|
{
|
|
|
|
vtkm::cont::ArrayHandle<T, S> dummy;
|
|
|
|
self->DoPostExecute(input, output, fieldMeta, dummy, policy);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
/// Helper function for saving the content of the tree for debugging
|
|
|
|
template <typename FieldType>
|
|
|
|
void SaveAfterFanInResults(
|
|
|
|
vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>* blockData,
|
2020-10-28 22:26:35 +00:00
|
|
|
vtkm::Id rank,
|
|
|
|
vtkm::cont::LogLevel logLevel)
|
2020-10-28 14:48:21 +00:00
|
|
|
{
|
2020-12-01 23:47:26 +00:00
|
|
|
(void)logLevel; // Suppress unused variable warning if logging is disabled
|
2020-10-28 22:26:35 +00:00
|
|
|
VTKM_LOG_S(logLevel,
|
2020-10-28 14:48:21 +00:00
|
|
|
"Fan In Complete" << std::endl
|
|
|
|
<< "# of CTs: " << blockData->ContourTrees.size() << std::endl
|
|
|
|
<< "# of CTMs: " << blockData->ContourTreeMeshes.size() << std::endl
|
|
|
|
<< "# of IFs: " << blockData->InteriorForests.size() << std::endl);
|
|
|
|
|
|
|
|
char buffer[256];
|
|
|
|
std::snprintf(buffer,
|
|
|
|
sizeof(buffer),
|
|
|
|
"AfterFanInResults_Rank%d_Block%d.txt",
|
|
|
|
static_cast<int>(rank),
|
|
|
|
static_cast<int>(blockData->BlockIndex));
|
|
|
|
std::ofstream os(buffer);
|
|
|
|
os << "Contour Trees" << std::endl;
|
|
|
|
os << "=============" << std::endl;
|
|
|
|
for (const auto& ct : blockData->ContourTrees)
|
|
|
|
ct.PrintContent(os);
|
|
|
|
os << std::endl;
|
|
|
|
os << "Contour Tree Meshes" << std::endl;
|
|
|
|
os << "===================" << std::endl;
|
|
|
|
for (const auto& cm : blockData->ContourTreeMeshes)
|
|
|
|
cm.PrintContent(os);
|
|
|
|
os << std::endl;
|
|
|
|
os << "Interior Forests" << std::endl;
|
|
|
|
os << "===================" << std::endl;
|
|
|
|
for (const auto& info : blockData->InteriorForests)
|
|
|
|
info.PrintContent(os);
|
|
|
|
os << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FieldType>
|
|
|
|
void SaveHierarchicalTreeDot(
|
|
|
|
vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>* blockData,
|
|
|
|
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>& hierarchicalTree,
|
|
|
|
vtkm::Id rank,
|
|
|
|
vtkm::Id nRounds)
|
|
|
|
{
|
|
|
|
std::string hierarchicalTreeFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<int>(blockData->BlockIndex)) + std::string("_Round_") +
|
|
|
|
std::to_string(nRounds) + std::string("_Hierarchical_Tree.gv");
|
|
|
|
std::string hierarchicalTreeLabel = std::string("Block ") +
|
|
|
|
std::to_string(static_cast<int>(blockData->BlockIndex)) + std::string(" Round ") +
|
|
|
|
std::to_string(nRounds) + std::string(" Hierarchical Tree");
|
|
|
|
vtkm::Id hierarchicalTreeDotSettings =
|
|
|
|
vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE |
|
|
|
|
vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE |
|
|
|
|
vtkm::worklet::contourtree_distributed::SHOW_ALL_IDS |
|
|
|
|
vtkm::worklet::contourtree_distributed::SHOW_ALL_SUPERIDS |
|
|
|
|
vtkm::worklet::contourtree_distributed::SHOW_ALL_HYPERIDS;
|
|
|
|
std::ofstream hierarchicalTreeFile(hierarchicalTreeFileName);
|
|
|
|
hierarchicalTreeFile
|
|
|
|
<< vtkm::worklet::contourtree_distributed::HierarchicalContourTreeDotGraphPrint<FieldType>(
|
|
|
|
hierarchicalTreeLabel, hierarchicalTree, hierarchicalTreeDotSettings);
|
|
|
|
}
|
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
} // end namespace contourtree_distributed_detail
|
|
|
|
|
|
|
|
|
2020-10-28 00:40:41 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Main constructor
|
2020-06-12 17:50:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2020-09-15 17:57:20 +00:00
|
|
|
ContourTreeUniformDistributed::ContourTreeUniformDistributed(
|
|
|
|
vtkm::Id3 blocksPerDim,
|
|
|
|
vtkm::Id3 globalSize,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
|
2020-11-10 12:19:10 +00:00
|
|
|
bool useBoundaryExtremaOnly,
|
2020-10-01 06:24:07 +00:00
|
|
|
bool useMarchingCubes,
|
2020-10-28 22:26:35 +00:00
|
|
|
bool saveDotFiles,
|
|
|
|
vtkm::cont::LogLevel timingsLogLevel,
|
|
|
|
vtkm::cont::LogLevel treeLogLevel)
|
2020-09-17 12:42:41 +00:00
|
|
|
: vtkm::filter::FilterField<ContourTreeUniformDistributed>()
|
2020-11-10 12:19:10 +00:00
|
|
|
, UseBoundaryExtremaOnly(useBoundaryExtremaOnly)
|
2020-06-12 17:50:01 +00:00
|
|
|
, UseMarchingCubes(useMarchingCubes)
|
2020-10-01 06:24:07 +00:00
|
|
|
, SaveDotFiles(saveDotFiles)
|
2020-10-28 22:26:35 +00:00
|
|
|
, TimingsLogLevel(timingsLogLevel)
|
|
|
|
, TreeLogLevel(treeLogLevel)
|
2020-09-15 17:57:20 +00:00
|
|
|
, MultiBlockSpatialDecomposition(blocksPerDim,
|
|
|
|
globalSize,
|
|
|
|
localBlockIndices,
|
|
|
|
localBlockOrigins,
|
|
|
|
localBlockSizes)
|
|
|
|
, LocalMeshes(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
|
|
|
, LocalContourTrees(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
|
|
|
, LocalBoundaryTrees(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
|
|
|
, LocalInteriorForests(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
2020-06-12 17:50:01 +00:00
|
|
|
{
|
|
|
|
this->SetOutputFieldName("resultData");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-28 00:40:41 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Functions used in PrepareForExecution() to compute the local contour
|
|
|
|
// tree for the data blocks processed by this rank.
|
2020-06-12 17:50:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
template <typename T, typename StorageType, typename DerivedPolicy>
|
2020-09-15 17:57:20 +00:00
|
|
|
void ContourTreeUniformDistributed::ComputeLocalTree(
|
|
|
|
const vtkm::Id blockIndex,
|
2020-06-12 17:50:01 +00:00
|
|
|
const vtkm::cont::DataSet& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
|
|
|
const vtkm::filter::FieldMetadata& fieldMeta,
|
|
|
|
vtkm::filter::PolicyBase<DerivedPolicy> policy)
|
|
|
|
{
|
|
|
|
// Check that the field is Ok
|
|
|
|
if (fieldMeta.IsPointField() == false)
|
|
|
|
{
|
|
|
|
throw vtkm::cont::ErrorFilterExecution("Point field expected.");
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:42:41 +00:00
|
|
|
// Get mesh size
|
|
|
|
vtkm::Id3 meshSize;
|
2020-06-12 17:50:01 +00:00
|
|
|
const auto& cells = input.GetCellSet();
|
|
|
|
vtkm::filter::ApplyPolicyCellSet(cells, policy, *this)
|
2020-09-17 12:42:41 +00:00
|
|
|
.CastAndCall(vtkm::worklet::contourtree_augmented::GetPointDimensions(), meshSize);
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-09-15 17:57:20 +00:00
|
|
|
// Create the mesh we need for the contour tree computation so that we have access to it
|
|
|
|
// afterwards to compute the BRACT for each data block as well
|
|
|
|
if (meshSize[2] == 1) // 2D mesh
|
2020-06-12 17:50:01 +00:00
|
|
|
{
|
2020-09-15 17:57:20 +00:00
|
|
|
vtkm::worklet::contourtree_augmented::DataSetMeshTriangulation2DFreudenthal mesh(
|
|
|
|
vtkm::Id2{ meshSize[0], meshSize[1] });
|
|
|
|
this->LocalMeshes[static_cast<std::size_t>(blockIndex)] = mesh;
|
|
|
|
auto meshBoundaryExecObject = mesh.GetMeshBoundaryExecutionObject();
|
|
|
|
this->ComputeLocalTreeImpl(
|
|
|
|
blockIndex, input, field, fieldMeta, policy, mesh, meshBoundaryExecObject);
|
2020-06-12 17:50:01 +00:00
|
|
|
}
|
2020-09-15 17:57:20 +00:00
|
|
|
else if (this->UseMarchingCubes) // 3D marching cubes mesh
|
|
|
|
{
|
|
|
|
vtkm::worklet::contourtree_augmented::DataSetMeshTriangulation3DMarchingCubes mesh(meshSize);
|
|
|
|
this->LocalMeshes[static_cast<std::size_t>(blockIndex)] = mesh;
|
|
|
|
auto meshBoundaryExecObject = mesh.GetMeshBoundaryExecutionObject();
|
|
|
|
this->ComputeLocalTreeImpl(
|
|
|
|
blockIndex, input, field, fieldMeta, policy, mesh, meshBoundaryExecObject);
|
|
|
|
}
|
|
|
|
else // Regular 3D mesh
|
|
|
|
{
|
|
|
|
vtkm::worklet::contourtree_augmented::DataSetMeshTriangulation3DFreudenthal mesh(meshSize);
|
|
|
|
this->LocalMeshes[static_cast<std::size_t>(blockIndex)] = mesh;
|
|
|
|
auto meshBoundaryExecObject = mesh.GetMeshBoundaryExecutionObject();
|
|
|
|
this->ComputeLocalTreeImpl(
|
|
|
|
blockIndex, input, field, fieldMeta, policy, mesh, meshBoundaryExecObject);
|
|
|
|
}
|
|
|
|
} // ContourTreeUniformDistributed::ComputeLocalTree
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-09-15 17:57:20 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
template <typename T,
|
|
|
|
typename StorageType,
|
|
|
|
typename DerivedPolicy,
|
|
|
|
typename MeshType,
|
|
|
|
typename MeshBoundaryExecType>
|
|
|
|
void ContourTreeUniformDistributed::ComputeLocalTreeImpl(
|
|
|
|
const vtkm::Id blockIndex,
|
|
|
|
const vtkm::cont::DataSet&, // input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
|
|
|
const vtkm::filter::FieldMetadata&, // fieldMeta,
|
|
|
|
vtkm::filter::PolicyBase<DerivedPolicy>, // policy,
|
|
|
|
MeshType& mesh,
|
|
|
|
MeshBoundaryExecType& meshBoundaryExecObject)
|
|
|
|
{
|
2020-11-08 16:00:26 +00:00
|
|
|
vtkm::cont::Timer timer;
|
|
|
|
timer.Start();
|
2020-09-15 17:57:20 +00:00
|
|
|
// We always need to compute the fully augmented contour tree for our local data block
|
|
|
|
const unsigned int compRegularStruct = 1;
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-09-15 17:57:20 +00:00
|
|
|
// Set up the worklet
|
|
|
|
vtkm::worklet::ContourTreeAugmented worklet;
|
2020-10-29 02:17:18 +00:00
|
|
|
worklet.TimingsLogLevel = vtkm::cont::LogLevel::Off; // turn of the loggin, we do this afterwards
|
2020-09-15 17:57:20 +00:00
|
|
|
worklet.Run(field,
|
|
|
|
mesh,
|
|
|
|
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
|
|
|
this->LocalMeshes[static_cast<std::size_t>(blockIndex)].SortOrder,
|
|
|
|
this->NumIterations,
|
|
|
|
compRegularStruct,
|
|
|
|
meshBoundaryExecObject);
|
2020-10-29 02:17:18 +00:00
|
|
|
// Log the contour tree timiing stats
|
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " ---------------- Contour Tree Worklet Timings ------------------"
|
|
|
|
<< std::endl
|
|
|
|
<< " Block Index : " << blockIndex << std::endl
|
|
|
|
<< worklet.TimingsLogString);
|
2020-11-08 16:00:26 +00:00
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " "
|
|
|
|
"ComputeLocalTree ContourTree (blockIndex="
|
|
|
|
<< blockIndex << ") "
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds");
|
|
|
|
timer.Start();
|
2020-09-15 17:57:20 +00:00
|
|
|
// Now we compute the BRACT for our data block. We do this here because we know the MeshType
|
|
|
|
// here and we don't need to store the mesh separately any more since it is stored in the BRACT
|
|
|
|
|
|
|
|
// Get the mesh information needed to create an IdRelabeler to relable local to global ids
|
|
|
|
// Create an IdRelabeler since we are using a DataSetMesh type here, we don't need
|
|
|
|
// the IdRelabeler for the BRACT construction when we are using a ContourTreeMesh.
|
2020-11-08 16:00:26 +00:00
|
|
|
|
2020-09-15 17:57:20 +00:00
|
|
|
auto localToGlobalIdRelabeler = vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockIndex),
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockIndex),
|
|
|
|
this->MultiBlockSpatialDecomposition.GlobalSize);
|
|
|
|
// Initialize the BoundaryTreeMaker
|
|
|
|
auto boundaryTreeMaker =
|
|
|
|
vtkm::worklet::contourtree_distributed::BoundaryTreeMaker<MeshType, MeshBoundaryExecType>(
|
|
|
|
&mesh, // The input mesh
|
|
|
|
meshBoundaryExecObject, // The mesh boundary
|
|
|
|
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)], // The contour tree
|
|
|
|
&this->LocalBoundaryTrees[static_cast<std::size_t>(
|
|
|
|
blockIndex)], // The boundary tree (a.k.a BRACT) to be computed
|
|
|
|
&this->LocalInteriorForests[static_cast<std::size_t>(
|
|
|
|
blockIndex)] // The interior forest (a.k.a. Residue) to be computed
|
|
|
|
);
|
|
|
|
// Execute the BRACT construction, including the compute of the InteriorForest
|
2020-11-10 12:19:10 +00:00
|
|
|
boundaryTreeMaker.Construct(&localToGlobalIdRelabeler, this->UseBoundaryExtremaOnly);
|
2020-11-08 16:00:26 +00:00
|
|
|
// Log timing statistics
|
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " "
|
|
|
|
"ComputeLocalTree BoundaryTreeMaker (blockIndex="
|
|
|
|
<< blockIndex << ") "
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds");
|
|
|
|
timer.Start();
|
2020-09-15 17:57:20 +00:00
|
|
|
|
|
|
|
// At this point, I'm reasonably certain that the contour tree has been computed regardless of data push/pull
|
|
|
|
// So although it might be logical to print things out earlier, I'll do it here
|
|
|
|
// save the regular structure
|
2020-10-01 06:24:07 +00:00
|
|
|
if (this->SaveDotFiles)
|
|
|
|
{
|
2020-11-04 00:57:16 +00:00
|
|
|
// Get the rank
|
2020-10-01 06:24:07 +00:00
|
|
|
vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
|
2020-10-01 21:36:42 +00:00
|
|
|
|
2020-10-01 06:24:07 +00:00
|
|
|
// Save the BRACT dot for debug
|
2020-10-01 21:36:42 +00:00
|
|
|
{ // make context so the file will be closed and potentially large strings are cleaned up
|
|
|
|
std::string bractFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) +
|
|
|
|
std::string("_Block_") + std::to_string(static_cast<int>(blockIndex)) + "_Initial_BRACT.gv";
|
|
|
|
std::ofstream bractFile(bractFileName);
|
|
|
|
std::string bractString =
|
|
|
|
this->LocalBoundaryTrees[static_cast<std::size_t>(blockIndex)].PrintGlobalDot(
|
|
|
|
"Before Fan In",
|
|
|
|
mesh,
|
|
|
|
field,
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockIndex),
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockIndex),
|
|
|
|
this->MultiBlockSpatialDecomposition.GlobalSize);
|
|
|
|
bractFile << bractString << std::endl;
|
|
|
|
}
|
2020-09-28 18:40:51 +00:00
|
|
|
|
2020-10-01 06:24:07 +00:00
|
|
|
// Save the regular structure as a dot file
|
2020-10-01 21:36:42 +00:00
|
|
|
{ // make context so the file will be closed and potentially large strings are cleaned up
|
|
|
|
std::string regularStructureFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<int>(blockIndex)) +
|
|
|
|
std::string("_Initial_Step_0_Contour_Tree_Regular_Structure.gv");
|
|
|
|
std::ofstream regularStructureFile(regularStructureFileName);
|
|
|
|
std::string label = std::string("Block ") +
|
|
|
|
std::to_string(static_cast<std::size_t>(blockIndex)) +
|
|
|
|
" Initial Step 0 Contour Tree Regular Structure";
|
|
|
|
vtkm::Id dotSettings = worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE |
|
|
|
|
worklet::contourtree_distributed::SHOW_ALL_IDS;
|
|
|
|
std::string regularStructureString =
|
|
|
|
worklet::contourtree_distributed::ContourTreeDotGraphPrint<
|
|
|
|
T,
|
|
|
|
StorageType,
|
|
|
|
MeshType,
|
|
|
|
vtkm::worklet::contourtree_augmented::IdArrayType>(
|
|
|
|
label, // graph title
|
|
|
|
static_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(
|
|
|
|
blockIndex)]), // the underlying mesh for the contour tree
|
|
|
|
&localToGlobalIdRelabeler, // relabler needed to compute global ids
|
|
|
|
field, // data values
|
|
|
|
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)], // local contour tree
|
|
|
|
dotSettings // mask with flags for what elements to show
|
|
|
|
);
|
|
|
|
regularStructureFile << regularStructureString << std::endl;
|
|
|
|
}
|
2020-09-28 18:40:51 +00:00
|
|
|
|
2020-10-01 06:24:07 +00:00
|
|
|
// Save the super structure as a dot file
|
2020-10-01 21:36:42 +00:00
|
|
|
{ // make context so the file will be closed and potentially large strings are cleaned up
|
|
|
|
std::string superStructureFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<int>(blockIndex)) +
|
|
|
|
std::string("_Initial_Step_1_Contour_Tree_Super_Structure.gv");
|
|
|
|
std::ofstream superStructureFile(superStructureFileName);
|
|
|
|
vtkm::Id ctPrintSettings = worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE |
|
|
|
|
worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE |
|
|
|
|
worklet::contourtree_distributed::SHOW_ALL_IDS |
|
|
|
|
worklet::contourtree_distributed::SHOW_ALL_SUPERIDS |
|
|
|
|
worklet::contourtree_distributed::SHOW_ALL_HYPERIDS;
|
|
|
|
std::string ctPrintLabel = std::string("Block ") +
|
|
|
|
std::to_string(static_cast<size_t>(blockIndex)) +
|
|
|
|
" Initial Step 1 Contour Tree Super Structure";
|
|
|
|
std::string superStructureString =
|
|
|
|
vtkm::worklet::contourtree_distributed::ContourTreeDotGraphPrint<
|
|
|
|
T,
|
|
|
|
StorageType,
|
|
|
|
MeshType,
|
|
|
|
vtkm::worklet::contourtree_augmented::IdArrayType>(
|
|
|
|
ctPrintLabel,
|
|
|
|
static_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(blockIndex)]),
|
|
|
|
&localToGlobalIdRelabeler,
|
|
|
|
field,
|
|
|
|
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
|
|
|
ctPrintSettings);
|
|
|
|
superStructureFile << superStructureString << std::endl;
|
|
|
|
}
|
2020-10-01 06:24:07 +00:00
|
|
|
|
|
|
|
// save the Boundary Tree as a dot file
|
2020-10-01 21:36:42 +00:00
|
|
|
{ // make context so the file will be closed and potentially large strings are cleaned up
|
|
|
|
std::string boundaryTreeFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<size_t>(blockIndex)) +
|
|
|
|
std::string("_Initial_Step_3_Boundary_Tree.gv");
|
|
|
|
std::ofstream boundaryTreeFile(boundaryTreeFileName);
|
|
|
|
std::string boundaryTreeString =
|
|
|
|
vtkm::worklet::contourtree_distributed::BoundaryTreeDotGraphPrint(
|
|
|
|
std::string("Block ") + std::to_string(static_cast<size_t>(blockIndex)) +
|
|
|
|
std::string(" Initial Step 3 Boundary Tree"),
|
|
|
|
static_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(blockIndex)]),
|
|
|
|
meshBoundaryExecObject,
|
|
|
|
this->LocalBoundaryTrees[static_cast<std::size_t>(blockIndex)],
|
|
|
|
&localToGlobalIdRelabeler,
|
|
|
|
field);
|
|
|
|
boundaryTreeFile << boundaryTreeString << std::endl;
|
|
|
|
}
|
2020-10-01 06:24:07 +00:00
|
|
|
|
|
|
|
// and save the Interior Forest as another dot file
|
2020-10-01 21:36:42 +00:00
|
|
|
{ // make context so the file will be closed and potentially large strings are cleaned up
|
|
|
|
std::string interiorForestFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<int>(blockIndex)) +
|
|
|
|
std::string("_Initial_Step_4_Interior_Forest.gv");
|
|
|
|
std::ofstream interiorForestFile(interiorForestFileName);
|
|
|
|
std::string interiorForestString =
|
|
|
|
worklet::contourtree_distributed::InteriorForestDotGraphPrint(
|
|
|
|
std::string("Block ") + std::to_string(rank) + " Initial Step 4 Interior Forest",
|
|
|
|
this->LocalInteriorForests[static_cast<std::size_t>(blockIndex)],
|
|
|
|
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
|
|
|
this->LocalBoundaryTrees[static_cast<std::size_t>(blockIndex)],
|
|
|
|
static_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(blockIndex)]),
|
|
|
|
meshBoundaryExecObject,
|
|
|
|
&localToGlobalIdRelabeler,
|
|
|
|
field);
|
|
|
|
interiorForestFile << interiorForestString << std::endl;
|
2020-11-04 00:57:16 +00:00
|
|
|
|
|
|
|
// Log timing statistics
|
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " " << std::setw(38) << std::left << "ComputeLocalTree Save Dot"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds");
|
2020-10-01 21:36:42 +00:00
|
|
|
}
|
2020-10-01 06:24:07 +00:00
|
|
|
} // if (this->SaveDotFiles)
|
|
|
|
} // ContourTreeUniformDistributed::ComputeLocalTreeImpl
|
2020-09-28 18:40:51 +00:00
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-10-28 00:40:41 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2020-10-28 00:52:09 +00:00
|
|
|
// Main execution phases of the filter
|
|
|
|
//
|
|
|
|
// The functions are executed by VTKm in the following order
|
|
|
|
// - PreExecute
|
2020-10-28 00:40:41 +00:00
|
|
|
// - PrepareForExecution
|
2020-10-28 00:52:09 +00:00
|
|
|
// --> ComputeLocalTree (struct)
|
|
|
|
// --> ComputeLocalTree (filter funct)
|
|
|
|
// --> ComputeLocalTreeImpl (filter funct)
|
|
|
|
// - PostExecute
|
|
|
|
// --> DoPostExecute
|
|
|
|
//-----------------------------------------------------------------------------
|
2020-10-28 00:40:41 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2020-10-28 00:52:09 +00:00
|
|
|
template <typename DerivedPolicy>
|
|
|
|
inline VTKM_CONT void ContourTreeUniformDistributed::PreExecute(
|
|
|
|
const vtkm::cont::PartitionedDataSet& input,
|
|
|
|
const vtkm::filter::PolicyBase<DerivedPolicy>&)
|
|
|
|
{
|
|
|
|
if (vtkm::worklet::contourtree_distributed::SpatialDecomposition::GetGlobalNumberOfBlocks(
|
|
|
|
input) != this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks())
|
|
|
|
{
|
|
|
|
throw vtkm::cont::ErrorFilterExecution(
|
|
|
|
"Global number of blocks in MultiBlock dataset does not match the SpatialDecomposition");
|
|
|
|
}
|
|
|
|
if (this->MultiBlockSpatialDecomposition.GetLocalNumberOfBlocks() !=
|
|
|
|
input.GetNumberOfPartitions())
|
|
|
|
{
|
|
|
|
throw vtkm::cont::ErrorFilterExecution(
|
|
|
|
"Local number of blocks in MultiBlock dataset does not match the SpatialDecomposition");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-28 00:40:41 +00:00
|
|
|
template <typename DerivedPolicy>
|
|
|
|
vtkm::cont::PartitionedDataSet ContourTreeUniformDistributed::PrepareForExecution(
|
|
|
|
const vtkm::cont::PartitionedDataSet& input,
|
|
|
|
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
|
|
|
|
{
|
|
|
|
// Time execution
|
|
|
|
vtkm::cont::Timer timer;
|
|
|
|
timer.Start();
|
|
|
|
|
|
|
|
// Compute the local contour tree, boundary tree, and interior forest for each local data block
|
|
|
|
for (vtkm::Id blockNo = 0; blockNo < input.GetNumberOfPartitions(); ++blockNo)
|
|
|
|
{
|
|
|
|
auto dataset = input.GetPartition(blockNo);
|
|
|
|
auto field = dataset.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
|
|
|
vtkm::filter::FieldMetadata metaData(field);
|
|
|
|
|
|
|
|
vtkm::filter::FilterTraits<ContourTreeUniformDistributed> traits;
|
|
|
|
vtkm::cont::CastAndCall(vtkm::filter::ApplyPolicyFieldActive(field, policy, traits),
|
|
|
|
vtkm::filter::contourtree_distributed_detail::ComputeLocalTree{},
|
|
|
|
this,
|
|
|
|
blockNo,
|
|
|
|
dataset,
|
|
|
|
metaData,
|
|
|
|
policy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log sizes of the local contour trees, boundary trees, and interior forests
|
|
|
|
for (size_t bi = 0; bi < this->LocalContourTrees.size(); bi++)
|
|
|
|
{
|
2020-10-28 22:26:35 +00:00
|
|
|
VTKM_LOG_S(this->TreeLogLevel,
|
2020-10-28 00:40:41 +00:00
|
|
|
std::endl
|
|
|
|
<< " ---------------- Contour Tree Array Sizes ---------------------"
|
|
|
|
<< std::endl
|
|
|
|
<< " Block Index : " << bi << std::endl
|
|
|
|
<< LocalContourTrees[bi].PrintArraySizes());
|
2020-10-28 22:26:35 +00:00
|
|
|
VTKM_LOG_S(this->TreeLogLevel,
|
2020-10-28 00:40:41 +00:00
|
|
|
std::endl
|
|
|
|
<< " ---------------- Boundary Tree Array Sizes ---------------------"
|
|
|
|
<< std::endl
|
|
|
|
<< " Block Index : " << bi << std::endl
|
|
|
|
<< LocalBoundaryTrees[bi].PrintArraySizes());
|
2020-10-28 22:26:35 +00:00
|
|
|
VTKM_LOG_S(this->TreeLogLevel,
|
2020-10-28 00:40:41 +00:00
|
|
|
std::endl
|
|
|
|
<< " ---------------- Interior Forest Array Sizes ---------------------"
|
|
|
|
<< std::endl
|
|
|
|
<< " Block Index : " << bi << std::endl
|
|
|
|
<< LocalInteriorForests[bi].PrintArraySizes());
|
2020-10-28 22:26:35 +00:00
|
|
|
// VTKM_LOG_S(this->TreeLogLevel,
|
2020-10-28 00:40:41 +00:00
|
|
|
// std::endl
|
|
|
|
// << " ---------------- Hyperstructure Statistics ---------------------" << std::endl
|
|
|
|
// << LocalContourTrees[bi].PrintHyperStructureStatistics(false) << std::endl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log timing statistics
|
2020-10-28 22:26:35 +00:00
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
2020-10-28 00:40:41 +00:00
|
|
|
std::endl
|
|
|
|
<< " " << std::setw(38) << std::left << "Contour Tree Filter PrepareForExecution"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds");
|
|
|
|
|
|
|
|
return input; // TODO/FIXME: What to return?
|
|
|
|
}
|
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
template <typename DerivedPolicy>
|
2020-10-28 00:52:09 +00:00
|
|
|
inline VTKM_CONT void ContourTreeUniformDistributed::PostExecute(
|
2020-06-12 17:50:01 +00:00
|
|
|
const vtkm::cont::PartitionedDataSet& input,
|
2020-10-28 00:52:09 +00:00
|
|
|
vtkm::cont::PartitionedDataSet& result,
|
|
|
|
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
|
2020-06-12 17:50:01 +00:00
|
|
|
{
|
2020-10-28 00:52:09 +00:00
|
|
|
vtkm::cont::Timer timer;
|
|
|
|
timer.Start();
|
|
|
|
// We are running in parallel and need to merge the contour tree in PostExecute
|
|
|
|
// TODO/FIXME: Make sure this still makes sense
|
|
|
|
if (this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks() == 1)
|
2020-09-15 17:57:20 +00:00
|
|
|
{
|
2020-10-28 00:52:09 +00:00
|
|
|
return;
|
2020-06-12 17:50:01 +00:00
|
|
|
}
|
2020-10-28 00:52:09 +00:00
|
|
|
auto field = // TODO/FIXME: Correct for more than one block per rank?
|
|
|
|
input.GetPartition(0).GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
|
|
|
vtkm::filter::FieldMetadata metaData(field);
|
|
|
|
|
|
|
|
vtkm::filter::FilterTraits<ContourTreeUniformDistributed> traits;
|
|
|
|
vtkm::cont::CastAndCall(vtkm::filter::ApplyPolicyFieldActive(field, policy, traits),
|
|
|
|
vtkm::filter::contourtree_distributed_detail::PostExecuteCaller{},
|
|
|
|
this,
|
|
|
|
input,
|
|
|
|
result,
|
|
|
|
metaData,
|
|
|
|
policy);
|
|
|
|
|
2020-10-28 22:26:35 +00:00
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
2020-10-28 00:52:09 +00:00
|
|
|
std::endl
|
|
|
|
<< " " << std::setw(38) << std::left << "Contour Tree Filter PostExecute"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds");
|
2020-06-12 17:50:01 +00:00
|
|
|
}
|
|
|
|
|
2020-10-28 00:52:09 +00:00
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2020-09-15 17:57:20 +00:00
|
|
|
template <typename FieldType, typename StorageType, typename DerivedPolicy>
|
2020-06-12 17:50:01 +00:00
|
|
|
VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
|
|
|
|
const vtkm::cont::PartitionedDataSet& input,
|
2020-09-22 02:05:10 +00:00
|
|
|
vtkm::cont::PartitionedDataSet& result,
|
2020-09-15 17:57:20 +00:00
|
|
|
const vtkm::filter::FieldMetadata&, // dummy parameter for field meta data
|
|
|
|
const vtkm::cont::ArrayHandle<FieldType, StorageType>&, // dummy parameter to get the type
|
|
|
|
vtkm::filter::PolicyBase<DerivedPolicy>) // dummy parameter for policy
|
2020-06-12 17:50:01 +00:00
|
|
|
{
|
2020-10-28 14:48:21 +00:00
|
|
|
vtkm::cont::Timer timer;
|
|
|
|
timer.Start();
|
2020-10-28 22:26:35 +00:00
|
|
|
std::stringstream timingsStream;
|
2020-10-28 14:48:21 +00:00
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
|
|
|
|
vtkm::Id size = comm.size();
|
|
|
|
vtkm::Id rank = comm.rank();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 1. Fan in to compute the hiearchical contour tree
|
|
|
|
// 1.1 Setup the block data for DIY
|
2020-09-15 17:57:20 +00:00
|
|
|
std::vector<vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>*>
|
|
|
|
localDataBlocks(static_cast<size_t>(input.GetNumberOfPartitions()), nullptr);
|
2020-06-12 17:50:01 +00:00
|
|
|
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
|
|
|
|
{
|
2020-09-15 17:57:20 +00:00
|
|
|
// Create the local data block structure and set extents
|
|
|
|
localDataBlocks[bi] =
|
|
|
|
new vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>();
|
|
|
|
localDataBlocks[bi]->BlockIndex = static_cast<vtkm::Id>(bi);
|
2020-06-12 17:50:01 +00:00
|
|
|
localDataBlocks[bi]->BlockOrigin =
|
2020-09-15 17:57:20 +00:00
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
|
2020-06-12 17:50:01 +00:00
|
|
|
static_cast<vtkm::Id>(bi));
|
|
|
|
localDataBlocks[bi]->BlockSize =
|
2020-09-15 17:57:20 +00:00
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
2020-06-12 17:50:01 +00:00
|
|
|
static_cast<vtkm::Id>(bi));
|
2020-09-15 17:57:20 +00:00
|
|
|
|
|
|
|
// Save local tree information for fan out FIXME: Try to avoid copy
|
|
|
|
localDataBlocks[bi]->ContourTrees.push_back(this->LocalContourTrees[bi]);
|
|
|
|
localDataBlocks[bi]->InteriorForests.push_back(this->LocalInteriorForests[bi]);
|
|
|
|
|
|
|
|
// ... Compute arrays needed for constructing contour tree mesh
|
|
|
|
const auto sortOrder = this->LocalMeshes[bi].SortOrder;
|
|
|
|
// ... Compute the global mesh index for the partially augmented contour tree. I.e., here we
|
|
|
|
// don't need the global mesh index for all nodes, but only for the augmented nodes from the
|
|
|
|
// tree. We, hence, permute the sortOrder by contourTree.augmentednodes and then compute the
|
|
|
|
// GlobalMeshIndex by tranforming those indices with our IdRelabler
|
|
|
|
vtkm::worklet::contourtree_augmented::IdArrayType localGlobalMeshIndex;
|
|
|
|
vtkm::cont::ArrayHandlePermutation<vtkm::worklet::contourtree_augmented::IdArrayType,
|
|
|
|
vtkm::worklet::contourtree_augmented::IdArrayType>
|
|
|
|
permutedSortOrder(this->LocalBoundaryTrees[bi].VertexIndex, sortOrder);
|
|
|
|
auto transformedIndex = vtkm::cont::make_ArrayHandleTransform(
|
|
|
|
permutedSortOrder,
|
|
|
|
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
|
|
|
|
static_cast<vtkm::Id>(bi)),
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
|
|
|
static_cast<vtkm::Id>(bi)),
|
|
|
|
this->MultiBlockSpatialDecomposition.GlobalSize));
|
|
|
|
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
|
|
|
|
|
|
|
|
// ... get data values
|
|
|
|
auto currBlock = input.GetPartition(static_cast<vtkm::Id>(bi));
|
|
|
|
auto currField =
|
|
|
|
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
|
|
|
vtkm::cont::ArrayHandle<FieldType> fieldData;
|
2021-02-01 23:36:47 +00:00
|
|
|
vtkm::cont::ArrayCopy(currField.GetData(), fieldData);
|
2020-09-15 17:57:20 +00:00
|
|
|
|
|
|
|
// ... compute and store the actual mesh
|
|
|
|
localDataBlocks[bi]->ContourTreeMeshes.emplace_back(this->LocalBoundaryTrees[bi].VertexIndex,
|
|
|
|
this->LocalBoundaryTrees[bi].Superarcs,
|
|
|
|
sortOrder,
|
|
|
|
fieldData,
|
|
|
|
localGlobalMeshIndex);
|
2020-11-04 00:57:16 +00:00
|
|
|
} // for
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time for setting block data
|
2020-11-04 00:57:16 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Compute Block Data for Fan In"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
timer.Start();
|
2020-09-15 17:57:20 +00:00
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// ... save for debugging in text and .gv/.dot format. We could do this in the loop above,
|
|
|
|
// but in order to separate timing we do this here and the extra loop over the partitions
|
|
|
|
// should not be significnatly more expensive then doing it all in one loop
|
2020-11-04 00:57:16 +00:00
|
|
|
if (this->SaveDotFiles)
|
|
|
|
{
|
|
|
|
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
|
2020-10-01 07:02:44 +00:00
|
|
|
{
|
|
|
|
// save the contour tree mesh
|
|
|
|
std::string contourTreeMeshFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<int>(bi)) + std::string("_Initial_Step_3_BRACT_Mesh.txt");
|
|
|
|
localDataBlocks[bi]->ContourTreeMeshes.back().Save(contourTreeMeshFileName.c_str());
|
2020-09-15 17:57:20 +00:00
|
|
|
|
2020-10-01 07:02:44 +00:00
|
|
|
// save the corresponding .gv file
|
|
|
|
std::string boundaryTreeMeshFileName = std::string("Rank_") +
|
|
|
|
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
|
|
|
std::to_string(static_cast<int>(bi)) + std::string("_Initial_Step_5_BRACT_Mesh.gv");
|
|
|
|
std::ofstream boundaryTreeMeshFile(boundaryTreeMeshFileName);
|
|
|
|
boundaryTreeMeshFile
|
|
|
|
<< vtkm::worklet::contourtree_distributed::ContourTreeMeshDotGraphPrint<FieldType>(
|
|
|
|
std::string("Block ") + std::to_string(static_cast<int>(rank)) +
|
|
|
|
std::string(" Initial Step 5 BRACT Mesh"),
|
|
|
|
localDataBlocks[bi]->ContourTreeMeshes.back(),
|
|
|
|
worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_ALL);
|
2020-11-04 00:57:16 +00:00
|
|
|
} // for
|
|
|
|
} // // if(SaveDotFiles)
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time for saving debug data
|
2020-11-04 00:57:16 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Save block data for debug"
|
2020-10-28 22:26:35 +00:00
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
2020-10-28 14:48:21 +00:00
|
|
|
timer.Start();
|
|
|
|
|
|
|
|
// 1.2 Setup vtkmdiy to do global binary reduction of neighbouring blocks.
|
|
|
|
// See also RecuctionOperation struct for example
|
2020-06-12 17:50:01 +00:00
|
|
|
// Create the vtkmdiy master
|
|
|
|
vtkmdiy::Master master(comm,
|
|
|
|
1, // Use 1 thread, VTK-M will do the treading
|
|
|
|
-1 // All block in memory
|
2020-08-17 14:18:24 +00:00
|
|
|
);
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time for creating the DIY master
|
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Create DIY Master"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
timer.Start();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 1.2.1 Compute the gids for our local blocks
|
2021-02-26 22:06:39 +00:00
|
|
|
using RegularDecomposer = vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>;
|
2020-06-12 17:50:01 +00:00
|
|
|
const vtkm::worklet::contourtree_distributed::SpatialDecomposition& spatialDecomp =
|
2020-09-15 17:57:20 +00:00
|
|
|
this->MultiBlockSpatialDecomposition;
|
2021-02-26 22:06:39 +00:00
|
|
|
const auto numDims = spatialDecomp.NumberOfDimensions();
|
|
|
|
|
|
|
|
// ... division vector
|
|
|
|
RegularDecomposer::DivisionsVector diyDivisions(numDims);
|
|
|
|
for (vtkm::IdComponent d = 0;
|
|
|
|
d < static_cast<vtkm::IdComponent>(spatialDecomp.NumberOfDimensions());
|
|
|
|
++d)
|
|
|
|
{
|
|
|
|
diyDivisions[d] = static_cast<int>(spatialDecomp.BlocksPerDimension[d]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ... coordinates of local blocks
|
2020-06-12 17:50:01 +00:00
|
|
|
auto localBlockIndicesPortal = spatialDecomp.LocalBlockIndices.ReadPortal();
|
|
|
|
std::vector<vtkm::Id> vtkmdiyLocalBlockGids(static_cast<size_t>(input.GetNumberOfPartitions()));
|
|
|
|
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
|
|
|
|
{
|
2021-02-26 22:06:39 +00:00
|
|
|
RegularDecomposer::DivisionsVector diyCoords(static_cast<size_t>(numDims));
|
2020-06-12 17:50:01 +00:00
|
|
|
auto currentCoords = localBlockIndicesPortal.Get(bi);
|
2021-02-26 22:06:39 +00:00
|
|
|
for (vtkm::IdComponent d = 0; d < numDims; ++d)
|
2020-06-12 17:50:01 +00:00
|
|
|
{
|
2021-02-26 22:06:39 +00:00
|
|
|
diyCoords[d] = static_cast<int>(currentCoords[d]);
|
2020-06-12 17:50:01 +00:00
|
|
|
}
|
|
|
|
vtkmdiyLocalBlockGids[static_cast<size_t>(bi)] =
|
2021-02-26 22:06:39 +00:00
|
|
|
RegularDecomposer::coords_to_gid(diyCoords, diyDivisions);
|
2020-06-12 17:50:01 +00:00
|
|
|
}
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time to compute the local block ids
|
2020-11-03 20:06:14 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Compute Block Ids and Local Links"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
timer.Start();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 1.2.2 Add my local blocks to the vtkmdiy master.
|
2020-06-12 17:50:01 +00:00
|
|
|
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
|
|
|
|
{
|
|
|
|
master.add(static_cast<int>(vtkmdiyLocalBlockGids[bi]), // block id
|
|
|
|
localDataBlocks[bi],
|
2021-02-26 22:06:39 +00:00
|
|
|
new vtkmdiy::Link); // Use dummy link to make DIY happy.
|
|
|
|
// NOTE: The dummy link is never used, since all communication is via RegularDecomposer,
|
|
|
|
// which sets up its own links
|
|
|
|
// NOTE: No need to keep the pointer, as DIY will "own" it and delete it when no longer
|
|
|
|
// needed TODO/FIXME: Confirm that last statement
|
2020-06-12 17:50:01 +00:00
|
|
|
}
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time for dding data blocks to the master
|
2020-11-03 20:06:14 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Add Data Blocks to DIY"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
timer.Start();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 1.2.3 Define the decomposition of the domain into regular blocks
|
2021-02-26 22:06:39 +00:00
|
|
|
RegularDecomposer::BoolVector shareFace(3, true);
|
|
|
|
RegularDecomposer::BoolVector wrap(3, false);
|
|
|
|
RegularDecomposer::CoordinateVector ghosts(3, 1);
|
|
|
|
RegularDecomposer decomposer(static_cast<int>(numDims),
|
|
|
|
spatialDecomp.GetVTKmDIYBounds(),
|
|
|
|
static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()),
|
|
|
|
shareFace,
|
|
|
|
wrap,
|
|
|
|
ghosts,
|
|
|
|
diyDivisions);
|
2020-06-12 17:50:01 +00:00
|
|
|
|
|
|
|
// Define which blocks live on which rank so that vtkmdiy can manage them
|
|
|
|
vtkmdiy::DynamicAssigner assigner(
|
|
|
|
comm, static_cast<int>(size), static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()));
|
|
|
|
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
|
|
|
|
{
|
|
|
|
assigner.set_rank(static_cast<int>(rank),
|
|
|
|
static_cast<int>(vtkmdiyLocalBlockGids[static_cast<size_t>(bi)]));
|
|
|
|
}
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time for creating the decomposer and assigner
|
2020-11-03 20:06:14 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Create DIY Decomposer and Assigner"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
timer.Start();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 1.2.4 Fix the vtkmdiy links.
|
2020-06-12 17:50:01 +00:00
|
|
|
vtkmdiy::fix_links(master, assigner);
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time to fix the links
|
2020-11-03 20:06:14 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Fix DIY Links"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
timer.Start();
|
|
|
|
|
2020-06-12 17:50:01 +00:00
|
|
|
// partners for merge over regular block grid
|
2020-09-15 17:57:20 +00:00
|
|
|
vtkmdiy::RegularSwapPartners partners(
|
2020-06-12 17:50:01 +00:00
|
|
|
decomposer, // domain decomposition
|
2021-02-27 01:01:14 +00:00
|
|
|
2, // radix of k-ary reduction.
|
|
|
|
true // contiguous: true=distance doubling, false=distance halving
|
2020-08-17 14:18:24 +00:00
|
|
|
);
|
2020-10-28 14:48:21 +00:00
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record time to create the swap partners
|
2020-11-03 20:06:14 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Create DIY Swap Partners"
|
2020-10-28 22:26:35 +00:00
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
2020-10-28 14:48:21 +00:00
|
|
|
timer.Start();
|
|
|
|
|
|
|
|
// 1.3 execute the fan in reduction
|
2020-09-15 17:57:20 +00:00
|
|
|
const vtkm::worklet::contourtree_distributed::ComputeDistributedContourTreeFunctor<FieldType>
|
2020-11-10 12:19:10 +00:00
|
|
|
computeDistributedContourTreeFunctor(this->MultiBlockSpatialDecomposition.GlobalSize,
|
|
|
|
this->UseBoundaryExtremaOnly,
|
|
|
|
this->TimingsLogLevel,
|
|
|
|
this->TreeLogLevel);
|
2020-09-15 17:57:20 +00:00
|
|
|
vtkmdiy::reduce(master, assigner, partners, computeDistributedContourTreeFunctor);
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Record timing for the actual reduction
|
2020-10-28 22:26:35 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Fan In Reduction"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
2020-10-28 14:48:21 +00:00
|
|
|
timer.Start();
|
|
|
|
|
|
|
|
// Be safe! that the Fan In is completed on all blocks and ranks
|
|
|
|
comm.barrier();
|
|
|
|
|
2020-10-28 22:26:35 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Post Fan In Barrier"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
2020-10-28 14:48:21 +00:00
|
|
|
timer.Start();
|
2020-06-12 17:50:01 +00:00
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 2. Fan out to update all the tree
|
|
|
|
// 2.1 DataSets for creating output data
|
|
|
|
std::vector<vtkm::cont::DataSet> hierarchicalTreeOutputDataSet(localDataBlocks.size());
|
|
|
|
// 2.2. Use foreach to compute the fan-out
|
|
|
|
master.foreach (
|
|
|
|
[&](
|
|
|
|
vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>* blockData,
|
|
|
|
const vtkmdiy::Master::ProxyWithLink&) {
|
2020-09-22 02:05:10 +00:00
|
|
|
#ifdef DEBUG_PRINT_CTUD
|
2020-10-28 14:48:21 +00:00
|
|
|
// Save the contour tree, contour tree meshes, and interior forest data for debugging
|
2020-10-28 22:26:35 +00:00
|
|
|
vtkm::filter::contourtree_distributed_detail::SaveAfterFanInResults(
|
|
|
|
blockData, rank, this->TreeLogLevel);
|
2020-09-22 02:05:10 +00:00
|
|
|
#endif
|
2020-11-08 16:00:26 +00:00
|
|
|
vtkm::cont::Timer iterationTimer;
|
|
|
|
iterationTimer.Start();
|
2020-11-04 01:37:57 +00:00
|
|
|
std::stringstream fanoutTimingsStream;
|
2020-09-15 17:57:20 +00:00
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// Fan out
|
|
|
|
auto nRounds = blockData->ContourTrees.size() - 1;
|
2020-09-15 17:57:20 +00:00
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType> hierarchicalTree;
|
|
|
|
hierarchicalTree.Initialize(static_cast<vtkm::Id>(nRounds),
|
|
|
|
blockData->ContourTrees[nRounds],
|
|
|
|
blockData->ContourTreeMeshes[nRounds - 1]);
|
2020-09-15 17:57:20 +00:00
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// save the corresponding .gv file
|
2020-10-01 07:02:44 +00:00
|
|
|
if (this->SaveDotFiles)
|
|
|
|
{
|
2020-10-28 14:48:21 +00:00
|
|
|
vtkm::filter::contourtree_distributed_detail::SaveHierarchicalTreeDot(
|
|
|
|
blockData, hierarchicalTree, rank, nRounds);
|
|
|
|
} // if(this->SaveDotFiles)
|
|
|
|
|
2020-11-08 16:00:26 +00:00
|
|
|
fanoutTimingsStream << " Fan Out Init Hierarchical Tree (block=" << blockData->BlockIndex
|
|
|
|
<< ") : " << iterationTimer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
iterationTimer.Start();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
for (auto round = nRounds - 1; round > 0; round--)
|
|
|
|
{
|
2020-10-29 02:17:18 +00:00
|
|
|
iterationTimer.Start();
|
2020-10-28 14:48:21 +00:00
|
|
|
vtkm::worklet::contourtree_distributed::
|
|
|
|
TreeGrafter<vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>, FieldType>
|
|
|
|
grafter(&(blockData->ContourTreeMeshes[round - 1]),
|
|
|
|
blockData->ContourTrees[round],
|
|
|
|
&(blockData->InteriorForests[round]));
|
|
|
|
grafter.GraftInteriorForests(static_cast<vtkm::Id>(round),
|
|
|
|
hierarchicalTree,
|
|
|
|
blockData->ContourTreeMeshes[round - 1].SortedValues);
|
2020-10-01 07:02:44 +00:00
|
|
|
// save the corresponding .gv file
|
2020-10-28 14:48:21 +00:00
|
|
|
if (this->SaveDotFiles)
|
|
|
|
{
|
|
|
|
vtkm::filter::contourtree_distributed_detail::SaveHierarchicalTreeDot(
|
|
|
|
blockData, hierarchicalTree, rank, nRounds);
|
|
|
|
} // if(this->SaveDotFiles)
|
2020-10-29 02:17:18 +00:00
|
|
|
// Log the time for each of the iterations of the fan out loop
|
2020-11-04 01:37:57 +00:00
|
|
|
fanoutTimingsStream << " Fan Out Time (block=" << blockData->BlockIndex
|
|
|
|
<< " , round=" << round << ") : " << iterationTimer.GetElapsedTime()
|
|
|
|
<< " seconds" << std::endl;
|
2020-10-28 22:26:35 +00:00
|
|
|
} // for
|
2020-10-28 14:48:21 +00:00
|
|
|
|
|
|
|
// bottom level
|
2020-10-29 02:17:18 +00:00
|
|
|
iterationTimer.Start();
|
2020-10-28 14:48:21 +00:00
|
|
|
vtkm::worklet::contourtree_distributed::
|
|
|
|
TreeGrafter<vtkm::worklet::contourtree_augmented::DataSetMesh, FieldType>
|
|
|
|
grafter(&(this->LocalMeshes[static_cast<std::size_t>(blockData->BlockIndex)]),
|
|
|
|
blockData->ContourTrees[0],
|
|
|
|
&(blockData->InteriorForests[0]));
|
|
|
|
auto currBlock = input.GetPartition(blockData->BlockIndex);
|
|
|
|
auto currField =
|
|
|
|
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
|
|
|
vtkm::cont::ArrayHandle<FieldType> fieldData;
|
2021-02-01 23:36:47 +00:00
|
|
|
vtkm::cont::ArrayCopy(currField.GetData(), fieldData);
|
2020-10-28 14:48:21 +00:00
|
|
|
auto localToGlobalIdRelabeler = vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
|
|
|
|
blockData->BlockIndex),
|
|
|
|
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
|
|
|
blockData->BlockIndex),
|
|
|
|
this->MultiBlockSpatialDecomposition.GlobalSize);
|
|
|
|
grafter.GraftInteriorForests(0, hierarchicalTree, fieldData, &localToGlobalIdRelabeler);
|
2020-10-29 02:17:18 +00:00
|
|
|
|
|
|
|
// Log the time for each of the iterations of the fan out loop
|
2020-11-04 01:37:57 +00:00
|
|
|
fanoutTimingsStream << " Fan Out Time (block=" << blockData->BlockIndex << " , round=" << 0
|
|
|
|
<< ") : " << iterationTimer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
iterationTimer.Start();
|
2020-10-28 14:48:21 +00:00
|
|
|
|
|
|
|
// Create data set from output
|
|
|
|
vtkm::cont::Field dataValuesField(
|
|
|
|
"DataValues", vtkm::cont::Field::Association::WHOLE_MESH, hierarchicalTree.DataValues);
|
|
|
|
hierarchicalTreeOutputDataSet[blockData->BlockIndex].AddField(dataValuesField);
|
|
|
|
vtkm::cont::Field regularNodeGlobalIdsField("RegularNodeGlobalIds",
|
|
|
|
vtkm::cont::Field::Association::WHOLE_MESH,
|
|
|
|
hierarchicalTree.RegularNodeGlobalIds);
|
|
|
|
hierarchicalTreeOutputDataSet[blockData->BlockIndex].AddField(regularNodeGlobalIdsField);
|
|
|
|
vtkm::cont::Field superarcsField(
|
|
|
|
"Superarcs", vtkm::cont::Field::Association::WHOLE_MESH, hierarchicalTree.Superarcs);
|
|
|
|
hierarchicalTreeOutputDataSet[blockData->BlockIndex].AddField(superarcsField);
|
|
|
|
vtkm::cont::Field supernodesField(
|
|
|
|
"Supernodes", vtkm::cont::Field::Association::WHOLE_MESH, hierarchicalTree.Supernodes);
|
|
|
|
hierarchicalTreeOutputDataSet[blockData->BlockIndex].AddField(supernodesField);
|
|
|
|
vtkm::cont::Field superparentsField(
|
|
|
|
"Superparents", vtkm::cont::Field::Association::WHOLE_MESH, hierarchicalTree.Superparents);
|
|
|
|
hierarchicalTreeOutputDataSet[blockData->BlockIndex].AddField(superparentsField);
|
|
|
|
|
|
|
|
// Copy cell set from input data set. This is mainly to ensure that the output data set
|
|
|
|
// has a defined cell set. Without one, serialization for DIY does not work properly.
|
|
|
|
// Having the extents of the input data set may also help in other use cases.
|
|
|
|
hierarchicalTreeOutputDataSet[blockData->BlockIndex].SetCellSet(
|
|
|
|
input.GetPartition(blockData->BlockIndex).GetCellSet());
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Log the time for each of the iterations of the fan out loop
|
|
|
|
fanoutTimingsStream << " Fan Out Create Output Dataset (block=" << blockData->BlockIndex
|
|
|
|
<< ") : " << iterationTimer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
iterationTimer.Start();
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// save the corresponding .gv file
|
|
|
|
if (this->SaveDotFiles)
|
|
|
|
{
|
|
|
|
vtkm::filter::contourtree_distributed_detail::SaveHierarchicalTreeDot(
|
|
|
|
blockData, hierarchicalTree, rank, nRounds);
|
2020-11-04 01:37:57 +00:00
|
|
|
|
|
|
|
fanoutTimingsStream << " Fan Out Save Dot (block=" << blockData->BlockIndex
|
|
|
|
<< ") : " << iterationTimer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
iterationTimer.Start();
|
2020-10-01 07:02:44 +00:00
|
|
|
} // if(this->SaveDotFiles)
|
2020-10-28 22:26:35 +00:00
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
// Log the timing stats we collected
|
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " ------------ Fan Out (block=" << blockData->BlockIndex
|
|
|
|
<< ") ------------" << std::endl
|
|
|
|
<< fanoutTimingsStream.str());
|
|
|
|
|
2020-10-28 22:26:35 +00:00
|
|
|
// Log the stats from the hierarchical contour tree
|
|
|
|
VTKM_LOG_S(this->TreeLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " ------------ Hierarchical Tree Construction Stats ------------"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42) << std::left << " BlockIndex"
|
|
|
|
<< ": " << blockData->BlockIndex << std::endl
|
|
|
|
<< hierarchicalTree.PrintTreeStats() << std::endl);
|
2020-10-28 14:48:21 +00:00
|
|
|
}); // master.foreach
|
|
|
|
|
2020-10-29 01:54:58 +00:00
|
|
|
// Clean-up
|
|
|
|
for (auto block : localDataBlocks)
|
|
|
|
delete block;
|
|
|
|
|
2020-10-28 14:48:21 +00:00
|
|
|
// 2.2 Log timings for fan out
|
2020-10-28 22:26:35 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Fan Out Foreach"
|
|
|
|
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
|
2020-11-04 01:37:57 +00:00
|
|
|
VTKM_LOG_S(this->TimingsLogLevel,
|
|
|
|
std::endl
|
|
|
|
<< " ------------ DoPostExecute Timings ------------" << std::endl
|
|
|
|
<< timingsStream.str());
|
2020-09-15 17:57:20 +00:00
|
|
|
|
2020-09-22 02:05:10 +00:00
|
|
|
result = vtkm::cont::PartitionedDataSet(hierarchicalTreeOutputDataSet);
|
2020-11-04 01:37:57 +00:00
|
|
|
} // DoPostExecute
|
2020-06-12 17:50:01 +00:00
|
|
|
|
|
|
|
} // namespace filter
|
|
|
|
} // namespace vtkm::filter
|
|
|
|
|
|
|
|
#endif
|