Viskores  1.0
BoundsMap.h
Go to the documentation of this file.
1 //============================================================================
2 // The contents of this file are covered by the Viskores license. See
3 // LICENSE.txt for details.
4 //
5 // By contributing to this file, all contributors agree to the Developer
6 // Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
7 //============================================================================
8 
9 //============================================================================
10 // Copyright (c) Kitware, Inc.
11 // All rights reserved.
12 // See LICENSE.txt for details.
13 //
14 // This software is distributed WITHOUT ANY WARRANTY; without even
15 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 // PURPOSE. See the above copyright notice for more information.
17 //============================================================================
18 
19 #ifndef viskores_filter_flow_internal_BoundsMap_h
20 #define viskores_filter_flow_internal_BoundsMap_h
21 
22 #include <viskores/Bounds.h>
24 #include <viskores/cont/DataSet.h>
27 #include <viskores/cont/Field.h>
29 
30 #include <viskores/thirdparty/diy/diy.h>
31 
32 #ifdef VISKORES_ENABLE_MPI
33 #include <mpi.h>
34 #include <viskores/thirdparty/diy/mpi-cast.h>
35 #endif
36 
37 #include <algorithm>
38 #include <iostream>
39 #include <set>
40 #include <vector>
41 
42 namespace viskores
43 {
44 namespace filter
45 {
46 namespace flow
47 {
48 namespace internal
49 {
50 
51 class VISKORES_ALWAYS_EXPORT BoundsMap
52 {
53 public:
54  BoundsMap() {}
55 
56  BoundsMap(const viskores::cont::DataSet& dataSet) { this->Init({ dataSet }); }
57 
58  BoundsMap(const viskores::cont::DataSet& dataSet, const viskores::Id& blockId)
59  {
60  this->Init({ dataSet }, { blockId });
61  }
62 
63  BoundsMap(const std::vector<viskores::cont::DataSet>& dataSets) { this->Init(dataSets); }
64 
65  BoundsMap(const viskores::cont::PartitionedDataSet& pds) { this->Init(pds.GetPartitions()); }
66 
67  BoundsMap(const viskores::cont::PartitionedDataSet& pds,
68  const std::vector<viskores::Id>& blockIds)
69  {
70  this->Init(pds.GetPartitions(), blockIds);
71  }
72 
73  viskores::Bounds GetGlobalBounds() const { return this->GlobalBounds; }
74 
75  viskores::Bounds GetBlockBounds(viskores::Id idx) const
76  {
77  VISKORES_ASSERT(idx >= 0 && static_cast<std::size_t>(idx) < this->BlockBounds.size());
78 
79  return this->BlockBounds[static_cast<std::size_t>(idx)];
80  }
81 
82  viskores::Id GetLocalBlockId(viskores::Id idx) const
83  {
84  VISKORES_ASSERT(idx >= 0 && idx < this->LocalNumBlocks);
85  return this->LocalIDs[static_cast<std::size_t>(idx)];
86  }
87 
88  std::vector<int> FindRank(viskores::Id blockId) const
89  {
90  auto it = this->BlockToRankMap.find(blockId);
91  if (it == this->BlockToRankMap.end())
92  return {};
93 
94  return it->second;
95  }
96 
97  std::vector<viskores::Id> FindBlocks(const viskores::Vec3f& p) const
98  {
99  return this->FindBlocks(p, -1);
100  }
101 
102  std::vector<viskores::Id> FindBlocks(const viskores::Vec3f& p,
103  const std::vector<viskores::Id>& ignoreBlocks) const
104  {
105  viskores::Id ignoreID = (ignoreBlocks.empty() ? -1 : ignoreBlocks[0]);
106  return FindBlocks(p, ignoreID);
107  }
108 
109  std::vector<viskores::Id> FindBlocks(const viskores::Vec3f& p, viskores::Id ignoreBlock) const
110  {
111  std::vector<viskores::Id> blockIDs;
112  if (this->GlobalBounds.Contains(p))
113  {
114  viskores::Id blockId = 0;
115  for (auto& it : this->BlockBounds)
116  {
117  if (blockId != ignoreBlock && it.Contains(p))
118  blockIDs.emplace_back(blockId);
119  blockId++;
120  }
121  }
122 
123  return blockIDs;
124  }
125 
126  viskores::Id GetTotalNumBlocks() const { return this->TotalNumBlocks; }
127  viskores::Id GetLocalNumBlocks() const { return this->LocalNumBlocks; }
128 
129 private:
130  void Init(const std::vector<viskores::cont::DataSet>& dataSets,
131  const std::vector<viskores::Id>& blockIds)
132  {
133  if (dataSets.size() != blockIds.size())
134  throw viskores::cont::ErrorFilterExecution("Number of datasets and block ids must match");
135 
136  this->LocalIDs = blockIds;
137  this->LocalNumBlocks = dataSets.size();
138 
139  viskoresdiy::mpi::communicator comm = viskores::cont::EnvironmentTracker::GetCommunicator();
140 
141  //1. Get the min/max blockId
142  viskores::Id locMinId = 0, locMaxId = 0;
143  if (!this->LocalIDs.empty())
144  {
145  locMinId = *std::min_element(this->LocalIDs.begin(), this->LocalIDs.end());
146  locMaxId = *std::max_element(this->LocalIDs.begin(), this->LocalIDs.end());
147  }
148 
149  viskores::Id globalMinId = 0, globalMaxId = 0;
150 
151  viskoresdiy::mpi::all_reduce(
152  comm, locMinId, globalMinId, viskoresdiy::mpi::minimum<viskores::Id>{});
153  viskoresdiy::mpi::all_reduce(
154  comm, locMaxId, globalMaxId, viskoresdiy::mpi::maximum<viskores::Id>{});
155  if (globalMinId != 0 || (globalMaxId - globalMinId) < 1)
156  throw viskores::cont::ErrorFilterExecution("Invalid block ids");
157 
158  //2. Find out how many blocks everyone has.
159  std::vector<viskores::Id> locBlockCounts(comm.size(), 0), globalBlockCounts(comm.size(), 0);
160  locBlockCounts[comm.rank()] = this->LocalIDs.size();
161  viskoresdiy::mpi::all_reduce(
162  comm, locBlockCounts, globalBlockCounts, std::plus<viskores::Id>{});
163 
164  //note: there might be duplicates...
165  viskores::Id globalNumBlocks =
166  std::accumulate(globalBlockCounts.begin(), globalBlockCounts.end(), viskores::Id{ 0 });
167 
168  //3. given the counts per rank, calc offset for this rank.
169  viskores::Id offset = 0;
170  for (int i = 0; i < comm.rank(); i++)
171  offset += globalBlockCounts[i];
172 
173  //4. calc the blocks on each rank.
174  std::vector<viskores::Id> localBlockIds(globalNumBlocks, 0);
175  viskores::Id idx = 0;
176  for (const auto& bid : this->LocalIDs)
177  localBlockIds[offset + idx++] = bid;
178 
179  //use an MPI_Alltoallv instead.
180  std::vector<viskores::Id> globalBlockIds(globalNumBlocks, 0);
181  viskoresdiy::mpi::all_reduce(comm, localBlockIds, globalBlockIds, std::plus<viskores::Id>{});
182 
183 
184  //5. create a rank -> blockId map.
185  // rankToBlockIds[rank] = {this->LocalIDs on rank}.
186  std::vector<std::vector<viskores::Id>> rankToBlockIds(comm.size());
187 
188  offset = 0;
189  for (int rank = 0; rank < comm.size(); rank++)
190  {
191  viskores::Id numBIds = globalBlockCounts[rank];
192  rankToBlockIds[rank].resize(numBIds);
193  for (viskores::Id i = 0; i < numBIds; i++)
194  rankToBlockIds[rank][i] = globalBlockIds[offset + i];
195 
196  offset += numBIds;
197  }
198 
199  //6. there might be duplicates, so count number of UNIQUE blocks.
200  std::set<viskores::Id> globalUniqueBlockIds;
201  globalUniqueBlockIds.insert(globalBlockIds.begin(), globalBlockIds.end());
202  this->TotalNumBlocks = globalUniqueBlockIds.size();
203 
204  //Build a vector of : blockIdsToRank[blockId] = {ranks that have this blockId}
205  std::vector<std::vector<viskores::Id>> blockIdsToRank(this->TotalNumBlocks);
206  for (int rank = 0; rank < comm.size(); rank++)
207  {
208  for (const auto& bid : rankToBlockIds[rank])
209  {
210  blockIdsToRank[bid].push_back(rank);
211  this->BlockToRankMap[bid].push_back(rank);
212  }
213  }
214 
215  this->Build(dataSets);
216  }
217 
218  void Init(const std::vector<viskores::cont::DataSet>& dataSets)
219  {
220  this->LocalNumBlocks = dataSets.size();
221 
222  viskores::cont::AssignerPartitionedDataSet assigner(this->LocalNumBlocks);
223  this->TotalNumBlocks = assigner.nblocks();
224  std::vector<int> ids;
225 
226  viskoresdiy::mpi::communicator Comm = viskores::cont::EnvironmentTracker::GetCommunicator();
227  assigner.local_gids(Comm.rank(), ids);
228  for (const auto& i : ids)
229  this->LocalIDs.emplace_back(static_cast<viskores::Id>(i));
230 
231  for (viskores::Id id = 0; id < this->TotalNumBlocks; id++)
232  this->BlockToRankMap[id] = { assigner.rank(static_cast<int>(id)) };
233  this->Build(dataSets);
234  }
235 
236  void Build(const std::vector<viskores::cont::DataSet>& dataSets)
237  {
238  std::vector<viskores::Float64> vals(static_cast<std::size_t>(this->TotalNumBlocks * 6), 0);
239  std::vector<viskores::Float64> vals2(vals.size());
240 
241  std::vector<viskores::Float64> localMins((this->TotalNumBlocks * 3),
242  std::numeric_limits<viskores::Float64>::max());
243  std::vector<viskores::Float64> localMaxs((this->TotalNumBlocks * 3),
244  -std::numeric_limits<viskores::Float64>::max());
245 
246  for (std::size_t i = 0; i < this->LocalIDs.size(); i++)
247  {
248  const viskores::cont::DataSet& ds = dataSets[static_cast<std::size_t>(i)];
250 
251  viskores::Id localID = this->LocalIDs[i];
252  localMins[localID * 3 + 0] = bounds.X.Min;
253  localMins[localID * 3 + 1] = bounds.Y.Min;
254  localMins[localID * 3 + 2] = bounds.Z.Min;
255  localMaxs[localID * 3 + 0] = bounds.X.Max;
256  localMaxs[localID * 3 + 1] = bounds.Y.Max;
257  localMaxs[localID * 3 + 2] = bounds.Z.Max;
258  }
259 
260  std::vector<viskores::Float64> globalMins, globalMaxs;
261 
262 #ifdef VISKORES_ENABLE_MPI
263  globalMins.resize(this->TotalNumBlocks * 3);
264  globalMaxs.resize(this->TotalNumBlocks * 3);
265 
266  viskoresdiy::mpi::communicator comm = viskores::cont::EnvironmentTracker::GetCommunicator();
267 
268  viskoresdiy::mpi::all_reduce(
269  comm, localMins, globalMins, viskoresdiy::mpi::minimum<viskores::Float64>{});
270  viskoresdiy::mpi::all_reduce(
271  comm, localMaxs, globalMaxs, viskoresdiy::mpi::maximum<viskores::Float64>{});
272 #else
273  globalMins = localMins;
274  globalMaxs = localMaxs;
275 #endif
276 
277  this->BlockBounds.resize(static_cast<std::size_t>(this->TotalNumBlocks));
278  this->GlobalBounds = viskores::Bounds();
279 
280  std::size_t idx = 0;
281  for (auto& block : this->BlockBounds)
282  {
283  block = viskores::Bounds(globalMins[idx + 0],
284  globalMaxs[idx + 0],
285  globalMins[idx + 1],
286  globalMaxs[idx + 1],
287  globalMins[idx + 2],
288  globalMaxs[idx + 2]);
289  this->GlobalBounds.Include(block);
290  idx += 3;
291  }
292  }
293 
294  viskores::Id LocalNumBlocks = 0;
295  std::vector<viskores::Id> LocalIDs;
296  std::map<viskores::Id, std::vector<viskores::Int32>> BlockToRankMap;
297  viskores::Id TotalNumBlocks = 0;
298  std::vector<viskores::Bounds> BlockBounds;
299  viskores::Bounds GlobalBounds;
300 };
301 
302 }
303 }
304 }
305 } // namespace viskores::filter::flow::internal
306 
307 #endif //viskores_filter_flow_internal_BoundsMap_h
viskores::cont::DataSet::GetCoordinateSystem
viskores::cont::CoordinateSystem GetCoordinateSystem(viskores::Id index=0) const
AssignerPartitionedDataSet.h
viskores::cont::DataSet
Contains and manages the geometric data structures that Viskores operates on.
Definition: DataSet.h:66
viskores::Bounds
Represent an axis-aligned 3D bounds in space.
Definition: Bounds.h:37
viskores::cont::CoordinateSystem::GetBounds
viskores::Bounds GetBounds() const
Definition: CoordinateSystem.h:137
viskores::Range::Min
viskores::Float64 Min
The minumum value of the range (inclusive).
Definition: Range.h:42
EnvironmentTracker.h
ErrorFilterExecution.h
viskores::cont::ErrorFilterExecution
This class is primarily intended to filters to throw in the control environment to indicate an execut...
Definition: ErrorFilterExecution.h:35
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
Bounds.h
viskores::cont::EnvironmentTracker::GetCommunicator
static const viskoresdiy::mpi::communicator & GetCommunicator()
viskores::cont::PartitionedDataSet::GetPartitions
const std::vector< viskores::cont::DataSet > & GetPartitions() const
Get an STL vector of all DataSet objects stored in PartitionedDataSet.
Field.h
VISKORES_ASSERT
#define VISKORES_ASSERT(condition)
Definition: Assert.h:51
viskores::cont::PartitionedDataSet
Comprises a set of viskores::cont::DataSet objects.
Definition: PartitionedDataSet.h:34
PartitionedDataSet.h
viskores::cont::AssignerPartitionedDataSet
Assigner for PartitionedDataSet partitions.
Definition: AssignerPartitionedDataSet.h:57
viskores::Vec< viskores::FloatDefault, 3 >
DataSet.h
viskores::Bounds::X
viskores::Range X
The range of values in the X direction.
Definition: Bounds.h:41