mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-20 02:55:47 +00:00
1440 lines
69 KiB
C++
1440 lines
69 KiB
C++
//============================================================================
|
|
// 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.
|
|
//
|
|
//=======================================================================================
|
|
//
|
|
// Parallel Peak Pruning v. 2.0
|
|
//
|
|
// Started June 15, 2017
|
|
//
|
|
// Copyright Hamish Carr, University of Leeds
|
|
//
|
|
// PrintGraph.h - routines for outputting dot files for debug purposes
|
|
//
|
|
//=======================================================================================
|
|
//
|
|
// COMMENTS: We have dot output scattered among multiple files, when it is primarily
|
|
// used for debug. Moreover, our principal data classes are public so that
|
|
// the algorithmic construction can be separated into factory classes.
|
|
// So we can collect all of the code for dot output into one place and be
|
|
// consistent about how we implement it
|
|
//
|
|
// We will want dot output for the following classes:
|
|
// BoundaryTree
|
|
// ContourTree
|
|
// ContourTreeMesh
|
|
// HierarchicalContourTree
|
|
// InteriorForest / InteriorForest
|
|
//
|
|
// In addition, it may be useful to be able to print out:
|
|
// MergeTree
|
|
//
|
|
// but as of the time of writing (30/07/2020) it is not priority for debug
|
|
//
|
|
// Factory classes will typically have multiple temporary arrays
|
|
// and will therefore primarily be debugged by printing the arrays
|
|
//
|
|
// However, since these classes are often indexed on our the main data classes
|
|
// we should also have a version of the graph output that shows a designated
|
|
// piece of text on each node
|
|
//
|
|
// The general design (initially) will be to produce all-purpose illustrations
|
|
// While these will probably be overkill, experience shows that confusion between
|
|
// the different indices is common, so it is better to be absolutely explicit
|
|
// and print out every piece of information possible in the graph.
|
|
// However, for the ContourTree and HierarchicalContourTree, we also want to have
|
|
// the option to show regular / super / hyper structure separately.
|
|
//
|
|
// NOTE ON CONST USAGE:
|
|
// I had originally planned to use NULL vectors for parameters not being passed
|
|
// but the compiler doesn't like the possibility of non-const temporary parameters
|
|
// so the flags arrays must be const.
|
|
// If I do the same with Mesh & ContourTree, I need to set functions elsewhere to
|
|
// be const. I will not do that unilaterally.
|
|
// All parameters of these print functions should on principal be const, except
|
|
// the stream parameter
|
|
//
|
|
//=======================================================================================
|
|
|
|
#ifndef vtk_m_worklet_contourtree_distributed_print_graph_h
|
|
#define vtk_m_worklet_contourtree_distributed_print_graph_h
|
|
|
|
#include <vtkm/Types.h>
|
|
#include <vtkm/cont/Algorithm.h>
|
|
#include <vtkm/worklet/contourtree_augmented/ContourTree.h>
|
|
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
|
#include <vtkm/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
|
|
#include <vtkm/worklet/contourtree_distributed/BoundaryTree.h>
|
|
#include <vtkm/worklet/contourtree_distributed/HierarchicalContourTree.h>
|
|
#include <vtkm/worklet/contourtree_distributed/InteriorForest.h>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace worklet
|
|
{
|
|
namespace contourtree_distributed
|
|
{
|
|
|
|
/// \brief Routines for printing various tree data structures in graphviz .dot format
|
|
///
|
|
/// These routines are primarily for debug at the moment, and share a number of constants and
|
|
/// software patterns.
|
|
/// They are therefore collected in a single unit rather than distributed in each clase
|
|
|
|
// Routines to print out a contour tree in regular and super/hyper format
|
|
// The older code ended up with separate versions depending on mesh type, but there are now
|
|
// accessor functions, and I will try to avoid this. However, this means templating everything
|
|
// to do with contour trees
|
|
|
|
// Routines for contour trees:
|
|
// 1. Routine to print super structure
|
|
// generic, with colour set according to iteration
|
|
// with option to print grey / white for boundary / interior nodes (regular tree only)
|
|
// with option to show BoundaryTree / Forest as different styles (super tree only)
|
|
// with option to show an arbitrary additional value passed as an array
|
|
|
|
// Routines for ContourTreeMesh:
|
|
// 2. Simple routine to dump out nodes / edges for cross-checking
|
|
// no options should be needed
|
|
|
|
// Routines for BoundaryTree:
|
|
// 3. All purpose routine to dump out the contents for comparison with contour tree
|
|
// Includes option to show how the InteriorForest connects to it
|
|
|
|
// Routines for HierarchicalContourTree:
|
|
// 4. Routine to print regular/super/hyper structure with similar options to contour tree
|
|
|
|
// Routines for contour trees:
|
|
// 1. Routine to print super structure
|
|
// generic, with colour set according to iteration
|
|
// with option to print grey / white for boundary / interior nodes (regular tree only)
|
|
// with option to show BoundaryTree / Forest as different styles (super tree only)
|
|
// with option to show an arbitrary additional value passed as an array
|
|
|
|
constexpr vtkm::Id INDEX_WIDTH = 6;
|
|
|
|
constexpr vtkm::Id NO_PER_NODE_VALUES = 0;
|
|
constexpr vtkm::Id PER_REGULAR_NODE_VALUES = 1;
|
|
constexpr vtkm::Id PER_REGULAR_NODE_BOUNDARY_FLAGS = 2;
|
|
constexpr vtkm::Id PER_SUPER_NODE_VALUES = 3;
|
|
constexpr vtkm::Id PER_SUPER_NODE_BOUNDARY_FLAGS = 4;
|
|
constexpr vtkm::Id PER_HYPER_NODE_VALUES = 5;
|
|
constexpr vtkm::Id BAD_PER_NODE_VALUES = 6;
|
|
|
|
constexpr vtkm::Id NODE_TYPE_REGULAR = 0;
|
|
constexpr vtkm::Id NODE_TYPE_SUPER = 1;
|
|
constexpr vtkm::Id NODE_TYPE_HYPER = 2;
|
|
|
|
// bitflags for various components
|
|
constexpr vtkm::Id SHOW_REGULAR_STRUCTURE = 0x00000001;
|
|
constexpr vtkm::Id SHOW_SUPER_STRUCTURE = 0x00000002;
|
|
constexpr vtkm::Id SHOW_HYPER_STRUCTURE = 0x00000004;
|
|
|
|
constexpr vtkm::Id SHOW_BOUNDARY_NODES = 0x00000010;
|
|
constexpr vtkm::Id SHOW_CRITICAL_BOUNDARY_NODES = 0x00000020;
|
|
constexpr vtkm::Id SHOW_NECESSARY_SUPERNODES = 0x00000040;
|
|
|
|
constexpr vtkm::Id SHOW_GLOBAL_ID = 0x00000100;
|
|
constexpr vtkm::Id SHOW_DATA_VALUE = 0x00000200;
|
|
constexpr vtkm::Id SHOW_MESH_REGULAR_ID = 0x00000400;
|
|
constexpr vtkm::Id SHOW_MESH_SORT_ID = 0x00000800;
|
|
|
|
constexpr vtkm::Id SHOW_NODE_ID = 0x00001000;
|
|
constexpr vtkm::Id SHOW_SUPERPARENT = 0x00002000;
|
|
constexpr vtkm::Id SHOW_ARC_ID = 0x00004000;
|
|
constexpr vtkm::Id SHOW_EXTRA_DATA = 0x00008000;
|
|
|
|
constexpr vtkm::Id SHOW_SUPERNODE_ID = 0x00010000;
|
|
constexpr vtkm::Id SHOW_HYPERPARENT = 0x00020000;
|
|
constexpr vtkm::Id SHOW_SUPERARC_ID = 0x0004000;
|
|
constexpr vtkm::Id SHOW_ITERATION = 0x00080000;
|
|
|
|
constexpr vtkm::Id SHOW_HYPERNODE_ID = 0x00100000;
|
|
constexpr vtkm::Id SHOW_HYPERARC_ID = 0x00200000;
|
|
|
|
// bit flags used for structures other than the contour tree
|
|
// the BoundaryTree has a vertex index, but doesn't have the contour tree's nodes, so we will reuse that bit flag
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_VERTEX_ID = SHOW_NODE_ID;
|
|
// others are just relabelling the same ID flag
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_GLOBAL_ID = SHOW_GLOBAL_ID;
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_DATA_VALUE = SHOW_DATA_VALUE;
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_MESH_REGULAR_ID = SHOW_MESH_REGULAR_ID;
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_MESH_SORT_ID = SHOW_MESH_SORT_ID;
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_ARC_ID = SHOW_ARC_ID;
|
|
constexpr vtkm::Id SHOW_BOUNDARY_TREE_ALL =
|
|
(SHOW_BOUNDARY_TREE_VERTEX_ID | SHOW_BOUNDARY_TREE_GLOBAL_ID | SHOW_BOUNDARY_TREE_DATA_VALUE |
|
|
SHOW_BOUNDARY_TREE_MESH_REGULAR_ID | SHOW_BOUNDARY_TREE_MESH_SORT_ID |
|
|
SHOW_BOUNDARY_TREE_ARC_ID);
|
|
|
|
// Similarly, relabel the IDs for use with contour tree meshes
|
|
constexpr vtkm::Id SHOW_CONTOUR_TREE_MESH_VERTEX_ID = SHOW_NODE_ID;
|
|
// others are just relabelling the same ID flag
|
|
constexpr vtkm::Id SHOW_CONTOUR_TREE_MESH_GLOBAL_ID = SHOW_GLOBAL_ID;
|
|
constexpr vtkm::Id SHOW_CONTOUR_TREE_MESH_DATA_VALUE = SHOW_DATA_VALUE;
|
|
constexpr vtkm::Id SHOW_CONTOUR_TREE_MESH_ALL =
|
|
(SHOW_CONTOUR_TREE_MESH_VERTEX_ID | SHOW_CONTOUR_TREE_MESH_GLOBAL_ID |
|
|
SHOW_CONTOUR_TREE_MESH_DATA_VALUE);
|
|
|
|
// InteriorForest is slightly tricky, but wants to be use the same set as BoundaryTree
|
|
constexpr vtkm::Id SHOW_INTERIOR_FOREST_VERTEX_ID = SHOW_SUPERNODE_ID;
|
|
constexpr vtkm::Id SHOW_INTERIOR_FOREST_GLOBAL_ID = SHOW_BOUNDARY_TREE_GLOBAL_ID;
|
|
constexpr vtkm::Id SHOW_INTERIOR_FOREST_DATA_VALUE = SHOW_BOUNDARY_TREE_DATA_VALUE;
|
|
constexpr vtkm::Id SHOW_INTERIOR_FOREST_MESH_REGULAR_ID = SHOW_BOUNDARY_TREE_MESH_REGULAR_ID;
|
|
constexpr vtkm::Id SHOW_INTERIOR_FOREST_MESH_SORT_ID = SHOW_BOUNDARY_TREE_MESH_SORT_ID;
|
|
constexpr vtkm::Id SHOW_INTERIOR_FOREST_ALL =
|
|
(SHOW_INTERIOR_FOREST_VERTEX_ID | SHOW_INTERIOR_FOREST_GLOBAL_ID |
|
|
SHOW_INTERIOR_FOREST_DATA_VALUE | SHOW_INTERIOR_FOREST_MESH_REGULAR_ID |
|
|
SHOW_INTERIOR_FOREST_MESH_SORT_ID);
|
|
|
|
constexpr vtkm::Id SHOW_ALL_STRUCTURE =
|
|
(SHOW_REGULAR_STRUCTURE | SHOW_SUPER_STRUCTURE | SHOW_HYPER_STRUCTURE);
|
|
constexpr vtkm::Id SHOW_BASIC_IDS = (SHOW_DATA_VALUE | SHOW_MESH_SORT_ID);
|
|
constexpr vtkm::Id SHOW_ALL_IDS =
|
|
(SHOW_GLOBAL_ID | SHOW_DATA_VALUE | SHOW_MESH_REGULAR_ID | SHOW_MESH_SORT_ID | SHOW_NODE_ID |
|
|
SHOW_SUPERPARENT | SHOW_ARC_ID);
|
|
constexpr vtkm::Id SHOW_BASIC_SUPERIDS = (SHOW_SUPERNODE_ID | SHOW_ITERATION);
|
|
constexpr vtkm::Id SHOW_ALL_SUPERIDS =
|
|
(SHOW_SUPERNODE_ID | SHOW_HYPERPARENT | SHOW_ITERATION | SHOW_SUPERARC_ID);
|
|
constexpr vtkm::Id SHOW_BASIC_HYPERIDS = SHOW_HYPERNODE_ID;
|
|
constexpr vtkm::Id SHOW_ALL_HYPERIDS = (SHOW_HYPERNODE_ID | SHOW_HYPERARC_ID);
|
|
|
|
constexpr vtkm::Id SHOW_REGULAR_SIMPLE = (SHOW_REGULAR_STRUCTURE | SHOW_BASIC_IDS);
|
|
constexpr vtkm::Id SHOW_REGULAR_BOUNDARY =
|
|
(SHOW_REGULAR_STRUCTURE | SHOW_BASIC_IDS | SHOW_BOUNDARY_NODES);
|
|
constexpr vtkm::Id SHOW_REGULAR_CRITICAL_BOUNDARY =
|
|
(SHOW_REGULAR_STRUCTURE | SHOW_BASIC_IDS | SHOW_CRITICAL_BOUNDARY_NODES);
|
|
|
|
constexpr vtkm::Id SHOW_SUPER_SIMPLE =
|
|
(SHOW_SUPER_STRUCTURE | SHOW_BASIC_IDS | SHOW_BASIC_SUPERIDS);
|
|
constexpr vtkm::Id SHOW_BOUNDARY_INTERIOR_DIVISION =
|
|
(SHOW_SUPER_STRUCTURE | SHOW_BASIC_IDS | SHOW_BASIC_SUPERIDS | SHOW_NECESSARY_SUPERNODES);
|
|
|
|
constexpr vtkm::Id SHOW_SUPER_AND_HYPER_SIMPLE =
|
|
(SHOW_SUPER_SIMPLE | SHOW_HYPER_STRUCTURE | SHOW_HYPERNODE_ID);
|
|
|
|
constexpr vtkm::Id SHOW_ALL_STANDARD =
|
|
(SHOW_ALL_STRUCTURE | SHOW_ALL_IDS | SHOW_ALL_SUPERIDS | SHOW_ALL_HYPERIDS);
|
|
|
|
constexpr vtkm::Id SHOW_HIERARCHICAL_STANDARD =
|
|
(SHOW_SUPER_STRUCTURE | SHOW_HYPER_STRUCTURE | SHOW_ALL_IDS | SHOW_ALL_SUPERIDS |
|
|
SHOW_ALL_HYPERIDS);
|
|
|
|
// 1. Routine for printing dot for contour tree regular / super / hyper structure
|
|
VTKM_CONT
|
|
template <typename T, typename StorageType, typename MeshType, typename VectorType>
|
|
std::string ContourTreeDotGraphPrint(
|
|
const std::string& label, // the label to use as title for the graph
|
|
MeshType& mesh, // the underlying mesh for the contour tree
|
|
const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler*
|
|
localToGlobalIdRelabeler, // relabler needed to compute global ids
|
|
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
|
vtkm::worklet::contourtree_augmented::ContourTree& contourTree, // the contour tree itself
|
|
const vtkm::Id showMask = SHOW_ALL_STANDARD, // mask with flags for what elements to show
|
|
// const vtkm::worklet::contourtree_augmented::IdArrayType &necessaryFlags = vtkm::worklet::contourtree_augmented::IdArrayType(),
|
|
// array with flags for "necessary"
|
|
const VectorType& perNodeValues = VectorType()) // an arbitrary vector of values
|
|
{ // ContourTreeSuperDotGraphPrint()
|
|
// initialise a string stream to capture the output
|
|
std::stringstream outStream;
|
|
|
|
// now grab portals to all the variables we will need
|
|
auto nodesPortal = contourTree.Nodes.ReadPortal();
|
|
auto arcsPortal = contourTree.Arcs.ReadPortal();
|
|
auto superparentsPortal = contourTree.Superparents.ReadPortal();
|
|
auto supernodesPortal = contourTree.Supernodes.ReadPortal();
|
|
auto superarcsPortal = contourTree.Superarcs.ReadPortal();
|
|
auto hyperparentsPortal = contourTree.Hyperparents.ReadPortal();
|
|
auto whenTransferredPortal = contourTree.WhenTransferred.ReadPortal();
|
|
auto hypernodesPortal = contourTree.Hypernodes.ReadPortal();
|
|
auto hyperarcsPortal = contourTree.Hyperarcs.ReadPortal();
|
|
// auto necessaryFlagsPortal = necessaryFlags.ReadPortal();
|
|
auto perNodeValuesPortal = perNodeValues.ReadPortal();
|
|
|
|
// work out how long the computed value is
|
|
int nodeValueType = vtkm::worklet::contourtree_distributed::BAD_PER_NODE_VALUES;
|
|
vtkm::Id perNodeSize = perNodeValues.GetNumberOfValues();
|
|
if (perNodeSize == 0)
|
|
nodeValueType = vtkm::worklet::contourtree_distributed::NO_PER_NODE_VALUES;
|
|
else if (perNodeSize == contourTree.Nodes.GetNumberOfValues())
|
|
nodeValueType = vtkm::worklet::contourtree_distributed::PER_REGULAR_NODE_VALUES;
|
|
else if (perNodeSize == contourTree.Supernodes.GetNumberOfValues())
|
|
nodeValueType = vtkm::worklet::contourtree_distributed::PER_SUPER_NODE_VALUES;
|
|
else if (perNodeSize == contourTree.Hypernodes.GetNumberOfValues())
|
|
nodeValueType = vtkm::worklet::contourtree_distributed::PER_HYPER_NODE_VALUES;
|
|
else
|
|
{ // error message
|
|
outStream << "ERROR in ContourTreeDotGraphPrint().\n";
|
|
outStream << "Per node values array must be empty, or\n";
|
|
outStream << "Same length as regular nodes ("
|
|
<< std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< contourTree.Nodes.GetNumberOfValues() << "), or\n";
|
|
outStream << "Same length as super nodes ("
|
|
<< std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< contourTree.Supernodes.GetNumberOfValues() << "), or\n";
|
|
outStream << "Same length as hyper nodes ("
|
|
<< std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< contourTree.Hypernodes.GetNumberOfValues() << ")\n";
|
|
outStream << "Actual length was ("
|
|
<< std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< perNodeValues.GetNumberOfValues() << ")\n";
|
|
} // error message
|
|
|
|
// print the header information
|
|
outStream << "digraph ContourTree\n\t{\n";
|
|
outStream << "\tlabel=\"" << std::setw(1) << label << "\"\n\tlabelloc=t\n\tfontsize=30\n";
|
|
outStream << "\t// Nodes" << std::endl;
|
|
|
|
auto meshSortOrderPortal = mesh.SortOrder.ReadPortal();
|
|
auto globalIds = mesh.GetGlobalIdsFromSortIndices(contourTree.Nodes, localToGlobalIdRelabeler);
|
|
auto globalIdsPortal = globalIds.ReadPortal();
|
|
auto dataValuesPortal = field.ReadPortal();
|
|
|
|
// loop through all of the nodes in the regular list
|
|
for (vtkm::Id node = 0; node < contourTree.Nodes.GetNumberOfValues(); node++)
|
|
{ // per node
|
|
// the nodes array is actually sorted by superarc, but the superarcs array is not
|
|
// so we ignore the nodes array and work directly with the node #
|
|
vtkm::Id sortID = nodesPortal.Get(node);
|
|
|
|
// retrieve the regular ID
|
|
vtkm::Id regularID = meshSortOrderPortal.Get(sortID);
|
|
|
|
// retrieve the global ID
|
|
vtkm::Id globalID = globalIdsPortal.Get(sortID);
|
|
|
|
// retrieve the values
|
|
auto dataValue = dataValuesPortal.Get(regularID);
|
|
|
|
// retrieve the superparent
|
|
vtkm::Id superparent = superparentsPortal.Get(sortID);
|
|
|
|
// and retrieve the iteration #
|
|
vtkm::Id iteration =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whenTransferredPortal.Get(superparent));
|
|
|
|
// work out the super ID & hyper ID
|
|
vtkm::Id superID = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
|
vtkm::Id hyperparent = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
|
vtkm::Id hyperID = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
|
vtkm::Id nodeType = vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR;
|
|
|
|
// test for super
|
|
if (supernodesPortal.Get(superparent) == sortID)
|
|
{ // at least super
|
|
// set super ID
|
|
superID = superparent;
|
|
// set hyperparent
|
|
hyperparent = hyperparentsPortal.Get(superID);
|
|
// set nodetype
|
|
nodeType = NODE_TYPE_SUPER;
|
|
// test for hyper
|
|
if (hypernodesPortal.Get(hyperparent) == superID)
|
|
{ // hyper node
|
|
nodeType = NODE_TYPE_HYPER;
|
|
hyperID = hyperparent;
|
|
} // hyper node
|
|
} // at least super
|
|
|
|
// now, if we don't want the regular nodes, we want to skip them entirely, so
|
|
bool showNode = false;
|
|
// regular structure always shows all nodes
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE)
|
|
showNode = true;
|
|
// super structure shows super & hyper nodes only
|
|
else if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE)
|
|
showNode = (nodeType != vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR);
|
|
else if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE)
|
|
showNode = (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER);
|
|
|
|
// if we didn't set the flag, skip the node
|
|
if (!showNode)
|
|
continue;
|
|
|
|
// print the vertex ID, which should be the sort ID & needs to be left-justified to work
|
|
outStream << "\ts" << std::setw(1) << sortID;
|
|
|
|
// print the style characteristics - node is filled and fixed size
|
|
outStream << " [style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\"";
|
|
// specify the style based on the type of node
|
|
if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR)
|
|
outStream << ",height=\"1.7in\",width=\"1.7in\",penwidth=5";
|
|
else if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_SUPER)
|
|
outStream << ",height=\"2.5in\",width=\"2.5in\",penwidth=10";
|
|
else if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER)
|
|
outStream << ",height=\"2.5in\",width=\"2.5in\",penwidth=15";
|
|
|
|
// shape should always be circular.
|
|
outStream << ",shape=circle";
|
|
|
|
// fill colour is grey for boundary or necessary, if these are passed in
|
|
bool isGrey = false;
|
|
// TODO: Add liesOnBoundary and isNecessary so we can define the gray value
|
|
/*
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_NODES)
|
|
isGrey = (showMask & vtkm::worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE) && mesh.liesOnBoundary(regularID);
|
|
else if (showMask & vtkm::worklet::contourtree_distributed::SHOW_CRITICAL_BOUNDARY_NODES)
|
|
isGrey = (showMask & vtkm::worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE) && mesh.isNecessary(regularID);
|
|
else if (showMask & vtkm::worklet::contourtree_distributed::SHOW_NECESSARY_SUPERNODES)
|
|
isGrey = (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE) // skip if superstructure not shown
|
|
&& !vtkm::worklet::contourtree_augmented::NoSuchElement(superID) // ignore non-super nodes
|
|
&& (necessaryFlags.GetNumberOfValues() == contourTree.Supernodes.GetNumberOfValues()) // skip if necessary flags array is wrong size
|
|
&& necessaryFlagsPortal.Get(superID);
|
|
*/
|
|
// after setting the flag, its easy
|
|
outStream << (isGrey ? ",fillcolor=grey" : ",fillcolor=white");
|
|
|
|
// stroke colour depends on iteration
|
|
outStream << ",color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[iteration % vtkm::worklet::contourtree_augmented::N_NODE_COLORS];
|
|
|
|
// start printing the label
|
|
outStream << ",label=\"";
|
|
// print the global ID
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_GLOBAL_ID)
|
|
outStream << "g " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< globalID << "\\n";
|
|
// print the value
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_DATA_VALUE)
|
|
outStream << "v " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< dataValue << "\\n";
|
|
// print the regular & sort IDs
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_MESH_REGULAR_ID)
|
|
outStream << "r " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< regularID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_MESH_SORT_ID)
|
|
outStream << "s " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << sortID
|
|
<< "\\n";
|
|
// and the node ID
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_NODE_ID)
|
|
outStream << "n " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << node
|
|
<< "\\n";
|
|
// print the superparent
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPERPARENT)
|
|
outStream << "sp" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< superparent << "\\n";
|
|
|
|
// add arbitrary per node value if it is regular in nature
|
|
if ((showMask & vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA) &&
|
|
(nodeValueType == vtkm::worklet::contourtree_distributed::PER_REGULAR_NODE_VALUES))
|
|
outStream << "x " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< perNodeValuesPortal.Get(regularID) << "\\n";
|
|
|
|
// we now want to add labelling information specific to supernodes, but also present in hypernodes
|
|
if (nodeType != vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR)
|
|
{ // at least super
|
|
|
|
// print the super node ID
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPERNODE_ID)
|
|
outStream << "SN" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< superID << "\\n";
|
|
|
|
// print the hyperparent as well
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPERPARENT)
|
|
outStream << "HP" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< hyperparent << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_ITERATION)
|
|
outStream << "IT" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< iteration << "\\n";
|
|
|
|
// add arbitrary per node value if it is super in nature
|
|
if ((showMask & vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA) &&
|
|
(nodeValueType == vtkm::worklet::contourtree_distributed::PER_SUPER_NODE_VALUES))
|
|
outStream << "X " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< perNodeValuesPortal.Get(superID) << "\\n";
|
|
} // at least super
|
|
|
|
// now add even more for hypernodes
|
|
if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER)
|
|
{ // hyper node
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPERNODE_ID)
|
|
outStream << "HN" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< hyperID << "\\n";
|
|
|
|
// add arbitrary per node value if it is hyper in nature
|
|
if ((showMask & vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA) &&
|
|
(nodeValueType == vtkm::worklet::contourtree_distributed::PER_HYPER_NODE_VALUES))
|
|
outStream << "X " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< perNodeValuesPortal.Get(hyperID) << "\\n";
|
|
} // hyper node
|
|
|
|
outStream << "\"]" << std::endl;
|
|
} // per node
|
|
|
|
// always show the null node
|
|
outStream << "\t// Null Node" << std::endl;
|
|
outStream
|
|
<< "\tNULL "
|
|
"[style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\",height=\"0.5in\","
|
|
"width=\"0.5in\",penwidth=1,shape=circle,fillcolor=white,color=black,label=\"NULL\"]"
|
|
<< std::endl;
|
|
|
|
// start the arcs
|
|
outStream << "\t// Arcs" << std::endl;
|
|
|
|
// now add regular arcs (if requested)
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE)
|
|
for (vtkm::Id node = 0; node < contourTree.Nodes.GetNumberOfValues(); node++)
|
|
{ // per node
|
|
// retrieve the "to" end
|
|
vtkm::Id to = arcsPortal.Get(node);
|
|
|
|
// if "to" is NSE, it's the root node
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
|
|
outStream << "\ts" << std::setw(1) << node << " -> NULL [penwidth=2";
|
|
else
|
|
{ // actual node
|
|
// mask out the flags to get the target node
|
|
to = vtkm::worklet::contourtree_augmented::MaskedIndex(to);
|
|
|
|
// since we're using sort IDs, we compare them
|
|
if (node < to)
|
|
outStream << "\ts" << std::setw(1) << to << " -> s" << std::setw(1) << node
|
|
<< " [dir=back,penwidth=3";
|
|
else
|
|
outStream << "\ts" << std::setw(1) << node << " -> s" << std::setw(1) << to
|
|
<< " [penwidth=3";
|
|
} // actual node
|
|
|
|
// set the color based on the from vertex
|
|
// retrieve the superparent
|
|
vtkm::Id superparent = superparentsPortal.Get(node);
|
|
vtkm::Id iteration =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whenTransferredPortal.Get(superparent));
|
|
outStream << ",color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[iteration % vtkm::worklet::contourtree_augmented::N_NODE_COLORS];
|
|
if (showMask & SHOW_ARC_ID)
|
|
outStream << ",label=\"A" << node << "\"";
|
|
outStream << "]" << std::endl;
|
|
} // per node
|
|
|
|
// show superarcs if requested
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE)
|
|
for (vtkm::Id supernode = 0; supernode < contourTree.Supernodes.GetNumberOfValues();
|
|
supernode++)
|
|
{ // per supernode
|
|
// retrieve the sort ID
|
|
vtkm::Id from = supernodesPortal.Get(supernode);
|
|
|
|
// retrieve the "to" end
|
|
vtkm::Id toSuper = superarcsPortal.Get(supernode);
|
|
|
|
// test for "NSE"
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(toSuper))
|
|
outStream << "\ts" << std::setw(1) << from << " -> NULL [penwidth=4";
|
|
else
|
|
{ // supernode
|
|
// mask out the ascending flag & convert to sort ID
|
|
vtkm::Id to =
|
|
supernodesPortal.Get(vtkm::worklet::contourtree_augmented::MaskedIndex(toSuper));
|
|
|
|
// now test for ascending with sort IDs as before
|
|
if (from < to)
|
|
outStream << "\ts" << std::setw(1) << to << " -> s" << std::setw(1) << from
|
|
<< " [dir=back,penwidth=7";
|
|
else
|
|
outStream << "\ts" << std::setw(1) << from << " -> s" << std::setw(1) << to
|
|
<< " [penwidth=7";
|
|
} // supernode
|
|
|
|
// set the color based on the from vertex
|
|
vtkm::Id iteration =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whenTransferredPortal.Get(supernode));
|
|
outStream << ",color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[iteration % vtkm::worklet::contourtree_augmented::N_NODE_COLORS];
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPERARC_ID)
|
|
outStream << ",label=\"SA" << supernode << "\"";
|
|
outStream << "]" << std::endl;
|
|
} // per supernode
|
|
|
|
// add hyper arcs if requested
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE)
|
|
for (vtkm::Id hypernode = 0; hypernode < contourTree.Hypernodes.GetNumberOfValues();
|
|
hypernode++)
|
|
{ // per hypernode
|
|
// retrieve the sort ID
|
|
vtkm::Id fromSuper = hypernodesPortal.Get(hypernode);
|
|
vtkm::Id from = supernodesPortal.Get(fromSuper);
|
|
|
|
// retrieve the "to" end
|
|
vtkm::Id toSuper = hyperarcsPortal.Get(hypernode);
|
|
|
|
// test for "NSE"
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(toSuper))
|
|
outStream << "\ts" << std::setw(1) << from << " -> NULL [penwidth=6";
|
|
else
|
|
{ // hypernode
|
|
// mask out the ascending flag & convert to sort ID
|
|
vtkm::Id to =
|
|
supernodesPortal.Get(vtkm::worklet::contourtree_augmented::MaskedIndex(toSuper));
|
|
|
|
// now test for ascending with sort IDs as before
|
|
if (from < to)
|
|
outStream << "\ts" << std::setw(1) << to << " -> s" << std::setw(1) << from
|
|
<< " [dir=back,penwidth=12";
|
|
else
|
|
outStream << "\ts" << std::setw(1) << from << " -> s" << std::setw(1) << to
|
|
<< " [penwidth=12";
|
|
} // hypernode
|
|
|
|
// set the color based on the from vertex
|
|
vtkm::Id iteration =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whenTransferredPortal.Get(fromSuper));
|
|
outStream << ",color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[iteration % vtkm::worklet::contourtree_augmented::N_NODE_COLORS];
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPERARC_ID)
|
|
outStream << ",label=\"HA" << hypernode << "\"";
|
|
outStream << "]" << std::endl;
|
|
} // per hypernode
|
|
|
|
// print the footer information
|
|
outStream << "\t}\n";
|
|
|
|
// now return the string
|
|
return outStream.str();
|
|
} // ContourTreeSuperDotGraphPrint()
|
|
|
|
|
|
// 2. Simple routine to dump out nodes / edges for cross-checking
|
|
VTKM_CONT
|
|
template <typename FieldType>
|
|
std::string ContourTreeMeshDotGraphPrint(
|
|
const std::string& label, // the label to use as title for the graph
|
|
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh, // the mesh itself
|
|
const vtkm::Id showMask = SHOW_CONTOUR_TREE_MESH_ALL) // mask with flags for what elements to show
|
|
{ // ContourTreeMeshDotGraphPrint()
|
|
// initialise a string stream to capture the output
|
|
std::stringstream outStream;
|
|
|
|
// now grab portals to all the variables we will need
|
|
auto globalMeshIndexPortal = mesh.GlobalMeshIndex.ReadPortal();
|
|
auto meshSortedValuesPortal = mesh.SortedValues.ReadPortal();
|
|
auto meshNeighboursPortal = mesh.Neighbours.ReadPortal();
|
|
auto meshFirstNeighbourPortal = mesh.FirstNeighbour.ReadPortal();
|
|
|
|
// print the header information
|
|
outStream << "digraph ContourTreeMesh\n\t{\n";
|
|
outStream << "\tlabel=\"" << std::setw(1) << label << "\"\n\tlabelloc=t\n\tfontsize=30\n";
|
|
outStream << "\t// Nodes" << std::endl;
|
|
|
|
// loop through all vertices
|
|
for (vtkm::Id vertex = 0; vertex < mesh.GetNumberOfVertices(); vertex++)
|
|
{ // per vertex
|
|
// work out the various ID's
|
|
vtkm::Id globalID = globalMeshIndexPortal.Get(vertex);
|
|
auto dataValue = meshSortedValuesPortal.Get(vertex);
|
|
|
|
// print the vertex
|
|
outStream << "\tr" << std::setw(1) << vertex;
|
|
outStream << "[style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\",height="
|
|
"\"1.7in\",width=\"1.7in\",penwidth=5,shape=circle";
|
|
outStream << ",fillcolor=white";
|
|
outStream << ",label=\"";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_VERTEX_ID)
|
|
outStream << "r " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << vertex
|
|
<< "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_GLOBAL_ID)
|
|
outStream << "g " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< globalID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_DATA_VALUE)
|
|
outStream << "v " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< dataValue << "\\n";
|
|
outStream << "\"];\n";
|
|
} // per vertex
|
|
|
|
// now print out the edges
|
|
for (vtkm::Id vertex = 0; vertex < mesh.FirstNeighbour.GetNumberOfValues(); vertex++)
|
|
{ // per vertex
|
|
// find iterators for the block of edges for this vertex
|
|
vtkm::Id neighboursBegin = meshFirstNeighbourPortal.Get(vertex);
|
|
vtkm::Id neighboursEnd = (vertex < mesh.GetNumberOfVertices() - 1)
|
|
? meshFirstNeighbourPortal.Get(vertex + 1)
|
|
: mesh.Neighbours.GetNumberOfValues();
|
|
|
|
// now loop through the neighbours
|
|
for (vtkm::Id whichNbr = neighboursBegin; whichNbr != neighboursEnd; ++whichNbr)
|
|
{ // per neighbour
|
|
vtkm::Id nbrID = meshNeighboursPortal.Get(whichNbr);
|
|
// skip if the neighbour is higher (use sim. of simp.)
|
|
if ((meshSortedValuesPortal.Get(nbrID) > meshSortedValuesPortal.Get(vertex)) ||
|
|
((meshSortedValuesPortal.Get(nbrID) == meshSortedValuesPortal.Get(vertex)) &&
|
|
(nbrID > vertex)))
|
|
// output the edge
|
|
outStream << "\tr" << std::setw(1) << nbrID << " -> r" << std::setw(1) << vertex
|
|
<< " [penwidth=3]" << std::endl;
|
|
else
|
|
outStream << "\tr" << std::setw(1) << vertex << " -> r" << std::setw(1) << nbrID
|
|
<< " [dir=back,penwidth=3]" << std::endl;
|
|
} // per neighbour
|
|
|
|
} // per vertex
|
|
|
|
// close the graph
|
|
outStream << "\t}" << std::endl;
|
|
|
|
// now return the string
|
|
return outStream.str();
|
|
} // ContourTreeMeshDotGraphPrint()
|
|
|
|
|
|
// 3. All purpose routine to dump out the contents for comparison with contour tree
|
|
VTKM_CONT
|
|
template <typename T, typename StorageType, typename MeshType, typename MeshBoundaryExecObjType>
|
|
std::string BoundaryTreeDotGraphPrint(
|
|
const std::string& label, // the label to use as title for the graph
|
|
MeshType& mesh, // the underlying mesh for the contour tree
|
|
MeshBoundaryExecObjType&
|
|
meshBoundaryExecutionObject, // the boundary description need to determin if a vertex is on the boundary
|
|
vtkm::worklet::contourtree_distributed::BoundaryTree& boundaryTree, // the boundary tree itself
|
|
const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler*
|
|
localToGlobalIdRelabeler, // relabler needed to compute global ids
|
|
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
|
const vtkm::Id showMask = vtkm::worklet::contourtree_distributed::
|
|
SHOW_BOUNDARY_TREE_ALL, // mask with flags for what elements to show
|
|
const bool printHeaderAndFooter = true)
|
|
{ // BoundaryTreeDotGraphPrint()
|
|
// initialise a string stream to capture the output
|
|
std::stringstream outStream;
|
|
|
|
// now grab portals to all the variables we will need
|
|
auto vertexIndexPortal = boundaryTree.VertexIndex.ReadPortal();
|
|
auto superarcsPortal = boundaryTree.Superarcs.ReadPortal();
|
|
|
|
// if requested
|
|
if (printHeaderAndFooter)
|
|
{ // print header
|
|
// print the header information
|
|
outStream << "digraph BoundaryTree\n\t{\n";
|
|
outStream << "\tlabel=\"" << std::setw(1) << label << "\"\n\tlabelloc=t\n\tfontsize=30\n";
|
|
outStream << "\t// Nodes" << std::endl;
|
|
} // print header
|
|
|
|
// prercompute the mesh boundary
|
|
// TODO: This should be done in parallel. We have the basic code but for printing this is fine for now
|
|
vtkm::cont::ArrayHandle<bool> liesOnBoundary;
|
|
{
|
|
vtkm::worklet::contourtree_augmented::IdArrayType boundaryVertexArray;
|
|
vtkm::worklet::contourtree_augmented::IdArrayType boundaryVertexSortIndexArray;
|
|
mesh.GetBoundaryVertices(boundaryVertexArray, // output
|
|
boundaryVertexSortIndexArray, // output
|
|
&meshBoundaryExecutionObject //input
|
|
);
|
|
auto boundaryVertexArrayPortal = boundaryVertexArray.ReadPortal();
|
|
// vtkm::cont::ArrayHandle<vtkm::Range> rangeArray = vtkm::cont::ArrayRangeCompute(mesh.SortOrder);
|
|
// vtkm::Id maxId = static_cast<vtkm::Id>(rangeArray.ReadPortal().Get(0).Max) + 1;
|
|
liesOnBoundary.Allocate(mesh.SortOrder.GetNumberOfValues());
|
|
auto liesOnBoundaryWritePortal = liesOnBoundary.WritePortal();
|
|
vtkm::cont::Algorithm::Copy(
|
|
vtkm::cont::ArrayHandleConstant<bool>(false, liesOnBoundary.GetNumberOfValues()),
|
|
liesOnBoundary);
|
|
for (vtkm::Id i = 0; i < boundaryVertexArray.GetNumberOfValues(); ++i)
|
|
{
|
|
liesOnBoundaryWritePortal.Set(boundaryVertexArrayPortal.Get(i), true);
|
|
}
|
|
}
|
|
auto liesOnBoundaryPortal = liesOnBoundary.ReadPortal();
|
|
|
|
// loop through all nodes
|
|
auto meshSortOrderPortal = mesh.SortOrder.ReadPortal();
|
|
auto globalIds = mesh.GetGlobalIdsFromSortIndices(mesh.SortOrder, localToGlobalIdRelabeler);
|
|
auto globalIdsPortal = globalIds.ReadPortal();
|
|
auto dataValuesPortal = field.ReadPortal();
|
|
for (vtkm::Id node = 0; node < boundaryTree.VertexIndex.GetNumberOfValues(); node++)
|
|
{ // per node
|
|
// work out the node and it's value
|
|
vtkm::Id sortID = vertexIndexPortal.Get(node);
|
|
vtkm::Id regularID = meshSortOrderPortal.Get(sortID);
|
|
// NOTE: globalIdsPortal already looked up by meshSortOrder so we need to
|
|
// look up globalID now by node not sortID
|
|
vtkm::Id globalID = globalIdsPortal.Get(node);
|
|
auto dataValue = dataValuesPortal.Get(regularID);
|
|
|
|
// print the vertex (using global ID to simplify things for the residue)
|
|
outStream << "\tg" << std::setw(1) << globalID;
|
|
outStream << "[style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\",height="
|
|
"\"1.7in\",width=\"1.7in\",penwidth=5,shape=circle";
|
|
outStream << ",fillcolor=" << (liesOnBoundaryPortal.Get(regularID) ? "grey" : "white");
|
|
outStream << ",label=\"";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_TREE_VERTEX_ID)
|
|
outStream << "b " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << node
|
|
<< "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_TREE_GLOBAL_ID)
|
|
outStream << "g " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< globalID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_TREE_DATA_VALUE)
|
|
outStream << "v " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< dataValue << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_TREE_MESH_REGULAR_ID)
|
|
outStream << "r " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< regularID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_TREE_MESH_SORT_ID)
|
|
outStream << "s " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << sortID
|
|
<< "\\n";
|
|
outStream << "\"];\n";
|
|
} // per vertex
|
|
// always show the null node
|
|
outStream << "\t// Null Node" << std::endl;
|
|
outStream
|
|
<< "\tNULL "
|
|
"[style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\",height=\"0.5in\","
|
|
"width=\"0.5in\",penwidth=1,shape=circle,fillcolor=white,color=black,label=\"NULL\"]"
|
|
<< std::endl;
|
|
|
|
// now print out the edges
|
|
for (vtkm::Id node = 0; node < boundaryTree.Superarcs.GetNumberOfValues(); node++)
|
|
{ // per node
|
|
// retrieve global ID of node
|
|
vtkm::Id sortID = vertexIndexPortal.Get(node);
|
|
vtkm::Id globalID = globalIdsPortal.Get(sortID);
|
|
|
|
// retrieve ID of target supernode
|
|
vtkm::Id to = superarcsPortal.Get(node);
|
|
|
|
// if this is true, it is the last pruned vertex & is omitted
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
|
|
outStream << "\tg" << std::setw(1) << globalID << " -> NULL [penwidth=2";
|
|
else
|
|
{ // actual superarc
|
|
vtkm::Id toSort = vertexIndexPortal.Get(to);
|
|
vtkm::Id toGlobal = globalIdsPortal.Get(toSort);
|
|
if (node < to)
|
|
outStream << "\tg" << std::setw(1) << toGlobal << " -> g" << std::setw(1) << globalID
|
|
<< " [dir=back,penwidth=3";
|
|
else
|
|
outStream << "\tg" << std::setw(1) << globalID << " -> g" << std::setw(1) << toGlobal
|
|
<< " [penwidth=3";
|
|
} // actual superarc
|
|
|
|
// now tidy up
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_BOUNDARY_TREE_ARC_ID)
|
|
outStream << ",label=\"BA" << node << "\"";
|
|
outStream << "]" << std::endl;
|
|
} // per node
|
|
|
|
if (printHeaderAndFooter)
|
|
{ // print footer
|
|
outStream << "\t}" << std::endl;
|
|
} // print footer
|
|
// now return the string
|
|
return outStream.str();
|
|
} // BoundaryTreeDotGraphPrint()
|
|
|
|
|
|
// Routines for InteriorForest:
|
|
// 4. All purpose routine to dump out the contents for comparison with contour tree
|
|
VTKM_CONT
|
|
template <typename T, typename StorageType, typename MeshType, typename MeshBoundaryExecObjType>
|
|
std::string InteriorForestDotGraphPrint(
|
|
const std::string& label, // the label to use as title for the graph
|
|
vtkm::worklet::contourtree_distributed::InteriorForest& forest, // the forest in question
|
|
vtkm::worklet::contourtree_augmented::ContourTree&
|
|
contourTree, // the contour tree to which it belongs
|
|
vtkm::worklet::contourtree_distributed::BoundaryTree& boundaryTree, // the boundary tree
|
|
MeshType& mesh, // the underlying mesh for the contour tree
|
|
MeshBoundaryExecObjType&
|
|
meshBoundaryExecutionObject, // the boundary description need to determin if a vertex is on the boundary
|
|
const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler*
|
|
localToGlobalIdRelabeler, // relabler needed to compute global ids
|
|
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
|
const vtkm::Id& showMask =
|
|
vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_ALL) // mask for what to show
|
|
{ // InteriorForestDotGraphPrint()
|
|
// initialise a string stream to capture the output
|
|
std::stringstream outStream;
|
|
|
|
// now grab portals to all the variables we will need
|
|
auto supernodesPortal = contourTree.Supernodes.ReadPortal();
|
|
auto superarcsPortal = contourTree.Superarcs.ReadPortal();
|
|
auto forestAbovePortal = forest.Above.ReadPortal();
|
|
auto forestBelowPortal = forest.Below.ReadPortal();
|
|
auto forestIsNecessaryPortal = forest.IsNecessary.ReadPortal();
|
|
|
|
// print the header information
|
|
outStream << "digraph InteriorForest\n\t{\n";
|
|
outStream << "\tlabel=\"" << std::setw(1) << label << "\"\n\tlabelloc=t\n\tfontsize=30\n";
|
|
outStream << "\t// Nodes" << std::endl;
|
|
|
|
// call the boundary tree routine first, telling it to omit the header and footer
|
|
// note that since we define our mask in the same bits as BRACT, we can pass through the mask
|
|
outStream << BoundaryTreeDotGraphPrint(
|
|
label,
|
|
mesh,
|
|
meshBoundaryExecutionObject,
|
|
boundaryTree,
|
|
localToGlobalIdRelabeler,
|
|
field,
|
|
vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_ALL,
|
|
false);
|
|
|
|
// now we need to show the forest and how it relates to the boundary tree
|
|
// note - we will ignore the boundary tree Mesh Indices array for now
|
|
auto meshSortOrderPortal = mesh.SortOrder.ReadPortal();
|
|
auto globalIds = mesh.GetGlobalIdsFromSortIndices(mesh.SortOrder, localToGlobalIdRelabeler);
|
|
auto globalIdsPortal = globalIds.ReadPortal();
|
|
auto dataValuesPortal = field.ReadPortal();
|
|
|
|
// loop through all of the supernodes in the contour tree
|
|
for (vtkm::Id supernode = 0; supernode < contourTree.Supernodes.GetNumberOfValues(); supernode++)
|
|
{ // per supernode
|
|
// retrieve the various IDs for the supernode
|
|
vtkm::Id sortID = supernodesPortal.Get(supernode);
|
|
vtkm::Id regularID = meshSortOrderPortal.Get(sortID);
|
|
// NOTE: globalIdsPortal already looked up by meshSortOrder so we need to
|
|
// look up globalID now by supernode not sortID
|
|
vtkm::Id globalID = globalIdsPortal.Get(supernode);
|
|
auto dataValue = dataValuesPortal.Get(regularID);
|
|
|
|
// vertices marked "necessary" are in the interior of the BRACT, but not all are in the BRACT
|
|
// but the ones in the BRACT always have above/below pointing to themselves, so we test that
|
|
if (forestIsNecessaryPortal.Get(supernode) && (forestAbovePortal.Get(supernode) == globalID) &&
|
|
(forestBelowPortal.Get(supernode) == globalID))
|
|
continue;
|
|
|
|
// now print out the node
|
|
// print the vertex
|
|
outStream << "\tg" << std::setw(1) << globalID;
|
|
outStream << "[style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\",height="
|
|
"\"1.7in\",width=\"1.7in\",penwidth=5,shape=circle";
|
|
outStream << ",fillcolor=white";
|
|
outStream << ",label=\"";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_VERTEX_ID)
|
|
outStream << "SN" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< supernode << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_GLOBAL_ID)
|
|
outStream << "g " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< globalID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_DATA_VALUE)
|
|
outStream << "v " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< dataValue << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_MESH_REGULAR_ID)
|
|
outStream << "r " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< regularID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_INTERIOR_FOREST_MESH_SORT_ID)
|
|
outStream << "s " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << sortID
|
|
<< "\\n";
|
|
outStream << "\"];\n";
|
|
} // per supernode
|
|
|
|
// now loop through the superarcs in the contour tree
|
|
for (vtkm::Id supernode = 0; supernode < contourTree.Supernodes.GetNumberOfValues(); supernode++)
|
|
{ // per supernode / superarc
|
|
// retrieve the various IDs for the supernode
|
|
vtkm::Id sortID = supernodesPortal.Get(supernode);
|
|
vtkm::Id globalID = globalIdsPortal.Get(sortID);
|
|
|
|
// for nodes not necessary, show their superarc
|
|
if (!forestIsNecessaryPortal.Get(supernode))
|
|
{ // not necessary
|
|
// retrieve the target of its superarc
|
|
vtkm::Id superarc = superarcsPortal.Get(supernode);
|
|
|
|
// check to see if it exists
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarc))
|
|
continue;
|
|
|
|
// separate out the ID
|
|
vtkm::Id superTo = vtkm::worklet::contourtree_augmented::MaskedIndex(superarc);
|
|
vtkm::Id toSort = supernodesPortal.Get(superTo);
|
|
vtkm::Id toGlobal = globalIdsPortal.Get(toSort);
|
|
|
|
// then print out the edge
|
|
if (contourtree_augmented::IsAscending(superTo))
|
|
outStream << "\tg" << std::setw(1) << toGlobal << " -> g" << globalID
|
|
<< "[dir=back,penwidth=3]" << std::endl;
|
|
else
|
|
outStream << "\tg" << std::setw(1) << globalID << " -> g" << toGlobal << "[penwidth=3]"
|
|
<< std::endl;
|
|
} // not necessary
|
|
else if ((forestAbovePortal.Get(supernode) != globalID) ||
|
|
(forestBelowPortal.Get(supernode) != globalID))
|
|
{ // attachment point
|
|
// all others are attachment points and have a valid above / below
|
|
outStream << "\tg" << std::setw(1) << forestAbovePortal.Get(supernode) << " -> g"
|
|
<< std::setw(1) << globalID << "[penwidth=1,style=dotted,label=above,dir=back]"
|
|
<< std::endl;
|
|
outStream << "\tg" << std::setw(1) << globalID << " -> g" << forestBelowPortal.Get(supernode)
|
|
<< "[penwidth=1,style=dotted,label=below]" << std::endl;
|
|
} // attachment point
|
|
|
|
} // per supernode / superarc
|
|
|
|
// print the footer
|
|
outStream << "\t}" << std::endl;
|
|
|
|
// now return the string
|
|
return outStream.str();
|
|
} // InteriorForestDotGraphPrint()
|
|
|
|
|
|
// 5. Routine to print regular/super/hyper structure with similar options to contour tree
|
|
VTKM_CONT
|
|
template <typename FieldType>
|
|
// template <typename FieldType, typename VectorType>
|
|
std::string HierarchicalContourTreeDotGraphPrint(
|
|
const std::string& label, // the label to use as title for the graph
|
|
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>&
|
|
hierarchicalTree, // the hierarchical contour tree itself
|
|
const unsigned long showMask = vtkm::worklet::contourtree_distributed::
|
|
SHOW_HIERARCHICAL_STANDARD) // mask with flags for what elements to show
|
|
// const unsigned long showMask = vtkm::worklet::contourtree_distributed::SHOW_HIERARCHICAL_STANDARD, // mask with flags for what elements to show
|
|
// const VectorType &perNodeValues = VectorType(0)) // an arbitrary vector of values
|
|
{ // HierarchicalContourTreeDotGraphPrint()
|
|
// initialise a string stream to capture the output
|
|
std::stringstream outStream;
|
|
|
|
// now grab portals to all the variables we will need
|
|
auto regularNodeGlobalIdsPortal = hierarchicalTree.RegularNodeGlobalIds.ReadPortal();
|
|
auto dataValuesPortal = hierarchicalTree.DataValues.ReadPortal();
|
|
auto regularNodeSortOrderPortal = hierarchicalTree.RegularNodeSortOrder.ReadPortal();
|
|
auto regular2supernodePortal = hierarchicalTree.Regular2Supernode.ReadPortal();
|
|
auto superparentsPortal = hierarchicalTree.Superparents.ReadPortal();
|
|
auto supernodesPortal = hierarchicalTree.Supernodes.ReadPortal();
|
|
auto superarcsPortal = hierarchicalTree.Superarcs.ReadPortal();
|
|
auto hyperparentsPortal = hierarchicalTree.Hyperparents.ReadPortal();
|
|
auto super2hypernodePortal = hierarchicalTree.Super2Hypernode.ReadPortal();
|
|
auto whichRoundPortal = hierarchicalTree.WhichRound.ReadPortal();
|
|
auto whichIterationPortal = hierarchicalTree.WhichIteration.ReadPortal();
|
|
auto hypernodesPortal = hierarchicalTree.Hypernodes.ReadPortal();
|
|
auto hyperarcsPortal = hierarchicalTree.Hyperarcs.ReadPortal();
|
|
|
|
// TODO: Resolve passing conventions for per node values
|
|
// auto perNodeValuesPortal = perNodeValues.ReadPortal();
|
|
|
|
// work out how long the computed value is
|
|
// int nodeValueType = vtkm::worklet::contourtree_distributed::BAD_PER_NODE_VALUES;
|
|
// vtkm::Id perNodeSize = perNodeValues.GetNumberOfValues();
|
|
// if (perNodeSize == 0)
|
|
// nodeValueType = vtkm::worklet::contourtree_distributed::NO_PER_NODE_VALUES;
|
|
// else if (perNodeSize == hierarchicalTree.Nodes.GetNumberOfValues())
|
|
// nodeValueType = vtkm::worklet::contourtree_distributed::PER_REGULAR_NODE_VALUES;
|
|
// else if (perNodeSize == hierarchicalTree.Supernodes.GetNumberOfValues())
|
|
// nodeValueType = vtkm::worklet::contourtree_distributed::PER_SUPER_NODE_VALUES;
|
|
// else if (perNodeSize == hierarchicalTree.Hypernodes.GetNumberOfValues())
|
|
// nodeValueType = vtkm::worklet::contourtree_distributed::PER_HYPER_NODE_VALUES;
|
|
// else
|
|
// { // error message
|
|
// outStream << "ERROR in HierarchicalContourTreeDotGraphPrint().\n";
|
|
// outStream << "Per node values array must be empty, or\n";
|
|
// outStream << "Same length as regular nodes (" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << hierarchicalTree.Nodes.GetNumberOfValues() << "), or\n";
|
|
// outStream << "Same length as super nodes (" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << hierarchicalTree.Supernodes.GetNumberOfValues() << "), or\n";
|
|
// outStream << "Same length as hyper nodes (" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << hierarchicalTree.Hypernodes.GetNumberOfValues() << ")\n";
|
|
// outStream << "Actual length was (" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << perNodeValues.GetNumberOfValues() << ")\n";
|
|
// } // error message
|
|
|
|
// print the header information
|
|
outStream << "digraph HierarchicalContourTree\n\t{\n";
|
|
outStream << "\tlabel=\"" << std::setw(1) << label << "\"\n\tlabelloc=t\n\tfontsize=30\n";
|
|
outStream << "\t// Nodes" << std::endl;
|
|
|
|
// loop through all of the nodes in the regular list
|
|
for (vtkm::Id node = 0; node < hierarchicalTree.RegularNodeGlobalIds.GetNumberOfValues(); node++)
|
|
{ // per node
|
|
// Since the superparent for an attachment point is set to another supernode, reset the calculation here
|
|
//vtkm::Id whichRound = maskedIndex(hierarchicalTree.WhichRound[superID]);
|
|
//vtkm::Id whichIteration = maskedIndex(hierarchicalTree.WhichIteration[superID]);
|
|
|
|
// the regular ID in this case is the node itself
|
|
vtkm::Id regularID = node;
|
|
|
|
// for a sort ID, we will take the sort order vector
|
|
vtkm::Id sortID = regularNodeSortOrderPortal.Get(node);
|
|
|
|
// retrieve the global ID
|
|
vtkm::Id globalID = regularNodeGlobalIdsPortal.Get(node);
|
|
|
|
// retrieve the values
|
|
auto dataValue = dataValuesPortal.Get(node);
|
|
|
|
// retrieve the superparent
|
|
vtkm::Id superparent = superparentsPortal.Get(node);
|
|
|
|
// and retrieve the iteration #
|
|
vtkm::Id whichRound =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whichRoundPortal.Get(superparent));
|
|
vtkm::Id whichIteration =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whichIterationPortal.Get(superparent));
|
|
|
|
// work out the super ID & hyper ID
|
|
vtkm::Id superID = regular2supernodePortal.Get(node);
|
|
vtkm::Id hyperparent = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
|
vtkm::Id hyperID = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
|
vtkm::Id nodeType = vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR;
|
|
|
|
// test for super
|
|
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(superID))
|
|
{ // at least super
|
|
// set hyperparent
|
|
hyperparent = hyperparentsPortal.Get(superID);
|
|
// set nodetype
|
|
nodeType = vtkm::worklet::contourtree_distributed::NODE_TYPE_SUPER;
|
|
// retrieve hyper ID
|
|
hyperID = super2hypernodePortal.Get(superparent);
|
|
// test it
|
|
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(hyperID))
|
|
{ // hyper node
|
|
nodeType = vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER;
|
|
} // hyper node
|
|
} // at least super
|
|
|
|
// now, if we don't want the regular nodes, we want to skip them entirely, so
|
|
bool showNode = false;
|
|
// regular structure always shows all nodes
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE)
|
|
showNode = true;
|
|
// super structure shows super & hyper nodes only
|
|
else if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE)
|
|
showNode = (nodeType != vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR);
|
|
else if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE)
|
|
showNode = (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER);
|
|
|
|
// if we didn't set the flag, skip the node
|
|
if (!showNode)
|
|
continue;
|
|
|
|
// print the vertex ID, which should be the sort ID & needs to be left-justified to work
|
|
outStream << "\ts" << std::setw(1) << sortID;
|
|
|
|
// print the style characteristics - node is filled and fixed size
|
|
outStream << " [style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\"";
|
|
// specify the style based on the type of node
|
|
if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR)
|
|
outStream << ",height=\"1.7in\",width=\"1.7in\",penwidth=5";
|
|
else if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_SUPER)
|
|
outStream << ",height=\"2.5in\",width=\"2.5in\",penwidth=10";
|
|
else if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER)
|
|
outStream << ",height=\"2.5in\",width=\"2.5in\",penwidth=15";
|
|
|
|
// shape should always be circular.
|
|
outStream << ",shape=circle";
|
|
|
|
// after setting the flag, its easy
|
|
outStream << ",fillcolor=white";
|
|
|
|
// stroke colour depends on which round
|
|
outStream << ",color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS];
|
|
|
|
// start printing the label
|
|
outStream << ",label=\"";
|
|
// print the global ID
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_GLOBAL_ID)
|
|
outStream << "g " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< globalID << "\\n";
|
|
// print the value
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_DATA_VALUE)
|
|
outStream << "v " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< dataValue << "\\n";
|
|
// print the regular & sort IDs
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_MESH_REGULAR_ID)
|
|
outStream << "r " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< regularID << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_MESH_SORT_ID)
|
|
outStream << "s " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << sortID
|
|
<< "\\n";
|
|
// print the superparent
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPERPARENT)
|
|
outStream << "sp" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< superparent << "\\n";
|
|
|
|
// add arbitrary per node value if it is regular in nature
|
|
// if ((showMask & vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA) && (nodeValueType == vtkm::worklet::contourtree_distributed::PER_REGULAR_NODE_VALUES))
|
|
// outStream << "x " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << perNodeValues[regularID] << "\\n";
|
|
|
|
// we now want to add labelling information specific to supernodes, but also present in hypernodes
|
|
if (nodeType != vtkm::worklet::contourtree_distributed::NODE_TYPE_REGULAR)
|
|
{ // at least super
|
|
|
|
// print the super node ID
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPERNODE_ID)
|
|
outStream << "SN" << std::setw(INDEX_WIDTH) << superID << "\\n";
|
|
|
|
// print the hyperparent as well
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPERPARENT)
|
|
outStream << "HP" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< hyperparent << "\\n";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_ITERATION)
|
|
outStream << "IT" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< whichRound << "." << whichIteration << "\\n";
|
|
|
|
// add arbitrary per node value if it is super in nature
|
|
// if ((showMask & vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA) && (nodeValueType == PER_SUPER_NODE_VALUES))
|
|
// outStream << "X " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << perNodeValues[superID] << "\\n";
|
|
} // at least super
|
|
|
|
// now add even more for hypernodes
|
|
if (nodeType == vtkm::worklet::contourtree_distributed::NODE_TYPE_HYPER)
|
|
{ // hyper node
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPERNODE_ID)
|
|
outStream << "HN" << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH)
|
|
<< hyperID << "\\n";
|
|
|
|
// add arbitrary per node value if it is hyper in nature
|
|
// if ((showMask & vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA) && (nodeValueType == vtkm::worklet::contourtree_distributed::PER_HYPER_NODE_VALUES))
|
|
// outStream << "X " << std::setw(vtkm::worklet::contourtree_distributed::INDEX_WIDTH) << perNodeValues[hyperID] << "\\n";
|
|
} // hyper node
|
|
|
|
outStream << "\"]" << std::endl;
|
|
} // per node
|
|
|
|
// always show the null node
|
|
outStream << "\t// Null Node" << std::endl;
|
|
outStream
|
|
<< "\tNULL "
|
|
"[style=filled,fixedsize=true,fontname=\"Courier\",margin=\"0.02,0.02\",height=\"0.5in\","
|
|
"width=\"0.5in\",penwidth=1,shape=circle,fillcolor=white,color=black,label=\"NULL\"]"
|
|
<< std::endl;
|
|
|
|
// now show superarc nodes
|
|
outStream << "\t// Superarc nodes\n";
|
|
// now repeat to create nodes for the middle of each superarc (to represent the superarcs themselves)
|
|
for (vtkm::Id superarc = 0; superarc < hierarchicalTree.Superarcs.GetNumberOfValues(); superarc++)
|
|
{ // per superarc
|
|
// retrieve ID of target superarc
|
|
vtkm::Id superarcFrom = superarc;
|
|
vtkm::Id superarcTo = superarcsPortal.Get(superarcFrom);
|
|
|
|
// and retrieve the iteration #
|
|
vtkm::Id whichRound =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whichRoundPortal.Get(superarcFrom));
|
|
|
|
// if this is true, it is the last pruned vertex (attachment point or root) and has no superarc vertex
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarcTo))
|
|
continue;
|
|
|
|
// print the superarc vertex
|
|
outStream << "\tSA" << std::setw(1) << superarc;
|
|
outStream << "[shape=circle,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS];
|
|
outStream << ",fillcolor=white";
|
|
outStream << ",fixedsize=true";
|
|
outStream << ",height=0.8,width=0.8";
|
|
outStream << ",label=\"";
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPERARC_ID)
|
|
outStream << "SA" << std::setw(1) << superarc;
|
|
outStream << "\"];" << std::endl;
|
|
} // per superarc
|
|
|
|
// now show regular arcs - since we do not maintain a sort, they will all attach to the parent superarc
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE)
|
|
{ // showing regular nodes
|
|
outStream << "\t// Superarc nodes\n";
|
|
for (vtkm::Id regularID = 0;
|
|
regularID < hierarchicalTree.RegularNodeGlobalIds.GetNumberOfValues();
|
|
regularID++)
|
|
{ // per regular node
|
|
// if it has a superID, then we don't want to attach it to a superarc
|
|
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(
|
|
regular2supernodePortal.Get(regularID)))
|
|
continue;
|
|
|
|
// retrieve the sort ID
|
|
vtkm::Id sortID = regularNodeSortOrderPortal.Get(regularID);
|
|
// retrieve the superparent
|
|
vtkm::Id superparent = superparentsPortal.Get(regularID);
|
|
|
|
// and connect to the superarc
|
|
outStream << "\ts" << sortID << " -> SA" << superparent << "[style=dotted]" << std::endl;
|
|
|
|
} // per regular node
|
|
} // showing regular nodes
|
|
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE)
|
|
{ // showing superstructure
|
|
outStream << "\t// Superarc edges\n";
|
|
// loop through all superarcs to draw them
|
|
for (vtkm::Id superarc = 0; superarc < hierarchicalTree.Superarcs.GetNumberOfValues();
|
|
superarc++)
|
|
{ // per superarc
|
|
// retrieve ID of target supernode
|
|
vtkm::Id superarcFrom = superarc;
|
|
// retrieve the sort ID
|
|
vtkm::Id fromRegular = supernodesPortal.Get(superarcFrom);
|
|
vtkm::Id fromSort = regularNodeSortOrderPortal.Get(fromRegular);
|
|
|
|
// and retrieve the destination
|
|
vtkm::Id superarcTo = superarcsPortal.Get(superarcFrom);
|
|
|
|
// and retrieve the iteration #
|
|
vtkm::Id whichRound =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whichRoundPortal.Get(superarcFrom));
|
|
|
|
// if this is true, it may be the last pruned vertex
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarcTo))
|
|
{ // no superarc
|
|
// if it occurred on the final round, it's the global root and is shown as the NULL node
|
|
if (whichRound == hierarchicalTree.NumRounds)
|
|
outStream << "\ts" << fromSort << " -> NULL[label=\"SA" << superarc << "\",style=dotted]"
|
|
<< std::endl;
|
|
else
|
|
{ // attachment point
|
|
// otherwise, the target is actually a superarc vertex not a supernode vertex
|
|
// so we use the regular ID to retrieve the superparent which tells us which superarc we insert into
|
|
vtkm::Id regularFrom = supernodesPortal.Get(superarcFrom);
|
|
superarcTo = superparentsPortal.Get(regularFrom);
|
|
|
|
// output a suitable edge
|
|
outStream << "\ts" << fromSort << " -> SA" << superarcTo << "[label=\"S" << superarc
|
|
<< "\",style=dotted,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
} // attachment point
|
|
} // no superarc
|
|
else
|
|
{ // there is a superarc
|
|
// retrieve the ascending flag
|
|
bool ascendingSuperarc = vtkm::worklet::contourtree_augmented::IsAscending(superarcTo);
|
|
|
|
// strip out the flags
|
|
superarcTo = vtkm::worklet::contourtree_augmented::MaskedIndex(superarcTo);
|
|
|
|
// retrieve the sort ID for the to end
|
|
vtkm::Id toRegular = supernodesPortal.Get(superarcTo);
|
|
vtkm::Id toSort = regularNodeSortOrderPortal.Get(toRegular);
|
|
|
|
// how we print depends on whether the superarc ascends
|
|
if (ascendingSuperarc)
|
|
{ // ascending arc
|
|
outStream << "\ts" << toSort << " -> SA" << superarc << "[label=\"SA" << superarc
|
|
<< "\",dir=back";
|
|
outStream << ",penwidth=3,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
outStream << "\tSA" << superarc << " -> s" << fromSort << "[label=\"SA" << superarc
|
|
<< "\",dir=back";
|
|
outStream << ",penwidth=3,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
} // ascending arc
|
|
else
|
|
{ // descending arc
|
|
outStream << "\ts" << fromSort << " -> SA" << superarc << "[label=\"SA" << superarc
|
|
<< "\"";
|
|
outStream << ",penwidth=3,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
outStream << "\tSA" << superarc << " -> s" << toSort << "[label=\"SA" << superarc << "\"";
|
|
outStream << ",penwidth=3,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
} // descending arc
|
|
} // there is a superarc
|
|
} // per superarc
|
|
} // showing superstructure
|
|
|
|
if (showMask & vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE)
|
|
{ // show hyperstructure
|
|
outStream << "\t// Hyperarcs\n";
|
|
// now loop through the hyperarcs to draw them
|
|
for (vtkm::Id hyperarc = 0; hyperarc < hierarchicalTree.Hyperarcs.GetNumberOfValues();
|
|
hyperarc++)
|
|
{ // per hyperarc
|
|
// down convert to a sort ID
|
|
vtkm::Id fromSuper = hypernodesPortal.Get(hyperarc);
|
|
vtkm::Id fromRegular = supernodesPortal.Get(fromSuper);
|
|
vtkm::Id fromSort = regularNodeSortOrderPortal.Get(fromRegular);
|
|
|
|
// and retrieve the iteration #
|
|
vtkm::Id whichRound =
|
|
vtkm::worklet::contourtree_augmented::MaskedIndex(whichRoundPortal.Get(fromSuper));
|
|
|
|
// and do the same with the to end
|
|
vtkm::Id toSuper = hyperarcsPortal.Get(hyperarc);
|
|
|
|
// if this is true, it is the last pruned vertex & connects to NULL
|
|
if (vtkm::worklet::contourtree_augmented::NoSuchElement(toSuper))
|
|
outStream << "\ts" << fromSort << " -> NULL[label=\"HA" << hyperarc
|
|
<< "\",penwidth=3.0,style=dotted]" << std::endl;
|
|
else
|
|
{ // not the last one
|
|
// otherwise, retrieve the ascending flag
|
|
bool ascendingHyperarc = vtkm::worklet::contourtree_augmented::IsAscending(toSuper);
|
|
|
|
// strip out the flags
|
|
toSuper = vtkm::worklet::contourtree_augmented::MaskedIndex(toSuper);
|
|
|
|
// retrieve the sort index
|
|
vtkm::Id toRegular = supernodesPortal.Get(toSuper);
|
|
vtkm::Id toSort = regularNodeSortOrderPortal.Get(toRegular);
|
|
|
|
// how we print depends on whether the hyperarc ascends
|
|
if (ascendingHyperarc)
|
|
{ // ascending arc
|
|
outStream << "\ts" << toSort << " -> s" << fromSort << "[label=\"HA" << hyperarc
|
|
<< "\",dir=back";
|
|
outStream << ",penwidth=5.0,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
} // ascending arc
|
|
else
|
|
{ // descending arc
|
|
outStream << "\ts" << fromSort << " -> s" << toSort << "[label=\"HA" << hyperarc << "\"";
|
|
outStream << ",penwidth=5.0,color="
|
|
<< vtkm::worklet::contourtree_augmented::NODE_COLORS
|
|
[whichRound % vtkm::worklet::contourtree_augmented::N_NODE_COLORS]
|
|
<< "]" << std::endl;
|
|
} // descending arc
|
|
} // not the last one
|
|
} // per hyperarc
|
|
} // show hyperstructure
|
|
|
|
// print the footer information
|
|
outStream << "\t}\n";
|
|
|
|
// now return the string
|
|
return outStream.str();
|
|
} // HierarchicalContourTreeDotGraphPrint()
|
|
|
|
|
|
} // namespace contourtree_distributed
|
|
} // namespace worklet
|
|
} // namespace vtkm
|
|
|
|
#endif
|