CellSetSingleType.h 10.7 KB
Newer Older
Robert Maynard's avatar
Robert Maynard committed
1 2 3 4 5 6 7 8
//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//
9
//  Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
Robert Maynard's avatar
Robert Maynard committed
10 11 12
//  Copyright 2015 UT-Battelle, LLC.
//  Copyright 2015 Los Alamos National Security.
//
13
//  Under the terms of Contract DE-NA0003525 with NTESS,
Robert Maynard's avatar
Robert Maynard committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
//  the U.S. Government retains certain rights in this software.
//
//  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
//  Laboratory (LANL), the U.S. Government retains certain rights in
//  this software.
//============================================================================
#ifndef vtk_m_cont_CellSetSingleType_h
#define vtk_m_cont_CellSetSingleType_h

#include <vtkm/CellShape.h>
#include <vtkm/CellTraits.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/CellSet.h>
#include <vtkm/cont/CellSetExplicit.h>

#include <map>
#include <utility>

33 34 35 36
namespace vtkm
{
namespace cont
{
Robert Maynard's avatar
Robert Maynard committed
37 38 39

//Only works with fixed sized cell sets

40 41 42 43 44 45 46 47 48
template <typename ConnectivityStorageTag = VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG>
class VTKM_ALWAYS_EXPORT CellSetSingleType
  : public vtkm::cont::CellSetExplicit<
      typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag, //ShapeStorageTag
      typename vtkm::cont::ArrayHandleConstant<
        vtkm::IdComponent>::StorageTag, //NumIndicesStorageTag
      ConnectivityStorageTag,
      typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag //IndexOffsetStorageTag
      >
Robert Maynard's avatar
Robert Maynard committed
49
{
50 51
  using Thisclass = vtkm::cont::CellSetSingleType<ConnectivityStorageTag>;
  using Superclass = vtkm::cont::CellSetExplicit<
52
    typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag,
53 54
    typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag,
    ConnectivityStorageTag,
55
    typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>;
Robert Maynard's avatar
Robert Maynard committed
56 57

public:
58
  VTKM_CONT
59 60 61 62 63
  CellSetSingleType(const std::string& name = std::string())
    : Superclass(name)
    , ExpectedNumberOfCellsAdded(-1)
    , CellShapeAsId(CellShapeTagEmpty::Id)
    , NumberOfPointsPerCell(0)
Robert Maynard's avatar
Robert Maynard committed
64 65 66
  {
  }

67
  VTKM_CONT
68 69 70 71 72 73 74
  CellSetSingleType(const Thisclass& src)
    : Superclass(src)
    , ExpectedNumberOfCellsAdded(-1)
    , CellShapeAsId(src.CellShapeAsId)
    , NumberOfPointsPerCell(src.NumberOfPointsPerCell)
  {
  }
75

76
  VTKM_CONT
77
  Thisclass& operator=(const Thisclass& src)
78 79
  {
    this->Superclass::operator=(src);
80 81
    this->CellShapeAsId = src.CellShapeAsId;
    this->NumberOfPointsPerCell = src.NumberOfPointsPerCell;
82 83 84
    return *this;
  }

85
  virtual ~CellSetSingleType() {}
86

87
  /// First method to add cells -- one at a time.
88
  VTKM_CONT
89
  void PrepareToAddCells(vtkm::Id numCells, vtkm::Id connectivityMaxLen)
90
  {
91
    this->CellShapeAsId = vtkm::CELL_SHAPE_EMPTY;
92

93
    this->Data->PointToCell.Connectivity.Allocate(connectivityMaxLen);
94

95 96
    this->Data->NumberOfCellsAdded = 0;
    this->Data->ConnectivityAdded = 0;
97
    this->ExpectedNumberOfCellsAdded = numCells;
98 99 100
  }

  /// Second method to add cells -- one at a time.
101
  template <typename IdVecType>
102
  VTKM_CONT void AddCell(vtkm::UInt8 shapeId, vtkm::IdComponent numVertices, const IdVecType& ids)
103
  {
104
    using Traits = vtkm::VecTraits<IdVecType>;
105 106
    VTKM_STATIC_ASSERT_MSG((std::is_same<typename Traits::ComponentType, vtkm::Id>::value),
                           "CellSetSingleType::AddCell requires vtkm::Id for indices.");
107 108 109

    if (Traits::GetNumberOfComponents(ids) < numVertices)
    {
110
      throw vtkm::cont::ErrorBadValue("Not enough indices given to CellSetSingleType::AddCell.");
111 112
    }

113 114
    if (this->Data->ConnectivityAdded + numVertices >
        this->Data->PointToCell.Connectivity.GetNumberOfValues())
115
    {
116
      throw vtkm::cont::ErrorBadValue(
117
        "Connectivity increased passed estimated maximum connectivity.");
118 119 120 121 122 123
    }

    if (this->CellShapeAsId == vtkm::CELL_SHAPE_EMPTY)
    {
      if (shapeId == vtkm::CELL_SHAPE_EMPTY)
      {
124
        throw vtkm::cont::ErrorBadValue("Cannot create cells of type empty.");
125 126 127 128 129 130 131 132 133
      }
      this->CellShapeAsId = shapeId;
      this->CheckNumberOfPointsPerCell(numVertices);
      this->NumberOfPointsPerCell = numVertices;
    }
    else
    {
      if (shapeId != this->GetCellShape(0))
      {
134
        throw vtkm::cont::ErrorBadValue("Cannot have differing shapes in CellSetSingleType.");
135 136 137
      }
      if (numVertices != this->NumberOfPointsPerCell)
      {
138
        throw vtkm::cont::ErrorBadValue(
139
          "Inconsistent number of points in cells for CellSetSingleType.");
140 141
      }
    }
142
    for (vtkm::IdComponent iVert = 0; iVert < numVertices; ++iVert)
143
    {
144 145
      this->Data->PointToCell.Connectivity.GetPortalControl().Set(
        this->Data->ConnectivityAdded + iVert, Traits::GetComponent(ids, iVert));
146
    }
147 148
    this->Data->NumberOfCellsAdded++;
    this->Data->ConnectivityAdded += numVertices;
149 150 151
  }

  /// Third and final method to add cells -- one at a time.
152
  VTKM_CONT
153
  void CompleteAddingCells(vtkm::Id numPoints)
154
  {
155
    this->Data->NumberOfPoints = numPoints;
156 157 158 159 160
    this->PointToCell.Connectivity.Shrink(this->ConnectivityAdded);

    vtkm::Id numCells = this->NumberOfCellsAdded;

    this->PointToCell.Shapes =
161
      vtkm::cont::make_ArrayHandleConstant(this->GetCellShape(0), numCells);
162
    this->PointToCell.NumIndices =
163 164 165
      vtkm::cont::make_ArrayHandleConstant(this->NumberOfPointsPerCell, numCells);
    this->PointToCell.IndexOffsets = vtkm::cont::make_ArrayHandleCounting(
      vtkm::Id(0), static_cast<vtkm::Id>(this->NumberOfPointsPerCell), numCells);
166

167 168
    this->PointToCell.ElementsValid = true;
    this->PointToCell.IndexOffsetsValid = true;
169 170 171

    if (this->ExpectedNumberOfCellsAdded != this->GetNumberOfCells())
    {
172
      throw vtkm::cont::ErrorBadValue("Did not add the expected number of cells.");
173 174 175 176 177
    }

    this->NumberOfCellsAdded = -1;
    this->ConnectivityAdded = -1;
    this->ExpectedNumberOfCellsAdded = -1;
178 179
  }

Robert Maynard's avatar
Robert Maynard committed
180
  //This is the way you can fill the memory from another system without copying
181
  VTKM_CONT
182 183 184
  void Fill(vtkm::Id numPoints,
            vtkm::UInt8 shapeId,
            vtkm::IdComponent numberOfPointsPerCell,
185
            const vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityStorageTag>& connectivity)
Robert Maynard's avatar
Robert Maynard committed
186
  {
187
    this->Data->NumberOfPoints = numPoints;
188 189
    this->CellShapeAsId = shapeId;
    this->CheckNumberOfPointsPerCell(numberOfPointsPerCell);
190
    const vtkm::Id numCells = connectivity.GetNumberOfValues() / numberOfPointsPerCell;
191
    VTKM_ASSERT((connectivity.GetNumberOfValues() % numberOfPointsPerCell) == 0);
192 193
    this->Data->PointToCell.Shapes = vtkm::cont::make_ArrayHandleConstant(shapeId, numCells);
    this->Data->PointToCell.NumIndices =
194
      vtkm::cont::make_ArrayHandleConstant(numberOfPointsPerCell, numCells);
195
    this->Data->PointToCell.IndexOffsets = vtkm::cont::make_ArrayHandleCounting(
196
      vtkm::Id(0), static_cast<vtkm::Id>(numberOfPointsPerCell), numCells);
197
    this->Data->PointToCell.Connectivity = connectivity;
Robert Maynard's avatar
Robert Maynard committed
198

199 200 201 202
    this->Data->PointToCell.ElementsValid = true;
    this->Data->PointToCell.IndexOffsetsValid = true;

    this->ResetConnectivity(TopologyElementTagCell{}, TopologyElementTagPoint{});
Robert Maynard's avatar
Robert Maynard committed
203 204
  }

205
  VTKM_CONT
206
  vtkm::Id GetCellShapeAsId() const { return this->CellShapeAsId; }
207 208 209

  VTKM_CONT
  vtkm::UInt8 GetCellShape(vtkm::Id vtkmNotUsed(cellIndex)) const
210
  {
211
    return static_cast<vtkm::UInt8>(this->CellShapeAsId);
212
  }
213

214
  virtual void PrintSummary(std::ostream& out) const
215
  {
216 217
    out << "   ExplicitSingleCellSet: " << this->Name << " Type " << this->CellShapeAsId
        << std::endl;
218
    out << "   PointToCell: " << std::endl;
219
    this->Data->PointToCell.PrintSummary(out);
220
    out << "   CellToPoint: " << std::endl;
221
    this->Data->CellToPoint.PrintSummary(out);
222
  }
223

Robert Maynard's avatar
Robert Maynard committed
224
private:
225
  template <typename CellShapeTag>
226 227
  void CheckNumberOfPointsPerCell(CellShapeTag,
                                  vtkm::CellTraitsTagSizeFixed,
228
                                  vtkm::IdComponent numVertices) const
Robert Maynard's avatar
Robert Maynard committed
229
  {
230 231
    if (numVertices != vtkm::CellTraits<CellShapeTag>::NUM_POINTS)
    {
232
      throw vtkm::cont::ErrorBadValue("Passed invalid number of points for cell shape.");
233
    }
Robert Maynard's avatar
Robert Maynard committed
234 235
  }

236
  template <typename CellShapeTag>
237 238
  void CheckNumberOfPointsPerCell(CellShapeTag,
                                  vtkm::CellTraitsTagSizeVariable,
239 240 241 242 243
                                  vtkm::IdComponent vtkmNotUsed(numVertices)) const
  {
    // Technically, a shape with a variable number of points probably has a
    // minimum number of points, but we are not being sophisticated enough to
    // check that. Instead, just pass the check by returning without error.
Robert Maynard's avatar
Robert Maynard committed
244 245
  }

246
  void CheckNumberOfPointsPerCell(vtkm::IdComponent numVertices) const
Robert Maynard's avatar
Robert Maynard committed
247
  {
248
    switch (this->CellShapeAsId)
Robert Maynard's avatar
Robert Maynard committed
249
    {
250 251
      vtkmGenericCellShapeMacro(this->CheckNumberOfPointsPerCell(
        CellShapeTag(), vtkm::CellTraits<CellShapeTag>::IsSizeFixed(), numVertices));
Robert Maynard's avatar
Robert Maynard committed
252
      default:
253
        throw vtkm::cont::ErrorBadValue("CellSetSingleType unable to determine the cell type");
Robert Maynard's avatar
Robert Maynard committed
254 255 256
    }
  }

257 258 259
  vtkm::Id ExpectedNumberOfCellsAdded;
  vtkm::Id CellShapeAsId;
  vtkm::IdComponent NumberOfPointsPerCell;
Robert Maynard's avatar
Robert Maynard committed
260 261 262 263
};
}
} // namespace vtkm::cont

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
//=============================================================================
// Specializations of serialization related classes
namespace vtkm
{
namespace cont
{

template <typename ConnectivityST>
struct TypeString<vtkm::cont::CellSetSingleType<ConnectivityST>>
{
  static VTKM_CONT const std::string& Get()
  {
    static std::string name =
      "CS_Single<" + TypeString<vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityST>>::Get() + "_ST>";

    return name;
  }
};
}
} // vtkm::cont

namespace diy
{

template <typename ConnectivityST>
struct Serialization<vtkm::cont::CellSetSingleType<ConnectivityST>>
{
private:
  using Type = vtkm::cont::CellSetSingleType<ConnectivityST>;

public:
  static VTKM_CONT void save(BinaryBuffer& bb, const Type& cs)
  {
    diy::save(bb, cs.GetName());
    diy::save(bb, cs.GetNumberOfPoints());
    diy::save(bb, cs.GetCellShape(0));
    diy::save(bb, cs.GetNumberOfPointsInCell(0));
    diy::save(
      bb, cs.GetConnectivityArray(vtkm::TopologyElementTagPoint{}, vtkm::TopologyElementTagCell{}));
  }

  static VTKM_CONT void load(BinaryBuffer& bb, Type& cs)
  {
    std::string name;
    diy::load(bb, name);
    vtkm::Id numberOfPoints = 0;
    diy::load(bb, numberOfPoints);
    vtkm::UInt8 shape;
    diy::load(bb, shape);
    vtkm::IdComponent count;
    diy::load(bb, count);
    vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityST> connectivity;
    diy::load(bb, connectivity);

    cs = Type(name);
    cs.Fill(numberOfPoints, shape, count, connectivity);
  }
};

} // diy

Robert Maynard's avatar
Robert Maynard committed
325
#endif //vtk_m_cont_CellSetSingleType_h