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 ...@@ -19,6 +19,7 @@ set(images
images/CameraMovement.pdf images/CameraMovement.pdf
images/CellConnectionsHexahedron.pdf images/CellConnectionsHexahedron.pdf
images/CellConnectionsLine.pdf images/CellConnectionsLine.pdf
images/CellConnectionsPolyLine.pdf
images/CellConnectionsPolygon.pdf images/CellConnectionsPolygon.pdf
images/CellConnectionsPyramid.pdf images/CellConnectionsPyramid.pdf
images/CellConnectionsQuadrilateral.pdf images/CellConnectionsQuadrilateral.pdf
...@@ -116,6 +117,7 @@ set(input_docs ...@@ -116,6 +117,7 @@ set(input_docs
FunctionInterface.tex FunctionInterface.tex
WorkletArguments.tex WorkletArguments.tex
NewWorkletTypes.tex NewWorkletTypes.tex
CellShapeFigure.tex
# Special inputs that go into verbatim-like arguments # Special inputs that go into verbatim-like arguments
examples/VTKmQuickStart.cmake 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 ...@@ -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 %% default storage is specified in much the same way as a default device
%% adapter is defined (as described in Section~\ref{sec:DefaultDeviceAdapter}). %% adapter is defined (as described in Section~\ref{sec:DefaultDeviceAdapter}).
%% It is done by setting the \vtkmmacro{VTKM\_STORAGE} macro. This macro must %% 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 %% be set before including any \VTKm header files. Currently the only
%% practical storage provided by VTK-m is the basic storage, which simply %% practical storage provided by \VTKm is the basic storage, which simply
%% allocates a continuous section of memory of the given base type. This %% allocates a continuous section of memory of the given base type. This
%% storage can be explicitly specified by setting \vtkmmacro{VTKM\_STORAGE} to %% storage can be explicitly specified by setting \vtkmmacro{VTKM\_STORAGE} to
%% \vtkmmacro{VTKM\_STORAGE\_BASIC} although the basic storage will also be %% \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 ...@@ -79,7 +79,7 @@ The remainder of this chapter uses the storage mechanism to customize the repres
\label{sec:ImplementingFancyArrays} \label{sec:ImplementingFancyArrays}
Although the behavior of fancy arrays might seem complicated, they are 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. implement fancy arrays.
\subsection{Implicit Array Handles} \subsection{Implicit Array Handles}
...@@ -90,7 +90,7 @@ implement fancy arrays. ...@@ -90,7 +90,7 @@ implement fancy arrays.
\index{implicit array handle|(} \index{implicit array handle|(}
\index{functional array|(} \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 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, 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 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 ...@@ -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 regular arrays but do special processing under the covers to provide
values. values.
Specifying a functional or implicit array in VTK-m is straightforward. Specifying a functional or implicit array in \VTKm is straightforward.
VTK-m has a special class named \vtkmcont{ArrayHandleImplicit} that makes \VTKm has a special class named \vtkmcont{ArrayHandleImplicit} that makes
an implicit array containing values generated by a user-specified an implicit array containing values generated by a user-specified
\keyterm{functor}. \index{functor} A functor is simply a C++ class or \keyterm{functor}. \index{functor} A functor is simply a C++ class or
struct that contains an overloaded parenthesis operator so that it can be 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 ...@@ -115,11 +115,9 @@ could easily create this array in memory, we can save space and possibly
time by computing these values on demand. time by computing these values on demand.
\begin{didyouknow} \begin{didyouknow}
VTK-m already comes with an implicit array handle named \VTKm already comes with an implicit array handle named \vtkmcont{ArrayHandleCounting} that can make implicit even numbers as well as other more general counts.
\vtkmcont{ArrayHandleCounting} that can make implicit even numbers as (See Section \ref{sec:CountingArrays} for details.)
well as other more general counts. So in practice you would not have to So in practice you would not have to create a special implicit array, but we are doing so here for demonstrative purposes.
create a special implicit array, but we are doing so here for
demonstrative purposes.
\end{didyouknow} \end{didyouknow}
The first step to using \textidentifier{ArrayHandleImplicit} is to declare The first step to using \textidentifier{ArrayHandleImplicit} is to declare
...@@ -161,16 +159,13 @@ is used in templated classes whereas ...@@ -161,16 +159,13 @@ is used in templated classes whereas
\vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} is used in non-templated \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} is used in non-templated
classes. classes.
The \textidentifier{ArrayHandle} subclass in \label{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}
Example~\ref{ex:ImplicitArrayHandleSubclass} is not templated, so it uses
the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} macro. (The other macro The \textidentifier{ArrayHandle} subclass in Example~\ref{ex:ImplicitArrayHandleSubclass} is not templated, so it uses the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} macro.
is described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS} on This macro takes two parameters.
page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS}). This macro takes two 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.
parameters. The first parameter is the name of the subclass where the macro The second parameter of the macro must be enclosed in parentheses so that the C pre-processor correctly handles commas in the template specification.
is defined and the second parameter is the immediate superclass including (The other macro is described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS} on page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS}).
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.
\index{functional array|)} \index{functional array|)}
\index{implicit array handle|)} \index{implicit array handle|)}
...@@ -191,7 +186,7 @@ except that a map operation writes its values to a new memory location ...@@ -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 whereas the transformed array handle produces its values on demand so that
no additional storage is required. 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 special class named \vtkmcont{ArrayHandleTransform} that takes an array
handle and a functor and provides an interface to a new array comprising handle and a functor and provides an interface to a new array comprising
values of the first array applied to the functor. values of the first array applied to the functor.
...@@ -234,8 +229,6 @@ convenience subclass of \vtkmcont{ArrayHandleTransform} or convenience ...@@ -234,8 +229,6 @@ convenience subclass of \vtkmcont{ArrayHandleTransform} or convenience
\vtkmlisting[ex:TransformArrayHandleSubclass]{Custom transform array handle for scale and bias.}{TransformArrayHandle.cxx} \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 Subclasses of \textidentifier{ArrayHandle} provide constructors that
establish the state of the array handle. All array handle subclasses must establish the state of the array handle. All array handle subclasses must
also use either the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro or the also use either the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro or the
...@@ -248,17 +241,13 @@ is used in templated classes whereas ...@@ -248,17 +241,13 @@ is used in templated classes whereas
\vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} is used in non-templated \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS\_NT} is used in non-templated
classes. classes.
The \textidentifier{ArrayHandle} subclass in \label{sec:VTKM_ARRAY_HANDLE_SUBCLASS}
Example~\ref{ex:TransformArrayHandleSubclass} is templated, so it uses the
\vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro. (The other macro is The \textidentifier{ArrayHandle} subclass in Example~\ref{ex:TransformArrayHandleSubclass} is templated, so it uses the \vtkmmacro{VTKM\_ARRAY\_HANDLE\_SUBCLASS} macro.
described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT} on This macro takes three parameters.
page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}). This macro takes three 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.
parameters. The first parameter is the name of the subclass where the macro 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.
is defined, the second parameter is the type of the subclass including the (The other macro is described in Section~\ref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT} on page~\pageref{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}).
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.
\index{transformed array|)} \index{transformed array|)}
\index{array handle!transform|)} \index{array handle!transform|)}
...@@ -267,6 +256,8 @@ pre-processor correctly handles commas in the template specification. ...@@ -267,6 +256,8 @@ pre-processor correctly handles commas in the template specification.
\subsection{Derived Storage} \subsection{Derived Storage}
\label{sec:DerivedStorage} \label{sec:DerivedStorage}
\fix{Change this to use ArrayHandleDecorator.}
\index{array handle!derived|(} \index{array handle!derived|(}
\index{storage!derived|(} \index{storage!derived|(}
\index{derived storage|(} \index{derived storage|(}
...@@ -448,7 +439,7 @@ parameters of the macro must be enclosed in parentheses so that the C ...@@ -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. pre-processor correctly handles commas in the template specification.
\vtkmcont{ArrayHandleCompositeVector} is an example of a derived array \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 pulls a specified component out of each, and produces a new component that
is a tuple of these retrieved components. is a tuple of these retrieved components.
...@@ -468,18 +459,18 @@ is a tuple of these retrieved components. ...@@ -468,18 +459,18 @@ is a tuple of these retrieved components.
\index{storage!adapting|(} \index{storage!adapting|(}
The intention of the storage parameter for \vtkmcont{ArrayHandle} is to The intention of the storage parameter for \vtkmcont{ArrayHandle} is to
implement the strategy design pattern to enable VTK-m to interface directly implement the strategy design pattern to enable \VTKm to interface directly
with the data of any third party code source. VTK-m is designed to work 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 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. structures.
\begin{commonerrors} \begin{commonerrors}
Keep in mind that memory layout used can have an effect on the running 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 change cache performance and introduce memory affinity problems. The
example code given in this section will likely have poorer cache 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. be an acceptable penalty to avoid data copies.
\end{commonerrors} \end{commonerrors}
...@@ -492,7 +483,7 @@ locations in a mesh in a \textcode{std::deque} object. ...@@ -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} \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 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 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} 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 ...@@ -504,7 +495,7 @@ Section~\ref{sec:ArrayPortals} and is generally straightforward for simple
containers like this. Here is an example implementation for our containers like this. Here is an example implementation for our
\textcode{FooFieldsDeque} container. \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 The next step in creating an adapter storage is to define a tag for the
adapter. We shall call ours adapter. We shall call ours
...@@ -552,7 +543,7 @@ The following provides an example implementation of our adapter to a ...@@ -552,7 +543,7 @@ The following provides an example implementation of our adapter to a
\textcode{ArrayPortalFooPressure} provided in \textcode{ArrayPortalFooPressure} provided in
Example~\ref{ex:ArrayPortalAdapter}. 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} \index{array handle!subclassing}
...@@ -562,9 +553,7 @@ storage. This can be done by creating a trivial subclass of ...@@ -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 \vtkmcont{ArrayHandle} that simply constructs the array handle to the state
of an existing container. of an existing container.
\vtkmlisting[ex:ArrayHandleAdapter]{Array handle to adapt a third-party container to VTK-m.}{ArrayHandleAdapter.cxx} \vtkmlisting[ex:ArrayHandleAdapter]{Array handle to adapt a third-party container to \VTKm.}{ArrayHandleAdapter.cxx}
\label{sec:VTKM_ARRAY_HANDLE_SUBCLASS_NT}
Subclasses of \textidentifier{ArrayHandle} provide constructors that Subclasses of \textidentifier{ArrayHandle} provide constructors that
establish the state of the array handle. All array handle subclasses must 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 ...@@ -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 enclosed in parentheses so that the C pre-processor correctly handles
commas in the template specification. 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. to and write from the \textcode{FooFieldsDeque} structure directly.
\vtkmlisting[ex:UsingArrayHandleAdapter]{Using an \textidentifier{ArrayHandle} with custom container.}{UsingArrayHandleAdapter.cxx} \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. ...@@ -604,14 +593,14 @@ to and write from the \textcode{FooFieldsDeque} structure directly.
\index{array handle!storage!default} \index{array handle!storage!default}
\index{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 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 specified. If you wish to replace the default storage used, then set the
\vtkmmacro{VTKM\_STORAGE} macro to \vtkmmacro{VTKM\_STORAGE\_UNDEFINED} and \vtkmmacro{VTKM\_STORAGE} macro to \vtkmmacro{VTKM\_STORAGE\_UNDEFINED} and
set the \vtkmmacro{VTKM\_DEFAULT\_STORAGE\_TAG} to your tag class. These 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) 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.} \begin{vtkmexample}{Redefining the default array handle storage.}
#define VTKM_STORAGE VTKM_STORAGE_UNDEFINED #define VTKM_STORAGE VTKM_STORAGE_UNDEFINED
...@@ -624,7 +613,7 @@ struct StorageTagFooPressure; ...@@ -624,7 +613,7 @@ struct StorageTagFooPressure;
\textidentifier{ArrayHandle}s are often stored in dynamic objects like \textidentifier{ArrayHandle}s are often stored in dynamic objects like
variant arrays (Chapter~\ref{chap:VariantArrayHandle}) or data sets variant arrays (Chapter~\ref{chap:VariantArrayHandle}) or data sets
(Chapter~\ref{chap:DataSets}). When this happens, the array's type (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 using the \textidentifier{ArrayHandleVirtual} interface. For hot path types
and storages for filters it is good to specify custom sets in the policy when and storages for filters it is good to specify custom sets in the policy when
executing filters. executing filters.
......
...@@ -122,14 +122,18 @@ spacing along each axis. ...@@ -122,14 +122,18 @@ spacing along each axis.
\index{explicit mesh} \index{explicit mesh}
\index{unstructured grid} \index{unstructured grid}
An explicit mesh is an arbitrary collection of cells with arbitrary An explicit mesh is an arbitrary collection of cells with arbitrary connections.
connections. It can have multiple different types of cells. Explicit meshes It can have multiple different types of cells.
are also known as unstructured grids. 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 \begin{figure}[htb]
indices, and the points that comprise it for each cell. These three things \centering
are stored in separate arrays. Figure~\ref{fig:ExplicitMesh} shows an \input{CellShapeFigure}
example of an explicit mesh and the arrays that can be used to define it. \caption{Basic Cell Shapes}
\label{fig:CreateExplicitMeshesCellShapes}
\end{figure}
\begin{figure}[htb] \begin{figure}[htb]
\centering \centering
...@@ -138,12 +142,34 @@ example of an explicit mesh and the arrays that can be used to define it. ...@@ -138,12 +142,34 @@ example of an explicit mesh and the arrays that can be used to define it.
\label{fig:ExplicitMesh} \label{fig:ExplicitMesh}
\end{figure} \end{figure}
The \vtkmcont{DataSetBuilderExplicit} class can be used to create data sets The cells of an explicit mesh are defined with the following 3 arrays, which are depicted graphically in Figure \ref{fig:ExplicitMesh}.
with explicit meshes. \textidentifier{DataSetBuilderExplicit} has several \begin{description}
versions of a method named \classmember*{DataSetBuilderExplicit}{Create}. Generally, these methods take \item[Shapes] \index{explicit mesh!shapes}
the shapes, number of indices, and connectivity arrays as well as an array An array of ids identifying the shape of the cell.
of point coordinates. These arrays can be given in \textcode{std::vector} Each value is a \vtkm{UInt8} and should be set to one of the \vtkm{}\textcode{::}\textidentifier{CELL\_SHAPE\_*} constants.
objects, and the data are copied into the \textidentifier{DataSet} created. 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 The following example creates a mesh like the one shown in
Figure~\ref{fig:ExplicitMesh}. Figure~\ref{fig:ExplicitMesh}.
...@@ -276,32 +302,36 @@ on page~\pageref{sec:DataSets:CoordinateSystems}. ...@@ -276,32 +302,36 @@ on page~\pageref{sec:DataSets:CoordinateSystems}.
\index{explicit cell set|(} \index{explicit cell set|(}
\index{cell set!explicit|(} \index{cell set!explicit|(}
A \vtkmcont{CellSetExplicit} defines an irregular collection of cells. The A \vtkmcont{CellSetExplicit} defines an irregular collection of cells.
cells can be of different types and connected in arbitrary ways. This is The cells can be of different types and connected in arbitrary ways.
done by explicitly providing for each cell a sequence of points that The types of cell sets are listed in Figure \ref{fig:ExplicitCellSetShapes}.
defines the cell. 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 An explicit cell set is defined with a minimum of three arrays.
array identifies the shape of each cell. (Cell shapes are discussed in The first array identifies the shape of each cell.
detail in Section~\ref{sec:CellShapeTagsIds} starting on (Identifiers for cell shapes are shown in Figure \ref{fig:ExplicitCellSetShapes}.)
page~\pageref{sec:CellShapeTagsIds}.) The second array identifies how many The second array has a sequence of point indices that make up each cell.
points are in each cell. The third array has a sequence of point indices 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.
that make up each cell. Figure~\ref{fig:CellSetExplicit} shows a simple Figure~\ref{fig:CellSetExplicit} shows a simple example of an explicit cell set.
example of an explicit cell set.
\begin{figure}[htb] \begin{figure}[htb]
\centering \centering
\includegraphics{images/ExplicitCellConnections} \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.} arrays that define them.}
\label{fig:CellSetExplicit} \label{fig:CellSetExplicit}
\end{figure} \end{figure}
An explicit cell set may also have other topological arrays such as an An explicit cell set can also identify the number of indices defined for each cell by subtracting consecutive entries in the offsets array.
array of offsets of each cell into the connectivity array or an array of It is often the case when creating a \textidentifier{CellSetExplicit} that you have an array containing the number of indices rather than the offsets.
cells incident on each point. Although these arrays can be provided, they Such an array can be converted to an offsets array that can be used with \textidentifier{CellSetExplicit} by using the \vtkmcont{ConvertNumIndicesToOffsets} convenience function.
are optional and can be internally derived from the shape, num indices, and
connectivity arrays.
\vtkmcont{ExplicitCellSet} is a powerful representation for a cell set \vtkmcont{ExplicitCellSet} is a powerful representation for a cell set
because it can represent an arbitrary collection of cells. However, because because it can represent an arbitrary collection of cells. However, because
......
...@@ -5,19 +5,15 @@ ...@@ -5,19 +5,15 @@
\index{function interface|(} \index{function interface|(}
For flexibility's sake a worklet is free to declare a \controlsignature For flexibility's sake a worklet is free to declare a \controlsignature with whatever number of arguments are sensible for its operation.
with whatever number of arguments are sensible for its operation. The 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.
\classmember*{DispatcherBase}{Invoke} method of the dispatcher is expected to support arguments This leaves the invoker with the tricky task of managing some collection of arguments of unknown size and unknown types.
that match these arguments, and part of the dispatching operation may
require these arguments to be augmented before the worklet is \fix{\textidentifier{FunctionInterface} is in the \vtkminternal{} interface.
scheduled. This leaves dispatchers with the tricky task of managing some I still can't decide if it should be moved to the \vtkm{} interface.
collection of arguments of unknown size and unknown types. Update: I'm glad I have not moved \textidentifier{FunctionInterface} ro \vtkm{} because now we are thinking of getting rid of it.}
\fix{\textidentifier{FunctionInterface} is in the \vtkminternal{} To simplify this management, \VTKm has the \vtkminternal{FunctionInterface}
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}
class. \textidentifier{FunctionInterface} is a templated class that manages class. \textidentifier{FunctionInterface} is a templated class that manages
a generic set of arguments and return value from a function. An instance of a generic set of arguments and return value from a function. An instance of
\textidentifier{FunctionInterface} holds an instance of each argument. You \textidentifier{FunctionInterface} holds an instance of each argument. You
......
This diff is collapsed.
...@@ -6,20 +6,20 @@ ...@@ -6,20 +6,20 @@
\index{device adapter|(} \index{device adapter|(}
\index{device adapter!implementing|(} \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. 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. 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}. 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}. 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 For the purposes of discussion in this section, we will give a simple
example of implementing a device adapter using the \textcode{std::thread} example of implementing a device adapter using the \textcode{std::thread}
class provided by C++11. We will call our device \textcode{Cxx11Thread} and class provided by C++11. We will call our device \textcode{Cxx11Thread} and
place it in the directory \textfilename{vtkm/cont/cxx11}. 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. 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}. 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). 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). ...@@ -33,7 +33,7 @@ The contents are the following (with minutia like include guards removed).
#include <vtkm/cont/cxx11/internal/DeviceAdapterAlgorithmCxx11Thread.h> #include <vtkm/cont/cxx11/internal/DeviceAdapterAlgorithmCxx11Thread.h>
\end{vtkmexample} \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 that there is an interdependence between the implementation of each device
adapter and the mechanism to pick a default device adapter. Breaking up the adapter and the mechanism to pick a default device adapter. Breaking up the
device adapter code in this way maintains an acyclic dependence among device adapter code in this way maintains an acyclic dependence among
...@@ -53,11 +53,11 @@ prefix of \textfilename{DeviceAdapterTag}. ...@@ -53,11 +53,11 @@ prefix of \textfilename{DeviceAdapterTag}.
The device adapter tag should be created with the macro The device adapter tag should be created with the macro
\vtkmmacro{VTKM\_VALID\_DEVICE\_ADAPTER}. This adapter takes an abbreviated \vtkmmacro{VTKM\_VALID\_DEVICE\_ADAPTER}. This adapter takes an abbreviated
name that it will append to \textcode{DeviceAdapterTag} to make the tag 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 introspect the device adapter. The macro also expects a unique integer
identifier that is usually stored in a macro prefixed with identifier that is usually stored in a macro prefixed with
\textcode{VTKM\_DEVICE\_ADAPTER\_}. These identifiers for the device \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}. \vtkmheader{vtkm/cont/internal}{DeviceAdapterTag.h}.
The following example gives the implementation of our custom device The following example gives the implementation of our custom device
...@@ -161,7 +161,7 @@ data from control array portals. ...@@ -161,7 +161,7 @@ data from control array portals.
However, if the control and execution environments share the same memory However, if the control and execution environments share the same memory
space, the execution array manager can, and should, delegate all of its 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 comes with a class called
\vtkmcontinternal{ArrayManagerExecutionShareWithControl} that provides the \vtkmcontinternal{ArrayManagerExecutionShareWithControl} that provides the
implementation for an execution array manager that shares a memory space 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 ...@@ -281,7 +281,7 @@ Continuing our example of a device adapter based on C++11's \textcode{std::threa
\index{virtual object transfer|(} \index{virtual object transfer|(}
\index{transfer virtual object|(} \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.} \fix{Re-add the following after it is implemented.}
%% Chapter~\ref{chap:VirtualObjects} discusses how to design and implement virtual objects. %% 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. 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 ...@@ -324,7 +324,7 @@ It can be assumed that the object can be trivially copied (with the exception of
\end{didyouknow} \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. 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. 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. 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 ...@@ -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{device adapter!atomic interface execution|(}
\index{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. \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. 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}. 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{ ...@@ -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}. 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}, 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 \vtkmcontinternal{DeviceAdapterAlgorithmGeneral} that provides generic
implementation for most of the required algorithms. By deriving the implementation for most of the required algorithms. By deriving the
specialization of \textidentifier{DeviceAdapterAlgorithm} from specialization of \textidentifier{DeviceAdapterAlgorithm} from
...@@ -447,7 +447,7 @@ header file. ...@@ -447,7 +447,7 @@ header file.
\index{timer|(} \index{timer|(}
\index{device adapter!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 internal class named \vtkmcont{DeviceAdapterTimerImplementation}. The
interface for this class is the same as that for \vtkmcont{Timer}. A default 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 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}. ...@@ -164,10 +164,16 @@ An example \vtkm{Frustum} is shown in Figure~\ref{fig:ImplicitFrustum}.
\index{implicit functions!handle|(} \index{implicit functions!handle|(}
To support \VTKm's device agnostic execution environment, \VTKm also provides a \vtkmcont{ImplicitFunctionHandle}. To support \VTKm's device agnostic execution environment, \VTKm also provides a \vtkmcont{ImplicitFunctionHandle}.
\vtkmcont{ImplicitFunctionHandle} should be used when executing on a device. 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.
See Chapter \ref{chap:GeneralApproach} for more information on \VTKm's execution environment. Thus the \textidentifier{ImplicitFunction} object needs to be transformed before it is ready for running in a parallel algorithm.
\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. 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} \vtkmlisting{Using \textidentifier{ImplicitFunctionHandle}.}{ImplicitFunctionHandle.cxx}
......
...@@ -197,6 +197,7 @@ ...@@ -197,6 +197,7 @@
DataSetBuilderRectilinear, DataSetBuilderRectilinear,
DataSetBuilderUniform, DataSetBuilderUniform,
DataSetFieldAdd, DataSetFieldAdd,
ConvertNumIndicesToOffsets,
CellLocator,CellLocatorGeneral, CellLocator,CellLocatorGeneral,
CellLocatorUniformGrid,CellLocatorRectilinearGrid, CellLocatorUniformGrid,CellLocatorRectilinearGrid,
CellLocatorUniformBins,CellLocatorBoundingIntervalHierarchy, CellLocatorUniformBins,CellLocatorBoundingIntervalHierarchy,
......
...@@ -6,27 +6,25 @@ ...@@ -6,27 +6,25 @@
\index{try execute|(} \index{try execute|(}
\index{device adapter!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. Most operations in \VTKm do not require specifying on which device to run.
This is an important aspect when writing portable parallel algorithms. 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.
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. 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.
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.
We saw this at work in the implementation of filters in Chapter \ref{chap:FilterTypeReference}. 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. \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. 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. If any further arguments are given to \textidentifier{TryExecute}, they are passed on to the functor.
\textidentifier{RuntimeDeviceTracker} is documented in Section~\ref{sec:RuntimeDeviceTracker}. 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. 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. 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} \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. 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 ...@@ -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} \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} \begin{commonerrors}
When \textidentifier{TryExecute} calls the operation of your functor, it will catch any exceptions that the functor might throw. 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. \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 ...@@ -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 accessible. However, there are a few generic queries you can make without
directly knowing the data type. The \classmember*{VariantArrayHandle}{GetNumberOfValues} method 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 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 components per value. The \classmember*{VariantArrayHandle}{GetNumberOfComponents} method returns
the number of components in a vector-like type (or 1 for scalars). 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. ...@@ -51,7 +51,7 @@ with the same underlying type as the original array.
Before the data with a \textidentifier{VariantArrayHandle} can be accessed, Before the data with a \textidentifier{VariantArrayHandle} can be accessed,
the type of the array must be established. This is usually done 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}. is converted into an \textidentifier{ArrayHandleVirtual}.
However, it is also possible to query the types and cast to a concrete However, it is also possible to query the types and cast to a concrete
\textidentifier{ArrayHandle}. \textidentifier{ArrayHandle}.
...@@ -75,7 +75,7 @@ Chapter~\ref{chap:AccessingAllocatingArrays}. The easiest ways to do this is to ...@@ -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}. or \classmember*{VariantArrayHandle}{CopyTo} method when wanting a concrete \textidentifier{ArrayHandle}.
The \classmember{VariantArrayHandle}{AsVirtual} templated method takes a 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}. array handle virtual that points to the array in \textidentifier{VariantArrayHandle}.
If the given types are incorrect, then \classmember*{VariantArrayHandle}{AsVirtual} throws If the given types are incorrect, then \classmember*{VariantArrayHandle}{AsVirtual} throws
a \vtkmcont{ErrorControlBadValue} exception. a \vtkmcont{ErrorControlBadValue} exception.
...@@ -83,14 +83,6 @@ a \vtkmcont{ErrorControlBadValue} exception. ...@@ -83,14 +83,6 @@ a \vtkmcont{ErrorControlBadValue} exception.
\vtkmlisting{Casting a \textidentifier{VariantArrayHandle} to a virtual \vtkmlisting{Casting a \textidentifier{VariantArrayHandle} to a virtual
\textidentifier{ArrayHandle}.}{AsVirtualVariantArrayHandle.cxx} \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 The \classmember{VariantArrayHandle}{CopyTo} templated method takes a
reference to an \textidentifier{ArrayHandle} as an argument and sets that reference to an \textidentifier{ArrayHandle} as an argument and sets that
array handle to point to the array in \textidentifier{VariantArrayHandle}. array handle to point to the array in \textidentifier{VariantArrayHandle}.
...@@ -140,7 +132,7 @@ appropriate type. ...@@ -140,7 +132,7 @@ appropriate type.
The \classmember*{VariantArrayHandle}{CastAndCall} method can only check a finite number of value types. 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 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}. facility, which is discussed at length in Section~\ref{sec:ListTags}.
Common type lists for value are defined in Common type lists for value are defined in
...@@ -165,7 +157,7 @@ templated on the type of \textidentifier{VariantArrayHandle}. This is to ...@@ -165,7 +157,7 @@ templated on the type of \textidentifier{VariantArrayHandle}. This is to
accommodate using the objects from the \textcode{ResetTypes} method, which accommodate using the objects from the \textcode{ResetTypes} method, which
have the same behavior but different type names.) 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 types. If you wanted to accommodate more types, you could use
\classmember*{VariantArrayHandle}{ResetTypes}. \classmember*{VariantArrayHandle}{ResetTypes}.
......
...@@ -40,36 +40,7 @@ tag names. ...@@ -40,36 +40,7 @@ tag names.
\begin{figure} \begin{figure}
\centering \centering
\small \input{CellShapeFigure}
\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}
\caption{Basic Cell Shapes} \caption{Basic Cell Shapes}
\label{fig:CellShapes} \label{fig:CellShapes}
\end{figure} \end{figure}
......
...@@ -4,15 +4,15 @@ ...@@ -4,15 +4,15 @@
\label{chap:TransferringArguments} \label{chap:TransferringArguments}
\label{chap:WorkletArguments} \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. 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. 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. 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}. 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. 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. 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 ...@@ -28,7 +28,7 @@ Plus, we will use this special worklet argument for our example of a custom work
\index{type check|(} \index{type check|(}
Before attempting to move data from the control to the execution 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 they are compatible with the associated \controlsignature concept. This is
done with the \vtkmcontarg{TypeCheck} \textcode{struct}. done with the \vtkmcontarg{TypeCheck} \textcode{struct}.
...@@ -44,7 +44,7 @@ Type checks are implemented with a defined type check tag (which, by ...@@ -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 convention, is defined in the \vtkmcontarg{} namespace and starts with
\textcode{TypeCheckTag}) and a partial specialization of the \textcode{TypeCheckTag}) and a partial specialization of the
\vtkmcontarg{TypeCheck} structure. The following type checks (identified by \vtkmcontarg{TypeCheck} structure. The following type checks (identified by
their tags) are provided in VTK-m. their tags) are provided in \VTKm.
\begin{description} \begin{description}
\item[\vtkmcontarg{TypeCheckTagExecObject}] \index{type check!execution object} \item[\vtkmcontarg{TypeCheckTagExecObject}] \index{type check!execution object}
...@@ -62,21 +62,21 @@ their tags) are provided in VTK-m. ...@@ -62,21 +62,21 @@ their tags) are provided in VTK-m.
Here are some trivial examples of using Here are some trivial examples of using
\textidentifier{TypeCheck}. Typically these checks are done internally in \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. only.
\vtkmlisting{Behavior of \protect\vtkmcontarg{TypeCheck}.}{TypeCheck.cxx} \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}. 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. 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. 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} \vtkmlisting[ex:TypeCheckTag2DCoordinates]{Defining a custom \textidentifier{TypeCheck}.}{TypeCheckImpl.h}
\begin{didyouknow} \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. 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}. 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} \end{didyouknow}
...@@ -89,9 +89,8 @@ This example of a \textidentifier{TypeCheck} returns true for control objects th ...@@ -89,9 +89,8 @@ This example of a \textidentifier{TypeCheck} returns true for control objects th
\index{transport|(} \index{transport|(}
After all the argument types are checked, the base dispatcher must load the 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.
data into the execution environment before scheduling a job to run This is done with the \vtkmcontarg{Transport} \textcode{struct}.
there. This is done with the \vtkmcontarg{Transport} \textcode{struct}.
The \textidentifier{Transport} \textcode{struct} is templated with three The \textidentifier{Transport} \textcode{struct} is templated with three
parameters. The first parameter is a tag that identifies which transport to 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 ...@@ -107,7 +106,7 @@ Transports are implemented with a defined transport tag (which, by
convention, is defined in the \vtkmcontarg{} namespace and starts with convention, is defined in the \vtkmcontarg{} namespace and starts with
\textcode{TransportTag}) and a partial specialization of the \textcode{TransportTag}) and a partial specialization of the
\vtkmcontarg{Transport} structure. The following transports (identified by \vtkmcontarg{Transport} structure. The following transports (identified by
their tags) are provided in VTK-m. their tags) are provided in \VTKm.
\begin{description} \begin{description}
\item[\vtkmcontarg{TransportTagExecObject}] \item[\vtkmcontarg{TransportTagExecObject}]
...@@ -168,7 +167,7 @@ their tags) are provided in VTK-m. ...@@ -168,7 +167,7 @@ their tags) are provided in VTK-m.
Here are some trivial examples of using Here are some trivial examples of using
\textidentifier{Transport}. Typically this movement is done internally in \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. only.
\vtkmlisting{Behavior of \protect\vtkmcontarg{Transport}.}{Transport.cxx} \vtkmlisting{Behavior of \protect\vtkmcontarg{Transport}.}{Transport.cxx}
...@@ -184,7 +183,7 @@ The resulting execution object is an array portal containing \textidentifier{Vec ...@@ -184,7 +183,7 @@ The resulting execution object is an array portal containing \textidentifier{Vec
\begin{commonerrors} \begin{commonerrors}
It is fair to assume that the \textidentifier{Transport}'s control object type matches whatever the associated \textidentifier{TypeCheck} allows. 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} \end{commonerrors}
\index{transport|)} \index{transport|)}
...@@ -195,7 +194,7 @@ The resulting execution object is an array portal containing \textidentifier{Vec ...@@ -195,7 +194,7 @@ The resulting execution object is an array portal containing \textidentifier{Vec
\index{fetch|(} \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 appropriate data out of the execution object and pass it to the worklet
function. A class named \vtkmexecarg{Fetch} is responsible for pulling this function. A class named \vtkmexecarg{Fetch} is responsible for pulling this
data out and putting computed data in to the execution objects. 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 ...@@ -282,7 +281,7 @@ As stated previously, the \textidentifier{Fetch} class must contain a \classmemb
\end{didyouknow} \end{didyouknow}
In addition to the aforementioned aspect tags that are explicitly paired 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. the behavior of a general fetch or simply ignore the type of fetch.
\begin{description} \begin{description}
...@@ -334,7 +333,7 @@ This example creates a specialization of a \textidentifier{Fetch} to retrieve th ...@@ -334,7 +333,7 @@ This example creates a specialization of a \textidentifier{Fetch} to retrieve th
\index{control signature!tags|(} \index{control signature!tags|(}
\index{signature!control!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. 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. These two types of tags are defined differently.
In this section we discuss the \controlsignature tags. In this section we discuss the \controlsignature tags.
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#include <vtkm/cont/DataSetBuilderUniform.h> #include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DeviceAdapter.h> #include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/PointElevation.h> #include <vtkm/worklet/PointElevation.h>
#include <vtkm/cont/testing/Testing.h> #include <vtkm/cont/testing/Testing.h>
...@@ -245,9 +244,8 @@ void GetElevationAirPressure(vtkm::cont::DataSet grid, FooFieldsDeque* fields) ...@@ -245,9 +244,8 @@ void GetElevationAirPressure(vtkm::cont::DataSet grid, FooFieldsDeque* fields)
elevation.SetHighPoint(vtkm::make_Vec(0.0, 0.0, 2000.0)); elevation.SetHighPoint(vtkm::make_Vec(0.0, 0.0, 2000.0));
elevation.SetRange(101325.0, 77325.0); elevation.SetRange(101325.0, 77325.0);
vtkm::worklet::DispatcherMapField<vtkm::worklet::PointElevation> dispatcher( vtkm::cont::Invoker invoke;
elevation); invoke(elevation, grid.GetCoordinateSystem().GetData(), pressureHandle);
dispatcher.Invoke(grid.GetCoordinateSystem().GetData(), pressureHandle);
// Make sure the values are flushed back to the control environment. // Make sure the values are flushed back to the control environment.
pressureHandle.SyncControlArray(); pressureHandle.SyncControlArray();
......
...@@ -38,7 +38,6 @@ set(example_src ...@@ -38,7 +38,6 @@ set(example_src
GenerateMeshConstantShape.cxx GenerateMeshConstantShape.cxx
GenerateMeshHash.cxx GenerateMeshHash.cxx
GenerateMeshVariableShape.cxx GenerateMeshVariableShape.cxx
ImplicitFunctions.cxx
Initialization.cxx Initialization.cxx
IO.cxx IO.cxx
ListTags.cxx ListTags.cxx
......
...@@ -219,8 +219,14 @@ struct ExtractFaces ...@@ -219,8 +219,14 @@ struct ExtractFaces
// To construct an ArrayHandleGroupVecVariable, we need to convert // To construct an ArrayHandleGroupVecVariable, we need to convert
// pointsPerFace to an array of offsets // pointsPerFace to an array of offsets
vtkm::Id faceIndicesSize; vtkm::Id faceIndicesSize;
vtkm::cont::ArrayHandle<vtkm::Id> faceIndexOffsets = vtkm::cont::ArrayHandle<vtkm::Id> faceIndexOffsetsExtended =
vtkm::cont::ConvertNumComponentsToOffsets(pointsPerFace, faceIndicesSize); 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 // We need to preallocate the array for faceIndices (because that is the
// way ArrayHandleGroupVecVariable works). We use the value previously // way ArrayHandleGroupVecVariable works). We use the value previously
...@@ -230,17 +236,16 @@ struct ExtractFaces ...@@ -230,17 +236,16 @@ struct ExtractFaces
// Get the cell index array for all the faces // Get the cell index array for all the faces
vtkm::worklet::DispatcherMapTopology<FacesExtract> extractDispatcher(scatter); vtkm::worklet::DispatcherMapTopology<FacesExtract> extractDispatcher(scatter);
extractDispatcher.Invoke( extractDispatcher.Invoke(cellSetIn,
cellSetIn, vtkm::cont::make_ArrayHandleGroupVecVariable(
vtkm::cont::make_ArrayHandleGroupVecVariable(faceIndices, faceIndexOffsets)); faceIndices, faceIndexOffsetsExclusive));
// Construct the resulting cell set and return // Construct the resulting cell set and return
vtkm::cont::CellSetExplicit<> cellSetOut; vtkm::cont::CellSetExplicit<> cellSetOut;
cellSetOut.Fill(cellSetIn.GetNumberOfPoints(), cellSetOut.Fill(cellSetIn.GetNumberOfPoints(),
faceShapes, faceShapes,
pointsPerFace,
faceIndices, faceIndices,
faceIndexOffsets); faceIndexOffsetsExtended);
return cellSetOut; return cellSetOut;
} }
}; };
......
...@@ -189,13 +189,12 @@ void CreateExplicitGrid() ...@@ -189,13 +189,12 @@ void CreateExplicitGrid()
// Do a simple check of the connectivity by getting the number of cells // 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 // incident on each point. This array is unlikely to be correct if the
// topology got screwed up. // topology got screwed up.
vtkm::cont::ArrayHandle<vtkm::IdComponent> numCellsPerPoint = auto numCellsPerPoint = cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
vtkm::TopologyElementTagCell());
vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout); vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout);
std::cout << std::endl; std::cout << std::endl;
vtkm::cont::ArrayHandle<vtkm::IdComponent>::PortalConstControl numCellsPortal = auto numCellsPortal = numCellsPerPoint.GetPortalConstControl();
numCellsPerPoint.GetPortalConstControl();
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2), VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2),
"Wrong number of cells on point 0"); "Wrong number of cells on point 0");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2), VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2),
...@@ -281,13 +280,12 @@ void CreateExplicitGridIterative() ...@@ -281,13 +280,12 @@ void CreateExplicitGridIterative()
// Do a simple check of the connectivity by getting the number of cells // 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 // incident on each point. This array is unlikely to be correct if the
// topology got screwed up. // topology got screwed up.
vtkm::cont::ArrayHandle<vtkm::IdComponent> numCellsPerPoint = auto numCellsPerPoint = cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
vtkm::TopologyElementTagCell());
vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout); vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout);
std::cout << std::endl; std::cout << std::endl;
vtkm::cont::ArrayHandle<vtkm::IdComponent>::PortalConstControl numCellsPortal = auto numCellsPortal = numCellsPerPoint.GetPortalConstControl();
numCellsPerPoint.GetPortalConstControl();
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2), VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2),
"Wrong number of cells on point 0"); "Wrong number of cells on point 0");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2), VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2),
......
...@@ -122,6 +122,7 @@ struct Transport<vtkm::cont::arg::TransportTag2DLineSegmentsIn, ...@@ -122,6 +122,7 @@ struct Transport<vtkm::cont::arg::TransportTag2DLineSegmentsIn,
ContObjectType, ContObjectType,
Device> Device>
{ {
//// LABEL CheckControlObject
VTKM_IS_ARRAY_HANDLE(ContObjectType); VTKM_IS_ARRAY_HANDLE(ContObjectType);
using GroupedArrayType = vtkm::cont::ArrayHandleGroupVec<ContObjectType, 2>; using GroupedArrayType = vtkm::cont::ArrayHandleGroupVec<ContObjectType, 2>;
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
#include <vtkm/exec/CellEdge.h> #include <vtkm/exec/CellEdge.h>
#include <vtkm/worklet/AverageByKey.h> #include <vtkm/worklet/AverageByKey.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/DispatcherReduceByKey.h>
#include <vtkm/worklet/Keys.h> #include <vtkm/worklet/Keys.h>
#include <vtkm/worklet/ScatterCounting.h> #include <vtkm/worklet/ScatterCounting.h>
...@@ -22,178 +20,102 @@ namespace worklet ...@@ -22,178 +20,102 @@ namespace worklet
namespace namespace
{ {
struct ExtractEdges ////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeCount.cxx
////
struct CountEdgesWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
{ {
//// using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
//// BEGIN-EXAMPLE GenerateMeshCombineLikeCount.cxx using ExecutionSignature = _2(CellShape, PointCount);
//// using InputDomain = _1;
struct CountEdges : vtkm::worklet::WorkletVisitCellsWithPoints
template<typename CellShapeTag>
VTKM_EXEC_CONT vtkm::IdComponent operator()(
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const
{ {
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges); return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this);
using ExecutionSignature = _2(CellShape, PointCount); }
using InputDomain = _1; };
////
template<typename CellShapeTag> //// END-EXAMPLE GenerateMeshCombineLikeCount.cxx
VTKM_EXEC_CONT vtkm::IdComponent operator()( ////
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const ////
{ //// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIds.cxx
return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this); ////
} class EdgeIdsWorklet : public vtkm::worklet::WorkletVisitCellsWithPoints
}; {
//// public:
//// END-EXAMPLE GenerateMeshCombineLikeCount.cxx using ControlSignature = void(CellSetIn cellSet, FieldOut canonicalIds);
//// using ExecutionSignature = void(CellShape cellShape,
PointIndices globalPointIndices,
//// VisitIndex localEdgeIndex,
//// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIds.cxx _2 canonicalIdOut);
//// using InputDomain = _1;
class EdgeIds : public vtkm::worklet::WorkletVisitCellsWithPoints
{ using ScatterType = vtkm::worklet::ScatterCounting;
public:
using ControlSignature = void(CellSetIn cellSet, FieldOut canonicalIds); template<typename CellShapeTag, typename PointIndexVecType>
using ExecutionSignature = void(CellShape cellShape, VTKM_EXEC void operator()(CellShapeTag cellShape,
PointIndices globalPointIndices, const PointIndexVecType& globalPointIndicesForCell,
VisitIndex localEdgeIndex, vtkm::IdComponent localEdgeIndex,
_2 canonicalIdOut); vtkm::Id2& canonicalIdOut) const
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)
{ {
VTKM_IS_DYNAMIC_OR_STATIC_CELL_SET(CellSetType); vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
// First, count the edges in each cell.
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts; canonicalIdOut = vtkm::exec::CellEdgeCanonicalId(
vtkm::worklet::DispatcherMapTopology<CountEdges> countEdgeDispatcher; numPointsInCell, localEdgeIndex, cellShape, globalPointIndicesForCell, *this);
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;
} }
//// };
//// END-EXAMPLE GenerateMeshCombineLikeInvoke.cxx ////
//// //// END-EXAMPLE GenerateMeshCombineLikeGenIds.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx ////
//// //// BEGIN-EXAMPLE GenerateMeshCombineLikeGenIndices.cxx
template<typename ValueType, typename Storage> ////
VTKM_CONT vtkm::cont::ArrayHandle<ValueType> ProcessCellField( class EdgeIndicesWorklet : public vtkm::worklet::WorkletReduceByKey
const vtkm::cont::ArrayHandle<ValueType, Storage>& inCellField) const {
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( // Regardless of how many cells are sharing the edge we are generating, we
this->CellToEdgeKeys, // know that each cell/edge given to us by the reduce-by-key refers to the
vtkm::cont::make_ArrayHandlePermutation(this->OutputToInputCellMap, // same edge, so we can just look at the first cell to get the edge.
inCellField)); 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 } // anonymous namespace
} // namespace worklet } // namespace worklet
...@@ -223,7 +145,8 @@ public: ...@@ -223,7 +145,8 @@ public:
const vtkm::filter::PolicyBase<Policy>& policy); const vtkm::filter::PolicyBase<Policy>& policy);
private: private:
vtkm::worklet::ExtractEdges Worklet; vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
vtkm::worklet::Keys<vtkm::Id2> CellToEdgeKeys;
}; };
//// PAUSE-EXAMPLE //// PAUSE-EXAMPLE
...@@ -242,20 +165,54 @@ namespace ...@@ -242,20 +165,54 @@ namespace
{ {
//// RESUME-EXAMPLE //// RESUME-EXAMPLE
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeInvoke.cxx
////
template<typename Policy> template<typename Policy>
inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute( inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
const vtkm::cont::DataSet& inData, const vtkm::cont::DataSet& inData,
vtkm::filter::PolicyBase<Policy> policy) vtkm::filter::PolicyBase<Policy> policy)
{ {
const vtkm::cont::DynamicCellSet& inCellSet =
const vtkm::cont::DynamicCellSet& inCells = inData.GetCellSet(); vtkm::filter::ApplyPolicyCellSet(inData.GetCellSet(), policy);
vtkm::cont::CellSetSingleType<> outCells = // First, count the edges in each cell.
this->Worklet.Run(vtkm::filter::ApplyPolicyCellSet(inCells, policy)); 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; vtkm::cont::DataSet outData;
outData.SetCellSet(outCells); outData.SetCellSet(outCellSet);
for (vtkm::IdComponent coordSystemIndex = 0; for (vtkm::IdComponent coordSystemIndex = 0;
coordSystemIndex < inData.GetNumberOfCoordinateSystems(); coordSystemIndex < inData.GetNumberOfCoordinateSystems();
...@@ -266,33 +223,46 @@ inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute( ...@@ -266,33 +223,46 @@ inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
return outData; return outData;
} }
////
//// END-EXAMPLE GenerateMeshCombineLikeInvoke.cxx
////
////
//// BEGIN-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx
////
template<typename T, typename StorageType, typename Policy> template<typename T, typename StorageType, typename Policy>
inline VTKM_CONT bool ExtractEdges::DoMapField( inline VTKM_CONT bool ExtractEdges::DoMapField(
vtkm::cont::DataSet& result, 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::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<Policy>&) const vtkm::filter::PolicyBase<Policy>&)
{ {
vtkm::cont::Field output; vtkm::cont::Field outputField;
if (fieldMeta.IsPointField()) if (fieldMeta.IsPointField())
{ {
output = fieldMeta.AsField(input); // pass through outputField = fieldMeta.AsField(inputArray); // pass through
} }
else if (fieldMeta.IsCellField()) 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 else
{ {
return false; return false;
} }
result.AddField(output); result.AddField(outputField);
return true; return true;
} }
////
//// END-EXAMPLE GenerateMeshCombineLikeMapCellField.cxx
////
//// PAUSE-EXAMPLE //// PAUSE-EXAMPLE
} // anonymous namespace } // anonymous namespace
...@@ -323,19 +293,6 @@ void CheckOutput(const vtkm::cont::CellSetSingleType<>& cellSet) ...@@ -323,19 +293,6 @@ void CheckOutput(const vtkm::cont::CellSetSingleType<>& cellSet)
VTKM_TEST_ASSERT(connectivityPortal.Get(43) == 10, "Bad edge index"); 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() void TryFilter()
{ {
std::cout << std::endl << "Trying calling filter." << std::endl; std::cout << std::endl << "Trying calling filter." << std::endl;
...@@ -344,9 +301,6 @@ void TryFilter() ...@@ -344,9 +301,6 @@ void TryFilter()
vtkm::filter::ExtractEdges filter; 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::DataSet outDataSet = filter.Execute(inDataSet);
vtkm::cont::CellSetSingleType<> outCellSet; vtkm::cont::CellSetSingleType<> outCellSet;
...@@ -372,7 +326,6 @@ void TryFilter() ...@@ -372,7 +326,6 @@ void TryFilter()
void DoTest() void DoTest()
{ {
TryWorklet();
TryFilter(); TryFilter();
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include <vtkm/exec/CellEdge.h> #include <vtkm/exec/CellEdge.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/ScatterCounting.h> #include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/WorkletMapTopology.h> #include <vtkm/worklet/WorkletMapTopology.h>
...@@ -21,114 +20,60 @@ namespace worklet ...@@ -21,114 +20,60 @@ namespace worklet
namespace namespace
{ {
struct ExtractEdges ////
//// BEGIN-EXAMPLE GenerateMeshConstantShapeCount.cxx
////
struct CountEdgesWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
{ {
//// using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
//// BEGIN-EXAMPLE GenerateMeshConstantShapeCount.cxx using ExecutionSignature = _2(CellShape, PointCount);
//// using InputDomain = _1;
struct CountEdges : vtkm::worklet::WorkletVisitCellsWithPoints
template<typename CellShapeTag>
VTKM_EXEC_CONT vtkm::IdComponent operator()(
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const
{ {
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges); return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this);
using ExecutionSignature = _2(CellShape, PointCount); }
using InputDomain = _1; };
////
template<typename CellShapeTag> //// END-EXAMPLE GenerateMeshConstantShapeCount.cxx
VTKM_EXEC_CONT vtkm::IdComponent operator()( ////
CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell) const ////
{ //// BEGIN-EXAMPLE GenerateMeshConstantShapeGenIndices.cxx
return vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, *this); ////
} class EdgeIndicesWorklet : public vtkm::worklet::WorkletVisitCellsWithPoints
}; {
//// public:
//// END-EXAMPLE GenerateMeshConstantShapeCount.cxx using ControlSignature = void(CellSetIn cellSet, FieldOut connectivityOut);
//// using ExecutionSignature = void(CellShape, PointIndices, _2, VisitIndex);
using InputDomain = _1;
////
//// 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);
vtkm::worklet::ScatterCounting scatter(edgeCounts); using ScatterType = vtkm::worklet::ScatterCounting;
this->OutputToInputCellMap =
scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray; template<typename CellShapeTag, typename PointIndexVecType>
vtkm::worklet::DispatcherMapTopology<EdgeIndices> edgeIndicesDispatcher(scatter); VTKM_EXEC void operator()(CellShapeTag cellShape,
edgeIndicesDispatcher.Invoke( const PointIndexVecType& globalPointIndicesForCell,
inCellSet, vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray)); vtkm::Id2& connectivityOut,
vtkm::IdComponent edgeIndex) const
{
vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
vtkm::cont::CellSetSingleType<> outCellSet; vtkm::IdComponent pointInCellIndex0 = vtkm::exec::CellEdgeLocalIndex(
outCellSet.Fill( numPointsInCell, 0, edgeIndex, cellShape, *this);
inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray); vtkm::IdComponent pointInCellIndex1 = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 1, edgeIndex, cellShape, *this);
return outCellSet; connectivityOut[0] = globalPointIndicesForCell[pointInCellIndex0];
} connectivityOut[1] = globalPointIndicesForCell[pointInCellIndex1];
////
//// 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;
} }
////
//// END-EXAMPLE GenerateMeshConstantShapeMapCellField.cxx
////
private:
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
}; };
////
//// END-EXAMPLE GenerateMeshConstantShapeGenIndices.cxx
////
} // anonymous namespace } // anonymous namespace
...@@ -159,7 +104,7 @@ public: ...@@ -159,7 +104,7 @@ public:
const vtkm::filter::PolicyBase<Policy>& policy); const vtkm::filter::PolicyBase<Policy>& policy);
private: private:
vtkm::worklet::ExtractEdges Worklet; vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
}; };
//// PAUSE-EXAMPLE //// PAUSE-EXAMPLE
...@@ -178,20 +123,45 @@ namespace ...@@ -178,20 +123,45 @@ namespace
{ {
//// RESUME-EXAMPLE //// 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> template<typename Policy>
inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute( inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
const vtkm::cont::DataSet& inData, const vtkm::cont::DataSet& inData,
vtkm::filter::PolicyBase<Policy> policy) 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 = // Build the scatter object (for non 1-to-1 mapping of input to output)
this->Worklet.Run(vtkm::filter::ApplyPolicyCellSet(inCells, policy)); 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; vtkm::cont::DataSet outData;
outData.SetCellSet(outCells); outData.SetCellSet(outCellSet);
for (vtkm::IdComponent coordSystemIndex = 0; for (vtkm::IdComponent coordSystemIndex = 0;
coordSystemIndex < inData.GetNumberOfCoordinateSystems(); coordSystemIndex < inData.GetNumberOfCoordinateSystems();
...@@ -202,33 +172,55 @@ inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute( ...@@ -202,33 +172,55 @@ inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
return outData; 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> template<typename T, typename StorageType, typename Policy>
inline VTKM_CONT bool ExtractEdges::DoMapField( inline VTKM_CONT bool ExtractEdges::DoMapField(
vtkm::cont::DataSet& result, 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::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<Policy>&) const vtkm::filter::PolicyBase<Policy>&)
{ {
vtkm::cont::Field output; vtkm::cont::Field outputField;
if (fieldMeta.IsPointField()) if (fieldMeta.IsPointField())
{ {
output = fieldMeta.AsField(input); // pass through outputField = fieldMeta.AsField(inputArray); // pass through
} }
else if (fieldMeta.IsCellField()) 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 else
{ {
return false; return false;
} }
result.AddField(output); result.AddField(outputField);
return true; return true;
} }
////
//// END-EXAMPLE GenerateMeshConstantShapeMapCellField.cxx
////
////
//// END-EXAMPLE ExtractEdgesFilterDoMapField.cxx
////
//// PAUSE-EXAMPLE //// PAUSE-EXAMPLE
} // anonymous namespace } // anonymous namespace
...@@ -260,19 +252,6 @@ void CheckOutput(const vtkm::cont::CellSetSingleType<>& cellSet) ...@@ -260,19 +252,6 @@ void CheckOutput(const vtkm::cont::CellSetSingleType<>& cellSet)
VTKM_TEST_ASSERT(connectivityPortal.Get(69) == 10, "Bad edge index"); 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() void TryFilter()
{ {
std::cout << std::endl << "Trying calling filter." << std::endl; std::cout << std::endl << "Trying calling filter." << std::endl;
...@@ -281,9 +260,6 @@ void TryFilter() ...@@ -281,9 +260,6 @@ void TryFilter()
vtkm::filter::ExtractEdges filter; 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::DataSet outDataSet = filter.Execute(inDataSet);
vtkm::cont::CellSetSingleType<> outCellSet; vtkm::cont::CellSetSingleType<> outCellSet;
...@@ -309,7 +285,6 @@ void TryFilter() ...@@ -309,7 +285,6 @@ void TryFilter()
void DoTest() void DoTest()
{ {
TryWorklet();
TryFilter(); TryFilter();
} }
......