Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • hankchilds/vtk-m-user-guide
  • chris.turney/vtk-m-user-guide
  • oruebel/vtk-m-user-guide
  • m-kim/vtk-m-user-guide
  • tberger/vtk-m-user-guide
  • ollielo/vtk-m-user-guide
  • dpugmire/vtk-m-user-guide
  • sujin.philip/vtk-m-user-guide
  • nadavi/vtk-m-user-guide
  • mletter1/vtk-m-user-guide
  • kmorel/vtk-m-user-guide
  • jameskress/vtk-m-user-guide
  • vbolea/vtk-m-user-guide
  • NAThompson/vtk-m-user-guide
  • vtk/vtk-m-user-guide
15 results
Show changes
Commits on Source (14)
Showing
with 518 additions and 574 deletions
......@@ -19,6 +19,7 @@ set(images
images/CameraMovement.pdf
images/CellConnectionsHexahedron.pdf
images/CellConnectionsLine.pdf
images/CellConnectionsPolyLine.pdf
images/CellConnectionsPolygon.pdf
images/CellConnectionsPyramid.pdf
images/CellConnectionsQuadrilateral.pdf
......@@ -116,6 +117,7 @@ set(input_docs
FunctionInterface.tex
WorkletArguments.tex
NewWorkletTypes.tex
CellShapeFigure.tex
# Special inputs that go into verbatim-like arguments
examples/VTKmQuickStart.cmake
)
......
% -*- latex -*-
{
\small
\begin{tabular}{@{}c@{ }c@{ }c@{}}
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsVertex}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsLine}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsPolyLine}} \\
\vtkm{CELL\_SHAPE\_VERTEX} &
\vtkm{CELL\_SHAPE\_LINE} &
\vtkm{CELL\_SHAPE\_POLY\_LINE} \\
\vtkm{CellShapeTagVertex} \index{vertex} &
\vtkm{CellShapeTagLine} \index{line} &
\vtkm{CellShapeTagPolyLine} \index{poly line} \\[2ex]
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsTriangle}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsPolygon}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsQuadrilateral}} \\
\vtkm{CELL\_SHAPE\_TRIANGLE} &
\vtkm{CELL\_SHAPE\_POLYGON} &
\vtkm{CELL\_SHAPE\_QUAD} \\
\vtkm{CellShapeTagTriangle} \index{triangle} &
\vtkm{CellShapeTagPolygon} \index{polygon} &
\vtkm{CellShapeTagQuad} \index{quadrilateral} \\[2ex]
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsTetrahedron}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsHexahedron}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsWedge}} \\
\vtkm{CELL\_SHAPE\_TETRA} &
\vtkm{CELL\_SHAPE\_HEXAHEDRON} &
\vtkm{CELL\_SHAPE\_WEDGE} \\
\vtkm{CellShapeTagTetra} \index{tetrahedron} &
\vtkm{CellShapeTagHexahedron} \index{hexahedron} &
\vtkm{CellShapeTagWedge} \index{wedge} \\[2ex]
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsPyramid}} \\
\vtkm{CELL\_SHAPE\_PYRAMID} \\
\vtkm{CellShapeTagPyramid} \index{pyramid}
\end{tabular}
}
......@@ -59,8 +59,8 @@ If the storage parameter is not explicitly defined, it is set to \vtkmmacro{VTKM
%% default storage is specified in much the same way as a default device
%% adapter is defined (as described in Section~\ref{sec:DefaultDeviceAdapter}).
%% It is done by setting the \vtkmmacro{VTKM\_STORAGE} macro. This macro must
%% be set before including any VTK-m header files. Currently the only
%% practical storage provided by VTK-m is the basic storage, which simply
%% be set before including any \VTKm header files. Currently the only
%% practical storage provided by \VTKm is the basic storage, which simply
%% allocates a continuous section of memory of the given base type. This
%% storage can be explicitly specified by setting \vtkmmacro{VTKM\_STORAGE} to
%% \vtkmmacro{VTKM\_STORAGE\_BASIC} although the basic storage will also be
......@@ -79,7 +79,7 @@ The remainder of this chapter uses the storage mechanism to customize the repres
\label{sec:ImplementingFancyArrays}
Although the behavior of fancy arrays might seem complicated, they are
actually straightforward to implement. VTK-m provides several mechanisms to
actually straightforward to implement. \VTKm provides several mechanisms to
implement fancy arrays.
\subsection{Implicit Array Handles}
......@@ -90,7 +90,7 @@ implement fancy arrays.
\index{implicit array handle|(}
\index{functional array|(}
The generic array handle and storage templating in VTK-m allows for
The generic array handle and storage templating in \VTKm allows for
any type of operations to retrieve a particular value. Typically this is
used to convert an index to some location or locations in memory. However,
it is also possible to compute a value directly from an index rather than
......@@ -101,8 +101,8 @@ requires no storage in memory at all. Such a functional array is called an
regular arrays but do special processing under the covers to provide
values.
Specifying a functional or implicit array in VTK-m is straightforward.
VTK-m has a special class named \vtkmcont{ArrayHandleImplicit} that makes
Specifying a functional or implicit array in \VTKm is straightforward.
\VTKm has a special class named \vtkmcont{ArrayHandleImplicit} that makes
an implicit array containing values generated by a user-specified
\keyterm{functor}. \index{functor} A functor is simply a C++ class or
struct that contains an overloaded parenthesis operator so that it can be
......@@ -115,11 +115,9 @@ could easily create this array in memory, we can save space and possibly
time by computing these values on demand.
\begin{didyouknow}
VTK-m already comes with an implicit array handle named
\vtkmcont{ArrayHandleCounting} that can make implicit even numbers as
well as other more general counts. So in practice you would not have to
create a special implicit array, but we are doing so here for
demonstrative purposes.
\VTKm already comes with an implicit array handle named \vtkmcont{ArrayHandleCounting} that can make implicit even numbers as well as other more general counts.
(See Section \ref{sec:CountingArrays} for details.)
So in practice you would not have to create a special implicit array, but we are doing so here for demonstrative purposes.
\end{didyouknow}
The first step to using \textidentifier{ArrayHandleImplicit} is to declare
......@@ -161,16 +159,13 @@ is used in templated classes whereas
\vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} is used in non-templated
classes.
The \textidentifier{ArrayHandle} subclass in
Example~\ref{ex:ImplicitArrayHandleSubclass} is not templated, so it uses
the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} macro. (The other macro
is described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS} on
page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS}). This macro takes two
parameters. The first parameter is the name of the subclass where the macro
is defined and the second parameter is the immediate superclass including
the full template specification. The second parameter of the macro must be
enclosed in parentheses so that the C pre-processor correctly handles
commas in the template specification.
\label{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}
The \textidentifier{ArrayHandle} subclass in Example~\ref{ex:ImplicitArrayHandleSubclass} is not templated, so it uses the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} macro.
This macro takes two parameters.
The first parameter is the name of the subclass where the macro is defined and the second parameter is the immediate superclass including the full template specification.
The second parameter of the macro must be enclosed in parentheses so that the C pre-processor correctly handles commas in the template specification.
(The other macro is described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS} on page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS}).
\index{functional array|)}
\index{implicit array handle|)}
......@@ -191,7 +186,7 @@ except that a map operation writes its values to a new memory location
whereas the transformed array handle produces its values on demand so that
no additional storage is required.
Specifying a transformed array in VTK-m is straightforward. VTK-m has a
Specifying a transformed array in \VTKm is straightforward. \VTKm has a
special class named \vtkmcont{ArrayHandleTransform} that takes an array
handle and a functor and provides an interface to a new array comprising
values of the first array applied to the functor.
......@@ -234,8 +229,6 @@ convenience subclass of \vtkmcont{ArrayHandleTransform} or convenience
\vtkmlisting[ex:TransformArrayHandleSubclass]{Custom transform array handle for scale and bias.}{TransformArrayHandle.cxx}
\label{sec:VTKM_ARRAY_HANDLE_SUBCLASS}
Subclasses of \textidentifier{ArrayHandle} provide constructors that
establish the state of the array handle. All array handle subclasses must
also use either the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro or the
......@@ -248,17 +241,13 @@ is used in templated classes whereas
\vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} is used in non-templated
classes.
The \textidentifier{ArrayHandle} subclass in
Example~\ref{ex:TransformArrayHandleSubclass} is templated, so it uses the
\vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro. (The other macro is
described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT} on
page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}). This macro takes three
parameters. The first parameter is the name of the subclass where the macro
is defined, the second parameter is the type of the subclass including the
full template specification, and the third parameter is the immediate
superclass including the full template specification. The second and third
parameters of the macro must be enclosed in parentheses so that the C
pre-processor correctly handles commas in the template specification.
\label{sec:VTKM_ARRAY_HANDLE_SUBCLASS}
The \textidentifier{ArrayHandle} subclass in Example~\ref{ex:TransformArrayHandleSubclass} is templated, so it uses the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro.
This macro takes three parameters.
The first parameter is the name of the subclass where the macro is defined, the second parameter is the type of the subclass including the full template specification, and the third parameter is the immediate superclass including the full template specification.
The second and third parameters of the macro must be enclosed in parentheses so that the C pre-processor correctly handles commas in the template specification.
(The other macro is described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT} on page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}).
\index{transformed array|)}
\index{array handle!transform|)}
......@@ -267,6 +256,8 @@ pre-processor correctly handles commas in the template specification.
\subsection{Derived Storage}
\label{sec:DerivedStorage}
\fix{Change this to use ArrayHandleDecorator.}
\index{array handle!derived|(}
\index{storage!derived|(}
\index{derived storage|(}
......@@ -448,7 +439,7 @@ parameters of the macro must be enclosed in parentheses so that the C
pre-processor correctly handles commas in the template specification.
\vtkmcont{ArrayHandleCompositeVector} is an example of a derived array
handle provided by VTK-m. It references some fixed number of other arrays,
handle provided by \VTKm. It references some fixed number of other arrays,
pulls a specified component out of each, and produces a new component that
is a tuple of these retrieved components.
......@@ -468,18 +459,18 @@ is a tuple of these retrieved components.
\index{storage!adapting|(}
The intention of the storage parameter for \vtkmcont{ArrayHandle} is to
implement the strategy design pattern to enable VTK-m to interface directly
with the data of any third party code source. VTK-m is designed to work
implement the strategy design pattern to enable \VTKm to interface directly
with the data of any third party code source. \VTKm is designed to work
with data originating in other libraries or applications. By creating a new
type of storage, VTK-m can be entirely adapted to new kinds of data
type of storage, \VTKm can be entirely adapted to new kinds of data
structures.
\begin{commonerrors}
Keep in mind that memory layout used can have an effect on the running
time of algorithms in VTK-m. Different data layouts and memory access can
time of algorithms in \VTKm. Different data layouts and memory access can
change cache performance and introduce memory affinity problems. The
example code given in this section will likely have poorer cache
performance than the basic storage provided by VTK-m. However, that might
performance than the basic storage provided by \VTKm. However, that might
be an acceptable penalty to avoid data copies.
\end{commonerrors}
......@@ -492,7 +483,7 @@ locations in a mesh in a \textcode{std::deque} object.
\vtkmlisting{Fictitious field storage used in custom array storage examples.}{FictitiousFieldStorage.cxx}
VTK-m expects separate arrays for each of the fields rather than a single
\VTKm expects separate arrays for each of the fields rather than a single
array containing a structure holding all of the fields. However, rather
than copy each field to its own array, we can create a storage for each
field that points directly to the data in a \textcode{FooFieldsDeque}
......@@ -504,7 +495,7 @@ Section~\ref{sec:ArrayPortals} and is generally straightforward for simple
containers like this. Here is an example implementation for our
\textcode{FooFieldsDeque} container.
\vtkmlisting[ex:ArrayPortalAdapter]{Array portal to adapt a third-party container to VTK-m.}{ArrayPortalAdapter.cxx}
\vtkmlisting[ex:ArrayPortalAdapter]{Array portal to adapt a third-party container to \VTKm.}{ArrayPortalAdapter.cxx}
The next step in creating an adapter storage is to define a tag for the
adapter. We shall call ours
......@@ -552,7 +543,7 @@ The following provides an example implementation of our adapter to a
\textcode{ArrayPortalFooPressure} provided in
Example~\ref{ex:ArrayPortalAdapter}.
\vtkmlisting{Storage to adapt a third-party container to VTK-m.}{StorageAdapter.cxx}
\vtkmlisting{Storage to adapt a third-party container to \VTKm.}{StorageAdapter.cxx}
\index{array handle!subclassing}
......@@ -562,9 +553,7 @@ storage. This can be done by creating a trivial subclass of
\vtkmcont{ArrayHandle} that simply constructs the array handle to the state
of an existing container.
\vtkmlisting[ex:ArrayHandleAdapter]{Array handle to adapt a third-party container to VTK-m.}{ArrayHandleAdapter.cxx}
\label{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}
\vtkmlisting[ex:ArrayHandleAdapter]{Array handle to adapt a third-party container to \VTKm.}{ArrayHandleAdapter.cxx}
Subclasses of \textidentifier{ArrayHandle} provide constructors that
establish the state of the array handle. All array handle subclasses must
......@@ -589,7 +578,7 @@ the full template specification. The second parameter of the macro must be
enclosed in parentheses so that the C pre-processor correctly handles
commas in the template specification.
With this new version of \textidentifier{ArrayHandle}, VTK-m can now read
With this new version of \textidentifier{ArrayHandle}, \VTKm can now read
to and write from the \textcode{FooFieldsDeque} structure directly.
\vtkmlisting[ex:UsingArrayHandleAdapter]{Using an \textidentifier{ArrayHandle} with custom container.}{UsingArrayHandleAdapter.cxx}
......@@ -604,14 +593,14 @@ to and write from the \textcode{FooFieldsDeque} structure directly.
\index{array handle!storage!default}
\index{storage!default}
Most of the code in VTK-m will create \textidentifier{ArrayHandle}s using
Most of the code in \VTKm will create \textidentifier{ArrayHandle}s using
the default storage, which is set to the basic storage if not otherwise
specified. If you wish to replace the default storage used, then set the
\vtkmmacro{VTKM\_STORAGE} macro to \vtkmmacro{VTKM\_STORAGE\_UNDEFINED} and
set the \vtkmmacro{VTKM\_DEFAULT\_STORAGE\_TAG} to your tag class. These
definitions have to happen \emph{before} including any VTK-m header files.
definitions have to happen \emph{before} including any \VTKm header files.
You will also have to declare the tag class (or at least a prototype of it)
before including VTK-m header files.
before including \VTKm header files.
\begin{vtkmexample}{Redefining the default array handle storage.}
#define VTKM_STORAGE VTKM_STORAGE_UNDEFINED
......@@ -624,7 +613,7 @@ struct StorageTagFooPressure;
\textidentifier{ArrayHandle}s are often stored in dynamic objects like
variant arrays (Chapter~\ref{chap:VariantArrayHandle}) or data sets
(Chapter~\ref{chap:DataSets}). When this happens, the array's type
information, including the storage used, is lost. VTK-m will execute algorithms
information, including the storage used, is lost. \VTKm will execute algorithms
using the \textidentifier{ArrayHandleVirtual} interface. For hot path types
and storages for filters it is good to specify custom sets in the policy when
executing filters.
......
......@@ -122,14 +122,18 @@ spacing along each axis.
\index{explicit mesh}
\index{unstructured grid}
An explicit mesh is an arbitrary collection of cells with arbitrary
connections. It can have multiple different types of cells. Explicit meshes
are also known as unstructured grids.
An explicit mesh is an arbitrary collection of cells with arbitrary connections.
It can have multiple different types of cells.
Explicit meshes are also known as unstructured grids.
Explicit meshes can contain cells of different shapes.
The shapes that \VTKm currently supports are listed in Figure \ref{fig:CreateExplicitMeshesCellShapes}.
The cells of an explicit mesh are defined by providing the shape, number of
indices, and the points that comprise it for each cell. These three things
are stored in separate arrays. Figure~\ref{fig:ExplicitMesh} shows an
example of an explicit mesh and the arrays that can be used to define it.
\begin{figure}[htb]
\centering
\input{CellShapeFigure}
\caption{Basic Cell Shapes}
\label{fig:CreateExplicitMeshesCellShapes}
\end{figure}
\begin{figure}[htb]
\centering
......@@ -138,12 +142,34 @@ example of an explicit mesh and the arrays that can be used to define it.
\label{fig:ExplicitMesh}
\end{figure}
The \vtkmcont{DataSetBuilderExplicit} class can be used to create data sets
with explicit meshes. \textidentifier{DataSetBuilderExplicit} has several
versions of a method named \classmember*{DataSetBuilderExplicit}{Create}. Generally, these methods take
the shapes, number of indices, and connectivity arrays as well as an array
of point coordinates. These arrays can be given in \textcode{std::vector}
objects, and the data are copied into the \textidentifier{DataSet} created.
The cells of an explicit mesh are defined with the following 3 arrays, which are depicted graphically in Figure \ref{fig:ExplicitMesh}.
\begin{description}
\item[Shapes] \index{explicit mesh!shapes}
An array of ids identifying the shape of the cell.
Each value is a \vtkm{UInt8} and should be set to one of the \vtkm{}\textcode{::}\textidentifier{CELL\_SHAPE\_*} constants.
The shapes and their identifiers are shown in Figure \ref{fig:CreateExplicitMeshesCellShapes}.
The size of this array is equal to the number of cells in the set.
\item[Connectivity] \index{explicit mesh!connectivity}
An array that lists all the points that comprise each cell.
Each entry in the array is a \vtkm{Id} giving the point id associated with a vertex of a cell.
The points for each cell are given in a prescribed order for each shape, which is also shown in Figure \ref{fig:CreateExplicitMeshesCellShapes}.
The point indices are stored consecutively from the first cell to the last.
\item[Offsets] \index{explicit mesh!offsets}
An array of \vtkm{Id}s pointing to the index in the connectivity array where the points for a particular cell starts.
The size of this array is equal to the number of cells in the set plus 1.
The first entry is expected to be 0 (since the connectivity of the first cell is at the start of the connectivity array).
The last entry, which does not correspond to any cell, should be the size of the connectivity array.
\end{description}
One important item that is missing from this list of arrays is a count of the number of indices associated with each cell.
This is not explicitly represented in \VTKm's mesh structure because it can be implicitly derived from the offsets array by subtracting consecutive entries.
However, it is usually the case when building an explicit mesh that you will have an array of these counts rather than the offsets.
It is for this reason that \VTKm contains mechanisms to build an explicit data set with a ``num indices'' arrays rather than an offsets array.
The \vtkmcont{DataSetBuilderExplicit} class can be used to create data sets with explicit meshes.
\textidentifier{DataSetBuilderExplicit} has several versions of a method named \classmember*{DataSetBuilderExplicit}{Create}.
Generally, these methods take the shapes, number of indices, and connectivity arrays as well as an array of point coordinates.
These arrays can be given in \textcode{std::vector} objects, and the data are copied into the \textidentifier{DataSet} created.
The following example creates a mesh like the one shown in
Figure~\ref{fig:ExplicitMesh}.
......@@ -276,32 +302,36 @@ on page~\pageref{sec:DataSets:CoordinateSystems}.
\index{explicit cell set|(}
\index{cell set!explicit|(}
A \vtkmcont{CellSetExplicit} defines an irregular collection of cells. The
cells can be of different types and connected in arbitrary ways. This is
done by explicitly providing for each cell a sequence of points that
defines the cell.
A \vtkmcont{CellSetExplicit} defines an irregular collection of cells.
The cells can be of different types and connected in arbitrary ways.
The types of cell sets are listed in Figure \ref{fig:ExplicitCellSetShapes}.
This is done by explicitly providing for each cell a sequence of points that defines the cell.
\begin{figure}[htb]
\centering
\input{CellShapeFigure}
\caption{Basic Cell Shapes in a \textidentifier{CellSetExplicit}.}
\label{fig:ExplicitCellSetShapes}
\end{figure}
An explicit cell set is defined with a minimum of three arrays. The first
array identifies the shape of each cell. (Cell shapes are discussed in
detail in Section~\ref{sec:CellShapeTagsIds} starting on
page~\pageref{sec:CellShapeTagsIds}.) The second array identifies how many
points are in each cell. The third array has a sequence of point indices
that make up each cell. Figure~\ref{fig:CellSetExplicit} shows a simple
example of an explicit cell set.
An explicit cell set is defined with a minimum of three arrays.
The first array identifies the shape of each cell.
(Identifiers for cell shapes are shown in Figure \ref{fig:ExplicitCellSetShapes}.)
The second array has a sequence of point indices that make up each cell.
The third array identifies an offset into the second array where the point indices for each cell is found plus an extra entry at the end set to the size of the second array.
Figure~\ref{fig:CellSetExplicit} shows a simple example of an explicit cell set.
\begin{figure}[htb]
\centering
\includegraphics{images/ExplicitCellConnections}
\caption{Example of cells in a \textidentifier{CellSetExplict} and the
\caption{Example of cells in a \textidentifier{CellSetExplicit} and the
arrays that define them.}
\label{fig:CellSetExplicit}
\end{figure}
An explicit cell set may also have other topological arrays such as an
array of offsets of each cell into the connectivity array or an array of
cells incident on each point. Although these arrays can be provided, they
are optional and can be internally derived from the shape, num indices, and
connectivity arrays.
An explicit cell set can also identify the number of indices defined for each cell by subtracting consecutive entries in the offsets array.
It is often the case when creating a \textidentifier{CellSetExplicit} that you have an array containing the number of indices rather than the offsets.
Such an array can be converted to an offsets array that can be used with \textidentifier{CellSetExplicit} by using the \vtkmcont{ConvertNumIndicesToOffsets} convenience function.
\vtkmcont{ExplicitCellSet} is a powerful representation for a cell set
because it can represent an arbitrary collection of cells. However, because
......
......@@ -5,19 +5,15 @@
\index{function interface|(}
For flexibility's sake a worklet is free to declare a \controlsignature
with whatever number of arguments are sensible for its operation. The
\classmember*{DispatcherBase}{Invoke} method of the dispatcher is expected to support arguments
that match these arguments, and part of the dispatching operation may
require these arguments to be augmented before the worklet is
scheduled. This leaves dispatchers with the tricky task of managing some
collection of arguments of unknown size and unknown types.
\fix{\textidentifier{FunctionInterface} is in the \vtkminternal{}
interface. I still can't decide if it should be moved to the \vtkm{}
interface.}
To simplify this management, VTK-m has the \vtkminternal{FunctionInterface}
For flexibility's sake a worklet is free to declare a \controlsignature with whatever number of arguments are sensible for its operation.
The \textidentifier{Invoker} is expected to support arguments that match these arguments, and part of the invocation operation may require these arguments to be augmented before the worklet is scheduled.
This leaves the invoker with the tricky task of managing some collection of arguments of unknown size and unknown types.
\fix{\textidentifier{FunctionInterface} is in the \vtkminternal{} interface.
I still can't decide if it should be moved to the \vtkm{} interface.
Update: I'm glad I have not moved \textidentifier{FunctionInterface} ro \vtkm{} because now we are thinking of getting rid of it.}
To simplify this management, \VTKm has the \vtkminternal{FunctionInterface}
class. \textidentifier{FunctionInterface} is a templated class that manages
a generic set of arguments and return value from a function. An instance of
\textidentifier{FunctionInterface} holds an instance of each argument. You
......
This diff is collapsed.
......@@ -6,20 +6,20 @@
\index{device adapter|(}
\index{device adapter!implementing|(}
VTK-m comes with several implementations of device adapters so that it may be ported to a variety of platforms.
\VTKm comes with several implementations of device adapters so that it may be ported to a variety of platforms.
It is also possible to provide new device adapters to support yet more devices, compilers, and libraries.
A new device adapter provides a tag, a class to manage arrays in the execution environment, a class to establish virtual objects in the execution environment, a collection of algorithms that run in the execution environment, and (optionally) a timer.
Most device adapters are associated with some type of device or library, and all source code related directly to that device is placed in a subdirectory of \textfilename{vtkm/cont}.
For example, files associated with CUDA are in \textfilename{vtkm/cont/cuda}, files associated with the Intel Threading Building Blocks (TBB) are located in \textfilename{vtkm/cont/tbb}, and files associated with OpenMP are in \textfilename{vtkm/cont/openmp}.
The documentation here assumes that you are adding a device adapter to the VTK-m source code and following these file conventions.
The documentation here assumes that you are adding a device adapter to the \VTKm source code and following these file conventions.
For the purposes of discussion in this section, we will give a simple
example of implementing a device adapter using the \textcode{std::thread}
class provided by C++11. We will call our device \textcode{Cxx11Thread} and
place it in the directory \textfilename{vtkm/cont/cxx11}.
By convention the implementation of device adapters within VTK-m are divided into 6 header files with the names \textfilename{DeviceAdapterTag\textasteriskcentered.h}, \textfilename{DeviceAdapterRuntimeDetector\textasteriskcentered.h}, \textfilename{ArrayManagerExecution\textasteriskcentered.h}, \textfilename{VirtualObjectTransfer\textasteriskcentered.h}, \textfilename{AtomicInterfaceExecution\textasteriskcentered.h} and \textfilename{DeviceAdapterAlgorithm\textasteriskcentered.h}, which are hidden in internal directories.
By convention the implementation of device adapters within \VTKm are divided into 6 header files with the names \textfilename{DeviceAdapterTag\textasteriskcentered.h}, \textfilename{DeviceAdapterRuntimeDetector\textasteriskcentered.h}, \textfilename{ArrayManagerExecution\textasteriskcentered.h}, \textfilename{VirtualObjectTransfer\textasteriskcentered.h}, \textfilename{AtomicInterfaceExecution\textasteriskcentered.h} and \textfilename{DeviceAdapterAlgorithm\textasteriskcentered.h}, which are hidden in internal directories.
The \textfilename{DeviceAdapter\textasteriskcentered.h} that most code includes is a trivial header that simply includes these other 6 files.
For our example \textcode{std::thread} device, we will create the base header at \textfilename{vtkm/cont/cxx11/DeviceAdapterCxx11Thread.h}.
The contents are the following (with minutia like include guards removed).
......@@ -33,7 +33,7 @@ The contents are the following (with minutia like include guards removed).
#include <vtkm/cont/cxx11/internal/DeviceAdapterAlgorithmCxx11Thread.h>
\end{vtkmexample}
The reason VTK-m breaks up the code for its device adapters this way is
The reason \VTKm breaks up the code for its device adapters this way is
that there is an interdependence between the implementation of each device
adapter and the mechanism to pick a default device adapter. Breaking up the
device adapter code in this way maintains an acyclic dependence among
......@@ -53,11 +53,11 @@ prefix of \textfilename{DeviceAdapterTag}.
The device adapter tag should be created with the macro
\vtkmmacro{VTKM\_VALID\_DEVICE\_ADAPTER}. This adapter takes an abbreviated
name that it will append to \textcode{DeviceAdapterTag} to make the tag
structure. It will also create some support classes that allow VTK-m to
structure. It will also create some support classes that allow \VTKm to
introspect the device adapter. The macro also expects a unique integer
identifier that is usually stored in a macro prefixed with
\textcode{VTKM\_DEVICE\_ADAPTER\_}. These identifiers for the device
adapters provided by the core VTK-m are declared in
adapters provided by the core \VTKm are declared in
\vtkmheader{vtkm/cont/internal}{DeviceAdapterTag.h}.
The following example gives the implementation of our custom device
......@@ -161,7 +161,7 @@ data from control array portals.
However, if the control and execution environments share the same memory
space, the execution array manager can, and should, delegate all of its
operations to the \textidentifier{Storage} it is constructed with. VTK-m
operations to the \textidentifier{Storage} it is constructed with. \VTKm
comes with a class called
\vtkmcontinternal{ArrayManagerExecutionShareWithControl} that provides the
implementation for an execution array manager that shares a memory space
......@@ -281,7 +281,7 @@ Continuing our example of a device adapter based on C++11's \textcode{std::threa
\index{virtual object transfer|(}
\index{transfer virtual object|(}
VTK-m defines a template named \vtkmcontinternal{VirtualObjectTransfer} that is responsible for instantiating virtual objects in the execution environment.
\VTKm defines a template named \vtkmcontinternal{VirtualObjectTransfer} that is responsible for instantiating virtual objects in the execution environment.
\fix{Re-add the following after it is implemented.}
%% Chapter~\ref{chap:VirtualObjects} discusses how to design and implement virtual objects.
The \textidentifier{VirtualObjectTransfer} class is the internal mechanism that allocates space for the object and sets up the virtual method tables for them.
......@@ -324,7 +324,7 @@ It can be assumed that the object can be trivially copied (with the exception of
\end{didyouknow}
However, if the control and execution environments share the same memory space, the virtual object transfer can, and should, just bind directly with the target concrete object.
VTK-m comes with a class called \vtkmcontinternal{VirtualObjectTransferShareWithControl} that provides the implementation for a virtual object transfer that shares a memory space with the control environment.
\VTKm comes with a class called \vtkmcontinternal{VirtualObjectTransferShareWithControl} that provides the implementation for a virtual object transfer that shares a memory space with the control environment.
In this case, making the \textidentifier{VirtualObjectTransfer} specialization be a trivial subclass is sufficient.
Continuing our example of a device adapter based on C++11's \textcode{std::thread} class, here is the implementation of \textidentifier{VirtualObjectTransfer}, which by convention would be placed in the \textfilename{vtkm/cont/cxx11/internal/VirtualObjectTransferCxx11Thread.h} header file.
......@@ -339,7 +339,7 @@ Continuing our example of a device adapter based on C++11's \textcode{std::threa
\index{device adapter!atomic interface execution|(}
\index{atomic interface execution|(}
VTK-m defines a template named \vtkmcontinternal{AtomicInterfaceExecution} that is responsible for performing atomic operations on raw addresses.
\VTKm defines a template named \vtkmcontinternal{AtomicInterfaceExecution} that is responsible for performing atomic operations on raw addresses.
\vtkmcontinternal{AtomicInterfaceExecution} defines a \textidentifier{WordTypePreferred} member that is the fastest available for bitwise operations of the given device.
At minimum, the interface must support operations on \textidentifier{WordTypePreferred} and \vtkm{WordTypeDefault}, which may be the same.
A full list of the supported word types is advertised in the type list stored in \textidentifier{WordTypes}.
......@@ -379,7 +379,7 @@ A device adapter implementation must also provide a specialization of \vtkmcont{
The implementation for the device adapter algorithms is typically placed in a header file with a prefix of \textfilename{DeviceAdapterAlgorithm}.
Although there are many methods in \textidentifier{DeviceAdapterAlgorithm},
it is seldom necessary to implement them all. Instead, VTK-m comes with
it is seldom necessary to implement them all. Instead, \VTKm comes with
\vtkmcontinternal{DeviceAdapterAlgorithmGeneral} that provides generic
implementation for most of the required algorithms. By deriving the
specialization of \textidentifier{DeviceAdapterAlgorithm} from
......@@ -447,7 +447,7 @@ header file.
\index{timer|(}
\index{device adapter!timer|(}
The VTK-m timer, described in Chapter~\ref{chap:Timers}, delegates to an
The \VTKm timer, described in Chapter~\ref{chap:Timers}, delegates to an
internal class named \vtkmcont{DeviceAdapterTimerImplementation}. The
interface for this class is the same as that for \vtkmcont{Timer}. A default
implementation of this templated class uses the system timer and the
......
......@@ -164,10 +164,16 @@ An example \vtkm{Frustum} is shown in Figure~\ref{fig:ImplicitFrustum}.
\index{implicit functions!handle|(}
To support \VTKm's device agnostic execution environment, \VTKm also provides a \vtkmcont{ImplicitFunctionHandle}.
\vtkmcont{ImplicitFunctionHandle} should be used when executing on a device.
See Chapter \ref{chap:GeneralApproach} for more information on \VTKm's execution environment.
\VTKm also provides some convenience functions for easily creating \vtkmcont{ImplicitFunctionHandle}.
The following example demostrantes how to create a \vtkmcont{ImplicitFunctionHandle} and apply it over a series of points.
The \textidentifier{ImplicitFunction} that your code creates on the host processor of your computer might not work as is on a device that a filter executes on.
Thus the \textidentifier{ImplicitFunction} object needs to be transformed before it is ready for running in a parallel algorithm.
This transformation is managed by the \vtkmcont{ImplicitFunctionHandle} class.
\textidentifier{ImplicitFunctionHandle} holds a reference to an \textidentifier{ImplicitFunction}.
The reference of \textidentifier{ImplicitFunctionHandle} is not dependent on the type of \textidentifier{ImplicitFunction} being held, so it is a convenient way to accept a user-defined function.
\textidentifier{ImplicitFunctionHandle} also manages the transfer of the \textidentifier{ImplicitFunction} to the device.
An \textidentifier{ImplicitFunctionHandle} is easily created with the \vtkmcont{make\_ImplicitFunctionHandle} function.
The following example demonstrates creating an \textidentifier{ImplicitFunction} and then putting it into an \textidentifier{ImplicitFunctionHandle} for use with the \vtkmfilter{ClipWithImplicitFunction} filter.
\vtkmlisting{Using \textidentifier{ImplicitFunctionHandle}.}{ImplicitFunctionHandle.cxx}
......
......@@ -197,6 +197,7 @@
DataSetBuilderRectilinear,
DataSetBuilderUniform,
DataSetFieldAdd,
ConvertNumIndicesToOffsets,
CellLocator,CellLocatorGeneral,
CellLocatorUniformGrid,CellLocatorRectilinearGrid,
CellLocatorUniformBins,CellLocatorBoundingIntervalHierarchy,
......
......@@ -6,27 +6,25 @@
\index{try execute|(}
\index{device adapter!try execute|(}
Throughout this chapter and elsewhere in this book we have seen examples that require specifying the device on which to run using a device adapter tag.
This is an important aspect when writing portable parallel algorithms.
However, it is often the case that users of these algorithms are agnostic about what device \VTKm algorithms run so long as they complete correctly and as fast as possible.
Thus, rather than directly specify a device adapter, you would like \VTKm to try using the best available device, and if that does not work try a different device.
Because of this, there are many features in \VTKm that behave this way.
For example, you may have noticed that running filters, as in the examples of Chapter~\ref{chap:RunningFilters}, you do not need to specify a device; they choose a device for you.
Internally, the filter superclasses have a mechanism to automatically select a device, try it, and fall back to other devices if the first one fails.
Most operations in \VTKm do not require specifying on which device to run.
For example, you may have noticed that when using \vtkmcont{Invoker} to execute a worklet, you do not need to specify a device; it chooses a device for you.
Internally, the \textidentifier{Invoker} has a mechanism to automatically select a device, try it, and fall back to other devices if the first one fails.
We saw this at work in the implementation of filters in Chapter \ref{chap:FilterTypeReference}.
Most of the outward facing interfaces of parallel algorithms in \VTKm are through these filter classes.
For everything else, there is the \vtkmcont{TryExecute} function.
The \textidentifier{Invoker} is internally using a function named \vtkmcont{TryExecute} to choose a device.
This \textidentifier{TryExecute} function can be also be used in other instances where a specific device needs to be chosen.
\textidentifier{TryExecute} is a simple, generic mechanism to run an algorithm that requires a device adapter without directly specifying a device adapter.
\vtkmcont{TryExecute} is a templated function with two arguments.
\vtkmcont{TryExecute} is a templated function.
The first argument is a functor object whose parenthesis operator takes a device adapter tag and returns a \textcode{bool} that is true if the call succeeds on the given device.
\index{runtime device tracker|}\index{device adapter!runtime tracker|}The second argument is a \vtkmcont{RuntimeDeviceTracker} that specifies what devices to try.
\textidentifier{RuntimeDeviceTracker} is documented in Section~\ref{sec:RuntimeDeviceTracker}.
If any further arguments are given to \textidentifier{TryExecute}, they are passed on to the functor.
Thus, the parenthesis operator on the functor should take a device adapter tag as its first argument and any remaining arguments must match those passed to \textidentifier{TryExecute}.
To demonstrate the operation of \textidentifier{TryExecute}, consider an operation to find the average value of an array.
Doing so with a given device adapter is a straightforward use of the reduction operator.
\fix{Change this example to simply the functor by passing InArray and OutValue as operator parameters.}
\vtkmlisting[ex:ArrayAverageImpl]{A function to find the average value of an array in parallel.}{ArrayAverageImpl.cxx}
The function in Example~\ref{ex:ArrayAverageImpl} requires a device adapter.
......@@ -37,12 +35,6 @@ We then create a new version of the array average function that does not need a
\vtkmlisting[ex:ArrayAverageTryExecute]{Using \textidentifier{TryExecute}.}{ArrayAverageTryExecute.cxx}
\begin{didyouknow}
\textidentifier{TryExecute} calls \vtkmcont{TryExecuteOnDevice} internally.
This means that \vtkmcont{GetRuntimeDeviceTracker} is automatically called and ensures execution on devices that have been enabled.
It is up to the application to enable/disable devices before calling \textidentifier{TryExecute} using the methods provided in Section~\ref{sec:RuntimeDeviceTracker}.
\end{didyouknow}
\begin{commonerrors}
When \textidentifier{TryExecute} calls the operation of your functor, it will catch any exceptions that the functor might throw.
\textidentifier{TryExecute} will interpret any thrown exception as a failure on that device and try another device.
......
......@@ -33,7 +33,7 @@ Data pointed to by a \textidentifier{VariantArrayHandle} is not directly
accessible. However, there are a few generic queries you can make without
directly knowing the data type. The \classmember*{VariantArrayHandle}{GetNumberOfValues} method
returns the length of the array with respect to its base data type. It is
also common in VTK-m to use data types, such as \vtkm{Vec}, with multiple
also common in \VTKm to use data types, such as \vtkm{Vec}, with multiple
components per value. The \classmember*{VariantArrayHandle}{GetNumberOfComponents} method returns
the number of components in a vector-like type (or 1 for scalars).
......@@ -51,7 +51,7 @@ with the same underlying type as the original array.
Before the data with a \textidentifier{VariantArrayHandle} can be accessed,
the type of the array must be established. This is usually done
internally within VTK-m when a worklet or filter is invoked and the \textidentifier{VariantArrayHandle}
internally within \VTKm when a worklet or filter is invoked and the \textidentifier{VariantArrayHandle}
is converted into an \textidentifier{ArrayHandleVirtual}.
However, it is also possible to query the types and cast to a concrete
\textidentifier{ArrayHandle}.
......@@ -75,7 +75,7 @@ Chapter~\ref{chap:AccessingAllocatingArrays}. The easiest ways to do this is to
or \classmember*{VariantArrayHandle}{CopyTo} method when wanting a concrete \textidentifier{ArrayHandle}.
The \classmember{VariantArrayHandle}{AsVirtual} templated method takes a
value type as a template parameter and returns a
value type as a template parameter and returns an
array handle virtual that points to the array in \textidentifier{VariantArrayHandle}.
If the given types are incorrect, then \classmember*{VariantArrayHandle}{AsVirtual} throws
a \vtkmcont{ErrorControlBadValue} exception.
......@@ -83,14 +83,6 @@ a \vtkmcont{ErrorControlBadValue} exception.
\vtkmlisting{Casting a \textidentifier{VariantArrayHandle} to a virtual
\textidentifier{ArrayHandle}.}{AsVirtualVariantArrayHandle.cxx}
\begin{commonerrors}
Remember that \textidentifier{ArrayHandle} and
\textidentifier{VariantArrayHandle} represent pointers to the data, so
this ``copy'' is a shallow copy. There is still only one copy of the
data, and if you change the data in one array handle that change is
reflected in the other.
\end{commonerrors}
The \classmember{VariantArrayHandle}{CopyTo} templated method takes a
reference to an \textidentifier{ArrayHandle} as an argument and sets that
array handle to point to the array in \textidentifier{VariantArrayHandle}.
......@@ -140,7 +132,7 @@ appropriate type.
The \classmember*{VariantArrayHandle}{CastAndCall} method can only check a finite number of value types.
The default form of \classmember*{VariantArrayHandle}{CastAndCall} uses a default set of common
types. These default lists can be overridden using the VTK-m list tags
types. These default lists can be overridden using the \VTKm list tags
facility, which is discussed at length in Section~\ref{sec:ListTags}.
Common type lists for value are defined in
......@@ -165,7 +157,7 @@ templated on the type of \textidentifier{VariantArrayHandle}. This is to
accommodate using the objects from the \textcode{ResetTypes} method, which
have the same behavior but different type names.)
So the default component type list contains a subset of the basic VTK-m
So the default component type list contains a subset of the basic \VTKm
types. If you wanted to accommodate more types, you could use
\classmember*{VariantArrayHandle}{ResetTypes}.
......
......@@ -40,36 +40,7 @@ tag names.
\begin{figure}
\centering
\small
\begin{tabular}{@{}c@{ }c@{ }c@{}}
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsVertex}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsLine}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsTriangle}} \\
\vtkm{CELL\_SHAPE\_VERTEX} &
\vtkm{CELL\_SHAPE\_LINE} &
\vtkm{CELL\_SHAPE\_TRIANGLE} \\
\vtkm{CellShapeTagVertex} \index{vertex} &
\vtkm{CellShapeTagLine} \index{line} &
\vtkm{CellShapeTagTriangle} \index{triangle} \\[2ex]
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsPolygon}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsQuadrilateral}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsTetrahedron}} \\
\vtkm{CELL\_SHAPE\_POLYGON} &
\vtkm{CELL\_SHAPE\_QUAD} &
\vtkm{CELL\_SHAPE\_TETRA} \\
\vtkm{CellShapeTagPolygon} \index{polygon} &
\vtkm{CellShapeTagQuad} \index{quadrilateral} &
\vtkm{CellShapeTagTetra} \index{tetrahedron} \\[2ex]
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsHexahedron}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsWedge}} &
\raisebox{-0.5\height}{\includegraphics{images/CellConnectionsPyramid}} \\
\vtkm{CELL\_SHAPE\_HEXAHEDRON} &
\vtkm{CELL\_SHAPE\_WEDGE} &
\vtkm{CELL\_SHAPE\_PYRAMID} \\
\vtkm{CellShapeTagHexahedron} \index{hexahedron} &
\vtkm{CellShapeTagWedge} \index{wedge} &
\vtkm{CellShapeTagPyramid} \index{pyramid}
\end{tabular}
\input{CellShapeFigure}
\caption{Basic Cell Shapes}
\label{fig:CellShapes}
\end{figure}
......
......@@ -4,15 +4,15 @@
\label{chap:TransferringArguments}
\label{chap:WorkletArguments}
From the \controlsignature and \executionsignature defined in worklets, VTK-m uses template meta-programming to build the code required to manage data from control to execution environment.
From the \controlsignature and \executionsignature defined in worklets, VTK-m uses template meta-programming to build the code required to manage data from the control to the execution environment.
These signatures contain tags that define the meaning of each argument and control how the argument data are transferred from the control to execution environments and broken up for each worklet instance.
Chapter \ref{chap:WorkletTypeReference} documents the many \controlsignature and \executionsignature tags that come with the worklet types.
This chapter discusses the internals of these tags and how they control data management.
Defining new worklet argument types can allow you to define new data structures in VTK-m.
Defining new worklet argument types can allow you to define new data structures in \VTKm.
New worklet arguments are also usually a critical components for making new worklet types, as described in Chapter~\ref{chap:NewWorkletTypes}.
The management of data in worklet arguments is handled by three classes that provide type checking, transportation, and fetching.
The management of data in worklet arguments is handled by three classes that provide type checking, transportation, and fetching, respectively.
This chapter will first describe these type checking, transportation, and fetching classes and then describe how \controlsignature and \executionsignature tags specify these classes.
Throughout this chapter we demonstrate the definition of worklet arguments using an example of a worklet argument that represents line segments in 2D.
......@@ -28,7 +28,7 @@ Plus, we will use this special worklet argument for our example of a custom work
\index{type check|(}
Before attempting to move data from the control to the execution
environment, the VTK-m dispatchers check the input types to ensure that
environment, the \VTKm invokers check the input types to ensure that
they are compatible with the associated \controlsignature concept. This is
done with the \vtkmcontarg{TypeCheck} \textcode{struct}.
......@@ -44,7 +44,7 @@ Type checks are implemented with a defined type check tag (which, by
convention, is defined in the \vtkmcontarg{} namespace and starts with
\textcode{TypeCheckTag}) and a partial specialization of the
\vtkmcontarg{TypeCheck} structure. The following type checks (identified by
their tags) are provided in VTK-m.
their tags) are provided in \VTKm.
\begin{description}
\item[\vtkmcontarg{TypeCheckTagExecObject}] \index{type check!execution object}
......@@ -62,21 +62,21 @@ their tags) are provided in VTK-m.
Here are some trivial examples of using
\textidentifier{TypeCheck}. Typically these checks are done internally in
the base VTK-m dispatcher code, so these examples are for demonstration
the base \VTKm invoker code, so these examples are for demonstration
only.
\vtkmlisting{Behavior of \protect\vtkmcontarg{TypeCheck}.}{TypeCheck.cxx}
A type check is created by first defining a type check tag object, which by convention is placed in the \vtkmcontarg{} namespace and whose name starts with \textidentifier{TypeCheckTag}.
Then, create a specialization of the \vtkmcontarg{TypeCheck} template class with the first template argument matching the aforementioned tag.
As stated previously, the \textidentifier{TypeCheck} class must contain a \classmember*{TypeCheck}{value} static constant Boolean representing whether the type is acceptable for the corresponding \textcode{Invoke} argument.
As stated previously, the \textidentifier{TypeCheck} class must contain a \classmember*{TypeCheck}{value} static constant Boolean representing whether the type is acceptable for the corresponding \textidentifier{Invoker} argument.
This example of a \textidentifier{TypeCheck} returns true for control objects that are \textidentifier{ArrayHandle}s with a value type that is a floating point \vtkm{Vec} of size 2.
\vtkmlisting[ex:TypeCheckTag2DCoordinates]{Defining a custom \textidentifier{TypeCheck}.}{TypeCheckImpl.h}
\begin{didyouknow}
The type check defined in Example~\ref{ex:TypeCheckTag2DCoordinates} could actually be replaced by the more general \textidentifier{TypeCheckTagArray} that already comes with \VTKm (and, in fact, the implementation uses this type check internally for simplicity).
The type check defined in Example~\ref{ex:TypeCheckTag2DCoordinates} could actually be replaced by the more general \textidentifier{TypeCheckTagArray} that already comes with \VTKm.
This example is mostly provided for demonstrative purposes.
In practice, it is often useful to use \textcode{std::is\_same} or \textcode{std::is\_base\_of}, which are provided by the standard template library starting with C++11, to determine \classmember*{TypeCheck}{value} in a \textidentifier{TypeCheck}.
\end{didyouknow}
......@@ -89,9 +89,8 @@ This example of a \textidentifier{TypeCheck} returns true for control objects th
\index{transport|(}
After all the argument types are checked, the base dispatcher must load the
data into the execution environment before scheduling a job to run
there. This is done with the \vtkmcontarg{Transport} \textcode{struct}.
After all the argument types are checked, the \VTKm dispatch mechanism must load the data into the execution environment before scheduling a job to run there.
This is done with the \vtkmcontarg{Transport} \textcode{struct}.
The \textidentifier{Transport} \textcode{struct} is templated with three
parameters. The first parameter is a tag that identifies which transport to
......@@ -107,7 +106,7 @@ Transports are implemented with a defined transport tag (which, by
convention, is defined in the \vtkmcontarg{} namespace and starts with
\textcode{TransportTag}) and a partial specialization of the
\vtkmcontarg{Transport} structure. The following transports (identified by
their tags) are provided in VTK-m.
their tags) are provided in \VTKm.
\begin{description}
\item[\vtkmcontarg{TransportTagExecObject}]
......@@ -168,7 +167,7 @@ their tags) are provided in VTK-m.
Here are some trivial examples of using
\textidentifier{Transport}. Typically this movement is done internally in
the base VTK-m dispatcher code, so these examples are for demonstration
the \VTKm dispatching code, so these examples are for demonstration
only.
\vtkmlisting{Behavior of \protect\vtkmcontarg{Transport}.}{Transport.cxx}
......@@ -184,7 +183,7 @@ The resulting execution object is an array portal containing \textidentifier{Vec
\begin{commonerrors}
It is fair to assume that the \textidentifier{Transport}'s control object type matches whatever the associated \textidentifier{TypeCheck} allows.
However, it is good practice to provide a secondary compile-time check in the \textidentifier{Transport} class for debugging purposes in case there is a problem with the \textidentifier{TypeCheck} or this \textidentifier{Transport} is used with an unexpected \textidentifier{TypeCheck}.
However, it is good practice to provide a secondary compile-time check in the \textidentifier{Transport} class, like the one on line \ref{ex:TransportImpl.h:CheckControlObject} in Example \ref{ex:TransportImpl}, for debugging purposes in case there is a problem with the \textidentifier{TypeCheck} or this \textidentifier{Transport} is used with an unexpected \textidentifier{TypeCheck}.
\end{commonerrors}
\index{transport|)}
......@@ -195,7 +194,7 @@ The resulting execution object is an array portal containing \textidentifier{Vec
\index{fetch|(}
Before the function of a worklet is invoked, the VTK-m internals pull the
Before the function of a worklet is invoked, the \VTKm internals pull the
appropriate data out of the execution object and pass it to the worklet
function. A class named \vtkmexecarg{Fetch} is responsible for pulling this
data out and putting computed data in to the execution objects.
......@@ -282,7 +281,7 @@ As stated previously, the \textidentifier{Fetch} class must contain a \classmemb
\end{didyouknow}
In addition to the aforementioned aspect tags that are explicitly paired
with fetch tags, VTK-m also provides some aspect tags that either modify
with fetch tags, \VTKm also provides some aspect tags that either modify
the behavior of a general fetch or simply ignore the type of fetch.
\begin{description}
......@@ -334,7 +333,7 @@ This example creates a specialization of a \textidentifier{Fetch} to retrieve th
\index{control signature!tags|(}
\index{signature!control!tags|(}
The type checks, transports, and fetches defined in the previous sections of this chapter conspire to interpret the arguments given to a dispatcher's \textcode{Invoke} method and provide data to an instance of a worklet.
The type checks, transports, and fetches defined in the previous sections of this chapter conspire to interpret the arguments given to a \textidentifier{Invoker} and provide data to an instance of a worklet.
What remains to be defined are the tags used in the \controlsignature and \executionsignature that bring these three items together.
These two types of tags are defined differently.
In this section we discuss the \controlsignature tags.
......
......@@ -3,7 +3,6 @@
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/PointElevation.h>
#include <vtkm/cont/testing/Testing.h>
......@@ -245,9 +244,8 @@ void GetElevationAirPressure(vtkm::cont::DataSet grid, FooFieldsDeque* fields)
elevation.SetHighPoint(vtkm::make_Vec(0.0, 0.0, 2000.0));
elevation.SetRange(101325.0, 77325.0);
vtkm::worklet::DispatcherMapField<vtkm::worklet::PointElevation> dispatcher(
elevation);
dispatcher.Invoke(grid.GetCoordinateSystem().GetData(), pressureHandle);
vtkm::cont::Invoker invoke;
invoke(elevation, grid.GetCoordinateSystem().GetData(), pressureHandle);
// Make sure the values are flushed back to the control environment.
pressureHandle.SyncControlArray();
......
......@@ -38,7 +38,6 @@ set(example_src
GenerateMeshConstantShape.cxx
GenerateMeshHash.cxx
GenerateMeshVariableShape.cxx
ImplicitFunctions.cxx
Initialization.cxx
IO.cxx
ListTags.cxx
......
......@@ -219,8 +219,14 @@ struct ExtractFaces
// To construct an ArrayHandleGroupVecVariable, we need to convert
// pointsPerFace to an array of offsets
vtkm::Id faceIndicesSize;
vtkm::cont::ArrayHandle<vtkm::Id> faceIndexOffsets =
vtkm::cont::ConvertNumComponentsToOffsets(pointsPerFace, faceIndicesSize);
vtkm::cont::ArrayHandle<vtkm::Id> faceIndexOffsetsExtended =
vtkm::cont::ConvertNumIndicesToOffsets(pointsPerFace, faceIndicesSize);
// faceIndexOffsetsExtended contains the extended scan needed to fill the output
// CellSetExplicit dataset; an exclusive scan is needed to construct a
// ArrayHandleGroupVecVariable
auto faceIndexOffsetsExclusive = vtkm::cont::make_ArrayHandleView(
faceIndexOffsetsExtended, 0, faceIndexOffsetsExtended.GetNumberOfValues() - 1);
// We need to preallocate the array for faceIndices (because that is the
// way ArrayHandleGroupVecVariable works). We use the value previously
......@@ -230,17 +236,16 @@ struct ExtractFaces
// Get the cell index array for all the faces
vtkm::worklet::DispatcherMapTopology<FacesExtract> extractDispatcher(scatter);
extractDispatcher.Invoke(
cellSetIn,
vtkm::cont::make_ArrayHandleGroupVecVariable(faceIndices, faceIndexOffsets));
extractDispatcher.Invoke(cellSetIn,
vtkm::cont::make_ArrayHandleGroupVecVariable(
faceIndices, faceIndexOffsetsExclusive));
// Construct the resulting cell set and return
vtkm::cont::CellSetExplicit<> cellSetOut;
cellSetOut.Fill(cellSetIn.GetNumberOfPoints(),
faceShapes,
pointsPerFace,
faceIndices,
faceIndexOffsets);
faceIndexOffsetsExtended);
return cellSetOut;
}
};
......
......@@ -189,13 +189,12 @@ void CreateExplicitGrid()
// Do a simple check of the connectivity by getting the number of cells
// incident on each point. This array is unlikely to be correct if the
// topology got screwed up.
vtkm::cont::ArrayHandle<vtkm::IdComponent> numCellsPerPoint =
cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
auto numCellsPerPoint = cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout);
std::cout << std::endl;
vtkm::cont::ArrayHandle<vtkm::IdComponent>::PortalConstControl numCellsPortal =
numCellsPerPoint.GetPortalConstControl();
auto numCellsPortal = numCellsPerPoint.GetPortalConstControl();
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2),
"Wrong number of cells on point 0");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2),
......@@ -281,13 +280,12 @@ void CreateExplicitGridIterative()
// Do a simple check of the connectivity by getting the number of cells
// incident on each point. This array is unlikely to be correct if the
// topology got screwed up.
vtkm::cont::ArrayHandle<vtkm::IdComponent> numCellsPerPoint =
cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
auto numCellsPerPoint = cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout);
std::cout << std::endl;
vtkm::cont::ArrayHandle<vtkm::IdComponent>::PortalConstControl numCellsPortal =
numCellsPerPoint.GetPortalConstControl();
auto numCellsPortal = numCellsPerPoint.GetPortalConstControl();
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2),
"Wrong number of cells on point 0");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2),
......
......@@ -122,6 +122,7 @@ struct Transport<vtkm::cont::arg::TransportTag2DLineSegmentsIn,
ContObjectType,
Device>
{
//// LABEL CheckControlObject
VTKM_IS_ARRAY_HANDLE(ContObjectType);
using GroupedArrayType = vtkm::cont::ArrayHandleGroupVec<ContObjectType, 2>;
......
......@@ -4,8 +4,6 @@
#include <vtkm/exec/CellEdge.h>
#include <vtkm/worklet/AverageByKey.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/DispatcherReduceByKey.h>
#include <vtkm/worklet/Keys.h>
#include <vtkm/worklet/ScatterCounting.h>
......@@ -22,178 +20,102 @@ namespace worklet
namespace
{
struct ExtractEdges
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeCount.cxx
////
struct CountEdgesWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
{
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeCount.cxx
////
struct CountEdges : vtkm::worklet::WorkletVisitCellsWithPoints
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
using ExecutionSignature = _2(CellShape, PointCount);
using InputDomain = _1;
template<typename CellShapeTag>
VTKM_EXEC_CONT vtkm::IdComponent operator()(
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const
{
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
using ExecutionSignature = _2(CellShape, PointCount);
using InputDomain = _1;
template<typename CellShapeTag>
VTKM_EXEC_CONT vtkm::IdComponent operator()(
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const
{
return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this);
}
};
////
//// END-EXAMPLE GenerateMeshCombineLikeCount.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIds.cxx
////
class EdgeIds : public vtkm::worklet::WorkletVisitCellsWithPoints
{
public:
using ControlSignature = void(CellSetIn cellSet, FieldOut canonicalIds);
using ExecutionSignature = void(CellShape cellShape,
PointIndices globalPointIndices,
VisitIndex localEdgeIndex,
_2 canonicalIdOut);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
template<typename CellShapeTag, typename PointIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
const PointIndexVecType& globalPointIndicesForCell,
vtkm::IdComponent localEdgeIndex,
vtkm::Id2& canonicalIdOut) const
{
vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
canonicalIdOut = vtkm::exec::CellEdgeCanonicalId(numPointsInCell,
localEdgeIndex,
cellShape,
globalPointIndicesForCell,
*this);
}
};
////
//// END-EXAMPLE GenerateMeshCombineLikeGenIds.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIndices.cxx
////
class EdgeIndices : public vtkm::worklet::WorkletReduceByKey
{
public:
using ControlSignature = void(KeysIn keys,
WholeCellSetIn<> inputCells,
ValuesIn originCells,
ValuesIn originEdges,
ReducedValuesOut connectivityOut);
using ExecutionSignature = void(_2 inputCells,
_3 originCell,
_4 originEdge,
_5 connectivityOut);
using InputDomain = _1;
template<typename CellSetType,
typename OriginCellsType,
typename OriginEdgesType>
VTKM_EXEC void operator()(const CellSetType& cellSet,
const OriginCellsType& originCells,
const OriginEdgesType& originEdges,
vtkm::Id2& connectivityOut) const
{
// Regardless of how many cells/edges are in our local input, we know they are
// all the same, so just pick the first one.
vtkm::IdComponent numPointsInCell = cellSet.GetNumberOfIndices(originCells[0]);
vtkm::IdComponent edgeIndex = originEdges[0];
auto cellShape = cellSet.GetCellShape(originCells[0]);
vtkm::IdComponent pointInCellIndex0 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 0, edgeIndex, cellShape, *this);
vtkm::IdComponent pointInCellIndex1 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 1, edgeIndex, cellShape, *this);
auto globalPointIndicesForCell = cellSet.GetIndices(originCells[0]);
connectivityOut[0] = globalPointIndicesForCell[pointInCellIndex0];
connectivityOut[1] = globalPointIndicesForCell[pointInCellIndex1];
}
};
////
//// END-EXAMPLE GenerateMeshCombineLikeGenIndices.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeInvoke.cxx
////
template<typename CellSetType>
VTKM_CONT vtkm::cont::CellSetSingleType<> Run(const CellSetType& inCellSet)
return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this);
}
};
////
//// END-EXAMPLE GenerateMeshCombineLikeCount.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIds.cxx
////
class EdgeIdsWorklet : public vtkm::worklet::WorkletVisitCellsWithPoints
{
public:
using ControlSignature = void(CellSetIn cellSet, FieldOut canonicalIds);
using ExecutionSignature = void(CellShape cellShape,
PointIndices globalPointIndices,
VisitIndex localEdgeIndex,
_2 canonicalIdOut);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
template<typename CellShapeTag, typename PointIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
const PointIndexVecType& globalPointIndicesForCell,
vtkm::IdComponent localEdgeIndex,
vtkm::Id2& canonicalIdOut) const
{
VTKM_IS_DYNAMIC_OR_STATIC_CELL_SET(CellSetType);
// First, count the edges in each cell.
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
vtkm::worklet::DispatcherMapTopology<CountEdges> countEdgeDispatcher;
countEdgeDispatcher.Invoke(inCellSet, edgeCounts);
vtkm::worklet::ScatterCounting scatter(edgeCounts);
this->OutputToInputCellMap =
scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
vtkm::worklet::ScatterCounting::VisitArrayType outputToInputEdgeMap =
scatter.GetVisitArray(inCellSet.GetNumberOfCells());
// Second, for each edge, extract a canonical id.
vtkm::cont::ArrayHandle<vtkm::Id2> canonicalIds;
vtkm::worklet::DispatcherMapTopology<EdgeIds> edgeIdsDispatcher(scatter);
edgeIdsDispatcher.Invoke(inCellSet, canonicalIds);
// Third, use a Keys object to combine all like edge ids.
this->CellToEdgeKeys = vtkm::worklet::Keys<vtkm::Id2>(canonicalIds);
// Fourth, use a reduce-by-key to extract indices for each unique edge.
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
vtkm::worklet::DispatcherReduceByKey<EdgeIndices> edgeIndicesDispatcher;
edgeIndicesDispatcher.Invoke(
this->CellToEdgeKeys,
inCellSet,
this->OutputToInputCellMap,
outputToInputEdgeMap,
vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
// Fifth, use the created connectivity array to build a cell set.
vtkm::cont::CellSetSingleType<> outCellSet;
outCellSet.Fill(
inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
return outCellSet;
vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
canonicalIdOut = vtkm::exec::CellEdgeCanonicalId(
numPointsInCell, localEdgeIndex, cellShape, globalPointIndicesForCell, *this);
}
////
//// END-EXAMPLE GenerateMeshCombineLikeInvoke.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx
////
template<typename ValueType, typename Storage>
VTKM_CONT vtkm::cont::ArrayHandle<ValueType> ProcessCellField(
const vtkm::cont::ArrayHandle<ValueType, Storage>& inCellField) const
};
////
//// END-EXAMPLE GenerateMeshCombineLikeGenIds.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIndices.cxx
////
class EdgeIndicesWorklet : public vtkm::worklet::WorkletReduceByKey
{
public:
using ControlSignature = void(KeysIn keys,
WholeCellSetIn<> inputCells,
ValuesIn originCells,
ValuesIn originEdges,
ReducedValuesOut connectivityOut);
using ExecutionSignature = void(_2 inputCells,
_3 originCell,
_4 originEdge,
_5 connectivityOut);
using InputDomain = _1;
template<typename CellSetType, typename OriginCellsType, typename OriginEdgesType>
VTKM_EXEC void operator()(const CellSetType& cellSet,
const OriginCellsType& originCells,
const OriginEdgesType& originEdges,
vtkm::Id2& connectivityOut) const
{
return vtkm::worklet::AverageByKey::Run(
this->CellToEdgeKeys,
vtkm::cont::make_ArrayHandlePermutation(this->OutputToInputCellMap,
inCellField));
// Regardless of how many cells are sharing the edge we are generating, we
// know that each cell/edge given to us by the reduce-by-key refers to the
// same edge, so we can just look at the first cell to get the edge.
vtkm::IdComponent numPointsInCell = cellSet.GetNumberOfIndices(originCells[0]);
vtkm::IdComponent edgeIndex = originEdges[0];
auto cellShape = cellSet.GetCellShape(originCells[0]);
vtkm::IdComponent pointInCellIndex0 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 0, edgeIndex, cellShape, *this);
vtkm::IdComponent pointInCellIndex1 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 1, edgeIndex, cellShape, *this);
auto globalPointIndicesForCell = cellSet.GetIndices(originCells[0]);
connectivityOut[0] = globalPointIndicesForCell[pointInCellIndex0];
connectivityOut[1] = globalPointIndicesForCell[pointInCellIndex1];
}
////
//// END-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx
////
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
vtkm::worklet::Keys<vtkm::Id2> CellToEdgeKeys;
};
////
//// END-EXAMPLE GenerateMeshCombineLikeGenIndices.cxx
////
} // anonymous namespace
} // namespace worklet
......@@ -223,7 +145,8 @@ public:
const vtkm::filter::PolicyBase<Policy>& policy);
private:
vtkm::worklet::ExtractEdges Worklet;
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
vtkm::worklet::Keys<vtkm::Id2> CellToEdgeKeys;
};
//// PAUSE-EXAMPLE
......@@ -242,20 +165,54 @@ namespace
{
//// RESUME-EXAMPLE
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeInvoke.cxx
////
template<typename Policy>
inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
const vtkm::cont::DataSet& inData,
vtkm::filter::PolicyBase<Policy> policy)
{
const vtkm::cont::DynamicCellSet& inCells = inData.GetCellSet();
vtkm::cont::CellSetSingleType<> outCells =
this->Worklet.Run(vtkm::filter::ApplyPolicyCellSet(inCells, policy));
const vtkm::cont::DynamicCellSet& inCellSet =
vtkm::filter::ApplyPolicyCellSet(inData.GetCellSet(), policy);
// First, count the edges in each cell.
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
this->Invoke(vtkm::worklet::CountEdgesWorklet{}, inCellSet, edgeCounts);
// Second, using these counts build a scatter that repeats a cell's visit
// for each edge in the cell.
vtkm::worklet::ScatterCounting scatter(edgeCounts);
this->OutputToInputCellMap =
scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
vtkm::worklet::ScatterCounting::VisitArrayType outputToInputEdgeMap =
scatter.GetVisitArray(inCellSet.GetNumberOfCells());
// Third, for each edge, extract a canonical id.
vtkm::cont::ArrayHandle<vtkm::Id2> canonicalIds;
this->Invoke(vtkm::worklet::EdgeIdsWorklet{}, scatter, inCellSet, canonicalIds);
// Fourth, construct a Keys object to combine all like edge ids.
this->CellToEdgeKeys = vtkm::worklet::Keys<vtkm::Id2>(canonicalIds);
// Fifth, use a reduce-by-key to extract indices for each unique edge.
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
//// LABEL InvokeEdgeIndices
this->Invoke(vtkm::worklet::EdgeIndicesWorklet{},
this->CellToEdgeKeys,
inCellSet,
this->OutputToInputCellMap,
outputToInputEdgeMap,
vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
// Sixth, use the created connectivity array to build a cell set.
vtkm::cont::CellSetSingleType<> outCellSet;
outCellSet.Fill(
inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
vtkm::cont::DataSet outData;
outData.SetCellSet(outCells);
outData.SetCellSet(outCellSet);
for (vtkm::IdComponent coordSystemIndex = 0;
coordSystemIndex < inData.GetNumberOfCoordinateSystems();
......@@ -266,33 +223,46 @@ inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
return outData;
}
////
//// END-EXAMPLE GenerateMeshCombineLikeInvoke.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx
////
template<typename T, typename StorageType, typename Policy>
inline VTKM_CONT bool ExtractEdges::DoMapField(
vtkm::cont::DataSet& result,
const vtkm::cont::ArrayHandle<T, StorageType>& input,
const vtkm::cont::ArrayHandle<T, StorageType>& inputArray,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<Policy>&)
{
vtkm::cont::Field output;
vtkm::cont::Field outputField;
if (fieldMeta.IsPointField())
{
output = fieldMeta.AsField(input); // pass through
outputField = fieldMeta.AsField(inputArray); // pass through
}
else if (fieldMeta.IsCellField())
{
output = fieldMeta.AsField(this->Worklet.ProcessCellField(input));
auto outputCellArray =
vtkm::worklet::AverageByKey::Run(this->CellToEdgeKeys,
vtkm::cont::make_ArrayHandlePermutation(
this->OutputToInputCellMap, inputArray));
outputField = fieldMeta.AsField(outputCellArray);
}
else
{
return false;
}
result.AddField(output);
result.AddField(outputField);
return true;
}
////
//// END-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx
////
//// PAUSE-EXAMPLE
} // anonymous namespace
......@@ -323,19 +293,6 @@ void CheckOutput(const vtkm::cont::CellSetSingleType<>& cellSet)
VTKM_TEST_ASSERT(connectivityPortal.Get(43) == 10, "Bad edge index");
}
void TryWorklet()
{
std::cout << std::endl << "Trying calling worklet." << std::endl;
vtkm::cont::DataSet inDataSet =
vtkm::cont::testing::MakeTestDataSet().Make3DExplicitDataSet5();
vtkm::cont::CellSetExplicit<> inCellSet;
inDataSet.GetCellSet().CopyTo(inCellSet);
vtkm::worklet::ExtractEdges worklet;
vtkm::cont::CellSetSingleType<> outCellSet = worklet.Run(inCellSet);
CheckOutput(outCellSet);
}
void TryFilter()
{
std::cout << std::endl << "Trying calling filter." << std::endl;
......@@ -344,9 +301,6 @@ void TryFilter()
vtkm::filter::ExtractEdges filter;
// NOTE 2018-03-21: I expect this to fail in the short term. Right now no fields
// are copied from input to output. The default should be changed to copy them
// all.
vtkm::cont::DataSet outDataSet = filter.Execute(inDataSet);
vtkm::cont::CellSetSingleType<> outCellSet;
......@@ -372,7 +326,6 @@ void TryFilter()
void DoTest()
{
TryWorklet();
TryFilter();
}
......
......@@ -4,7 +4,6 @@
#include <vtkm/exec/CellEdge.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/WorkletMapTopology.h>
......@@ -21,114 +20,60 @@ namespace worklet
namespace
{
struct ExtractEdges
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeCount.cxx
////
struct CountEdgesWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
{
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeCount.cxx
////
struct CountEdges : vtkm::worklet::WorkletVisitCellsWithPoints
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
using ExecutionSignature = _2(CellShape, PointCount);
using InputDomain = _1;
template<typename CellShapeTag>
VTKM_EXEC_CONT vtkm::IdComponent operator()(
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const
{
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
using ExecutionSignature = _2(CellShape, PointCount);
using InputDomain = _1;
template<typename CellShapeTag>
VTKM_EXEC_CONT vtkm::IdComponent operator()(
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const
{
return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this);
}
};
////
//// END-EXAMPLE GenerateMeshConstantShapeCount.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeGenIndices.cxx
////
class EdgeIndices : public vtkm::worklet::WorkletVisitCellsWithPoints
{
public:
using ControlSignature = void(CellSetIn cellSet, FieldOut connectivityOut);
using ExecutionSignature = void(CellShape, PointIndices, _2, VisitIndex);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
template<typename CellShapeTag, typename PointIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
const PointIndexVecType& globalPointIndicesForCell,
vtkm::Id2& connectivityOut,
vtkm::IdComponent edgeIndex) const
{
vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
vtkm::IdComponent pointInCellIndex0 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 0, edgeIndex, cellShape, *this);
vtkm::IdComponent pointInCellIndex1 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 1, edgeIndex, cellShape, *this);
connectivityOut[0] = globalPointIndicesForCell[pointInCellIndex0];
connectivityOut[1] = globalPointIndicesForCell[pointInCellIndex1];
}
};
////
//// END-EXAMPLE GenerateMeshConstantShapeGenIndices.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeInvoke.cxx
////
template<typename CellSetType>
VTKM_CONT vtkm::cont::CellSetSingleType<> Run(const CellSetType& inCellSet)
{
VTKM_IS_DYNAMIC_OR_STATIC_CELL_SET(CellSetType);
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
vtkm::worklet::DispatcherMapTopology<CountEdges> countEdgeDispatcher;
countEdgeDispatcher.Invoke(inCellSet, edgeCounts);
return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this);
}
};
////
//// END-EXAMPLE GenerateMeshConstantShapeCount.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeGenIndices.cxx
////
class EdgeIndicesWorklet : public vtkm::worklet::WorkletVisitCellsWithPoints
{
public:
using ControlSignature = void(CellSetIn cellSet, FieldOut connectivityOut);
using ExecutionSignature = void(CellShape, PointIndices, _2, VisitIndex);
using InputDomain = _1;
vtkm::worklet::ScatterCounting scatter(edgeCounts);
this->OutputToInputCellMap =
scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
using ScatterType = vtkm::worklet::ScatterCounting;
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
vtkm::worklet::DispatcherMapTopology<EdgeIndices> edgeIndicesDispatcher(scatter);
edgeIndicesDispatcher.Invoke(
inCellSet, vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
template<typename CellShapeTag, typename PointIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
const PointIndexVecType& globalPointIndicesForCell,
vtkm::Id2& connectivityOut,
vtkm::IdComponent edgeIndex) const
{
vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
vtkm::cont::CellSetSingleType<> outCellSet;
outCellSet.Fill(
inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
vtkm::IdComponent pointInCellIndex0 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 0, edgeIndex, cellShape, *this);
vtkm::IdComponent pointInCellIndex1 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 1, edgeIndex, cellShape, *this);
return outCellSet;
}
////
//// END-EXAMPLE GenerateMeshConstantShapeInvoke.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeMapCellField.cxx
////
template<typename ValueType, typename Storage>
VTKM_CONT vtkm::cont::ArrayHandle<ValueType> ProcessCellField(
const vtkm::cont::ArrayHandle<ValueType, Storage>& inCellField) const
{
vtkm::cont::ArrayHandle<ValueType> outCellField;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandlePermutation(
this->OutputToInputCellMap, inCellField),
outCellField);
return outCellField;
connectivityOut[0] = globalPointIndicesForCell[pointInCellIndex0];
connectivityOut[1] = globalPointIndicesForCell[pointInCellIndex1];
}
////
//// END-EXAMPLE GenerateMeshConstantShapeMapCellField.cxx
////
private:
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
};
////
//// END-EXAMPLE GenerateMeshConstantShapeGenIndices.cxx
////
} // anonymous namespace
......@@ -159,7 +104,7 @@ public:
const vtkm::filter::PolicyBase<Policy>& policy);
private:
vtkm::worklet::ExtractEdges Worklet;
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
};
//// PAUSE-EXAMPLE
......@@ -178,20 +123,45 @@ namespace
{
//// RESUME-EXAMPLE
// TODO: It would be nice if there was a simpler example of DoExecute.
////
//// BEGIN-EXAMPLE ExtractEdgesFilterDoExecute.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeInvoke.cxx
////
template<typename Policy>
inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
const vtkm::cont::DataSet& inData,
vtkm::filter::PolicyBase<Policy> policy)
{
const vtkm::cont::DynamicCellSet& inCells = inData.GetCellSet();
const vtkm::cont::DynamicCellSet& inCellSet =
vtkm::filter::ApplyPolicyCellSet(inData.GetCellSet(), policy);
// Count number of edges in each cell.
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
this->Invoke(vtkm::worklet::CountEdgesWorklet{}, inCellSet, edgeCounts);
vtkm::cont::CellSetSingleType<> outCells =
this->Worklet.Run(vtkm::filter::ApplyPolicyCellSet(inCells, policy));
// Build the scatter object (for non 1-to-1 mapping of input to output)
vtkm::worklet::ScatterCounting scatter(edgeCounts);
this->OutputToInputCellMap =
scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
//// LABEL InvokeEdgeIndices
this->Invoke(vtkm::worklet::EdgeIndicesWorklet{},
scatter,
inCellSet,
vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
vtkm::cont::CellSetSingleType<> outCellSet;
outCellSet.Fill(
inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
vtkm::cont::DataSet outData;
outData.SetCellSet(outCells);
outData.SetCellSet(outCellSet);
for (vtkm::IdComponent coordSystemIndex = 0;
coordSystemIndex < inData.GetNumberOfCoordinateSystems();
......@@ -202,33 +172,55 @@ inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
return outData;
}
////
//// END-EXAMPLE GenerateMeshConstantShapeInvoke.cxx
////
////
//// END-EXAMPLE ExtractEdgesFilterDoExecute.cxx
////
////
//// BEGIN-EXAMPLE ExtractEdgesFilterDoMapField.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeMapCellField.cxx
////
template<typename T, typename StorageType, typename Policy>
inline VTKM_CONT bool ExtractEdges::DoMapField(
vtkm::cont::DataSet& result,
const vtkm::cont::ArrayHandle<T, StorageType>& input,
const vtkm::cont::ArrayHandle<T, StorageType>& inputArray,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<Policy>&)
{
vtkm::cont::Field output;
vtkm::cont::Field outputField;
if (fieldMeta.IsPointField())
{
output = fieldMeta.AsField(input); // pass through
outputField = fieldMeta.AsField(inputArray); // pass through
}
else if (fieldMeta.IsCellField())
{
output = fieldMeta.AsField(this->Worklet.ProcessCellField(input));
vtkm::cont::ArrayHandle<T> outputCellArray;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandlePermutation(
this->OutputToInputCellMap, inputArray),
outputCellArray);
outputField = fieldMeta.AsField(outputCellArray);
}
else
{
return false;
}
result.AddField(output);
result.AddField(outputField);
return true;
}
////
//// END-EXAMPLE GenerateMeshConstantShapeMapCellField.cxx
////
////
//// END-EXAMPLE ExtractEdgesFilterDoMapField.cxx
////
//// PAUSE-EXAMPLE
} // anonymous namespace
......@@ -260,19 +252,6 @@ void CheckOutput(const vtkm::cont::CellSetSingleType<>& cellSet)
VTKM_TEST_ASSERT(connectivityPortal.Get(69) == 10, "Bad edge index");
}
void TryWorklet()
{
std::cout << std::endl << "Trying calling worklet." << std::endl;
vtkm::cont::DataSet inDataSet =
vtkm::cont::testing::MakeTestDataSet().Make3DExplicitDataSet5();
vtkm::cont::CellSetExplicit<> inCellSet;
inDataSet.GetCellSet().CopyTo(inCellSet);
vtkm::worklet::ExtractEdges worklet;
vtkm::cont::CellSetSingleType<> outCellSet = worklet.Run(inCellSet);
CheckOutput(outCellSet);
}
void TryFilter()
{
std::cout << std::endl << "Trying calling filter." << std::endl;
......@@ -281,9 +260,6 @@ void TryFilter()
vtkm::filter::ExtractEdges filter;
// NOTE 2018-03-21: I expect this to fail in the short term. Right now no fields
// are copied from input to output. The default should be changed to copy them
// all.
vtkm::cont::DataSet outDataSet = filter.Execute(inDataSet);
vtkm::cont::CellSetSingleType<> outCellSet;
......@@ -309,7 +285,6 @@ void TryFilter()
void DoTest()
{
TryWorklet();
TryFilter();
}
......