VTK-m  2.0
DataSetIntegrator.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 
11 #ifndef vtk_m_filter_flow_internal_DataSetIntegrator_h
12 #define vtk_m_filter_flow_internal_DataSetIntegrator_h
13 
14 #include <vtkm/cont/DataSet.h>
24 
25 #include <vtkm/cont/Variant.h>
26 
27 namespace vtkm
28 {
29 namespace filter
30 {
31 namespace flow
32 {
33 namespace internal
34 {
35 
36 template <typename ParticleType>
37 class DSIHelperInfo
38 {
39 public:
40  DSIHelperInfo(const std::vector<ParticleType>& v,
41  const vtkm::filter::flow::internal::BoundsMap& boundsMap,
42  const std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& particleBlockIDsMap)
43  : BoundsMap(boundsMap)
44  , ParticleBlockIDsMap(particleBlockIDsMap)
45  , V(v)
46  {
47  }
48 
49  const vtkm::filter::flow::internal::BoundsMap BoundsMap;
50  const std::unordered_map<vtkm::Id, std::vector<vtkm::Id>> ParticleBlockIDsMap;
51 
52  std::vector<ParticleType> A, I, V;
53  std::unordered_map<vtkm::Id, std::vector<vtkm::Id>> IdMapA, IdMapI;
54  std::vector<vtkm::Id> TermIdx, TermID;
55 };
56 
57 using DSIHelperInfoType =
58  vtkm::cont::Variant<DSIHelperInfo<vtkm::Particle>, DSIHelperInfo<vtkm::ChargedParticle>>;
59 
60 template <typename Derived>
61 class DataSetIntegrator
62 {
63 public:
64  using VelocityFieldNameType = std::string;
65  using ElectroMagneticFieldNameType = std::pair<std::string, std::string>;
66 
67 protected:
68  using FieldNameType = vtkm::cont::Variant<VelocityFieldNameType, ElectroMagneticFieldNameType>;
69 
70  using RType =
71  vtkm::cont::Variant<vtkm::worklet::flow::ParticleAdvectionResult<vtkm::Particle>,
75 
76 public:
77  DataSetIntegrator(vtkm::Id id,
78  const FieldNameType& fieldName,
82  : FieldName(fieldName)
83  , Id(id)
84  , SolverType(solverType)
85  , VecFieldType(vecFieldType)
86  , AdvectionResType(resultType)
87  , Rank(this->Comm.rank())
88  {
89  //check that things are valid.
90  }
91 
92  VTKM_CONT vtkm::Id GetID() const { return this->Id; }
93  VTKM_CONT void SetCopySeedFlag(bool val) { this->CopySeedArray = val; }
94 
95  VTKM_CONT
96  void Advect(DSIHelperInfoType& b,
97  vtkm::FloatDefault stepSize, //move these to member data(?)
98  vtkm::Id maxSteps)
99  {
100  Derived* inst = static_cast<Derived*>(this);
101 
102  //Cast the DSIHelperInfo<ParticleType> to the concrete type and call DoAdvect.
103  b.CastAndCall([&](auto& concrete) { inst->DoAdvect(concrete, stepSize, maxSteps); });
104  }
105 
106  template <typename ParticleType>
107  VTKM_CONT bool GetOutput(vtkm::cont::DataSet& ds) const;
108 
109 
110 protected:
111  template <typename ParticleType, template <typename> class ResultType>
112  VTKM_CONT void UpdateResult(const ResultType<ParticleType>& result,
113  DSIHelperInfo<ParticleType>& dsiInfo);
114 
115  VTKM_CONT bool IsParticleAdvectionResult() const
116  {
117  return this->AdvectionResType == FlowResultType::PARTICLE_ADVECT_TYPE;
118  }
119 
120  VTKM_CONT bool IsStreamlineResult() const
121  {
122  return this->AdvectionResType == FlowResultType::STREAMLINE_TYPE;
123  }
124 
125  template <typename ParticleType>
126  VTKM_CONT inline void ClassifyParticles(const vtkm::cont::ArrayHandle<ParticleType>& particles,
127  DSIHelperInfo<ParticleType>& dsiInfo) const;
128 
129  //Data members.
130  vtkm::cont::Variant<VelocityFieldNameType, ElectroMagneticFieldNameType> FieldName;
131 
132  vtkm::Id Id;
135  vtkm::filter::flow::FlowResultType AdvectionResType =
137 
138  vtkmdiy::mpi::communicator Comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
139  vtkm::Id Rank;
140  bool CopySeedArray = false;
141  std::vector<RType> Results;
142 };
143 
144 template <typename Derived>
145 template <typename ParticleType>
146 VTKM_CONT inline void DataSetIntegrator<Derived>::ClassifyParticles(
147  const vtkm::cont::ArrayHandle<ParticleType>& particles,
148  DSIHelperInfo<ParticleType>& dsiInfo) const
149 {
150  dsiInfo.A.clear();
151  dsiInfo.I.clear();
152  dsiInfo.TermID.clear();
153  dsiInfo.TermIdx.clear();
154  dsiInfo.IdMapI.clear();
155  dsiInfo.IdMapA.clear();
156 
157  auto portal = particles.WritePortal();
158  vtkm::Id n = portal.GetNumberOfValues();
159 
160  for (vtkm::Id i = 0; i < n; i++)
161  {
162  auto p = portal.Get(i);
163 
164  if (p.GetStatus().CheckTerminate())
165  {
166  dsiInfo.TermIdx.emplace_back(i);
167  dsiInfo.TermID.emplace_back(p.GetID());
168  }
169  else
170  {
171  const auto& it = dsiInfo.ParticleBlockIDsMap.find(p.GetID());
172  VTKM_ASSERT(it != dsiInfo.ParticleBlockIDsMap.end());
173  auto currBIDs = it->second;
174  VTKM_ASSERT(!currBIDs.empty());
175 
176  std::vector<vtkm::Id> newIDs;
177  if (p.GetStatus().CheckSpatialBounds() && !p.GetStatus().CheckTookAnySteps())
178  newIDs.assign(std::next(currBIDs.begin(), 1), currBIDs.end());
179  else
180  newIDs = dsiInfo.BoundsMap.FindBlocks(p.GetPosition(), currBIDs);
181 
182  //reset the particle status.
183  p.GetStatus() = vtkm::ParticleStatus();
184 
185  if (newIDs.empty()) //No blocks, we're done.
186  {
187  p.GetStatus().SetTerminate();
188  dsiInfo.TermIdx.emplace_back(i);
189  dsiInfo.TermID.emplace_back(p.GetID());
190  }
191  else
192  {
193  //If we have more than blockId, we want to minimize communication
194  //and put any blocks owned by this rank first.
195  if (newIDs.size() > 1)
196  {
197  for (auto idit = newIDs.begin(); idit != newIDs.end(); idit++)
198  {
199  vtkm::Id bid = *idit;
200  if (dsiInfo.BoundsMap.FindRank(bid) == this->Rank)
201  {
202  newIDs.erase(idit);
203  newIDs.insert(newIDs.begin(), bid);
204  break;
205  }
206  }
207  }
208 
209  int dstRank = dsiInfo.BoundsMap.FindRank(newIDs[0]);
210  if (dstRank == this->Rank)
211  {
212  dsiInfo.A.emplace_back(p);
213  dsiInfo.IdMapA[p.GetID()] = newIDs;
214  }
215  else
216  {
217  dsiInfo.I.emplace_back(p);
218  dsiInfo.IdMapI[p.GetID()] = newIDs;
219  }
220  }
221  portal.Set(i, p);
222  }
223  }
224 
225  //Make sure we didn't miss anything. Every particle goes into a single bucket.
226  VTKM_ASSERT(static_cast<std::size_t>(n) ==
227  (dsiInfo.A.size() + dsiInfo.I.size() + dsiInfo.TermIdx.size()));
228  VTKM_ASSERT(dsiInfo.TermIdx.size() == dsiInfo.TermID.size());
229 }
230 
231 template <typename Derived>
232 template <typename ParticleType, template <typename> class ResultType>
233 VTKM_CONT inline void DataSetIntegrator<Derived>::UpdateResult(
234  const ResultType<ParticleType>& result,
235  DSIHelperInfo<ParticleType>& dsiInfo)
236 {
237  this->ClassifyParticles(result.Particles, dsiInfo);
238 
239  if (this->IsParticleAdvectionResult())
240  {
241  if (dsiInfo.TermIdx.empty())
242  return;
243 
245  auto indicesAH = vtkm::cont::make_ArrayHandle(dsiInfo.TermIdx, vtkm::CopyFlag::Off);
246  auto termPerm = vtkm::cont::make_ArrayHandlePermutation(indicesAH, result.Particles);
247 
249  vtkm::cont::Algorithm::Copy(termPerm, termParticles);
250 
251  ResType termRes(termParticles);
252  this->Results.emplace_back(termRes);
253  }
254  else if (this->IsStreamlineResult())
255  this->Results.emplace_back(result);
256 }
257 
258 template <typename Derived>
259 template <typename ParticleType>
260 VTKM_CONT inline bool DataSetIntegrator<Derived>::GetOutput(vtkm::cont::DataSet& ds) const
261 {
262  std::size_t nResults = this->Results.size();
263  if (nResults == 0)
264  return false;
265 
266  if (this->IsParticleAdvectionResult())
267  {
269 
270  std::vector<vtkm::cont::ArrayHandle<ParticleType>> allParticles;
271  allParticles.reserve(nResults);
272  for (const auto& vres : this->Results)
273  allParticles.emplace_back(vres.template Get<ResType>().Particles);
274 
276  vtkm::cont::ParticleArrayCopy(allParticles, pts);
277 
278  vtkm::Id numPoints = pts.GetNumberOfValues();
279  if (numPoints > 0)
280  {
281  //Create coordinate system and vertex cell set.
282  ds.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", pts));
283 
285  vtkm::cont::ArrayHandleIndex conn(numPoints);
287 
288  vtkm::cont::ArrayCopy(conn, connectivity);
289  cells.Fill(numPoints, vtkm::CELL_SHAPE_VERTEX, 1, connectivity);
290  ds.SetCellSet(cells);
291  }
292  }
293  else if (this->IsStreamlineResult())
294  {
296 
297  //Easy case with one result.
298  if (nResults == 1)
299  {
300  const auto& res = this->Results[0].template Get<ResType>();
301  ds.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", res.Positions));
302  ds.SetCellSet(res.PolyLines);
303  }
304  else
305  {
306  std::vector<vtkm::Id> posOffsets(nResults, 0);
307  vtkm::Id totalNumCells = 0, totalNumPts = 0;
308  for (std::size_t i = 0; i < nResults; i++)
309  {
310  const auto& res = this->Results[i].template Get<ResType>();
311  if (i == 0)
312  posOffsets[i] = 0;
313  else
314  posOffsets[i] = totalNumPts;
315 
316  totalNumPts += res.Positions.GetNumberOfValues();
317  totalNumCells += res.PolyLines.GetNumberOfCells();
318  }
319 
320  //Append all the points together.
322  appendPts.Allocate(totalNumPts);
323  for (std::size_t i = 0; i < nResults; i++)
324  {
325  const auto& res = this->Results[i].template Get<ResType>();
326  // copy all values into appendPts starting at offset.
328  res.Positions, 0, res.Positions.GetNumberOfValues(), appendPts, posOffsets[i]);
329  }
330  ds.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", appendPts));
331 
332  //Create polylines.
333  std::vector<vtkm::Id> numPtsPerCell(static_cast<std::size_t>(totalNumCells));
334  std::size_t off = 0;
335  for (std::size_t i = 0; i < nResults; i++)
336  {
337  const auto& res = this->Results[i].template Get<ResType>();
338  vtkm::Id nCells = res.PolyLines.GetNumberOfCells();
339  for (vtkm::Id j = 0; j < nCells; j++)
340  numPtsPerCell[off++] = static_cast<vtkm::Id>(res.PolyLines.GetNumberOfPointsInCell(j));
341  }
342 
343  auto numPointsPerCellArray = vtkm::cont::make_ArrayHandle(numPtsPerCell, vtkm::CopyFlag::Off);
344 
346  vtkm::Id connectivityLen =
347  vtkm::cont::Algorithm::ScanExclusive(numPointsPerCellArray, cellIndex);
348  vtkm::cont::ArrayHandleIndex connCount(connectivityLen);
350  vtkm::cont::ArrayCopy(connCount, connectivity);
351 
353  auto polyLineShape = vtkm::cont::make_ArrayHandleConstant<vtkm::UInt8>(
354  vtkm::CELL_SHAPE_POLY_LINE, totalNumCells);
355  vtkm::cont::ArrayCopy(polyLineShape, cellTypes);
356  auto offsets = vtkm::cont::ConvertNumComponentsToOffsets(numPointsPerCellArray);
357 
359  polyLines.Fill(totalNumPts, cellTypes, connectivity, offsets);
360  ds.SetCellSet(polyLines);
361  }
362  }
363  else
364  {
365  throw vtkm::cont::ErrorFilterExecution("Unsupported ParticleAdvectionResultType");
366  }
367 
368  return true;
369 }
370 
371 }
372 }
373 }
374 } //vtkm::filter::flow::internal
375 
376 #endif //vtk_m_filter_flow_internal_DataSetIntegrator_h
vtkm::cont::ArrayHandle::GetNumberOfValues
VTKM_CONT vtkm::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:448
vtkm::cont::make_ArrayHandle
VTKM_CONT vtkm::cont::ArrayHandleBasic< T > make_ArrayHandle(const T *array, vtkm::Id numberOfValues, vtkm::CopyFlag copy)
A convenience function for creating an ArrayHandle from a standard C array.
Definition: ArrayHandleBasic.h:217
vtkm::cont::ArrayHandle< ParticleType >
vtkm::cont::EnvironmentTracker::GetCommunicator
static const VTKM_CONT vtkmdiy::mpi::communicator & GetCommunicator()
BoundsMap.h
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
VTKM_ASSERT
#define VTKM_ASSERT(condition)
Definition: Assert.h:43
vtkm::cont::ArrayHandle::Allocate
VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::CopyFlag preserve, vtkm::cont::Token &token) const
Allocates an array large enough to hold the given number of values.
Definition: ArrayHandle.h:465
vtkm::cont::ErrorFilterExecution
This class is primarily intended to filters to throw in the control environment to indicate an execut...
Definition: ErrorFilterExecution.h:27
vtkm::worklet::flow::ParticleAdvectionResult
Definition: worklet/ParticleAdvection.h:52
vtkm::cont::Algorithm::CopySubRange
static VTKM_CONT bool CopySubRange(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, vtkm::Id inputStartIndex, vtkm::Id numberOfElementsToCopy, vtkm::cont::ArrayHandle< U, COut > &output, vtkm::Id outputIndex=0)
Definition: Algorithm.h:472
Variant.h
vtkm::cont::CellSetSingleType
Definition: CastAndCall.h:34
vtkm::cont::DataSet
Definition: DataSet.h:34
RK4Integrator.h
vtkm::filter::flow::STREAMLINE_TYPE
@ STREAMLINE_TYPE
Definition: FlowTypes.h:35
vtkm::cont::Algorithm::Copy
static VTKM_CONT bool Copy(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, vtkm::cont::ArrayHandle< U, COut > &output)
Definition: Algorithm.h:410
ErrorFilterExecution.h
vtkm::worklet::flow::StreamlineResult
Definition: worklet/ParticleAdvection.h:126
ParticleAdvection.h
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
vtkm::cont::CoordinateSystem
Definition: CoordinateSystem.h:25
vtkm::CELL_SHAPE_POLY_LINE
@ CELL_SHAPE_POLY_LINE
Definition: CellShape.h:40
vtkm::filter::flow::FlowResultType
FlowResultType
Definition: FlowTypes.h:31
vtkm::cont::Algorithm::ScanExclusive
static VTKM_CONT T ScanExclusive(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, vtkm::cont::ArrayHandle< T, COut > &output)
Definition: Algorithm.h:816
vtkm::filter::flow::IntegrationSolverType
IntegrationSolverType
Definition: FlowTypes.h:19
vtkm::cont::ArrayCopy
void ArrayCopy(const SourceArrayType &source, DestArrayType &destination)
Does a deep copy from one array to another array.
Definition: ArrayCopy.h:142
vtkm::filter::flow::VectorFieldType
VectorFieldType
Definition: FlowTypes.h:25
ParticleArrayCopy.h
VTKM_CONT
#define VTKM_CONT
Definition: ExportMacros.h:57
vtkm::cont::ArrayHandle::WritePortal
VTKM_CONT WritePortalType WritePortal() const
Get an array portal that can be used in the control environment.
Definition: ArrayHandle.h:435
vtkm::cont::CellSetExplicit::Fill
VTKM_CONT void Fill(vtkm::Id numPoints, const vtkm::cont::ArrayHandle< vtkm::UInt8, ShapesStorageTag > &cellTypes, const vtkm::cont::ArrayHandle< vtkm::Id, ConnectivityStorageTag > &connectivity, const vtkm::cont::ArrayHandle< vtkm::Id, OffsetsStorageTag > &offsets)
Second method to add cells – all at once.
vtkm::ParticleStatus
Definition: Particle.h:23
Stepper.h
vtkm::cont::make_ArrayHandlePermutation
VTKM_CONT vtkm::cont::ArrayHandlePermutation< IndexArrayHandleType, ValueArrayHandleType > make_ArrayHandlePermutation(IndexArrayHandleType indexArray, ValueArrayHandleType valueArray)
make_ArrayHandleTransform is convenience function to generate an ArrayHandleTransform.
Definition: ArrayHandlePermutation.h:279
vtkm::cont::ConvertNumComponentsToOffsets
VTKM_CONT_EXPORT void ConvertNumComponentsToOffsets(const vtkm::cont::UnknownArrayHandle &numComponentsArray, vtkm::cont::ArrayHandle< vtkm::Id > &offsetsArray, vtkm::Id &componentsArraySize, vtkm::cont::DeviceAdapterId device=vtkm::cont::DeviceAdapterTagAny{})
vtkm::CopyFlag::Off
@ Off
vtkm::FloatDefault
vtkm::Float32 FloatDefault
The floating point type to use when no other precision is specified.
Definition: Types.h:198
vtkm::cont::ParticleArrayCopy
VTKM_ALWAYS_EXPORT void ParticleArrayCopy(const vtkm::cont::ArrayHandle< ParticleType, vtkm::cont::StorageTagBasic > &inP, vtkm::cont::ArrayHandle< vtkm::Vec3f, vtkm::cont::StorageTagBasic > &outPos, bool CopyTerminatedOnly=false)
Copy fields in vtkm::Particle to standard types.
vtkm::cont::CellSetExplicit
Definition: CastAndCall.h:36
vtkm::cont::DataSet::AddCoordinateSystem
VTKM_CONT vtkm::IdComponent AddCoordinateSystem(const vtkm::cont::CoordinateSystem &cs)
Adds the given CoordinateSystem to the DataSet.
vtkm::cont::DataSet::SetCellSet
VTKM_CONT void SetCellSet(const CellSetType &cellSet)
Definition: DataSet.h:355
vtkm::filter::flow::PARTICLE_ADVECT_TYPE
@ PARTICLE_ADVECT_TYPE
Definition: FlowTypes.h:34
vtkm::cont::CellSetSingleType::Fill
VTKM_CONT void Fill(vtkm::Id numPoints, vtkm::UInt8 shapeId, vtkm::IdComponent numberOfPointsPerCell, const vtkm::cont::ArrayHandle< vtkm::Id, ConnectivityStorageTag > &connectivity)
Definition: CellSetSingleType.h:186
EulerIntegrator.h
vtkm::filter::flow::UNKNOWN_TYPE
@ UNKNOWN_TYPE
Definition: FlowTypes.h:33
IntegratorStatus.h
FlowTypes.h
DataSet.h
vtkm::cont::ArrayHandleIndex
An implicit array handle containing the its own indices.
Definition: ArrayHandleIndex.h:54
vtkm::CELL_SHAPE_VERTEX
@ CELL_SHAPE_VERTEX
Definition: CellShape.h:37