2018-08-08 18:38:06 +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.
|
2019-08-28 18:34:42 +00:00
|
|
|
//
|
|
|
|
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
|
|
|
|
// Copyright 2014 UT-Battelle, LLC.
|
|
|
|
// Copyright 2014 Los Alamos National Security.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-NA0003525 with NTESS,
|
|
|
|
// the U.S. Government retains certain rights in this software.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
|
|
|
// Laboratory (LANL), the U.S. Government retains certain rights in
|
|
|
|
// this software.
|
2018-08-08 18:38:06 +00:00
|
|
|
//============================================================================
|
|
|
|
// 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)
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
#include <vtkm/Types.h>
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
|
|
#include <vtkm/cont/DataSet.h>
|
|
|
|
#include <vtkm/cont/DataSetBuilderUniform.h>
|
|
|
|
#include <vtkm/cont/DataSetFieldAdd.h>
|
2020-01-22 01:31:44 +00:00
|
|
|
#include <vtkm/cont/Initialize.h>
|
2019-08-28 18:34:42 +00:00
|
|
|
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
2018-08-08 18:38:06 +00:00
|
|
|
#include <vtkm/cont/Timer.h>
|
2018-09-26 17:48:37 +00:00
|
|
|
#include <vtkm/filter/ContourTreeUniformAugmented.h>
|
|
|
|
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
|
|
|
|
#include <vtkm/worklet/contourtree_augmented/ProcessContourTree.h>
|
|
|
|
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
2019-08-28 18:34:42 +00:00
|
|
|
#include <vtkm/worklet/contourtree_augmented/processcontourtree/Branch.h>
|
|
|
|
|
|
|
|
#ifdef ENABLE_SET_NUM_THREADS
|
|
|
|
#include "tbb/task_scheduler_init.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
#ifdef WITH_MPI
|
|
|
|
#include <mpi.h>
|
|
|
|
#endif
|
2018-08-08 18:38:06 +00:00
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iostream>
|
2020-01-22 03:38:29 +00:00
|
|
|
#include <sstream>
|
2019-08-28 18:34:42 +00:00
|
|
|
#include <stdio.h>
|
2018-08-08 18:38:06 +00:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
using ValueType = vtkm::Float32;
|
|
|
|
using BranchType = vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch<ValueType>;
|
|
|
|
|
2020-01-22 09:40:49 +00:00
|
|
|
namespace ctaug_ns = vtkm::worklet::contourtree_augmented;
|
2018-08-08 18:38:06 +00:00
|
|
|
|
|
|
|
// Simple helper class for parsing the command line options
|
|
|
|
class ParseCL
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ParseCL() {}
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
void parse(int& argc, char** argv)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2019-08-28 18:34:42 +00:00
|
|
|
mCLOptions.resize(static_cast<std::size_t>(argc));
|
|
|
|
for (std::size_t i = 1; i < static_cast<std::size_t>(argc); ++i)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
|
|
|
this->mCLOptions[i] = std::string(argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vtkm::Id findOption(const std::string& option) const
|
|
|
|
{
|
|
|
|
auto it =
|
|
|
|
std::find_if(this->mCLOptions.begin(),
|
|
|
|
this->mCLOptions.end(),
|
|
|
|
[option](const std::string& val) -> bool { return val.find(option) == 0; });
|
|
|
|
if (it == this->mCLOptions.end())
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-08-28 18:34:42 +00:00
|
|
|
return (it - this->mCLOptions.begin());
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasOption(const std::string& option) const { return this->findOption(option) >= 0; }
|
|
|
|
|
|
|
|
std::string getOption(const std::string& option) const
|
|
|
|
{
|
2019-09-07 00:48:45 +00:00
|
|
|
std::size_t index = static_cast<std::size_t>(this->findOption(option));
|
2019-09-25 15:50:00 +00:00
|
|
|
std::string val = this->mCLOptions[index];
|
|
|
|
auto valPos = val.find("=");
|
|
|
|
if (valPos)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2019-09-25 15:50:00 +00:00
|
|
|
return val.substr(valPos + 1);
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
|
|
|
return std::string("");
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<std::string>& getOptions() const { return this->mCLOptions; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<std::string> mCLOptions;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compute and render an isosurface for a uniform grid example
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
// Setup the MPI environment.
|
|
|
|
MPI_Init(&argc, &argv);
|
|
|
|
auto comm = MPI_COMM_WORLD;
|
|
|
|
|
|
|
|
// Tell VTK-m which communicator it should use.
|
|
|
|
vtkm::cont::EnvironmentTracker::SetCommunicator(vtkmdiy::mpi::communicator(comm));
|
|
|
|
|
|
|
|
// get the rank and size
|
|
|
|
int rank, size;
|
|
|
|
MPI_Comm_rank(comm, &rank);
|
|
|
|
MPI_Comm_size(comm, &size);
|
|
|
|
int numBlocks = size;
|
|
|
|
int blocksPerRank = 1;
|
|
|
|
#endif
|
2019-04-09 13:52:53 +00:00
|
|
|
|
2020-01-22 01:31:44 +00:00
|
|
|
// initialize vtkm-m (e.g., logging via -v and device via the -d option)
|
|
|
|
vtkm::cont::InitializeOptions vtkm_initialize_options =
|
|
|
|
vtkm::cont::InitializeOptions::RequireDevice;
|
|
|
|
vtkm::cont::InitializeResult vtkm_config =
|
|
|
|
vtkm::cont::Initialize(argc, argv, vtkm_initialize_options);
|
|
|
|
auto device = vtkm_config.Device;
|
|
|
|
|
2020-01-22 03:38:29 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Info, rank == 0, "Running with MPI. #ranks=" << size);
|
|
|
|
#else
|
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Single node run");
|
|
|
|
int rank = 0;
|
|
|
|
#endif
|
|
|
|
|
2020-01-22 01:31:44 +00:00
|
|
|
// Setup timing
|
2018-08-08 18:38:06 +00:00
|
|
|
vtkm::Float64 prevTime = 0;
|
|
|
|
vtkm::Float64 currTime = 0;
|
2019-08-28 18:34:42 +00:00
|
|
|
vtkm::cont::Timer totalTime;
|
|
|
|
|
|
|
|
totalTime.Start();
|
2018-08-08 18:38:06 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////
|
|
|
|
// Parse the command line options
|
|
|
|
////////////////////////////////////////////
|
|
|
|
ParseCL parser;
|
2019-08-28 18:34:42 +00:00
|
|
|
parser.parse(argc, argv);
|
2018-08-08 18:38:06 +00:00
|
|
|
std::string filename = parser.getOptions().back();
|
2019-09-07 00:48:45 +00:00
|
|
|
unsigned int computeRegularStructure = 1; // 1=fully augmented
|
2018-08-08 18:38:06 +00:00
|
|
|
bool useMarchingCubes = false;
|
|
|
|
bool computeBranchDecomposition = true;
|
|
|
|
bool printContourTree = false;
|
|
|
|
if (parser.hasOption("--augmentTree"))
|
2019-09-07 00:48:45 +00:00
|
|
|
computeRegularStructure =
|
|
|
|
static_cast<unsigned int>(std::stoi(parser.getOption("--augmentTree")));
|
2018-08-08 18:38:06 +00:00
|
|
|
if (parser.hasOption("--mc"))
|
|
|
|
useMarchingCubes = true;
|
|
|
|
if (parser.hasOption("--printCT"))
|
|
|
|
printContourTree = true;
|
|
|
|
if (parser.hasOption("--branchDecomp"))
|
|
|
|
computeBranchDecomposition = std::stoi(parser.getOption("--branchDecomp"));
|
2019-09-07 00:48:45 +00:00
|
|
|
// We need the fully augmented tree to compute the branch decomposition
|
|
|
|
if (computeBranchDecomposition && (computeRegularStructure != 1))
|
2019-08-28 18:34:42 +00:00
|
|
|
{
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
|
|
|
"Regular structure is required for branch decomposition."
|
|
|
|
" Disabling branch decomposition");
|
2019-08-28 18:34:42 +00:00
|
|
|
computeBranchDecomposition = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-08 18:38:06 +00:00
|
|
|
#ifdef ENABLE_SET_NUM_THREADS
|
|
|
|
int numThreads = tbb::task_scheduler_init::default_num_threads();
|
|
|
|
if (parser.hasOption("--numThreads"))
|
2019-08-28 18:34:42 +00:00
|
|
|
{
|
2020-01-22 01:31:44 +00:00
|
|
|
// Print warning about mismatch between the --numThreads and -d/--device opton
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S_IF(vtkm::cont::LogLevel::Warn,
|
|
|
|
device != vtkm::cont::DeviceAdapterTagTBB,
|
|
|
|
"WARNING: Mismatch between --numThreads and -d/--device option."
|
|
|
|
"numThreads option requires the use of TBB as device. "
|
|
|
|
"Ignoring the numThread option.");
|
|
|
|
// Set the number of threads to be used for TBB
|
|
|
|
if (device == vtkm::cont::DeviceAdapterTagTBB)
|
2019-08-28 18:34:42 +00:00
|
|
|
{
|
2020-01-22 01:31:44 +00:00
|
|
|
numThreads = std::stoi(parser.getOption("--numThreads"));
|
|
|
|
tbb::task_scheduler_init schedulerInit(numThreads);
|
2019-08-28 18:34:42 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-08 18:38:06 +00:00
|
|
|
#endif
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
// Iso value selection parameters
|
|
|
|
// Approach to be used to select contours based on the tree
|
|
|
|
vtkm::Id contourType = 0;
|
|
|
|
// Error away from critical point
|
|
|
|
ValueType eps = 0.00001f;
|
|
|
|
// Number of iso levels to be selected. By default we disable the isovalue selection.
|
|
|
|
vtkm::Id numLevels = 0;
|
|
|
|
// Number of components the tree should be simplified to
|
|
|
|
vtkm::Id numComp = numLevels + 1;
|
|
|
|
// Method to be used to compute the relevant iso values
|
|
|
|
vtkm::Id contourSelectMethod = 0;
|
|
|
|
bool usePersistenceSorter = true;
|
|
|
|
if (parser.hasOption("--levels"))
|
|
|
|
numLevels = std::stoi(parser.getOption("--levels"));
|
|
|
|
if (parser.hasOption("--type"))
|
|
|
|
contourType = std::stoi(parser.getOption("--type"));
|
|
|
|
if (parser.hasOption("--eps"))
|
|
|
|
eps = std::stof(parser.getOption("--eps"));
|
|
|
|
if (parser.hasOption("--method"))
|
|
|
|
contourSelectMethod = std::stoi(parser.getOption("--method"));
|
|
|
|
if (parser.hasOption("--comp"))
|
|
|
|
numComp = std::stoi(parser.getOption("--comp"));
|
|
|
|
if (contourSelectMethod == 0)
|
|
|
|
numComp = numLevels + 1;
|
|
|
|
if (parser.hasOption("--useVolumeSorter"))
|
|
|
|
usePersistenceSorter = false;
|
|
|
|
if ((numLevels > 0) && (!computeBranchDecomposition))
|
|
|
|
{
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
|
|
|
"Iso level selection only available when branch decomposition is enabled. "
|
|
|
|
"Disabling iso value selection");
|
2019-08-28 18:34:42 +00:00
|
|
|
numLevels = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rank == 0 && (argc < 2 || parser.hasOption("--help") || parser.hasOption("-h")))
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2020-01-22 03:38:29 +00:00
|
|
|
std::cout << "ContourTreeAugmented <options> <fileName>" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << "<fileName> Name of the input data file." << std::endl;
|
|
|
|
std::cout << "The file is expected to be ASCII with either: " << std::endl;
|
2018-08-08 18:38:06 +00:00
|
|
|
std::cout << " - xdim ydim integers for 2D or" << std::endl;
|
|
|
|
std::cout << " - xdim ydim zdim integers for 3D" << std::endl;
|
|
|
|
std::cout << "followed by vector data last dimension varying fastest" << std::endl;
|
|
|
|
std::cout << std::endl;
|
2020-01-22 01:31:44 +00:00
|
|
|
std::cout << "----------------------------- VTKM Options -----------------------------"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << vtkm_config.Usage << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << "------------------------- Contour Tree Options -------------------------"
|
|
|
|
<< std::endl;
|
2018-08-08 18:38:06 +00:00
|
|
|
std::cout << "Options: (Bool options are give via int, i.e. =0 for False and =1 for True)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--mc Use marching cubes interpolation for contour tree calculation. "
|
|
|
|
"(Default=False)"
|
|
|
|
<< std::endl;
|
2019-09-07 00:48:45 +00:00
|
|
|
std::cout << "--augmentTree 1 = compute the fully augmented contour tree (Default)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << " 2 = compute the boundary augmented contour tree " << std::endl;
|
|
|
|
std::cout << " 0 = no augmentation. NOTE: When using MPI, local ranks use"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << " boundary augmentation to support parallel merge of blocks"
|
2018-08-08 18:38:06 +00:00
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--branchDecomp Compute the volume branch decomposition for the contour tree. "
|
|
|
|
"Requires --augmentTree (Default=True)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--printCT Print the contour tree. (Default=False)" << std::endl;
|
|
|
|
#ifdef ENABLE_SET_NUM_THREADS
|
2019-08-28 18:34:42 +00:00
|
|
|
std::cout << "--numThreads Specifiy the number of threads to use. Available only with TBB."
|
2018-08-08 18:38:06 +00:00
|
|
|
<< std::endl;
|
|
|
|
#endif
|
2019-08-28 18:34:42 +00:00
|
|
|
std::cout << std::endl;
|
2020-01-22 01:31:44 +00:00
|
|
|
std::cout << "---------------------- Isovalue Selection Options ----------------------"
|
|
|
|
<< std::endl;
|
2019-08-28 18:34:42 +00:00
|
|
|
std::cout << "Isovalue selection options: (require --branchDecomp=1 and augmentTree=1)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--levels=<int> Number of iso-contour levels to be used (default=0, i.e., "
|
|
|
|
"disable isovalue computation)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--comp=<int> Number of components the contour tree should be simplified to. "
|
|
|
|
"Only used if method==1. (default=0)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout
|
|
|
|
<< "--eps=<float> Floating point offset awary from the critical point. (default=0.00001)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--type=<int> Approach to be used for selection of iso-values. 0=saddle+-eps; "
|
|
|
|
"1=mid point between saddle and extremum, 2=extremum+-eps. (default=0)"
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << "--method=<int> Method used for selecting relevant iso-values. (default=0)"
|
|
|
|
<< std::endl;
|
2020-01-22 01:31:44 +00:00
|
|
|
std::cout << std::endl;
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
MPI_Finalize();
|
|
|
|
#endif
|
|
|
|
return EXIT_SUCCESS;
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
if (rank == 0)
|
|
|
|
{
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
|
|
|
std::endl
|
|
|
|
<< " ------------ Settings -----------"
|
|
|
|
<< std::endl
|
|
|
|
<< " filename="
|
|
|
|
<< filename
|
|
|
|
<< std::endl
|
|
|
|
<< " device="
|
|
|
|
<< device.GetName()
|
|
|
|
<< std::endl
|
|
|
|
<< " mc="
|
|
|
|
<< useMarchingCubes
|
|
|
|
<< std::endl
|
|
|
|
<< " augmentTree="
|
|
|
|
<< computeRegularStructure
|
|
|
|
<< std::endl
|
|
|
|
<< " branchDecomp="
|
|
|
|
<< computeBranchDecomposition
|
|
|
|
<< std::endl
|
|
|
|
<<
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
2020-01-22 03:38:29 +00:00
|
|
|
" nblocks=" << numBlocks << std::endl
|
|
|
|
<<
|
2019-08-28 18:34:42 +00:00
|
|
|
#endif
|
2018-08-08 18:38:06 +00:00
|
|
|
#ifdef ENABLE_SET_NUM_THREADS
|
2020-01-22 03:38:29 +00:00
|
|
|
" numThreads=" << numThreads << std::endl
|
|
|
|
<<
|
2018-08-08 18:38:06 +00:00
|
|
|
#endif
|
2020-01-22 03:38:29 +00:00
|
|
|
" computeIsovalues=" << (numLevels > 0));
|
|
|
|
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Info,
|
|
|
|
numLevels > 0,
|
2020-01-22 09:11:45 +00:00
|
|
|
std::endl
|
|
|
|
<< " ------------ Settings Isolevel Selection -----------"
|
|
|
|
<< std::endl
|
|
|
|
<< " levels="
|
|
|
|
<< numLevels
|
|
|
|
<< std::endl
|
|
|
|
<< " eps="
|
|
|
|
<< eps
|
|
|
|
<< std::endl
|
|
|
|
<< " comp"
|
|
|
|
<< numComp
|
|
|
|
<< std::endl
|
|
|
|
<< " type="
|
|
|
|
<< contourType
|
|
|
|
<< std::endl
|
|
|
|
<< " method="
|
|
|
|
<< contourSelectMethod
|
|
|
|
<< std::endl
|
|
|
|
<< " mc="
|
|
|
|
<< useMarchingCubes
|
|
|
|
<< std::endl
|
|
|
|
<< " use"
|
|
|
|
<< (usePersistenceSorter ? "PersistenceSorter" : "VolumeSorter"));
|
2019-08-28 18:34:42 +00:00
|
|
|
}
|
2018-08-08 18:38:06 +00:00
|
|
|
currTime = totalTime.GetElapsedTime();
|
|
|
|
vtkm::Float64 startUpTime = currTime - prevTime;
|
|
|
|
prevTime = currTime;
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
// Redirect stdout to file if we are using MPI with Debugging
|
|
|
|
#ifdef WITH_MPI
|
|
|
|
#ifdef DEBUG_PRINT
|
|
|
|
// From https://www.unix.com/302983597-post2.html
|
|
|
|
char* cstr_filename = new char[15];
|
|
|
|
snprintf(cstr_filename, sizeof(filename), "cout_%d.log", rank);
|
|
|
|
int out = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
|
|
|
|
if (-1 == out)
|
|
|
|
{
|
|
|
|
perror("opening cout.log");
|
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(cstr_filename, sizeof(cstr_filename), "cerr_%d.log", rank);
|
|
|
|
int err = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
|
|
|
|
if (-1 == err)
|
|
|
|
{
|
|
|
|
perror("opening cerr.log");
|
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
int save_out = dup(fileno(stdout));
|
|
|
|
int save_err = dup(fileno(stderr));
|
|
|
|
|
|
|
|
if (-1 == dup2(out, fileno(stdout)))
|
|
|
|
{
|
|
|
|
perror("cannot redirect stdout");
|
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
if (-1 == dup2(err, fileno(stderr)))
|
|
|
|
{
|
|
|
|
perror("cannot redirect stderr");
|
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] cstr_filename;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-08-08 18:38:06 +00:00
|
|
|
///////////////////////////////////////////////
|
|
|
|
// Read the input data
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
std::ifstream inFile(filename);
|
|
|
|
if (inFile.bad())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Read the dimensions of the mesh, i.e,. number of elementes in x, y, and z
|
2019-08-28 18:34:42 +00:00
|
|
|
std::vector<std::size_t> dims;
|
2018-08-08 18:38:06 +00:00
|
|
|
std::string line;
|
|
|
|
getline(inFile, line);
|
|
|
|
std::istringstream linestream(line);
|
2019-08-28 18:34:42 +00:00
|
|
|
std::size_t dimVertices;
|
2018-08-08 18:38:06 +00:00
|
|
|
while (linestream >> dimVertices)
|
|
|
|
{
|
|
|
|
dims.push_back(dimVertices);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the number of vertices, i.e., xdim * ydim * zdim
|
2019-08-28 18:34:42 +00:00
|
|
|
unsigned short nDims = static_cast<unsigned short>(dims.size());
|
2020-01-23 08:03:36 +00:00
|
|
|
std::size_t numVertices = static_cast<std::size_t>(
|
2020-02-10 23:31:00 +00:00
|
|
|
std::accumulate(dims.begin(), dims.end(), std::size_t(1), std::multiplies<std::size_t>()));
|
2018-08-08 18:38:06 +00:00
|
|
|
|
|
|
|
// Print the mesh metadata
|
2019-08-28 18:34:42 +00:00
|
|
|
if (rank == 0)
|
|
|
|
{
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
|
|
|
std::endl
|
2020-01-22 09:11:45 +00:00
|
|
|
<< " ---------------- Input Mesh Properties --------------"
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< " Number of dimensions: "
|
|
|
|
<< nDims
|
|
|
|
<< std::endl
|
|
|
|
<< " Number of mesh vertices: "
|
2020-01-23 08:03:36 +00:00
|
|
|
<< numVertices
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl);
|
2019-08-28 18:34:42 +00:00
|
|
|
}
|
2020-01-22 03:38:29 +00:00
|
|
|
|
|
|
|
// Check for fatal input errors
|
2018-08-08 18:38:06 +00:00
|
|
|
// Check the the number of dimensiosn is either 2D or 3D
|
2019-08-28 18:34:42 +00:00
|
|
|
bool invalidNumDimensions = (nDims < 2 || nDims > 3);
|
2020-01-22 03:38:29 +00:00
|
|
|
// Check if marching cubes is enabled for non 3D data
|
2019-08-28 18:34:42 +00:00
|
|
|
bool invalidMCOption = (useMarchingCubes && nDims != 3);
|
2020-01-22 03:38:29 +00:00
|
|
|
// Log any errors if found on rank 0
|
|
|
|
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
|
|
|
invalidNumDimensions && (rank == 0),
|
|
|
|
"The input mesh is " << nDims << "D. "
|
|
|
|
"The input data must be either 2D or 3D.");
|
|
|
|
VTKM_LOG_IF_S(
|
|
|
|
vtkm::cont::LogLevel::Error,
|
|
|
|
invalidMCOption && (rank == 0),
|
|
|
|
"The input mesh is " << nDims << "D. "
|
|
|
|
<< "Contour tree using marching cubes is only supported for 3D data.");
|
|
|
|
// If we found any errors in the setttings than finalize MPI and exit the execution
|
2019-08-28 18:34:42 +00:00
|
|
|
if (invalidNumDimensions || invalidMCOption)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
MPI_Finalize();
|
|
|
|
#endif
|
|
|
|
return EXIT_SUCCESS;
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
// Read data
|
2020-01-23 08:03:36 +00:00
|
|
|
std::vector<ValueType> values(numVertices);
|
|
|
|
for (std::size_t vertex = 0; vertex < numVertices; ++vertex)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
|
|
|
inFile >> values[vertex];
|
|
|
|
}
|
|
|
|
|
|
|
|
// finish reading the data
|
|
|
|
inFile.close();
|
|
|
|
|
|
|
|
currTime = totalTime.GetElapsedTime();
|
|
|
|
vtkm::Float64 dataReadTime = currTime - prevTime;
|
|
|
|
prevTime = currTime;
|
2019-08-28 18:34:42 +00:00
|
|
|
|
2018-08-08 18:38:06 +00:00
|
|
|
vtkm::cont::DataSetBuilderUniform dsb;
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifndef WITH_MPI // construct regular, single-block VTK-M input dataset
|
|
|
|
vtkm::cont::DataSet inDataSet; // Single block dataset
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2019-08-28 18:34:42 +00:00
|
|
|
// build the input dataset
|
|
|
|
// 2D data
|
|
|
|
if (nDims == 2)
|
|
|
|
{
|
|
|
|
vtkm::Id2 vdims;
|
2019-11-20 13:17:46 +00:00
|
|
|
vdims[0] = static_cast<vtkm::Id>(dims[1]);
|
|
|
|
vdims[1] = static_cast<vtkm::Id>(dims[0]);
|
2019-08-28 18:34:42 +00:00
|
|
|
inDataSet = dsb.Create(vdims);
|
|
|
|
}
|
|
|
|
// 3D data
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vtkm::Id3 vdims;
|
2019-11-20 13:17:46 +00:00
|
|
|
vdims[0] = static_cast<vtkm::Id>(dims[1]);
|
|
|
|
vdims[1] = static_cast<vtkm::Id>(dims[0]);
|
2019-08-28 18:34:42 +00:00
|
|
|
vdims[2] = static_cast<vtkm::Id>(dims[2]);
|
|
|
|
inDataSet = dsb.Create(vdims);
|
|
|
|
}
|
|
|
|
vtkm::cont::DataSetFieldAdd dsf;
|
|
|
|
dsf.AddPointField(inDataSet, "values", values);
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
2019-08-28 18:34:42 +00:00
|
|
|
#else // Create a multi-block dataset for multi-block DIY-paralle processing
|
2019-09-17 15:42:19 +00:00
|
|
|
vtkm::cont::PartitionedDataSet inDataSet; // Partitioned variant of the input dataset
|
2019-08-28 18:34:42 +00:00
|
|
|
vtkm::Id3 blocksPerDim =
|
|
|
|
nDims == 3 ? vtkm::Id3(1, 1, numBlocks) : vtkm::Id3(1, numBlocks, 1); // Decompose the data into
|
|
|
|
vtkm::Id3 globalSize = nDims == 3 ? vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
|
|
|
|
static_cast<vtkm::Id>(dims[1]),
|
|
|
|
static_cast<vtkm::Id>(dims[2]))
|
|
|
|
: vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
|
|
|
|
static_cast<vtkm::Id>(dims[1]),
|
|
|
|
static_cast<vtkm::Id>(0));
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
|
|
|
|
localBlockIndices.Allocate(blocksPerRank);
|
|
|
|
localBlockOrigins.Allocate(blocksPerRank);
|
|
|
|
localBlockSizes.Allocate(blocksPerRank);
|
2020-01-28 19:14:32 +00:00
|
|
|
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
|
|
|
|
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
|
|
|
|
auto localBlockSizesPortal = localBlockSizes.WritePortal();
|
2019-08-28 18:34:42 +00:00
|
|
|
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2019-08-28 18:34:42 +00:00
|
|
|
vtkm::Id lastDimSize =
|
|
|
|
(nDims == 2) ? static_cast<vtkm::Id>(dims[1]) : static_cast<vtkm::Id>(dims[2]);
|
|
|
|
if (size > (lastDimSize / 2.))
|
|
|
|
{
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
|
|
|
rank == 0,
|
|
|
|
"Number of ranks to large for data. Use " << lastDimSize / 2
|
|
|
|
<< "or fewer ranks");
|
2019-08-28 18:34:42 +00:00
|
|
|
MPI_Finalize();
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
vtkm::Id standardBlockSize = (vtkm::Id)(lastDimSize / numBlocks);
|
|
|
|
vtkm::Id blockSize = standardBlockSize;
|
|
|
|
vtkm::Id blockSliceSize =
|
|
|
|
nDims == 2 ? static_cast<vtkm::Id>(dims[0]) : static_cast<vtkm::Id>((dims[0] * dims[1]));
|
|
|
|
vtkm::Id blockNumValues = blockSize * blockSliceSize;
|
|
|
|
|
|
|
|
vtkm::Id startBlock = blocksPerRank * rank;
|
|
|
|
vtkm::Id endBlock = startBlock + blocksPerRank;
|
|
|
|
for (vtkm::Id blockIndex = startBlock; blockIndex < endBlock; ++blockIndex)
|
|
|
|
{
|
|
|
|
vtkm::Id localBlockIndex = blockIndex - startBlock;
|
|
|
|
vtkm::Id blockStart = blockIndex * blockNumValues;
|
|
|
|
vtkm::Id blockEnd = blockStart + blockNumValues;
|
|
|
|
if (blockIndex < (numBlocks - 1)) // add overlap between regions
|
|
|
|
{
|
|
|
|
blockEnd += blockSliceSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blockEnd = lastDimSize * blockSliceSize;
|
|
|
|
}
|
|
|
|
vtkm::Id currBlockSize = (vtkm::Id)((blockEnd - blockStart) / blockSliceSize);
|
|
|
|
|
|
|
|
vtkm::cont::DataSet ds;
|
|
|
|
|
|
|
|
// 2D data
|
|
|
|
if (nDims == 2)
|
|
|
|
{
|
|
|
|
vtkm::Id2 vdims;
|
|
|
|
vdims[0] = static_cast<vtkm::Id>(currBlockSize);
|
|
|
|
vdims[1] = static_cast<vtkm::Id>(dims[0]);
|
|
|
|
vtkm::Vec<ValueType, 2> origin(0, blockIndex * blockSize);
|
|
|
|
vtkm::Vec<ValueType, 2> spacing(1, 1);
|
|
|
|
ds = dsb.Create(vdims, origin, spacing);
|
|
|
|
|
|
|
|
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(blockIndex, 0, 0));
|
|
|
|
localBlockOriginsPortal.Set(localBlockIndex,
|
|
|
|
vtkm::Id3((blockStart / blockSliceSize), 0, 0));
|
|
|
|
localBlockSizesPortal.Set(localBlockIndex,
|
|
|
|
vtkm::Id3(currBlockSize, static_cast<vtkm::Id>(dims[0]), 0));
|
|
|
|
}
|
|
|
|
// 3D data
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vtkm::Id3 vdims;
|
|
|
|
vdims[0] = static_cast<vtkm::Id>(dims[0]);
|
|
|
|
vdims[1] = static_cast<vtkm::Id>(dims[1]);
|
|
|
|
vdims[2] = static_cast<vtkm::Id>(currBlockSize);
|
|
|
|
vtkm::Vec<ValueType, 3> origin(0, 0, (blockIndex * blockSize));
|
|
|
|
vtkm::Vec<ValueType, 3> spacing(1, 1, 1);
|
|
|
|
ds = dsb.Create(vdims, origin, spacing);
|
|
|
|
|
|
|
|
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, 0, blockIndex));
|
|
|
|
localBlockOriginsPortal.Set(localBlockIndex,
|
|
|
|
vtkm::Id3(0, 0, (blockStart / blockSliceSize)));
|
|
|
|
localBlockSizesPortal.Set(
|
|
|
|
localBlockIndex,
|
|
|
|
vtkm::Id3(static_cast<vtkm::Id>(dims[0]), static_cast<vtkm::Id>(dims[1]), currBlockSize));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
|
|
|
|
(values.begin() + blockEnd));
|
|
|
|
|
|
|
|
vtkm::cont::DataSetFieldAdd dsf;
|
|
|
|
dsf.AddPointField(ds, "values", subValues);
|
2019-09-17 15:42:19 +00:00
|
|
|
inDataSet.AppendPartition(ds);
|
2019-08-28 18:34:42 +00:00
|
|
|
}
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
2019-08-28 18:34:42 +00:00
|
|
|
#endif // WITH_MPI construct input dataset
|
2018-08-08 18:38:06 +00:00
|
|
|
|
|
|
|
currTime = totalTime.GetElapsedTime();
|
|
|
|
vtkm::Float64 buildDatasetTime = currTime - prevTime;
|
|
|
|
prevTime = currTime;
|
|
|
|
|
|
|
|
// Convert the mesh of values into contour tree, pairs of vertex ids
|
2020-01-22 09:40:49 +00:00
|
|
|
vtkm::filter::ContourTreeAugmented filter(useMarchingCubes, computeRegularStructure);
|
2019-08-28 18:34:42 +00:00
|
|
|
|
|
|
|
#ifdef WITH_MPI
|
|
|
|
filter.SetSpatialDecomposition(
|
|
|
|
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
|
|
|
|
#endif
|
2018-08-08 18:38:06 +00:00
|
|
|
filter.SetActiveField("values");
|
2019-08-28 18:34:42 +00:00
|
|
|
|
|
|
|
// Execute the contour tree analysis. NOTE: If MPI is used the result will be
|
2019-09-17 17:18:40 +00:00
|
|
|
// a vtkm::cont::PartitionedDataSet instead of a vtkm::cont::DataSet
|
2019-08-28 18:34:42 +00:00
|
|
|
auto result = filter.Execute(inDataSet);
|
2018-08-08 18:38:06 +00:00
|
|
|
|
|
|
|
currTime = totalTime.GetElapsedTime();
|
|
|
|
vtkm::Float64 computeContourTreeTime = currTime - prevTime;
|
|
|
|
prevTime = currTime;
|
|
|
|
|
|
|
|
////////////////////////////////////////////
|
|
|
|
// Compute the branch decomposition
|
|
|
|
////////////////////////////////////////////
|
2019-08-28 18:34:42 +00:00
|
|
|
if (rank == 0 && computeBranchDecomposition && computeRegularStructure)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
2020-01-22 09:22:54 +00:00
|
|
|
// Time branch decompostion
|
2019-02-06 16:16:10 +00:00
|
|
|
vtkm::cont::Timer branchDecompTimer;
|
|
|
|
branchDecompTimer.Start();
|
2018-08-08 18:38:06 +00:00
|
|
|
// compute the volume for each hyperarc and superarc
|
2020-01-22 09:40:49 +00:00
|
|
|
ctaug_ns::IdArrayType superarcIntrinsicWeight;
|
|
|
|
ctaug_ns::IdArrayType superarcDependentWeight;
|
|
|
|
ctaug_ns::IdArrayType supernodeTransferWeight;
|
|
|
|
ctaug_ns::IdArrayType hyperarcDependentWeight;
|
|
|
|
ctaug_ns::ProcessContourTree::ComputeVolumeWeights(filter.GetContourTree(),
|
2018-08-30 15:53:18 +00:00
|
|
|
filter.GetNumIterations(),
|
|
|
|
superarcIntrinsicWeight, // (output)
|
|
|
|
superarcDependentWeight, // (output)
|
|
|
|
supernodeTransferWeight, // (output)
|
|
|
|
hyperarcDependentWeight); // (output)
|
2020-01-22 09:22:54 +00:00
|
|
|
// Record the timings for the branch decomposition
|
2020-01-22 09:11:45 +00:00
|
|
|
std::stringstream timingsStream; // Use a string stream to log in one message
|
2020-01-22 03:38:29 +00:00
|
|
|
timingsStream << std::endl;
|
|
|
|
timingsStream << " --------------- Branch Decomposition Timings " << rank
|
|
|
|
<< " --------------" << std::endl;
|
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Compute Volume Weights"
|
|
|
|
<< ": " << branchDecompTimer.GetElapsedTime() << " seconds" << std::endl;
|
2019-02-06 16:16:10 +00:00
|
|
|
branchDecompTimer.Start();
|
2020-01-22 09:22:54 +00:00
|
|
|
|
2018-08-08 18:38:06 +00:00
|
|
|
// compute the branch decomposition by volume
|
2020-01-22 09:40:49 +00:00
|
|
|
ctaug_ns::IdArrayType whichBranch;
|
|
|
|
ctaug_ns::IdArrayType branchMinimum;
|
|
|
|
ctaug_ns::IdArrayType branchMaximum;
|
|
|
|
ctaug_ns::IdArrayType branchSaddle;
|
|
|
|
ctaug_ns::IdArrayType branchParent;
|
|
|
|
ctaug_ns::ProcessContourTree::ComputeVolumeBranchDecomposition(filter.GetContourTree(),
|
2018-08-30 15:53:18 +00:00
|
|
|
superarcDependentWeight,
|
|
|
|
superarcIntrinsicWeight,
|
|
|
|
whichBranch, // (output)
|
|
|
|
branchMinimum, // (output)
|
|
|
|
branchMaximum, // (output)
|
|
|
|
branchSaddle, // (output)
|
|
|
|
branchParent); // (output)
|
2020-01-22 09:22:54 +00:00
|
|
|
// Record and log the branch decompostion timings
|
2020-01-22 03:38:29 +00:00
|
|
|
timingsStream << " " << std::setw(38) << std::left << "Compute Volume Branch Decomposition"
|
|
|
|
<< ": " << branchDecompTimer.GetElapsedTime() << " seconds" << std::endl;
|
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info, timingsStream.str());
|
2019-08-28 18:34:42 +00:00
|
|
|
|
|
|
|
//----main branch decompostion end
|
|
|
|
//----Isovalue seleciton start
|
|
|
|
if (numLevels > 0) // if compute isovalues
|
|
|
|
{
|
|
|
|
// Get the data values for computing the explicit branch decomposition
|
|
|
|
// TODO Can we cast the handle we get from GetData() instead of doing a CopyTo?
|
|
|
|
#ifdef WITH_MPI
|
|
|
|
vtkm::cont::ArrayHandle<ValueType> dataField;
|
2019-09-17 15:42:19 +00:00
|
|
|
result.GetPartitions()[0].GetField(0).GetData().CopyTo(dataField);
|
2019-08-28 18:34:42 +00:00
|
|
|
bool dataFieldIsSorted = true;
|
|
|
|
#else
|
|
|
|
vtkm::cont::ArrayHandle<ValueType> dataField;
|
|
|
|
inDataSet.GetField(0).GetData().CopyTo(dataField);
|
|
|
|
bool dataFieldIsSorted = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// create explicit representation of the branch decompostion from the array representation
|
|
|
|
BranchType* branchDecompostionRoot =
|
2020-01-22 09:40:49 +00:00
|
|
|
ctaug_ns::ProcessContourTree::ComputeBranchDecomposition<ValueType>(
|
2020-01-23 18:46:56 +00:00
|
|
|
filter.GetContourTree().Superparents,
|
|
|
|
filter.GetContourTree().Supernodes,
|
2019-08-28 18:34:42 +00:00
|
|
|
whichBranch,
|
|
|
|
branchMinimum,
|
|
|
|
branchMaximum,
|
|
|
|
branchSaddle,
|
|
|
|
branchParent,
|
|
|
|
filter.GetSortOrder(),
|
|
|
|
dataField,
|
|
|
|
dataFieldIsSorted);
|
|
|
|
|
|
|
|
#ifdef DEBUG_PRINT
|
2020-01-22 22:54:52 +00:00
|
|
|
branchDecompostionRoot->PrintBranchDecomposition(std::cout);
|
2019-08-28 18:34:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Simplify the contour tree of the branch decompostion
|
2020-01-22 22:54:52 +00:00
|
|
|
branchDecompostionRoot->SimplifyToSize(numComp, usePersistenceSorter);
|
2019-08-28 18:34:42 +00:00
|
|
|
|
|
|
|
// Compute the relevant iso-values
|
|
|
|
std::vector<ValueType> isoValues;
|
|
|
|
switch (contourSelectMethod)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case 0:
|
|
|
|
{
|
2020-01-22 22:54:52 +00:00
|
|
|
branchDecompostionRoot->GetRelevantValues(static_cast<int>(contourType), eps, isoValues);
|
2019-08-28 18:34:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
vtkm::worklet::contourtree_augmented::process_contourtree_inc::PiecewiseLinearFunction<
|
|
|
|
ValueType>
|
|
|
|
plf;
|
2020-01-22 22:54:52 +00:00
|
|
|
branchDecompostionRoot->AccumulateIntervals(static_cast<int>(contourType), eps, plf);
|
2019-08-28 18:34:42 +00:00
|
|
|
isoValues = plf.nLargest(static_cast<unsigned int>(numLevels));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print the compute iso values
|
2020-01-22 03:38:29 +00:00
|
|
|
std::stringstream isoStream; // Use a string stream to log in one message
|
|
|
|
isoStream << std::endl;
|
|
|
|
isoStream << " ------------------- Isovalue Suggestions --------------------" << std::endl;
|
2019-08-28 18:34:42 +00:00
|
|
|
std::sort(isoValues.begin(), isoValues.end());
|
2020-01-22 03:38:29 +00:00
|
|
|
isoStream << " Isovalues: ";
|
2019-08-28 18:34:42 +00:00
|
|
|
for (ValueType val : isoValues)
|
2020-01-22 03:38:29 +00:00
|
|
|
{
|
|
|
|
isoStream << val << " ";
|
|
|
|
}
|
|
|
|
isoStream << std::endl;
|
2019-08-28 18:34:42 +00:00
|
|
|
// Unique isovalues
|
|
|
|
std::vector<ValueType>::iterator it = std::unique(isoValues.begin(), isoValues.end());
|
|
|
|
isoValues.resize(static_cast<std::size_t>(std::distance(isoValues.begin(), it)));
|
2020-01-22 03:38:29 +00:00
|
|
|
isoStream << " Unique Isovalues (" << isoValues.size() << "):";
|
2019-08-28 18:34:42 +00:00
|
|
|
for (ValueType val : isoValues)
|
2020-01-22 03:38:29 +00:00
|
|
|
{
|
|
|
|
isoStream << val << " ";
|
|
|
|
}
|
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info, isoStream.str());
|
2019-08-28 18:34:42 +00:00
|
|
|
} //end if compute isovalue
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
2019-08-28 18:34:42 +00:00
|
|
|
|
2018-08-08 18:38:06 +00:00
|
|
|
currTime = totalTime.GetElapsedTime();
|
|
|
|
vtkm::Float64 computeBranchDecompTime = currTime - prevTime;
|
|
|
|
prevTime = currTime;
|
|
|
|
|
|
|
|
//vtkm::cont::Field resultField = result.GetField();
|
|
|
|
//vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
|
|
|
|
//resultField.GetData().CopyTo(saddlePeak);
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
// Dump out contour tree for comparison
|
|
|
|
if (rank == 0 && printContourTree)
|
2018-08-08 18:38:06 +00:00
|
|
|
{
|
|
|
|
std::cout << "Contour Tree" << std::endl;
|
|
|
|
std::cout << "============" << std::endl;
|
2020-01-22 09:40:49 +00:00
|
|
|
ctaug_ns::EdgePairArray saddlePeak;
|
|
|
|
ctaug_ns::ProcessContourTree::CollectSortedSuperarcs(
|
2018-08-08 18:38:06 +00:00
|
|
|
filter.GetContourTree(), filter.GetSortOrder(), saddlePeak);
|
2020-01-23 07:30:44 +00:00
|
|
|
ctaug_ns::PrintEdgePairArray(saddlePeak);
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
// Force a simple round-robin on the ranks for the summary prints. Its not perfect for MPI but
|
|
|
|
// it works well enough to sort the summaries from the ranks for small-scale debugging.
|
|
|
|
if (rank > 0)
|
|
|
|
{
|
|
|
|
int temp;
|
|
|
|
MPI_Status status;
|
|
|
|
MPI_Recv(&temp, 1, MPI_INT, (rank - 1), 0, comm, &status);
|
|
|
|
}
|
|
|
|
#endif
|
2018-08-08 18:38:06 +00:00
|
|
|
currTime = totalTime.GetElapsedTime();
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
|
|
|
std::endl
|
|
|
|
<< " -------------------------- Totals "
|
|
|
|
<< rank
|
|
|
|
<< " -----------------------------"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " Start-up"
|
|
|
|
<< ": "
|
|
|
|
<< startUpTime
|
|
|
|
<< " seconds"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " Data Read"
|
|
|
|
<< ": "
|
|
|
|
<< dataReadTime
|
|
|
|
<< " seconds"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " Build VTKM Dataset"
|
|
|
|
<< ": "
|
|
|
|
<< buildDatasetTime
|
|
|
|
<< " seconds"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " Compute Contour Tree"
|
|
|
|
<< ": "
|
|
|
|
<< computeContourTreeTime
|
|
|
|
<< " seconds"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " Compute Branch Decomposition"
|
|
|
|
<< ": "
|
|
|
|
<< computeBranchDecompTime
|
|
|
|
<< " seconds"
|
2020-01-22 09:11:45 +00:00
|
|
|
<< std::endl
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " Total Time"
|
|
|
|
<< ": "
|
|
|
|
<< currTime
|
|
|
|
<< " seconds");
|
|
|
|
|
2020-01-22 09:40:49 +00:00
|
|
|
const ctaug_ns::ContourTree& ct = filter.GetContourTree();
|
2020-01-22 03:38:29 +00:00
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
|
|
|
std::endl
|
|
|
|
<< " ---------------- Contour Tree Array Sizes ---------------------"
|
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Nodes"
|
|
|
|
<< ": "
|
2020-01-23 19:32:33 +00:00
|
|
|
<< ct.Nodes.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Arcs"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Arcs.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Superparents"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Superparents.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Superarcs"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Superarcs.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Supernodes"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Supernodes.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Hyperparents"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Hyperparents.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #WhenTransferred"
|
|
|
|
<< ": "
|
2020-01-23 19:32:33 +00:00
|
|
|
<< ct.WhenTransferred.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Hypernodes"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Hypernodes.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl
|
|
|
|
<< std::setw(42)
|
|
|
|
<< std::left
|
|
|
|
<< " #Hyperarcs"
|
|
|
|
<< ": "
|
2020-01-23 18:46:56 +00:00
|
|
|
<< ct.Hyperarcs.GetNumberOfValues()
|
2020-01-22 03:38:29 +00:00
|
|
|
<< std::endl);
|
|
|
|
// Flush ouput streams just to make sure everything has been logged (in particular when using MPI)
|
2019-08-28 18:34:42 +00:00
|
|
|
std::cout << std::flush;
|
2020-01-22 03:38:29 +00:00
|
|
|
std::cerr << std::flush;
|
2018-08-08 18:38:06 +00:00
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
// Let the next rank know that it is time to print their summary.
|
|
|
|
if (rank < (size - 1))
|
|
|
|
{
|
|
|
|
int message = 1;
|
|
|
|
MPI_Send(&message, 1, MPI_INT, (rank + 1), 0, comm);
|
|
|
|
}
|
2018-08-08 18:38:06 +00:00
|
|
|
#endif
|
|
|
|
|
2019-08-28 18:34:42 +00:00
|
|
|
#ifdef WITH_MPI
|
|
|
|
MPI_Finalize();
|
|
|
|
#endif
|
|
|
|
return EXIT_SUCCESS;
|
2018-08-08 18:38:06 +00:00
|
|
|
}
|