==============================
Data Sets
==============================

.. index:: data set

A *data set*, implemented with the :class:`viskores::cont::DataSet` class,
contains and manages the geometric data structures that |Viskores| operates on.

.. index::
   single: cell set
   single: field
   single: coordinate system

.. doxygenclass:: viskores::cont::DataSet

In addition to the base :class:`viskores::cont::DataSet`, |Viskores| provides :class:`viskores::cont::PartitionedDataSet` to represent data partitioned into multiple domains.
A :class:`viskores::cont::PartitionedDataSet` is implemented as a collection of :class:`viskores::cont::DataSet` objects.
Partitioned data sets are described later in :secref:`dataset:Partitioned Data Sets`.

As will be seen throughout this chapter, there is a lot of variability in the structure that can be represented in a :class:`viskores::cont::DataSet`.
To get a human-readable synopsis of its contents, use the :func:`viskores::cont::DataSet::PrintSummary` method.
This is particularly helpful for debugging.

.. doxygenfunction:: viskores::cont::DataSet::PrintSummary

The :func:`viskores::cont::DataSet::PrintSummary` method takes a C++ output stream to direct the description.
Usually ``std::cout`` is provided to direct the output to the terminal.

.. load-example:: DataSetPrintSummary
   :file: GuideExampleDataSetCreation.cxx
   :caption: Printing a summary of a :class:`viskores::cont::DataSet`.


------------------------------
Building Data Sets
------------------------------

.. index:: data set ; building

Before we go into detail on the cell sets, fields, and coordinate systems that make up a data set in |Viskores|, let us first discuss how to build a data set.
One simple way to build a data set is to load data from a file using the `viskores::io` module.
Reading files is discussed in detail in :chapref:`io:File I/O`.

This section describes building data sets of different types using a set of
classes named `DataSetBuilder*`, which provide a convenience layer
on top of :class:`viskores::cont::DataSet` to make it easier to create data sets.

.. didyouknow::
  To simplify the introduction of :class:`viskores::cont::DataSet` objects, this section uses the simplest mechanisms.
  In many cases this involves loading data in a `std::vector` and passing that to |Viskores|, which usually causes the data to be copied.
  This is not the most efficient method to load data into |Viskores|.
  Although it is sufficient for small data or data that come from a "slow" source, such as a file, it might be a bottleneck for large data generated by another library.
  It is possible to adapt |Viskores|'s :class:`viskores::cont::DataSet` to externally defined data.
  This is done by wrapping existing data into what is called `ArrayHandle`, but this is a more advanced topic that will not be addressed in this chapter.
  `ArrayHandle` objects are introduced in :chapref:`basic-array-handles:Basic Array Handles` and more adaptive techniques are described in later chapters.

Creating Uniform Grids
==============================

.. index::
   single: uniform grid
   single: regular grid
   single: image

Uniform grids are meshes that have a regular array structure with points uniformly spaced parallel to the axes.
Uniform grids are also sometimes called regular grids or images.

The :class:`viskores::cont::DataSetBuilderUniform` class can be used to easily create 2- or 3-dimensional uniform grids.
:class:`viskores::cont::DataSetBuilderUniform` has several versions of a method named :func:`viskores::cont::DataSetBuilderUniform::Create` that takes the number of points in each dimension, the origin, and the spacing.
The origin is the location of the first point of the data (in the lower left corner), and the spacing is the distance between points in the x, y, and z directions.

.. doxygenclass:: viskores::cont::DataSetBuilderUniform
   :members:

The following example creates a :class:`viskores::cont::DataSet` containing a uniform grid of :math:`101 \times 101 \times 26` points.

.. load-example:: CreateUniformGrid
   :file: GuideExampleDataSetCreation.cxx
   :caption: Creating a uniform grid.}{.cxx}

If not specified, the origin will be at the coordinates :math:`(0,0,0)` and the spacing will be :math:`1` in each direction.
Thus, in the previous example the width, height, and depth of the mesh in physical space will be :math:`100`, :math:`100`, and :math`25`, respectively, and the mesh will be centered at :math:`(50, 50, 12.5)`.
Let us say we actually want a mesh of the same dimensions, but we want the :math:`z` direction to be stretched out so that the mesh will be the same size in each direction, and we want the mesh centered at the origin.

.. load-example:: CreateUniformGridCustomOriginSpacing
   :file: GuideExampleDataSetCreation.cxx
   :caption: Creating a uniform grid with custom origin and spacing.

Creating Rectilinear Grids
==============================

.. index:: rectilinear grid

A rectilinear grid is similar to a uniform grid except that a rectilinear grid can adjust the spacing between adjacent grid points.
This allows the rectilinear grid to have tighter sampling in some areas of space, but the points are still constrained to be aligned with the axes and each other.
The irregular spacing of a rectilinear grid is specified by providing a separate array each for the x, y, and z coordinates.

The :class:`viskores::cont::DataSetBuilderRectilinear` class can be used to easily create
2- or 3-dimensional rectilinear grids.
:class:`viskores::cont::DataSetBuilderRectilinear` has several versions of a method
named :func:`viskores::cont::DataSetBuilderRectilinear::Create` that takes these coordinate arrays and builds a
:class:`viskores::cont::DataSet` out of them. The arrays can be supplied as either
standard C arrays or as `std::vector` objects, in which case the
data in the arrays are copied into the :class:`viskores::cont::DataSet`. These
arrays can also be passed as :class:`viskores::cont::ArrayHandle` objects (introduced later in this book), in which
case the data are shallow copied.

.. doxygenclass:: viskores::cont::DataSetBuilderRectilinear
   :members:

The following example creates a :class:`viskores::cont::DataSet` containing a rectilinear
grid with :math:`201 \times 201 \times 101` points with different irregular
spacing along each axis.


.. load-example:: CreateRectilinearGrid
   :file: GuideExampleDataSetCreation.cxx
   :caption: Creating a rectilinear grid.

Creating Explicit Meshes
==============================

.. index::
   single: explicit mesh
   single: unstructured grid

An explicit mesh is an arbitrary collection of cells with arbitrary connections.
It can have multiple different types of cells.
Explicit meshes are also known as unstructured grids.
Explicit meshes can contain cells of different shapes.
The shapes that |Viskores| currently supports are listed in :numref:`fig:CreateExplicitMeshesCellShapes`.
Each shape is identified using either a numeric identifier, provided by |Viskores| with identifiers of the form ``viskores::CELL_SHAPE_*`` or special tag structures of the form ``viskores::CellSetTag*``.
Cell shapes are discussed in detail in :chapref:`working-with-cells:Working with Cells`.

.. figure::  ../../data/users-guide/images/CellConnections.png
   :width: 100%
   :name: fig:CreateExplicitMeshesCellShapes

   Basic Cell Shapes.

.. todo:: Add ``viskores::CellShapeTagPolyLine`` to this figure.

..
   .. |CellConnectionsVertex| image:: images/CellConnectionsVertex.png
   .. |CellConnectionsLine| image:: images/CellConnectionsLine.png
   .. |CellConnectionsPolyLine| image:: images/CellConnectionsPolyLine.png
   .. |CellConnectionsTriangle| image:: images/CellConnectionsTriangle.png
   .. |CellConnectionsPolygon| image:: images/CellConnectionsPolygon.png
   .. |CellConnectionsQuadrilateral| image:: images/CellConnectionsQuadrilateral.png
   .. |CellConnectionsTetrahedron| image:: images/CellConnectionsTetrahedron.png
   .. |CellConnectionsHexahedron| image:: images/CellConnectionsHexahedron.png
   .. |CellConnectionsWedge| image:: images/CellConnectionsWedge.png
   .. |CellConnectionsPyramid| image:: images/CellConnectionsPyramid.png

   .. table:: Basic Cell Shapes
      :name: ExplicitCellShapes
      :width: 100%

      +----------------------------------------------+----------------------------------------------+----------------------------------------------+
      | :enumerator:`viskores::CELL_SHAPE_VERTEX`        | :enumerator:`viskores::CELL_SHAPE_Line`          | :enumerator:`viskores::CELL_SHAPE_POLY_LINE`     |
      | :struct:`viskores::CellShapeTagVertex`           | :struct:`viskores::CellShapeTagLine`             | :struct:`viskores::CellShapeTagPolyLine`         |
      | |CellConnectionsVertex|                      | |CellConnectionsLine|                        | |CellConnectionsPolyLine|                    |
      +----------------------------------------------+----------------------------------------------+----------------------------------------------+
      | :enumerator:`viskores::CELL_SHAPE_TRIANGLE`      | :enumerator:`viskores::CELL_SHAPE_POLYGON`       | :enumerator:`viskores::CELL_SHAPE_QUADRILATERAL` |
      | :struct:`viskores::CellShapeTagTriangle`         | :struct:`viskores::CellShapeTagPolygon`          | :struct:`viskores::CellShapeTagQuadrilateral`    |
      | |CellConnectionsTriangle|                    | |CellConnectionsPolygon|                     | |CellConnectionsQuadrilateral|               |
      +----------------------------------------------+----------------------------------------------+----------------------------------------------+
      | :enumerator:`viskores::CELL_SHAPE_TETRAHEDRON`   | :enumerator:`viskores::CELL_SHAPE_HEXAHEDRON`    | :enumerator:`viskores::CELL_SHAPE_WEDGE`         |
      | :struct:`viskores::CellShapeTagTetrahedron`      | :struct:`viskores::CellShapeTagHexahedron`       | :struct:`viskores::CellShapeTagWedge`            |
      | |CellConnectionsTetrahedron|                 | |CellConnectionsHexahedron|                  | |CellConnectionsWedge|                       |
      +----------------------------------------------+----------------------------------------------+----------------------------------------------+
      |                                              | :enumerator:`viskores::CELL_SHAPE_PYRAMID`       |                                              |
      |                                              | :struct:`viskores::CellShapeTagPyramid`          |                                              |
      |                                              | |CellConnectionsPyramid|                     |                                              |
      +----------------------------------------------+----------------------------------------------+----------------------------------------------+

.. figure::  ../../data/users-guide/images/ExplicitCellConnections.png
   :width: 100%
   :name: fig:ExplicitMesh

   An example explicit mesh.

The cells of an explicit mesh are defined with the following 3 arrays, which are depicted graphically in :numref:`fig:ExplicitMesh`.

.. index:: explicit mesh ; shapes

Shapes
  An array of ids identifying the shape of the cell.
  Each value is a :type:`viskores::UInt8` and should be set to one of the ``viskores::CELL_SHAPE_*`` constants.
  The shapes and their identifiers are shown in :numref:`fig:CreateExplicitMeshesCellShapes`.
  The size of this array is equal to the number of cells in the set.

.. index:: explicit mesh ; connectivity

Connectivity
  An array that lists all the points that comprise each cell.
  Each entry in the array is a :type:`viskores::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 :numref:`fig:CreateExplicitMeshesCellShapes`.
  The point indices are stored consecutively from the first cell to the last.

.. index:: explicit mesh ; offsets

Offsets
  An array of :type:`viskores::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.

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 |Viskores|'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 |Viskores| contains mechanisms to build an explicit data set with a "num indices" arrays rather than an offsets array.

The :class:`viskores::cont::DataSetBuilderExplicit` class can be used to create data sets with explicit meshes.
:class:`viskores::cont::DataSetBuilderExplicit` has several versions of a method named :func:`viskores::cont::DataSetBuilderExplicit::Create`.
Generally, these methods take the shapes, number of indices, and connectivity arrays as well as an array of point coordinates.

.. doxygenclass:: viskores::cont::DataSetBuilderExplicit
   :members:

The following example creates a mesh like the one shown in
:numref:`fig:ExplicitMesh`.

.. load-example:: CreateExplicitGrid
   :file: GuideExampleDataSetCreation.cxx
   :caption: Creating an explicit mesh with :class:`viskores::cont::DataSetBuilderExplicit`.

Often it is awkward to build your own arrays and then pass them to :class:`viskores::cont::DataSetBuilderExplicit`.
There also exists an alternate builder class named :class:`viskores::cont::DataSetBuilderExplicitIterative` that allows you to specify each cell and point one at a time rather than all at once.
This is done by calling one of the versions of :func:`viskores::cont::DataSetBuilderExplicitIterative::AddPoint` and one of the versions of :func:`viskores::cont::DataSetBuilderExplicitIterative::AddCell` for each point and cell, respectively.

.. doxygenclass:: viskores::cont::DataSetBuilderExplicitIterative
   :members:

The next example also builds the mesh shown in :numref:`fig:ExplicitMesh` except this time using :class:`viskores::cont::DataSetBuilderExplicitIterative`.

.. load-example:: CreateExplicitGridIterative
   :file: GuideExampleDataSetCreation.cxx
   :caption: Creating an explicit mesh with :class:`viskores::cont::DataSetBuilderExplicitIterative`.

Add Fields
==============================

In addition to creating the geometric structure of a data set, it is usually important to add fields to the data.
Fields describe numerical data associated with the topological elements in a cell.
They often represent a physical quantity (such as temperature, mass, or volume fraction) but can also represent other information (such as indices or classifications).

The easiest way to define fields in a data set is to use the :func:`viskores::cont::DataSet::AddPointField` and :func:`viskores::cont::DataSet::AddCellField` methods.
Each of these methods take a requisite field name and the array with with field data.

Both :func:`viskores::cont::DataSet::AddPointField` and :func:`viskores::cont::DataSet::AddCellField` are overloaded to accept arrays of data in different structures.
Field arrays can be passed as standard C arrays or as ``std::vector``'s, in which case the data are copied.
Field arrays can also be passed in a ``ArrayHandle`` (introduced later in this book), in which case the data are not copied.

.. doxygenfunction:: viskores::cont::DataSet::AddPointField(const std::string&, const viskores::cont::UnknownArrayHandle&)

.. doxygenfunction:: viskores::cont::DataSet::AddPointField(const std::string&, const std::vector<T>&)

.. doxygenfunction:: viskores::cont::DataSet::AddPointField(const std::string&, const T*, const viskores::Id&)

.. doxygenfunction:: viskores::cont::DataSet::AddCellField(const std::string&, const viskores::cont::UnknownArrayHandle&)

.. doxygenfunction:: viskores::cont::DataSet::AddCellField(const std::string&, const std::vector<T>&)

.. doxygenfunction:: viskores::cont::DataSet::AddCellField(const std::string&, const T*, const viskores::Id&)

The following (somewhat contrived) example defines fields for a uniform grid that identify which points and cells are on the boundary of the mesh.

.. load-example:: AddFieldData
   :file: GuideExampleDataSetCreation.cxx
   :caption: Adding fields to a :class:`viskores::cont::DataSet`.

Copying Data Sets
==============================

It is sometimes the case where you want to derive one :class:`viskores::cont::DataSet` from another.
In this case, you might need to copy the information from one object to another.
To copy all the information from one :class:`viskores::cont::DataSet` to another, simply use the assignment operator.

.. load-example:: DataSetCopyOperator
   :file: GuideExampleDataSetCreation.cxx
   :caption: Copying a :class:`viskores::cont::DataSet` with the copy operator.

Sometimes it is desirable to copy the structure of a :class:`viskores::cont::DataSet` without copying the entire data.
That is, you wish to use the same geometry but have different information about the physical properties.
This can be done with the :func:`viskores::cont::DataSet::CopyStructure` method.

.. doxygenfunction:: viskores::cont::DataSet::CopyStructure

.. load-example:: DataSetCopyStructure
   :file: GuideExampleDataSetCreation.cxx
   :caption: Copying the structure of a :class:`viskores::cont::DataSet`.


------------------------------
Cell Sets
------------------------------

.. index:: cell set
.. index:: data set ; cell set

.. index::
   triple: cell; shape; point
   triple: cell; shape; edge
   triple: cell; shape; face

A cell set determines the topological structure of the data in a data set.

.. doxygenclass:: viskores::cont::CellSet
   :members:

A :class:`viskores::cont::DataSet` holds a :class:`viskores::cont::CellSet` structure to define the cells it contains.
This cell set can be set or retrieved from a :class:`viskores::cont::DataSet` object.

.. doxygenfunction:: viskores::cont::DataSet::SetCellSet
.. doxygenfunction:: viskores::cont::DataSet::GetCellSet()
.. doxygenfunction:: viskores::cont::DataSet::GetCellSet() const

Cell sets are returned from a data set wrapped in a :class:`viskores::cont::UnknownCellSet`, which is documented in :secref:`dataset:Unknown Cell Sets`.

3D cells are made up of *points*, *edges*, and *faces*.
(2D cells have only points and edges, and 1D cells have only points.)
:numref:`fig:CellTopology` shows the relationship between a cell's shape and these topological elements.
The arrangement of these points, edges, and faces is defined by the *shape* of the cell, which prescribes a specific ordering of each.
The basic cell shapes provided by |Viskores| are discussed in detail in :chapref:`working-with-cells:Working with Cells`.

.. figure::  ../../data/users-guide/images/CellConstituents.png
   :width: 50%
   :name: fig:CellTopology

   The relationship between a cell shape and its topological elements (points, edges, and faces).

The number of points and cells can be retrieved from the :func:`viskores::cont::CellSet::GetNumberOfPoints` and :func:`viskores::cont::CellSet::GetNumberOfCells` methods, respectively.
The :class:`viskores::cont::DataSet` class contains convenience methods to get the number of points or cells without retrieving the cell set.

.. doxygenfunction:: viskores::cont::DataSet::GetNumberOfPoints
.. doxygenfunction:: viskores::cont::DataSet::GetNumberOfCells

There are multiple ways to express the connections of a cell set, each with
different benefits and restrictions. These different cell set types are
managed by different cell set classes in |Viskores|. All |Viskores| cell set classes
inherit from :class:`viskores::cont::CellSet`. The two basic types of cell sets are
structured and explicit, and there are several variations of these types.

Structured Cell Sets
==============================

.. index::
   single: cell set; structured
   single: structured cell set

.. doxygenclass:: viskores::cont::CellSetStructured
   :members:

The number of points in a :class:`viskores::cont::CellSetStructured` is implicitly :math:`i \times j \times k` and the number of cells is implicitly :math:`(i-1) \times (j-1) \times (k-1)` (for 3D grids).
:numref:`fig:CellSetStructured` demonstrates this arrangement.

.. figure::  ../../data/users-guide/images/StructuredCellSet.png
   :width: 100%
   :name: fig:CellSetStructured

   The arrangement of points and cells in a 3D structured grid.

The big advantage of using :class:`viskores::cont::CellSetStructured` to define a cell set is that it is very space efficient because the entire topology can be defined by the three integers specifying the dimensions.
Also, algorithms can be optimized for :class:`viskores::cont::CellSetStructured`'s regular nature.
However, :class:`viskores::cont::CellSetStructured`'s strictly regular grid also limits its applicability.
A structured cell set can only be a dense grid of lines, quadrilaterals, or hexahedra.
It cannot represent irregular data well.

Many data models in other software packages, such as the one for VTK, make a distinction between uniform, rectilinear, and curvilinear grids.
|Viskores|'s cell sets do not.
All three of these grid types are represented by :class:`viskores::cont::CellSetStructured`.
This is because in a |Viskores| data set the cell set and the coordinate system are defined independently and used interchangeably.
A structured cell set with uniform point coordinates makes a uniform grid.
A structured cell set with point coordinates defined irregularly along coordinate axes makes a rectilinear grid.
And a structured cell set with arbitrary point coordinates makes a curvilinear grid.
The point coordinates are defined by the data set's coordinate system, which is discussed in :secref:`dataset:Coordinate Systems`.

Explicit Cell Sets
==============================

.. index::
   single: cell set; explicit
   single: explicit cell set

.. doxygenclass:: viskores::cont::CellSetExplicit
   :members:

The types of cell sets are listed in :numref:`fig:ExplicitCellSetShapes`.


.. figure::  ../../data/users-guide/images/CellConnections.png
   :width: 100%
   :name: fig:ExplicitCellSetShapes

   Basic Cell Shapes in a :class:`viskores::cont::CellSetExplicit`.

An explicit cell set is defined with a minimum of three arrays.
The first array identifies the shape of each cell.
(Identifiers for cell shapes are shown in :numref:`fig:ExplicitCellSetShapes`.)
The second array has a sequence of point indices that make up each cell.
The third array identifies an offset into the second array where the point indices for each cell is found plus an extra entry at the end set to the size of the second array.
:numref:`fig:CellSetExplicit` shows a simple example of an explicit cell set.

.. figure::  ../../data/users-guide/images/ExplicitCellConnections.png
   :width: 100%
   :name: fig:CellSetExplicit

   Example of cells in a :class:`viskores::cont::CellSetExplicit` and the arrays that define them.

An explicit cell set can also identify the number of indices defined for each cell by subtracting consecutive entries in the offsets array.
It is often the case when creating a :class:`viskores::cont::CellSetExplicit` that you have an array containing the number of indices rather than the offsets.
Such an array can be converted to an offsets array that can be used with :class:`viskores::cont::CellSetExplicit` by using the :func:`viskores::cont::ConvertNumComponentsToOffsets` convenience function.
See the documentation for :class:`viskores::cont::ArrayHandleGroupVecVariable` in :secref:`fancy-array-handles:Grouped Vector Arrays` for examples of using :func:`viskores::cont::ConvertNumComponentsToOffsets`.

:class:`viskores::cont::CellSetExplicit` is a powerful representation for a cell set
because it can represent an arbitrary collection of cells. However, because
all connections must be explicitly defined,
:class:`viskores::cont::CellSetExplicit` requires a significant amount of memory to
represent the topology.

.. index::
   single: cell set; single type
   single: explicit cell set; single type
   single: single type cell set

An important specialization of an explicit cell set is
:class:`viskores::cont::CellSetSingleType`.

.. doxygenclass:: viskores::cont::CellSetSingleType
   :members:

Cell Set Permutations
==============================

.. index::
   single: cell set; permutation
   single: permutation cell set

To rearrange, and possibly subsample, cells in a ``CellSet``, use :type:`viskores::cont::CellSetPermutation` to define a new set without copying.

.. doxygenclass:: viskores::cont::CellSetPermutation
   :members:

.. didyouknow::
   Although :class:`viskores::cont::CellSetPermutation` can mask cells, it cannot mask points.
   All points from the original cell set are available in the permuted cell set regardless of whether they are used.

The following example uses :class:`viskores::cont::CellSetPermutation` with a counting array to expose every tenth cell.
This provides a simple way to subsample a data set.

.. load-example:: CreateCellSetPermutation
   :file: GuideExampleDataSetCreation.cxx
   :caption: Subsampling a data set with :class:`viskores::cont::CellSetPermutation`.

Cell Set Extrude
==============================

.. doxygenclass:: viskores::cont::CellSetExtrude
   :members:

.. figure::  ../../data/users-guide/images/ExtrudedCellSet.png
   :width: 100%
   :name: fig:CellSetExtruded

   An example of an extruded wedge from XZ-plane coordinates.
   Six wedges are extracted from three XZ-plane points.

The extruded mesh is advantageous because it is represented on-the-fly as required, so no additional memory is required.
In contrast other forms of cell sets, such as :class:`viskores::cont::CellSetExplicit`, need to be explicitly constructed by replicating the vertices and cells.
:numref:`fig:CellSetExtruded` shows an example of six wedges extruded from three 2-dimensional coordinates.

Unknown Cell Sets
==============================

Each of the aforementioned cell set types are represented by a different class.
A :class:`viskores::cont::DataSet` object must hold one of these cell set objects that represent the cell structure.
The actual object used is not determined until run time.

The :class:`viskores::cont::DataSet` object manages the cell set object with :class:`viskores::cont::UnknownCellSet`.
When you call :func:`viskores::cont::DataSet::GetCellSet`, it returns a :class:`viskores::cont::UnknownCellSet`.

The :class:`viskores::cont::UnknownCellSet` object provides mechanisms to query the cell set, identify its type, and cast it to one of the concrete ``CellSet`` types.
See Chapter \ref{chap:UnknownCellSet} for details on working with :class:`viskores::cont::UnknownCellSet`.

.. todo:: Add previous reference to UnknownCellSet chapter.


------------------------------
Fields
------------------------------

.. index::
   single: field
   single: data set; field

A field on a data set provides a value on every point in space on the mesh.
Fields are often used to describe physical properties such as pressure, temperature, mass, velocity, and much more.
Fields are represented in a |Viskores| data set as an array where each value is associated with a particular element type of a mesh (such as points or cells).
This association of field values to mesh elements and the structure of the cell set determines how the field is interpolated throughout the space of the mesh.

Field Class
==============================

Fields are manged by the :class:`viskores::cont::Field` class.

.. doxygenclass:: viskores::cont::Field

Fields are identified by a simple name string.

.. doxygenfunction:: viskores::cont::Field::GetName

The :class:`viskores::cont::Field` object internally holds a reference to an array in a type-agnostic way.
Filters and other |Viskores| units will determine the type of the array and pull it out of the :class:`viskores::cont::Field`.

.. doxygenfunction:: viskores::cont::Field::GetData() const

The field data is associated with a particular type of element of a mesh such as points, cells, or the whole mesh.

.. doxygenfunction:: viskores::cont::Field::GetAssociation

Associations are identified by the :enum:`viskores::cont::Field::Association` enumeration.

.. doxygenenum:: viskores::cont::Field::Association

A :class:`viskores::cont::Field` class can be constructed by providing the name, association and data.

.. doxygenfunction:: viskores::cont::Field::Field(std::string, Association, const viskores::cont::UnknownArrayHandle&)

The :class:`viskores::cont::Field` class also has several convenience methods for querying the association.

.. doxygenfunction:: viskores::cont::Field::IsPointField

.. doxygenfunction:: viskores::cont::Field::IsCellField

.. doxygenfunction:: viskores::cont::Field::IsWholeDataSetField

.. doxygenfunction:: viskores::cont::Field::IsPartitionsField

.. doxygenfunction:: viskores::cont::Field::IsGlobalField

.. index:: double: range; field

:class:`viskores::cont::Field` has a convenience method named :func:`viskores::cont::Field::GetRange` that finds the range of values stored in the field array.

.. doxygenfunction:: viskores::cont::Field::GetRange() const

.. didyouknow::
   The :class:`viskores::cont::Field` class does not give direct access to the data in the field.
   This is in part because the field can hold any number of data types and in part because data access is more efficient in filters and other features that run in parallel.
   The :func:`viskores::cont::Field::PrintSummary` function can be used to get some summary information for debugging.
   To get direct access to the data, you will first have to get a :class:`viskores::cont::UnknownArrayHandle` from :func:`viskores::cont::Field::Data`.
   The :class:`viskores::cont::UnknownArrayHandle` then has to be converted to a :class:`viskores::cont::ArrayHandle` of the proper type as described in :chapref:`unknown-array-handle:Unknown Array Handles`.
   Once the proper :class:`viskores::cont::ArrayHandle` is retrieved, the data can finally be accessed through an array portal as described in :secref:`basic-array-handles:Array Portals`.

Managing Data Set Fields
==============================

:secref:`dataset:Add Fields` describes the convenient :func:`viskores::cont::DataSet::AddPointField` and :func:`viskores::cont::DataSet::AddCellField` methods for adding fields to a :class:`viskores::cont::DataSet` from an array.
Fields can be added more generally by passing a :class:`viskores::cont::Field` object or by providing a :enum:`viskores::cont::Field::Association`.

.. doxygenfunction:: viskores::cont::DataSet::AddField(const Field&)
.. doxygenfunction:: viskores::cont::DataSet::AddField(const std::string&, viskores::cont::Field::Association, const viskores::cont::UnknownArrayHandle&)

A :class:`viskores::cont::Field` can be retrieved from a :class:`viskores::cont::DataSet` by name and an optional association.

.. doxygenfunction:: viskores::cont::DataSet::GetField(const std::string&, viskores::cont::Field::Association) const
.. doxygenfunction:: viskores::cont::DataSet::GetField(const std::string&, viskores::cont::Field::Association)
.. doxygenfunction:: viskores::cont::DataSet::GetPointField(const std::string&) const
.. doxygenfunction:: viskores::cont::DataSet::GetPointField(const std::string&)
.. doxygenfunction:: viskores::cont::DataSet::GetCellField(const std::string&) const
.. doxygenfunction:: viskores::cont::DataSet::GetCellField(const std::string&)

The number of fields in a :class:`viskores::cont::DataSet` is returned by :func:`viskores::cont::DataSet::GetNumberOfFields`.

.. doxygenfunction:: viskores::cont::DataSet::GetNumberOfFields

It is possible to iterate over all fields of a :class:`viskores::cont::DataSet` by quering the number of fields and then retrieving the fields by index.

.. doxygenfunction:: viskores::cont::DataSet::GetField(viskores::Id) const
.. doxygenfunction:: viskores::cont::DataSet::GetField(viskores::Id)

.. load-example:: IterateFields
   :file: GuideExampleDataSetCreation.cxx
   :caption: Iterating over all the fields in a :class:`viskores::cont::DataSet`.

.. commonerrors::
   Avoid retrieving fields by index unless doing simple iterations like this.
   The ordering of the fields can change so under some circumstances you may get different :class:`viskores::cont::Field` objects for the same index.

:func:`viskores::cont::DataSet::GetField` and the related methods will throw an exception if the :class:`viskores::cont::DataSet` does not contain the requested field.
You can test whether a :class:`viskores::cont::DataSet` has a field without having an exception thrown using one of the variations of :func:`viskores::cont::DataSet::HasField`.

.. doxygenfunction:: viskores::cont::DataSet::HasField
.. doxygenfunction:: viskores::cont::DataSet::HasPointField
.. doxygenfunction:: viskores::cont::DataSet::HasCellField

------------------------------
Coordinate Systems
------------------------------

.. index::
   single: coordinate system
   single: data set; coordinate system

A coordinate system determines the location of a mesh's elements in space.
The spatial location is described by providing a 3D vector at each point that gives the coordinates there.
The point coordinates can then be interpolated throughout the mesh.

Coordinate System Class
==============================

Coordinate systems are managed by :class:`viskores::cont::CoordinateSystem`, which is a subclass of :class:`viskores::cont::Field`.
This is because a coordinate system is conceptually just a field with some special properties.

.. doxygenclass:: viskores::cont::CoordinateSystem

Because a :class:`viskores::cont::CoordinateSystem` is a field that is always associated with points, it can be constructed with just the name and the data.

.. doxygenfunction:: viskores::cont::CoordinateSystem::CoordinateSystem(std::string, const viskores::cont::UnknownArrayHandle&)

:class:`viskores::cont::CoordinateSystem` also has a convenience constructor for creating a uniform mesh of points.

.. doxygenfunction:: viskores::cont::CoordinateSystem::CoordinateSystem(std::string, viskores::Id3, viskores::Vec3f, viskores::Vec3f)

In addition to all the methods provided by the :class:`viskores::cont::Field` superclass, the :class:`viskores::cont::CoordinateSystem` also provides a :func:`viskores::cont::CoordinateSystem::GetBounds` convenience method that returns a :class:`viskores::Bounds` object giving the spatial bounds of the coordinate system.

.. doxygenfunction:: viskores::cont::CoordinateSystem::GetBounds

Managing Data Set Coordinate Systems
========================================

It is typical for a :class:`viskores::cont::DataSet` to have one coordinate system defined, but it is possible to define multiple coordinate systems.
This is helpful when there are multiple ways to express coordinates.
For example, planetary positions may be expressed as Cartesian coordinates or as latitude-longitude coordinates.
Both are valid and useful in different ways.

It is also valid to have a :class:`viskores::cont::DataSet` with no coordinate system.
This is useful when the structure is not rooted in physical space.
For example, if the cell set is representing a graph structure, there might not be any physical space that has meaning for the graph.

Similar to regular fields, coordinate systems can be added to a :class:`viskores::cont::DataSet` by either constructing a :class:`viskores::cont::CoordinateSystem` or by providing the array and field information.

.. doxygenfunction:: viskores::cont::DataSet::AddCoordinateSystem(const viskores::cont::CoordinateSystem&)
.. doxygenfunction:: viskores::cont::DataSet::AddCoordinateSystem(const std::string&, const viskores::cont::UnknownArrayHandle&)

Because coordinate systems are part of the list of fields, an existing point field can be marked as a coordinate system by just providing its name.

.. doxygenfunction:: viskores::cont::DataSet::AddCoordinateSystem(const std::string&)

A :class:`viskores::cont::CoordinateSystem` can be retrieved from a :class:`viskores::cont::DataSet` by name.

.. doxygenfunction:: viskores::cont::DataSet::GetCoordinateSystem(const std::string&) const

:func:`viskores::cont::DataSet::GetCoordianteSystem` will throw an exception if the :class:`viskores::cont::DataSet` does not contain the requested field.
You can test whether a :class:`viskores::cont::DataSet` has a field without having an exception thrown by using :func:`viskores::cont::DataSet::HasCoordinateSystem`.

.. doxygenfunction:: viskores::cont::DataSet::HasCoordinateSystem

Coordiante systems can also be retrieved by index.
Because most ``DataSet``'s contain exactly one coordiante system, it is common to pick the coordinate system at index 0, which is the default argument.

.. doxygenfunction:: viskores::cont::DataSet::GetCoordinateSystem(viskores::Id) const

It is also possible to iterate over all coordinate systems by retrieving the number of coordinate systems.

.. doxygenfunction:: viskores::cont::DataSet::GetNumberOfCoordinateSystems


------------------------------
Partitioned Data Sets
------------------------------

.. index::
   single: partitioned data set
   single: data set; partitioned

.. doxygenclass:: viskores::cont::PartitionedDataSet
   :members:

The following example creates a :class:`viskores::cont::PartitionedDataSet` containing two uniform grid data sets.

.. load-example:: CreatePartitionedDataSet
   :file: GuideExampleDataSetCreation.cxx
   :caption: Creating a :class:`viskores::cont::PartitionedDataSet`.

It is always possible to retrieve the independent blocks in a :class:`viskores::cont::PartitionedDataSet`, from which you can iterate and get information about the data.
However, |Viskores| provides several helper functions to collect metadata information about the collection as a whole.

.. doxygenfunction:: viskores::cont::BoundsCompute(const viskores::cont::DataSet&, viskores::Id)

.. doxygenfunction:: viskores::cont::BoundsCompute(const viskores::cont::PartitionedDataSet&, viskores::Id)

.. doxygenfunction:: viskores::cont::BoundsCompute(const viskores::cont::DataSet&, const std::string&)

.. doxygenfunction:: viskores::cont::BoundsCompute(const viskores::cont::PartitionedDataSet&, const std::string&)

.. doxygenfunction:: viskores::cont::BoundsGlobalCompute(const viskores::cont::DataSet&, viskores::Id)

.. doxygenfunction:: viskores::cont::BoundsGlobalCompute(const viskores::cont::PartitionedDataSet&, viskores::Id)

.. doxygenfunction:: viskores::cont::BoundsGlobalCompute(const viskores::cont::DataSet&, const std::string&)

.. doxygenfunction:: viskores::cont::BoundsGlobalCompute(const viskores::cont::PartitionedDataSet&, const std::string&)

.. doxygenfunction:: viskores::cont::FieldRangeCompute(const viskores::cont::DataSet&, const std::string&, viskores::cont::Field::Association)

.. doxygenfunction:: viskores::cont::FieldRangeCompute(const viskores::cont::PartitionedDataSet&, const std::string&, viskores::cont::Field::Association)

.. doxygenfunction:: viskores::cont::FieldRangeGlobalCompute(const viskores::cont::DataSet&, const std::string&, viskores::cont::Field::Association)

.. doxygenfunction:: viskores::cont::FieldRangeGlobalCompute(const viskores::cont::PartitionedDataSet&, const std::string&, viskores::cont::Field::Association)

The following example illustrates a spatial bounds query and a field range query on a :class:`viskores::cont::PartitionedDataSet`.

.. load-example:: QueryPartitionedDataSet
   :file: GuideExampleDataSetCreation.cxx
   :caption: Queries on a :class:`viskores::cont::PartitionedDataSet`.

.. didyouknow::
  The aforementioned functions for querying a :class:`viskores::cont::PartitionedDataSet` object also work on :class:`viskores::cont::DataSet` objects.
  This is particularly useful with the :func:`viskores::cont::BoundsGlobalCompute` and :func:`viskores::cont::FieldRangeGlobalCompute` functions to manage distributed parallel objects.

Filters can be executed on :class:`viskores::cont::PartitionedDataSet` objects in a similar way they are executed on :class:`viskores::cont::DataSet` objects.
In both cases, the :func:`viskores::cont::Filter::Execute` method is called on the filter giving data object as an argument.

.. load-example:: FilterPartitionedDataSet
   :file: GuideExampleDataSetCreation.cxx
   :caption: Applying a filter to multi block data.


-----------------------------------
Cell Classification and Ghost Cells
-----------------------------------

.. index::
   single: ghost cell
   single: cell; ghost
   single: halo cell
   single: cell; halo

One of the challenges of managing data that is divided into partitions, such as in a :class:`viskores::cont::PartitionedDataSet` or across MPI ranks, is dealing with the boundary between partitions.
A cell on the boundary on one partition will not have the connection information to an adjacent cell in a neighboring partition.
This can cause a problem with many of the filtering operations in |Viskores| that operate on each partition independently.

A simple remedy to many of the issues with this missing connectivity information is the introduction of *ghost cells* (sometimes also known as halo cells).
A ghost cell is one that is included in a :class:`viskores::cont::DataSet`, but should not be considered part of the partition.
It is assumed a ghost cell can be removed from the data as it is repeated information.
However, it is provided so that algorithms using information across cell neighbors will get that information.

There exist some filters in |Viskores| to manipulate ghost cells such as those described in :secref:`provided-filters:Ghost Cell Removal`, :secref:`provided-filters:Ghost Cell Classification`, and :secref:`provided-filters:AMR Arrays`.
The following operations document how to add and use ghost cell information.

Ghost Cell Fields
==============================

Each :class:`viskores::cont::DataSet` can contain a special cell field that provides for each cell a flag identifying the cell as normal, ghost, or other properties.

.. doxygenfunction:: viskores::cont::DataSet::GetGhostCellField
.. doxygenfunction:: viskores::cont::DataSet::HasGhostCellField
.. doxygenfunction:: viskores::cont::DataSet::SetGhostCellField(const viskores::cont::Field&)
.. doxygenfunction:: viskores::cont::DataSet::SetGhostCellField(const std::string&, const viskores::cont::UnknownArrayHandle&)

Like coordinate systems, ghost cell fields are stored with the list of all fields within a :class:`viskores::cont::DataSet` and are identified by the name of the field.
So, the ghost cell field can be specified by providing the name of an existing field.

.. doxygenfunction:: viskores::cont::DataSet::SetGhostCellField(const std::string&)

The name of the field used for ghost cells is set independently of the field.

.. doxygenfunction:: viskores::cont::DataSet::GetGhostCellFieldName
.. doxygenfunction:: viskores::cont::DataSet::SetGhostCellFieldName

The :class:`viskores::cont::DataSet` may name a ghost cell field that does not exist.
In this case, :func:`viskores::cont::DataSet::HasGhostCellField` will report no ghost cell field, but the name will still exist.
If a cell field with this name is later added to the :class:`viskores::cont::DataSet`, it will automatically become the ghost cell field.
Likewise, because the name of the ghost cell field already exists, a ghost cell field can be created by just providing the array without the name.

.. doxygenfunction:: viskores::cont::DataSet::SetGhostCellField(const viskores::cont::UnknownArrayHandle&)

|Viskores| also specifies a "global" cell field name.
All :class:`viskores::cont::DataSet` objects will be born with this global cell field name.

.. doxygenfunction:: viskores::cont::GetGlobalGhostCellFieldName
.. doxygenfunction:: viskores::cont::SetGlobalGhostCellFieldName

This global cell field name makes it easier to work with other libraries or data sources that have a particular naming convention for ghost cells.

.. didyouknow::
   The default global ghost cell name is ``vtkGhostCells``.
   This follows the convention of the VTK visualization library.

Cell Classification Flags
==============================

The ghost cell field is typically a field of :type:`viskores::UInt8` values.
Each value is treated as bit flags specifying the classification of the cell.
The interpretation of the ghost cell field flags is determined by :class:`viskores::CellClassification`.

.. doxygenclass:: viskores::CellClassification

.. index::
   double: cell; blanking
   double: cell; invalid

:class:`viskores::CellClassification` behaves like a scoped enum, but values of type :class:`viskores::CellClassification` can be used interchangeably with :type:`viskores::UInt8`.
This simplifies working with classification flags.
Valid classification flags can be the or-ing of any of the following flags.

.. doxygenenumvalue:: viskores::CellClassification::Normal
.. doxygenenumvalue:: viskores::CellClassification::Ghost
.. doxygenenumvalue:: viskores::CellClassification::Invalid
.. doxygenenumvalue:: viskores::CellClassification::Blanked

.. didyouknow::
   Like the default ghost cell field name, the :class:`viskores::CellClassification` flags follow the same flags used in the VTK library.
   This allows data to be more easily imported between the two libraries.

.. load-example:: SettingGhostCells
   :file: GuideExampleFields.cxx
   :caption: Using :class:`viskores::CellClassification` to establish ghost and blanked cells.
