Merge topic 'bounding-interval-hierarchy-in-vtkm-cont'

5960b8abf Suppress nvlink warnings about virtual methods not used
0af017b03 Move virtual methods of other CellLocators to vtkm_cont
e87864b0e Put CellLocatorBoundingIntervalHierarchy in vtkm_cont library

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !1594
This commit is contained in:
Kenneth Moreland 2019-03-21 17:40:59 +00:00 committed by Kitware Robot
commit 07fe1060a0
16 changed files with 773 additions and 733 deletions

@ -57,5 +57,8 @@ list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
"nvlink warning : Stack size for entry function.*ArrayPortalWrapper.*"
"nvlink warning : .*ArrayPortalWrapper.* has address taken but no possible call to it"
"nvlink warning : .*ArrayPortalVirtual.* has address taken but no possible call to it"
"nvlink warning : .*CellLocatorBoundingIntervalHierarchyExec.* has address taken but no possible call to it"
"nvlink warning : .*CellLocatorRectilinearGrid.* has address taken but no possible call to it"
"nvlink warning : .*CellLocatorUniformGrid.* has address taken but no possible call to it"
)

@ -0,0 +1,10 @@
# Put CellLocatorBoundingIntervalHierarchy in vtkm_cont library
All of the methods in CellLocatorBoundingIntervalHierarchy were listed in
header files. This is sometimes problematic with virtual methods. Since
everything implemented in it can just be embedded in a library, move the
code into the vtkm_cont library.
These changes caused some warnings in clang to show up based on virtual
methods in other cell locators. Hence, the rest of the cell locators
have also had some of their code moved to vtkm_cont.

@ -114,7 +114,6 @@ set(template_sources
ArrayHandle.hxx
ArrayHandleVirtual.hxx
ArrayRangeCompute.hxx
CellLocatorBoundingIntervalHierarchy.hxx
CellSetExplicit.hxx
CellSetStructured.hxx
ColorTable.hxx
@ -132,6 +131,7 @@ set(sources
AssignerMultiBlock.cxx
BoundsCompute.cxx
BoundsGlobalCompute.cxx
CellLocator.cxx
CellSet.cxx
CellSetStructured.cxx
ColorTable.cxx
@ -166,6 +166,9 @@ set(sources
# compiled with a device-specific compiler (like CUDA).
set(device_sources
ArrayRangeCompute.cxx
CellLocatorBoundingIntervalHierarchy.cxx
CellLocatorRectilinearGrid.cxx
CellLocatorUniformGrid.cxx
CellSetExplicit.cxx
CoordinateSystem.cxx
StorageVirtual.cxx

23
vtkm/cont/CellLocator.cxx Normal file

@ -0,0 +1,23 @@
//============================================================================
// 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 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2019 UT-Battelle, LLC.
// Copyright 2019 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.
//============================================================================
#include <vtkm/cont/CellLocator.h>
vtkm::cont::CellLocator::~CellLocator() = default;

@ -36,7 +36,7 @@ namespace vtkm
namespace cont
{
class VTKM_ALWAYS_EXPORT CellLocator : public vtkm::cont::ExecutionObjectBase
class VTKM_CONT_EXPORT CellLocator : public vtkm::cont::ExecutionObjectBase
{
public:
@ -45,6 +45,8 @@ public:
{
}
virtual ~CellLocator();
vtkm::cont::DynamicCellSet GetCellSet() const { return CellSet; }
void SetCellSet(const vtkm::cont::DynamicCellSet& cellSet)

@ -0,0 +1,541 @@
//============================================================================
// 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 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.
//============================================================================
#include <vtkm/Bounds.h>
#include <vtkm/Types.h>
#include <vtkm/VecFromPortalPermute.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleReverse.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/exec/CellLocatorBoundingIntervalHierarchyExec.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/Invoker.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
namespace vtkm
{
namespace cont
{
using IdArrayHandle = vtkm::cont::ArrayHandle<vtkm::Id>;
using IdPermutationArrayHandle = vtkm::cont::ArrayHandlePermutation<IdArrayHandle, IdArrayHandle>;
using BoundsArrayHandle = vtkm::cont::ArrayHandle<vtkm::Bounds>;
using CoordsArrayHandle = vtkm::cont::ArrayHandle<vtkm::FloatDefault>;
using CoordsPermutationArrayHandle =
vtkm::cont::ArrayHandlePermutation<IdArrayHandle, CoordsArrayHandle>;
using CountingIdArrayHandle = vtkm::cont::ArrayHandleCounting<vtkm::Id>;
using RangeArrayHandle = vtkm::cont::ArrayHandle<vtkm::Range>;
using RangePermutationArrayHandle =
vtkm::cont::ArrayHandlePermutation<IdArrayHandle, RangeArrayHandle>;
using SplitArrayHandle = vtkm::cont::ArrayHandle<vtkm::worklet::spatialstructure::TreeNode>;
using SplitPermutationArrayHandle =
vtkm::cont::ArrayHandlePermutation<IdArrayHandle, SplitArrayHandle>;
using SplitPropertiesArrayHandle =
vtkm::cont::ArrayHandle<vtkm::worklet::spatialstructure::SplitProperties>;
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::CellLocator>;
namespace
{
VTKM_CONT IdArrayHandle CalculateSegmentSizes(const IdArrayHandle& segmentIds, vtkm::Id numCells)
{
IdArrayHandle discardKeys;
IdArrayHandle segmentSizes;
vtkm::cont::Algorithm::ReduceByKey(segmentIds,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(1, numCells),
discardKeys,
segmentSizes,
vtkm::Add());
return segmentSizes;
}
VTKM_CONT IdArrayHandle GenerateSegmentIds(const IdArrayHandle& segmentSizes, vtkm::Id numCells)
{
// Compact segment ids, removing non-contiguous values.
// 1. Perform ScanInclusive to calculate the end positions of each segment
IdArrayHandle segmentEnds;
vtkm::cont::Algorithm::ScanInclusive(segmentSizes, segmentEnds);
// 2. Perform UpperBounds to perform the final compaction.
IdArrayHandle segmentIds;
vtkm::cont::Algorithm::UpperBounds(
segmentEnds, vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, numCells), segmentIds);
return segmentIds;
}
VTKM_CONT void CalculatePlaneSplitCost(vtkm::IdComponent planeIndex,
vtkm::IdComponent numPlanes,
RangePermutationArrayHandle& segmentRanges,
RangeArrayHandle& ranges,
CoordsArrayHandle& coords,
IdArrayHandle& segmentIds,
SplitPropertiesArrayHandle& splits,
vtkm::IdComponent index,
vtkm::IdComponent numTotalPlanes)
{
vtkm::worklet::Invoker invoker;
// Make candidate split plane array
vtkm::cont::ArrayHandle<vtkm::FloatDefault> splitPlanes;
vtkm::worklet::spatialstructure::SplitPlaneCalculatorWorklet splitPlaneCalcWorklet(planeIndex,
numPlanes);
invoker(splitPlaneCalcWorklet, segmentRanges, splitPlanes);
// Check if a point is to the left of the split plane or right
vtkm::cont::ArrayHandle<vtkm::Id> isLEQOfSplitPlane, isROfSplitPlane;
invoker(vtkm::worklet::spatialstructure::LEQWorklet{},
coords,
splitPlanes,
isLEQOfSplitPlane,
isROfSplitPlane);
// Count of points to the left
vtkm::cont::ArrayHandle<vtkm::Id> pointsToLeft;
IdArrayHandle discardKeys;
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, isLEQOfSplitPlane, discardKeys, pointsToLeft, vtkm::Add());
// Count of points to the right
vtkm::cont::ArrayHandle<vtkm::Id> pointsToRight;
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, isROfSplitPlane, discardKeys, pointsToRight, vtkm::Add());
isLEQOfSplitPlane.ReleaseResourcesExecution();
isROfSplitPlane.ReleaseResourcesExecution();
// Calculate Lmax and Rmin
vtkm::cont::ArrayHandle<vtkm::Range> lMaxRanges;
{
vtkm::cont::ArrayHandle<vtkm::Range> leqRanges;
vtkm::worklet::spatialstructure::FilterRanges<true> worklet;
invoker(worklet, coords, splitPlanes, ranges, leqRanges);
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, leqRanges, discardKeys, lMaxRanges, vtkm::worklet::spatialstructure::RangeAdd());
}
vtkm::cont::ArrayHandle<vtkm::Range> rMinRanges;
{
vtkm::cont::ArrayHandle<vtkm::Range> rRanges;
vtkm::worklet::spatialstructure::FilterRanges<false> worklet;
invoker(worklet, coords, splitPlanes, ranges, rRanges);
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, rRanges, discardKeys, rMinRanges, vtkm::worklet::spatialstructure::RangeAdd());
}
vtkm::cont::ArrayHandle<vtkm::FloatDefault> segmentedSplitPlanes;
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, splitPlanes, discardKeys, segmentedSplitPlanes, vtkm::Minimum());
// Calculate costs
vtkm::worklet::spatialstructure::SplitPropertiesCalculator splitPropertiesCalculator(
index, numTotalPlanes + 1);
invoker(splitPropertiesCalculator,
pointsToLeft,
pointsToRight,
lMaxRanges,
rMinRanges,
segmentedSplitPlanes,
splits);
}
VTKM_CONT void CalculateSplitCosts(vtkm::IdComponent numPlanes,
RangePermutationArrayHandle& segmentRanges,
RangeArrayHandle& ranges,
CoordsArrayHandle& coords,
IdArrayHandle& segmentIds,
SplitPropertiesArrayHandle& splits)
{
for (vtkm::IdComponent planeIndex = 0; planeIndex < numPlanes; ++planeIndex)
{
CalculatePlaneSplitCost(planeIndex,
numPlanes,
segmentRanges,
ranges,
coords,
segmentIds,
splits,
planeIndex,
numPlanes);
}
// Calculate median costs
CalculatePlaneSplitCost(
0, 1, segmentRanges, ranges, coords, segmentIds, splits, numPlanes, numPlanes);
}
VTKM_CONT IdArrayHandle CalculateSplitScatterIndices(const IdArrayHandle& cellIds,
const IdArrayHandle& leqFlags,
const IdArrayHandle& segmentIds)
{
vtkm::worklet::Invoker invoker;
// Count total number of true flags preceding in segment
IdArrayHandle trueFlagCounts;
vtkm::cont::Algorithm::ScanExclusiveByKey(segmentIds, leqFlags, trueFlagCounts);
// Make a counting iterator.
CountingIdArrayHandle counts(0, 1, cellIds.GetNumberOfValues());
// Total number of elements in previous segment
vtkm::cont::ArrayHandle<vtkm::Id> countPreviousSegments;
vtkm::cont::Algorithm::ScanInclusiveByKey(
segmentIds, counts, countPreviousSegments, vtkm::Minimum());
// Total number of false flags so far in segment
vtkm::cont::ArrayHandleTransform<IdArrayHandle, vtkm::worklet::spatialstructure::Invert>
flagsInverse(leqFlags, vtkm::worklet::spatialstructure::Invert());
vtkm::cont::ArrayHandle<vtkm::Id> runningFalseFlagCount;
vtkm::cont::Algorithm::ScanInclusiveByKey(
segmentIds, flagsInverse, runningFalseFlagCount, vtkm::Add());
// Total number of false flags in segment
IdArrayHandle totalFalseFlagSegmentCount =
vtkm::worklet::spatialstructure::ReverseScanInclusiveByKey(
segmentIds, runningFalseFlagCount, vtkm::Maximum());
// if point is to the left,
// index = total number in previous segments + total number of false flags in this segment + total number of trues in previous segment
// else
// index = total number in previous segments + number of falses preceding it in the segment.
IdArrayHandle scatterIndices;
invoker(vtkm::worklet::spatialstructure::SplitIndicesCalculator{},
leqFlags,
trueFlagCounts,
countPreviousSegments,
runningFalseFlagCount,
totalFalseFlagSegmentCount,
scatterIndices);
return scatterIndices;
}
} // anonymous namespace
VTKM_CONT CellLocatorBoundingIntervalHierarchy::~CellLocatorBoundingIntervalHierarchy() = default;
VTKM_CONT
void CellLocatorBoundingIntervalHierarchy::Build()
{
vtkm::worklet::Invoker invoker;
vtkm::cont::DynamicCellSet cellSet = this->GetCellSet();
vtkm::Id numCells = cellSet.GetNumberOfCells();
vtkm::cont::CoordinateSystem coords = this->GetCoordinates();
vtkm::cont::ArrayHandleVirtualCoordinates points = coords.GetData();
//std::cout << "No of cells: " << numCells << "\n";
//std::cout.precision(3);
//START_TIMER(s11);
IdArrayHandle cellIds;
vtkm::cont::Algorithm::Copy(CountingIdArrayHandle(0, 1, numCells), cellIds);
IdArrayHandle segmentIds;
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleConstant<vtkm::Id>(0, numCells), segmentIds);
//PRINT_TIMER("1.1", s11);
//START_TIMER(s12);
CoordsArrayHandle centerXs, centerYs, centerZs;
RangeArrayHandle xRanges, yRanges, zRanges;
invoker(vtkm::worklet::spatialstructure::CellRangesExtracter{},
cellSet,
points,
xRanges,
yRanges,
zRanges,
centerXs,
centerYs,
centerZs);
//PRINT_TIMER("1.2", s12);
bool done = false;
//vtkm::IdComponent iteration = 0;
vtkm::Id nodesIndexOffset = 0;
vtkm::Id numSegments = 1;
IdArrayHandle discardKeys;
IdArrayHandle segmentSizes;
segmentSizes.Allocate(1);
segmentSizes.GetPortalControl().Set(0, numCells);
this->ProcessedCellIds.Allocate(numCells);
vtkm::Id cellIdsOffset = 0;
IdArrayHandle parentIndices;
parentIndices.Allocate(1);
parentIndices.GetPortalControl().Set(0, -1);
while (!done)
{
//std::cout << "**** Iteration " << (++iteration) << " ****\n";
//Output(segmentSizes);
//START_TIMER(s21);
// Calculate the X, Y, Z bounding ranges for each segment
RangeArrayHandle perSegmentXRanges, perSegmentYRanges, perSegmentZRanges;
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, xRanges, discardKeys, perSegmentXRanges, vtkm::Add());
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, yRanges, discardKeys, perSegmentYRanges, vtkm::Add());
vtkm::cont::Algorithm::ReduceByKey(
segmentIds, zRanges, discardKeys, perSegmentZRanges, vtkm::Add());
//PRINT_TIMER("2.1", s21);
// Expand the per segment bounding ranges, to per cell;
RangePermutationArrayHandle segmentXRanges(segmentIds, perSegmentXRanges);
RangePermutationArrayHandle segmentYRanges(segmentIds, perSegmentYRanges);
RangePermutationArrayHandle segmentZRanges(segmentIds, perSegmentZRanges);
//START_TIMER(s22);
// Calculate split costs for NumPlanes split planes, across X, Y and Z dimensions
vtkm::Id numSplitPlanes = numSegments * (this->NumPlanes + 1);
vtkm::cont::ArrayHandle<vtkm::worklet::spatialstructure::SplitProperties> xSplits, ySplits,
zSplits;
xSplits.Allocate(numSplitPlanes);
ySplits.Allocate(numSplitPlanes);
zSplits.Allocate(numSplitPlanes);
CalculateSplitCosts(this->NumPlanes, segmentXRanges, xRanges, centerXs, segmentIds, xSplits);
CalculateSplitCosts(this->NumPlanes, segmentYRanges, yRanges, centerYs, segmentIds, ySplits);
CalculateSplitCosts(this->NumPlanes, segmentZRanges, zRanges, centerZs, segmentIds, zSplits);
//PRINT_TIMER("2.2", s22);
segmentXRanges.ReleaseResourcesExecution();
segmentYRanges.ReleaseResourcesExecution();
segmentZRanges.ReleaseResourcesExecution();
//START_TIMER(s23);
// Select best split plane and dimension across X, Y, Z dimension, per segment
SplitArrayHandle segmentSplits;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> segmentPlanes;
vtkm::cont::ArrayHandle<vtkm::Id> splitChoices;
CountingIdArrayHandle indices(0, 1, numSegments);
vtkm::worklet::spatialstructure::SplitSelector worklet(
this->NumPlanes, this->MaxLeafSize, this->NumPlanes + 1);
invoker(worklet,
indices,
xSplits,
ySplits,
zSplits,
segmentSizes,
segmentSplits,
segmentPlanes,
splitChoices);
//PRINT_TIMER("2.3", s23);
// Expand the per segment split plane to per cell
SplitPermutationArrayHandle splits(segmentIds, segmentSplits);
CoordsPermutationArrayHandle planes(segmentIds, segmentPlanes);
//START_TIMER(s31);
IdArrayHandle leqFlags;
invoker(vtkm::worklet::spatialstructure::CalculateSplitDirectionFlag{},
centerXs,
centerYs,
centerZs,
splits,
planes,
leqFlags);
//PRINT_TIMER("3.1", s31);
//START_TIMER(s32);
IdArrayHandle scatterIndices = CalculateSplitScatterIndices(cellIds, leqFlags, segmentIds);
IdArrayHandle newSegmentIds;
IdPermutationArrayHandle sizes(segmentIds, segmentSizes);
invoker(vtkm::worklet::spatialstructure::SegmentSplitter{ this->MaxLeafSize },
segmentIds,
leqFlags,
sizes,
newSegmentIds);
//PRINT_TIMER("3.2", s32);
//START_TIMER(s33);
vtkm::cont::ArrayHandle<vtkm::Id> choices;
vtkm::cont::Algorithm::Copy(IdPermutationArrayHandle(segmentIds, splitChoices), choices);
cellIds = vtkm::worklet::spatialstructure::ScatterArray(cellIds, scatterIndices);
segmentIds = vtkm::worklet::spatialstructure::ScatterArray(segmentIds, scatterIndices);
newSegmentIds = vtkm::worklet::spatialstructure::ScatterArray(newSegmentIds, scatterIndices);
xRanges = vtkm::worklet::spatialstructure::ScatterArray(xRanges, scatterIndices);
yRanges = vtkm::worklet::spatialstructure::ScatterArray(yRanges, scatterIndices);
zRanges = vtkm::worklet::spatialstructure::ScatterArray(zRanges, scatterIndices);
centerXs = vtkm::worklet::spatialstructure::ScatterArray(centerXs, scatterIndices);
centerYs = vtkm::worklet::spatialstructure::ScatterArray(centerYs, scatterIndices);
centerZs = vtkm::worklet::spatialstructure::ScatterArray(centerZs, scatterIndices);
choices = vtkm::worklet::spatialstructure::ScatterArray(choices, scatterIndices);
//PRINT_TIMER("3.3", s33);
// Move the cell ids at leafs to the processed cellids list
//START_TIMER(s41);
IdArrayHandle nonSplitSegmentSizes;
invoker(vtkm::worklet::spatialstructure::NonSplitIndexCalculator{ this->MaxLeafSize },
segmentSizes,
nonSplitSegmentSizes);
IdArrayHandle nonSplitSegmentIndices;
vtkm::cont::Algorithm::ScanExclusive(nonSplitSegmentSizes, nonSplitSegmentIndices);
IdArrayHandle runningSplitSegmentCounts;
vtkm::Id numNewSegments =
vtkm::cont::Algorithm::ScanExclusive(splitChoices, runningSplitSegmentCounts);
//PRINT_TIMER("4.1", s41);
//START_TIMER(s42);
IdArrayHandle doneCellIds;
vtkm::cont::Algorithm::CopyIf(
cellIds, choices, doneCellIds, vtkm::worklet::spatialstructure::Invert());
vtkm::cont::Algorithm::CopySubRange(
doneCellIds, 0, doneCellIds.GetNumberOfValues(), this->ProcessedCellIds, cellIdsOffset);
cellIds = vtkm::worklet::spatialstructure::CopyIfArray(cellIds, choices);
newSegmentIds = vtkm::worklet::spatialstructure::CopyIfArray(newSegmentIds, choices);
xRanges = vtkm::worklet::spatialstructure::CopyIfArray(xRanges, choices);
yRanges = vtkm::worklet::spatialstructure::CopyIfArray(yRanges, choices);
zRanges = vtkm::worklet::spatialstructure::CopyIfArray(zRanges, choices);
centerXs = vtkm::worklet::spatialstructure::CopyIfArray(centerXs, choices);
centerYs = vtkm::worklet::spatialstructure::CopyIfArray(centerYs, choices);
centerZs = vtkm::worklet::spatialstructure::CopyIfArray(centerZs, choices);
//PRINT_TIMER("4.2", s42);
//START_TIMER(s43);
// Make a new nodes with enough nodes for the current level, copying over the old one
vtkm::Id nodesSize = this->Nodes.GetNumberOfValues() + numSegments;
vtkm::cont::ArrayHandle<vtkm::exec::CellLocatorBoundingIntervalHierarchyNode> newTree;
newTree.Allocate(nodesSize);
vtkm::cont::Algorithm::CopySubRange(this->Nodes, 0, this->Nodes.GetNumberOfValues(), newTree);
IdArrayHandle nextParentIndices;
nextParentIndices.Allocate(2 * numNewSegments);
CountingIdArrayHandle nodesIndices(nodesIndexOffset, 1, numSegments);
vtkm::worklet::spatialstructure::TreeLevelAdder nodesAdder(
cellIdsOffset, nodesSize, this->MaxLeafSize);
invoker(nodesAdder,
nodesIndices,
segmentSplits,
nonSplitSegmentIndices,
segmentSizes,
runningSplitSegmentCounts,
parentIndices,
newTree,
nextParentIndices);
nodesIndexOffset = nodesSize;
cellIdsOffset += doneCellIds.GetNumberOfValues();
this->Nodes = newTree;
//PRINT_TIMER("4.3", s43);
//START_TIMER(s51);
segmentIds = newSegmentIds;
segmentSizes = CalculateSegmentSizes(segmentIds, segmentIds.GetNumberOfValues());
segmentIds = GenerateSegmentIds(segmentSizes, segmentIds.GetNumberOfValues());
IdArrayHandle uniqueSegmentIds;
vtkm::cont::Algorithm::Copy(segmentIds, uniqueSegmentIds);
vtkm::cont::Algorithm::Unique(uniqueSegmentIds);
numSegments = uniqueSegmentIds.GetNumberOfValues();
done = segmentIds.GetNumberOfValues() == 0;
parentIndices = nextParentIndices;
//PRINT_TIMER("5.1", s51);
//std::cout << "Iteration time: " << iterationTimer.GetElapsedTime() << "\n";
}
//std::cout << "Total time: " << totalTimer.GetElapsedTime() << "\n";
}
class CellLocatorBoundingIntervalHierarchy::PrepareForExecutionFunctor
{
public:
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::CellLocatorBoundingIntervalHierarchy& bih,
HandleType& bihExec) const
{
vtkm::cont::DynamicCellSet cellSet = bih.GetCellSet();
if (cellSet.IsType<vtkm::cont::CellSetExplicit<>>())
{
using CellSetType = vtkm::cont::CellSetExplicit<>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
{
using CellSetType = vtkm::cont::CellSetStructured<2>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
{
using CellSetType = vtkm::cont::CellSetStructured<3>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else if (cellSet.IsType<vtkm::cont::CellSetSingleType<>>())
{
using CellSetType = vtkm::cont::CellSetSingleType<>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else
{
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
}
return true;
}
};
VTKM_CONT
const HandleType CellLocatorBoundingIntervalHierarchy::PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const
{
const bool success =
vtkm::cont::TryExecuteOnDevice(deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("BoundingIntervalHierarchy", deviceId);
}
return this->ExecHandle;
}
} //namespace cont
} //namespace vtkm

@ -35,7 +35,7 @@ namespace vtkm
namespace cont
{
class VTKM_ALWAYS_EXPORT CellLocatorBoundingIntervalHierarchy : public vtkm::cont::CellLocator
class VTKM_CONT_EXPORT CellLocatorBoundingIntervalHierarchy : public vtkm::cont::CellLocator
{
private:
using IdArrayHandle = vtkm::cont::ArrayHandle<vtkm::Id>;
@ -50,37 +50,6 @@ private:
class BuildFunctor;
class PrepareForExecutionFunctor;
template <typename DeviceAdapter>
VTKM_CONT IdArrayHandle CalculateSegmentSizes(const IdArrayHandle&, vtkm::Id);
template <typename DeviceAdapter>
VTKM_CONT IdArrayHandle GenerateSegmentIds(const IdArrayHandle&, vtkm::Id);
template <typename DeviceAdapter>
VTKM_CONT void CalculateSplitCosts(RangePermutationArrayHandle&,
RangeArrayHandle&,
CoordsArrayHandle&,
IdArrayHandle&,
SplitPropertiesArrayHandle&,
DeviceAdapter);
template <typename DeviceAdapter>
VTKM_CONT void CalculatePlaneSplitCost(vtkm::IdComponent,
vtkm::IdComponent,
RangePermutationArrayHandle&,
RangeArrayHandle&,
CoordsArrayHandle&,
IdArrayHandle&,
SplitPropertiesArrayHandle&,
vtkm::IdComponent,
DeviceAdapter);
template <typename DeviceAdapter>
VTKM_CONT IdArrayHandle CalculateSplitScatterIndices(const IdArrayHandle&,
const IdArrayHandle&,
const IdArrayHandle&,
DeviceAdapter);
public:
VTKM_CONT
CellLocatorBoundingIntervalHierarchy(vtkm::IdComponent numPlanes = 4,
@ -92,6 +61,8 @@ public:
{
}
VTKM_CONT ~CellLocatorBoundingIntervalHierarchy() override;
VTKM_CONT
void SetNumberOfSplittingPlanes(vtkm::IdComponent numPlanes)
{

@ -1,573 +0,0 @@
//============================================================================
// 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 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.
//============================================================================
#include <vtkm/Bounds.h>
#include <vtkm/Types.h>
#include <vtkm/VecFromPortalPermute.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleReverse.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/exec/CellLocatorBoundingIntervalHierarchyExec.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/Invoker.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
namespace vtkm
{
namespace cont
{
using IdArrayHandle = vtkm::cont::ArrayHandle<vtkm::Id>;
using IdPermutationArrayHandle = vtkm::cont::ArrayHandlePermutation<IdArrayHandle, IdArrayHandle>;
using BoundsArrayHandle = vtkm::cont::ArrayHandle<vtkm::Bounds>;
using CoordsArrayHandle = vtkm::cont::ArrayHandle<vtkm::FloatDefault>;
using CoordsPermutationArrayHandle =
vtkm::cont::ArrayHandlePermutation<IdArrayHandle, CoordsArrayHandle>;
using CountingIdArrayHandle = vtkm::cont::ArrayHandleCounting<vtkm::Id>;
using RangeArrayHandle = vtkm::cont::ArrayHandle<vtkm::Range>;
using RangePermutationArrayHandle =
vtkm::cont::ArrayHandlePermutation<IdArrayHandle, RangeArrayHandle>;
using SplitArrayHandle = vtkm::cont::ArrayHandle<vtkm::worklet::spatialstructure::TreeNode>;
using SplitPermutationArrayHandle =
vtkm::cont::ArrayHandlePermutation<IdArrayHandle, SplitArrayHandle>;
using SplitPropertiesArrayHandle =
vtkm::cont::ArrayHandle<vtkm::worklet::spatialstructure::SplitProperties>;
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::CellLocator>;
template <typename DeviceAdapter>
VTKM_CONT IdArrayHandle
CellLocatorBoundingIntervalHierarchy::CalculateSegmentSizes(const IdArrayHandle& segmentIds,
vtkm::Id numCells)
{
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
IdArrayHandle discardKeys;
IdArrayHandle segmentSizes;
Algorithms::ReduceByKey(segmentIds,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(1, numCells),
discardKeys,
segmentSizes,
vtkm::Add());
return segmentSizes;
}
template <typename DeviceAdapter>
VTKM_CONT IdArrayHandle
CellLocatorBoundingIntervalHierarchy::GenerateSegmentIds(const IdArrayHandle& segmentSizes,
vtkm::Id numCells)
{
// Compact segment ids, removing non-contiguous values.
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
// 1. Perform ScanInclusive to calculate the end positions of each segment
IdArrayHandle segmentEnds;
Algorithms::ScanInclusive(segmentSizes, segmentEnds);
// 2. Perform UpperBounds to perform the final compaction.
IdArrayHandle segmentIds;
Algorithms::UpperBounds(
segmentEnds, vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, numCells), segmentIds);
return segmentIds;
}
template <typename DeviceAdapter>
VTKM_CONT void CellLocatorBoundingIntervalHierarchy::CalculateSplitCosts(
RangePermutationArrayHandle& segmentRanges,
RangeArrayHandle& ranges,
CoordsArrayHandle& coords,
IdArrayHandle& segmentIds,
SplitPropertiesArrayHandle& splits,
DeviceAdapter)
{
for (vtkm::IdComponent planeIndex = 0; planeIndex < NumPlanes; ++planeIndex)
{
CalculatePlaneSplitCost(planeIndex,
NumPlanes,
segmentRanges,
ranges,
coords,
segmentIds,
splits,
planeIndex,
DeviceAdapter());
}
// Calculate median costs
CalculatePlaneSplitCost(
0, 1, segmentRanges, ranges, coords, segmentIds, splits, NumPlanes, DeviceAdapter());
}
template <typename DeviceAdapter>
VTKM_CONT void CellLocatorBoundingIntervalHierarchy::CalculatePlaneSplitCost(
vtkm::IdComponent planeIndex,
vtkm::IdComponent numPlanes,
RangePermutationArrayHandle& segmentRanges,
RangeArrayHandle& ranges,
CoordsArrayHandle& coords,
IdArrayHandle& segmentIds,
SplitPropertiesArrayHandle& splits,
vtkm::IdComponent index,
DeviceAdapter)
{
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
vtkm::worklet::Invoker invoker(DeviceAdapter{});
// Make candidate split plane array
vtkm::cont::ArrayHandle<vtkm::FloatDefault> splitPlanes;
vtkm::worklet::spatialstructure::SplitPlaneCalculatorWorklet splitPlaneCalcWorklet(planeIndex,
numPlanes);
invoker(splitPlaneCalcWorklet, segmentRanges, splitPlanes);
// Check if a point is to the left of the split plane or right
vtkm::cont::ArrayHandle<vtkm::Id> isLEQOfSplitPlane, isROfSplitPlane;
invoker(vtkm::worklet::spatialstructure::LEQWorklet{},
coords,
splitPlanes,
isLEQOfSplitPlane,
isROfSplitPlane);
// Count of points to the left
vtkm::cont::ArrayHandle<vtkm::Id> pointsToLeft;
IdArrayHandle discardKeys;
Algorithms::ReduceByKey(segmentIds, isLEQOfSplitPlane, discardKeys, pointsToLeft, vtkm::Add());
// Count of points to the right
vtkm::cont::ArrayHandle<vtkm::Id> pointsToRight;
Algorithms::ReduceByKey(segmentIds, isROfSplitPlane, discardKeys, pointsToRight, vtkm::Add());
isLEQOfSplitPlane.ReleaseResourcesExecution();
isROfSplitPlane.ReleaseResourcesExecution();
// Calculate Lmax and Rmin
vtkm::cont::ArrayHandle<vtkm::Range> lMaxRanges;
{
vtkm::cont::ArrayHandle<vtkm::Range> leqRanges;
vtkm::worklet::spatialstructure::FilterRanges<true> worklet;
invoker(worklet, coords, splitPlanes, ranges, leqRanges);
Algorithms::ReduceByKey(
segmentIds, leqRanges, discardKeys, lMaxRanges, vtkm::worklet::spatialstructure::RangeAdd());
}
vtkm::cont::ArrayHandle<vtkm::Range> rMinRanges;
{
vtkm::cont::ArrayHandle<vtkm::Range> rRanges;
vtkm::worklet::spatialstructure::FilterRanges<false> worklet;
invoker(worklet, coords, splitPlanes, ranges, rRanges);
Algorithms::ReduceByKey(
segmentIds, rRanges, discardKeys, rMinRanges, vtkm::worklet::spatialstructure::RangeAdd());
}
vtkm::cont::ArrayHandle<vtkm::FloatDefault> segmentedSplitPlanes;
Algorithms::ReduceByKey(
segmentIds, splitPlanes, discardKeys, segmentedSplitPlanes, vtkm::Minimum());
// Calculate costs
vtkm::worklet::spatialstructure::SplitPropertiesCalculator splitPropertiesCalculator(
index, NumPlanes + 1);
invoker(splitPropertiesCalculator,
pointsToLeft,
pointsToRight,
lMaxRanges,
rMinRanges,
segmentedSplitPlanes,
splits);
}
template <typename DeviceAdapter>
VTKM_CONT IdArrayHandle
CellLocatorBoundingIntervalHierarchy::CalculateSplitScatterIndices(const IdArrayHandle& cellIds,
const IdArrayHandle& leqFlags,
const IdArrayHandle& segmentIds,
DeviceAdapter)
{
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
vtkm::worklet::Invoker invoker(DeviceAdapter{});
// Count total number of true flags preceding in segment
IdArrayHandle trueFlagCounts;
Algorithms::ScanExclusiveByKey(segmentIds, leqFlags, trueFlagCounts);
// Make a counting iterator.
CountingIdArrayHandle counts(0, 1, cellIds.GetNumberOfValues());
// Total number of elements in previous segment
vtkm::cont::ArrayHandle<vtkm::Id> countPreviousSegments;
Algorithms::ScanInclusiveByKey(segmentIds, counts, countPreviousSegments, vtkm::Minimum());
// Total number of false flags so far in segment
vtkm::cont::ArrayHandleTransform<IdArrayHandle, vtkm::worklet::spatialstructure::Invert>
flagsInverse(leqFlags, vtkm::worklet::spatialstructure::Invert());
vtkm::cont::ArrayHandle<vtkm::Id> runningFalseFlagCount;
Algorithms::ScanInclusiveByKey(segmentIds, flagsInverse, runningFalseFlagCount, vtkm::Add());
// Total number of false flags in segment
IdArrayHandle totalFalseFlagSegmentCount =
vtkm::worklet::spatialstructure::ReverseScanInclusiveByKey(
segmentIds, runningFalseFlagCount, vtkm::Maximum(), DeviceAdapter());
// if point is to the left,
// index = total number in previous segments + total number of false flags in this segment + total number of trues in previous segment
// else
// index = total number in previous segments + number of falses preceding it in the segment.
IdArrayHandle scatterIndices;
invoker(vtkm::worklet::spatialstructure::SplitIndicesCalculator{},
leqFlags,
trueFlagCounts,
countPreviousSegments,
runningFalseFlagCount,
totalFalseFlagSegmentCount,
scatterIndices);
return scatterIndices;
}
class CellLocatorBoundingIntervalHierarchy::BuildFunctor
{
protected:
CellLocatorBoundingIntervalHierarchy* Self;
public:
VTKM_CONT
BuildFunctor(CellLocatorBoundingIntervalHierarchy* self)
: Self(self)
{
}
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapter);
// Accommodate into a Functor, so that this could be used with TryExecute
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
vtkm::worklet::Invoker invoker(DeviceAdapter{});
vtkm::cont::DynamicCellSet cellSet = Self->GetCellSet();
vtkm::Id numCells = cellSet.GetNumberOfCells();
vtkm::cont::CoordinateSystem coords = Self->GetCoordinates();
vtkm::cont::ArrayHandleVirtualCoordinates points = coords.GetData();
//std::cout << "No of cells: " << numCells << "\n";
//std::cout.precision(3);
//START_TIMER(s11);
IdArrayHandle cellIds;
Algorithms::Copy(CountingIdArrayHandle(0, 1, numCells), cellIds);
IdArrayHandle segmentIds;
Algorithms::Copy(vtkm::cont::ArrayHandleConstant<vtkm::Id>(0, numCells), segmentIds);
//PRINT_TIMER("1.1", s11);
//START_TIMER(s12);
CoordsArrayHandle centerXs, centerYs, centerZs;
RangeArrayHandle xRanges, yRanges, zRanges;
invoker(vtkm::worklet::spatialstructure::CellRangesExtracter{},
cellSet,
points,
xRanges,
yRanges,
zRanges,
centerXs,
centerYs,
centerZs);
//PRINT_TIMER("1.2", s12);
bool done = false;
//vtkm::IdComponent iteration = 0;
vtkm::Id nodesIndexOffset = 0;
vtkm::Id numSegments = 1;
IdArrayHandle discardKeys;
IdArrayHandle segmentSizes;
segmentSizes.Allocate(1);
segmentSizes.GetPortalControl().Set(0, numCells);
Self->ProcessedCellIds.Allocate(numCells);
vtkm::Id cellIdsOffset = 0;
IdArrayHandle parentIndices;
parentIndices.Allocate(1);
parentIndices.GetPortalControl().Set(0, -1);
while (!done)
{
//std::cout << "**** Iteration " << (++iteration) << " ****\n";
//Output(segmentSizes);
//START_TIMER(s21);
// Calculate the X, Y, Z bounding ranges for each segment
RangeArrayHandle perSegmentXRanges, perSegmentYRanges, perSegmentZRanges;
Algorithms::ReduceByKey(segmentIds, xRanges, discardKeys, perSegmentXRanges, vtkm::Add());
Algorithms::ReduceByKey(segmentIds, yRanges, discardKeys, perSegmentYRanges, vtkm::Add());
Algorithms::ReduceByKey(segmentIds, zRanges, discardKeys, perSegmentZRanges, vtkm::Add());
//PRINT_TIMER("2.1", s21);
// Expand the per segment bounding ranges, to per cell;
RangePermutationArrayHandle segmentXRanges(segmentIds, perSegmentXRanges);
RangePermutationArrayHandle segmentYRanges(segmentIds, perSegmentYRanges);
RangePermutationArrayHandle segmentZRanges(segmentIds, perSegmentZRanges);
//START_TIMER(s22);
// Calculate split costs for NumPlanes split planes, across X, Y and Z dimensions
vtkm::Id numSplitPlanes = numSegments * (Self->NumPlanes + 1);
vtkm::cont::ArrayHandle<vtkm::worklet::spatialstructure::SplitProperties> xSplits, ySplits,
zSplits;
xSplits.Allocate(numSplitPlanes);
ySplits.Allocate(numSplitPlanes);
zSplits.Allocate(numSplitPlanes);
Self->CalculateSplitCosts(
segmentXRanges, xRanges, centerXs, segmentIds, xSplits, DeviceAdapter());
Self->CalculateSplitCosts(
segmentYRanges, yRanges, centerYs, segmentIds, ySplits, DeviceAdapter());
Self->CalculateSplitCosts(
segmentZRanges, zRanges, centerZs, segmentIds, zSplits, DeviceAdapter());
//PRINT_TIMER("2.2", s22);
segmentXRanges.ReleaseResourcesExecution();
segmentYRanges.ReleaseResourcesExecution();
segmentZRanges.ReleaseResourcesExecution();
//START_TIMER(s23);
// Select best split plane and dimension across X, Y, Z dimension, per segment
SplitArrayHandle segmentSplits;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> segmentPlanes;
vtkm::cont::ArrayHandle<vtkm::Id> splitChoices;
CountingIdArrayHandle indices(0, 1, numSegments);
vtkm::worklet::spatialstructure::SplitSelector worklet(
Self->NumPlanes, Self->MaxLeafSize, Self->NumPlanes + 1);
invoker(worklet,
indices,
xSplits,
ySplits,
zSplits,
segmentSizes,
segmentSplits,
segmentPlanes,
splitChoices);
//PRINT_TIMER("2.3", s23);
// Expand the per segment split plane to per cell
SplitPermutationArrayHandle splits(segmentIds, segmentSplits);
CoordsPermutationArrayHandle planes(segmentIds, segmentPlanes);
//START_TIMER(s31);
IdArrayHandle leqFlags;
invoker(vtkm::worklet::spatialstructure::CalculateSplitDirectionFlag{},
centerXs,
centerYs,
centerZs,
splits,
planes,
leqFlags);
//PRINT_TIMER("3.1", s31);
//START_TIMER(s32);
IdArrayHandle scatterIndices =
Self->CalculateSplitScatterIndices(cellIds, leqFlags, segmentIds, DeviceAdapter());
IdArrayHandle newSegmentIds;
IdPermutationArrayHandle sizes(segmentIds, segmentSizes);
invoker(vtkm::worklet::spatialstructure::SegmentSplitter{ Self->MaxLeafSize },
segmentIds,
leqFlags,
sizes,
newSegmentIds);
//PRINT_TIMER("3.2", s32);
//START_TIMER(s33);
vtkm::cont::ArrayHandle<vtkm::Id> choices;
Algorithms::Copy(IdPermutationArrayHandle(segmentIds, splitChoices), choices);
cellIds = vtkm::worklet::spatialstructure::ScatterArray(cellIds, scatterIndices);
segmentIds = vtkm::worklet::spatialstructure::ScatterArray(segmentIds, scatterIndices);
newSegmentIds = vtkm::worklet::spatialstructure::ScatterArray(newSegmentIds, scatterIndices);
xRanges = vtkm::worklet::spatialstructure::ScatterArray(xRanges, scatterIndices);
yRanges = vtkm::worklet::spatialstructure::ScatterArray(yRanges, scatterIndices);
zRanges = vtkm::worklet::spatialstructure::ScatterArray(zRanges, scatterIndices);
centerXs = vtkm::worklet::spatialstructure::ScatterArray(centerXs, scatterIndices);
centerYs = vtkm::worklet::spatialstructure::ScatterArray(centerYs, scatterIndices);
centerZs = vtkm::worklet::spatialstructure::ScatterArray(centerZs, scatterIndices);
choices = vtkm::worklet::spatialstructure::ScatterArray(choices, scatterIndices);
//PRINT_TIMER("3.3", s33);
// Move the cell ids at leafs to the processed cellids list
//START_TIMER(s41);
IdArrayHandle nonSplitSegmentSizes;
invoker(vtkm::worklet::spatialstructure::NonSplitIndexCalculator{ Self->MaxLeafSize },
segmentSizes,
nonSplitSegmentSizes);
IdArrayHandle nonSplitSegmentIndices;
Algorithms::ScanExclusive(nonSplitSegmentSizes, nonSplitSegmentIndices);
IdArrayHandle runningSplitSegmentCounts;
vtkm::Id numNewSegments = Algorithms::ScanExclusive(splitChoices, runningSplitSegmentCounts);
//PRINT_TIMER("4.1", s41);
//START_TIMER(s42);
IdArrayHandle doneCellIds;
Algorithms::CopyIf(cellIds, choices, doneCellIds, vtkm::worklet::spatialstructure::Invert());
Algorithms::CopySubRange(
doneCellIds, 0, doneCellIds.GetNumberOfValues(), Self->ProcessedCellIds, cellIdsOffset);
cellIds = vtkm::worklet::spatialstructure::CopyIfArray(cellIds, choices, DeviceAdapter());
newSegmentIds =
vtkm::worklet::spatialstructure::CopyIfArray(newSegmentIds, choices, DeviceAdapter());
xRanges = vtkm::worklet::spatialstructure::CopyIfArray(xRanges, choices, DeviceAdapter());
yRanges = vtkm::worklet::spatialstructure::CopyIfArray(yRanges, choices, DeviceAdapter());
zRanges = vtkm::worklet::spatialstructure::CopyIfArray(zRanges, choices, DeviceAdapter());
centerXs = vtkm::worklet::spatialstructure::CopyIfArray(centerXs, choices, DeviceAdapter());
centerYs = vtkm::worklet::spatialstructure::CopyIfArray(centerYs, choices, DeviceAdapter());
centerZs = vtkm::worklet::spatialstructure::CopyIfArray(centerZs, choices, DeviceAdapter());
//PRINT_TIMER("4.2", s42);
//START_TIMER(s43);
// Make a new nodes with enough nodes for the current level, copying over the old one
vtkm::Id nodesSize = Self->Nodes.GetNumberOfValues() + numSegments;
vtkm::cont::ArrayHandle<vtkm::exec::CellLocatorBoundingIntervalHierarchyNode> newTree;
newTree.Allocate(nodesSize);
Algorithms::CopySubRange(Self->Nodes, 0, Self->Nodes.GetNumberOfValues(), newTree);
IdArrayHandle nextParentIndices;
nextParentIndices.Allocate(2 * numNewSegments);
CountingIdArrayHandle nodesIndices(nodesIndexOffset, 1, numSegments);
vtkm::worklet::spatialstructure::TreeLevelAdder nodesAdder(
cellIdsOffset, nodesSize, Self->MaxLeafSize);
invoker(nodesAdder,
nodesIndices,
segmentSplits,
nonSplitSegmentIndices,
segmentSizes,
runningSplitSegmentCounts,
parentIndices,
newTree,
nextParentIndices);
nodesIndexOffset = nodesSize;
cellIdsOffset += doneCellIds.GetNumberOfValues();
Self->Nodes = newTree;
//PRINT_TIMER("4.3", s43);
//START_TIMER(s51);
segmentIds = newSegmentIds;
segmentSizes =
Self->CalculateSegmentSizes<DeviceAdapter>(segmentIds, segmentIds.GetNumberOfValues());
segmentIds =
Self->GenerateSegmentIds<DeviceAdapter>(segmentSizes, segmentIds.GetNumberOfValues());
IdArrayHandle uniqueSegmentIds;
Algorithms::Copy(segmentIds, uniqueSegmentIds);
Algorithms::Unique(uniqueSegmentIds);
numSegments = uniqueSegmentIds.GetNumberOfValues();
done = segmentIds.GetNumberOfValues() == 0;
parentIndices = nextParentIndices;
//PRINT_TIMER("5.1", s51);
//std::cout << "Iteration time: " << iterationTimer.GetElapsedTime() << "\n";
}
//std::cout << "Total time: " << totalTimer.GetElapsedTime() << "\n";
return true;
}
};
class CellLocatorBoundingIntervalHierarchy::PrepareForExecutionFunctor
{
public:
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::CellLocatorBoundingIntervalHierarchy& bih,
HandleType& bihExec) const
{
vtkm::cont::DynamicCellSet cellSet = bih.GetCellSet();
if (cellSet.IsType<vtkm::cont::CellSetExplicit<>>())
{
using CellSetType = vtkm::cont::CellSetExplicit<>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
{
using CellSetType = vtkm::cont::CellSetStructured<2>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
{
using CellSetType = vtkm::cont::CellSetStructured<3>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else if (cellSet.IsType<vtkm::cont::CellSetSingleType<>>())
{
using CellSetType = vtkm::cont::CellSetSingleType<>;
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject = new ExecutionType(bih.Nodes,
bih.ProcessedCellIds,
bih.GetCellSet().Cast<CellSetType>(),
bih.GetCoordinates().GetData(),
DeviceAdapter());
bihExec.Reset(execObject);
}
else
{
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
}
return true;
}
};
VTKM_CONT
void CellLocatorBoundingIntervalHierarchy::Build()
{
BuildFunctor functor(this);
vtkm::cont::TryExecute(functor);
}
VTKM_CONT
const HandleType CellLocatorBoundingIntervalHierarchy::PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const
{
const bool success =
vtkm::cont::TryExecuteOnDevice(deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("BoundingIntervalHierarchy", deviceId);
}
return this->ExecHandle;
}
} //namespace cont
} //namespace vtkm

@ -0,0 +1,76 @@
//============================================================================
// 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 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2019 UT-Battelle, LLC.
// Copyright 2019 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.
//============================================================================
#include <vtkm/cont/CellLocatorRectilinearGrid.h>
#include <vtkm/exec/CellLocatorRectilinearGrid.h>
vtkm::cont::CellLocatorRectilinearGrid::CellLocatorRectilinearGrid() = default;
vtkm::cont::CellLocatorRectilinearGrid::~CellLocatorRectilinearGrid() = default;
void vtkm::cont::CellLocatorRectilinearGrid::Build()
{
vtkm::cont::CoordinateSystem coords = this->GetCoordinates();
vtkm::cont::DynamicCellSet cellSet = this->GetCellSet();
if (!coords.GetData().IsType<RectilinearType>())
throw vtkm::cont::ErrorInternal("Coordinates are not rectilinear.");
if (!cellSet.IsSameType(StructuredType()))
throw vtkm::cont::ErrorInternal("Cells are not 3D structured.");
vtkm::Vec<vtkm::Id, 3> celldims =
cellSet.Cast<StructuredType>().GetSchedulingRange(vtkm::TopologyElementTagCell());
this->PlaneSize = celldims[0] * celldims[1];
this->RowSize = celldims[0];
}
struct vtkm::cont::CellLocatorRectilinearGrid::PrepareForExecutionFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::CellLocatorRectilinearGrid& contLocator,
HandleType& execLocator) const
{
using ExecutionType = vtkm::exec::CellLocatorRectilinearGrid<DeviceAdapter>;
ExecutionType* execObject =
new ExecutionType(contLocator.PlaneSize,
contLocator.RowSize,
contLocator.GetCellSet().template Cast<StructuredType>(),
contLocator.GetCoordinates().GetData().template Cast<RectilinearType>(),
DeviceAdapter());
execLocator.Reset(execObject);
return true;
}
};
const vtkm::cont::CellLocator::HandleType
vtkm::cont::CellLocatorRectilinearGrid::PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const
{
const bool success =
vtkm::cont::TryExecuteOnDevice(deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("CellLocatorRectilinearGrid", deviceId);
}
return this->ExecHandle;
}

@ -22,10 +22,6 @@
#include <vtkm/cont/CellLocator.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/exec/CellLocatorRectilinearGrid.h>
namespace vtkm
{
@ -33,7 +29,7 @@ namespace vtkm
namespace cont
{
class CellLocatorRectilinearGrid : public vtkm::cont::CellLocator
class VTKM_CONT_EXPORT CellLocatorRectilinearGrid : public vtkm::cont::CellLocator
{
public:
using StructuredType = vtkm::cont::CellSetStructured<3>;
@ -41,64 +37,23 @@ public:
using RectilinearType =
vtkm::cont::ArrayHandleCartesianProduct<AxisHandle, AxisHandle, AxisHandle>;
VTKM_CONT
CellLocatorRectilinearGrid() = default;
VTKM_CONT CellLocatorRectilinearGrid();
VTKM_CONT
void Build() override
{
vtkm::cont::CoordinateSystem coords = this->GetCoordinates();
vtkm::cont::DynamicCellSet cellSet = this->GetCellSet();
VTKM_CONT ~CellLocatorRectilinearGrid() override;
if (!coords.GetData().IsType<RectilinearType>())
throw vtkm::cont::ErrorInternal("Coordinates are not rectilinear.");
if (!cellSet.IsSameType(StructuredType()))
throw vtkm::cont::ErrorInternal("Cells are not 3D structured.");
vtkm::Vec<vtkm::Id, 3> celldims =
cellSet.Cast<StructuredType>().GetSchedulingRange(vtkm::TopologyElementTagCell());
this->PlaneSize = celldims[0] * celldims[1];
this->RowSize = celldims[0];
}
struct PrepareForExecutionFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::CellLocatorRectilinearGrid& contLocator,
HandleType& execLocator) const
{
using ExecutionType = vtkm::exec::CellLocatorRectilinearGrid<DeviceAdapter>;
ExecutionType* execObject =
new ExecutionType(contLocator.PlaneSize,
contLocator.RowSize,
contLocator.GetCellSet().template Cast<StructuredType>(),
contLocator.GetCoordinates().GetData().template Cast<RectilinearType>(),
DeviceAdapter());
execLocator.Reset(execObject);
return true;
}
};
VTKM_CONT void Build() override;
VTKM_CONT
const HandleType PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const override
{
const bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("CellLocatorRectilinearGrid", deviceId);
}
return this->ExecHandle;
}
const vtkm::cont::DeviceAdapterId deviceId) const override;
private:
vtkm::Bounds Bounds;
vtkm::Id PlaneSize;
vtkm::Id RowSize;
mutable HandleType ExecHandle;
struct PrepareForExecutionFunctor;
};
} //namespace cont

@ -0,0 +1,82 @@
//============================================================================
// 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 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2019 UT-Battelle, LLC.
// Copyright 2019 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.
//============================================================================
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/CellLocatorUniformGrid.h>
#include <vtkm/exec/CellLocatorUniformGrid.h>
vtkm::cont::CellLocatorUniformGrid::CellLocatorUniformGrid() = default;
vtkm::cont::CellLocatorUniformGrid::~CellLocatorUniformGrid() = default;
void vtkm::cont::CellLocatorUniformGrid::Build()
{
vtkm::cont::CoordinateSystem coords = this->GetCoordinates();
vtkm::cont::DynamicCellSet cellSet = this->GetCellSet();
if (!coords.GetData().IsType<UniformType>())
throw vtkm::cont::ErrorBadType("Coordinate system is not uniform type");
if (!cellSet.IsSameType(StructuredType()))
throw vtkm::cont::ErrorBadType("Cell set is not 3D structured type");
Bounds = coords.GetBounds();
CellDims = cellSet.Cast<StructuredType>().GetSchedulingRange(vtkm::TopologyElementTagCell());
RangeTransform[0] = static_cast<vtkm::FloatDefault>(CellDims[0]) /
static_cast<vtkm::FloatDefault>(Bounds.X.Length());
RangeTransform[1] = static_cast<vtkm::FloatDefault>(CellDims[1]) /
static_cast<vtkm::FloatDefault>(Bounds.Y.Length());
RangeTransform[2] = static_cast<vtkm::FloatDefault>(CellDims[2]) /
static_cast<vtkm::FloatDefault>(Bounds.Z.Length());
}
struct vtkm::cont::CellLocatorUniformGrid::PrepareForExecutionFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::CellLocatorUniformGrid& contLocator,
HandleType& execLocator) const
{
using ExecutionType = vtkm::exec::CellLocatorUniformGrid<DeviceAdapter>;
ExecutionType* execObject =
new ExecutionType(contLocator.Bounds,
contLocator.RangeTransform,
contLocator.CellDims,
contLocator.GetCellSet().template Cast<StructuredType>(),
contLocator.GetCoordinates().GetData(),
DeviceAdapter());
execLocator.Reset(execObject);
return true;
}
};
const vtkm::cont::CellLocator::HandleType
vtkm::cont::CellLocatorUniformGrid::PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const
{
const bool success =
vtkm::cont::TryExecuteOnDevice(deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("CellLocatorUniformGrid", deviceId);
}
return this->ExecHandle;
}

@ -22,10 +22,6 @@
#include <vtkm/cont/CellLocator.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/exec/CellLocatorUniformGrid.h>
namespace vtkm
{
@ -33,71 +29,25 @@ namespace vtkm
namespace cont
{
class CellLocatorUniformGrid : public vtkm::cont::CellLocator
class VTKM_CONT_EXPORT CellLocatorUniformGrid : public vtkm::cont::CellLocator
{
public:
VTKM_CONT
CellLocatorUniformGrid() = default;
VTKM_CONT CellLocatorUniformGrid();
VTKM_CONT
void Build() override
{
vtkm::cont::CoordinateSystem coords = this->GetCoordinates();
vtkm::cont::DynamicCellSet cellSet = this->GetCellSet();
VTKM_CONT ~CellLocatorUniformGrid() override;
if (!coords.GetData().IsType<UniformType>())
throw vtkm::cont::ErrorBadType("Coordinate system is not uniform type");
if (!cellSet.IsSameType(StructuredType()))
throw vtkm::cont::ErrorBadType("Cell set is not 3D structured type");
Bounds = coords.GetBounds();
CellDims = cellSet.Cast<StructuredType>().GetSchedulingRange(vtkm::TopologyElementTagCell());
RangeTransform[0] = static_cast<vtkm::FloatDefault>(CellDims[0]) /
static_cast<vtkm::FloatDefault>(Bounds.X.Length());
RangeTransform[1] = static_cast<vtkm::FloatDefault>(CellDims[1]) /
static_cast<vtkm::FloatDefault>(Bounds.Y.Length());
RangeTransform[2] = static_cast<vtkm::FloatDefault>(CellDims[2]) /
static_cast<vtkm::FloatDefault>(Bounds.Z.Length());
}
struct PrepareForExecutionFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::CellLocatorUniformGrid& contLocator,
HandleType& execLocator) const
{
using ExecutionType = vtkm::exec::CellLocatorUniformGrid<DeviceAdapter>;
ExecutionType* execObject =
new ExecutionType(contLocator.Bounds,
contLocator.RangeTransform,
contLocator.CellDims,
contLocator.GetCellSet().template Cast<StructuredType>(),
contLocator.GetCoordinates().GetData(),
DeviceAdapter());
execLocator.Reset(execObject);
return true;
}
};
VTKM_CONT void Build() override;
VTKM_CONT
const HandleType PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const override
{
const bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("CellLocatorUniformGrid", deviceId);
}
return this->ExecHandle;
}
const vtkm::cont::DeviceAdapterId deviceId) const override;
private:
using UniformType = vtkm::cont::ArrayHandleUniformPointCoordinates;
using StructuredType = vtkm::cont::CellSetStructured<3>;
struct PrepareForExecutionFunctor;
vtkm::Bounds Bounds;
vtkm::Vec<vtkm::FloatDefault, 3> RangeTransform;
vtkm::Vec<vtkm::Id, 3> CellDims;

@ -20,7 +20,6 @@
#include <iostream>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.h>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.hxx>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/testing/Testing.h>

@ -40,6 +40,8 @@ namespace exec
class CellInterpolationHelper : public vtkm::VirtualObjectBase
{
public:
VTKM_EXEC_CONT virtual ~CellInterpolationHelper() = default;
VTKM_EXEC
virtual void GetCellInfo(const vtkm::Id& cellId,
vtkm::UInt8& cellShape,
@ -194,6 +196,8 @@ class CellInterpolationHelper : public vtkm::cont::ExecutionObjectBase
public:
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::CellInterpolationHelper>;
VTKM_CONT virtual ~CellInterpolationHelper() = default;
template <typename DeviceAdapter>
VTKM_CONT const vtkm::exec::CellInterpolationHelper* PrepareForExecution(
DeviceAdapter device) const

@ -25,6 +25,7 @@
#include <vtkm/Bounds.h>
#include <vtkm/Types.h>
#include <vtkm/VecFromPortalPermute.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
@ -558,34 +559,28 @@ struct TreeLevelAdder : public vtkm::worklet::WorkletMapField
vtkm::IdComponent MaxLeafSize;
}; // struct TreeLevelAdder
template <typename T, class BinaryFunctor, typename DeviceAdapter>
template <typename T, class BinaryFunctor>
vtkm::cont::ArrayHandle<T> ReverseScanInclusiveByKey(const vtkm::cont::ArrayHandle<T>& keys,
const vtkm::cont::ArrayHandle<T>& values,
BinaryFunctor binaryFunctor,
DeviceAdapter)
BinaryFunctor binaryFunctor)
{
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
vtkm::cont::ArrayHandle<T> result;
auto reversedResult = vtkm::cont::make_ArrayHandleReverse(result);
Algorithms::ScanInclusiveByKey(vtkm::cont::make_ArrayHandleReverse(keys),
vtkm::cont::make_ArrayHandleReverse(values),
reversedResult,
binaryFunctor);
vtkm::cont::Algorithm::ScanInclusiveByKey(vtkm::cont::make_ArrayHandleReverse(keys),
vtkm::cont::make_ArrayHandleReverse(values),
reversedResult,
binaryFunctor);
return result;
}
template <typename T, typename U, typename DeviceAdapter>
template <typename T, typename U>
vtkm::cont::ArrayHandle<T> CopyIfArray(const vtkm::cont::ArrayHandle<T>& input,
const vtkm::cont::ArrayHandle<U>& stencil,
DeviceAdapter)
const vtkm::cont::ArrayHandle<U>& stencil)
{
using Algorithms = typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
vtkm::cont::ArrayHandle<T> result;
Algorithms::CopyIf(input, stencil, result);
vtkm::cont::Algorithm::CopyIf(input, stencil, result);
return result;
}

@ -21,7 +21,6 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandleConcatenate.h>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.h>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.hxx>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/internal/DeviceAdapterTag.h>