19 #ifndef viskores_filter_flow_internal_AdvectAlgorithm_h
20 #define viskores_filter_flow_internal_AdvectAlgorithm_h
26 #ifdef VISKORES_ENABLE_MPI
29 #include <viskores/thirdparty/diy/diy.h>
30 #include <viskores/thirdparty/diy/mpi-cast.h>
42 template <
typename DSIType>
46 using ParticleType =
typename DSIType::PType;
48 AdvectAlgorithm(
const viskores::filter::flow::internal::BoundsMap& bm,
49 std::vector<DSIType>& blocks)
52 #ifdef VISKORES_ENABLE_MPI
53 , Exchanger(this->Comm)
54 , Terminator(this->Comm)
56 , NumRanks(this->Comm.size())
57 , Rank(this->Comm.rank())
64 this->SetStepSize(stepSize);
65 this->SetSeeds(seeds);
73 for (
const auto& b : this->Blocks)
86 this->ClearParticles();
91 std::vector<std::vector<viskores::Id>> blockIDs;
92 std::vector<ParticleType> particles;
95 const ParticleType p = portal.Get(i);
96 std::vector<viskores::Id> ids = this->BoundsMap.FindBlocks(p.GetPosition());
101 auto ranks = this->BoundsMap.FindRank(ids[0]);
102 if (!ranks.empty() && this->Rank == ranks[0])
104 particles.emplace_back(p);
105 blockIDs.emplace_back(ids);
109 this->SetSeedArray(particles, blockIDs);
112 virtual bool HaveWork()
114 const bool haveParticles = !this->Active.empty() || !this->Inactive.empty();
115 #ifndef VISKORES_ENABLE_MPI
116 return haveParticles;
118 return haveParticles || this->Exchanger.HaveWork();
122 virtual bool GetDone()
124 #ifndef VISKORES_ENABLE_MPI
125 return !this->HaveWork();
127 return this->Terminator.Done();
134 while (!this->GetDone())
136 std::vector<ParticleType> v;
139 if (this->GetActiveParticles(v, blockId))
142 auto& block = this->GetDataSet(blockId);
143 DSIHelperInfo<ParticleType> bb(v, this->BoundsMap, this->ParticleBlockIDsMap);
144 block.Advect(bb, this->StepSize);
145 this->UpdateResult(bb);
148 this->ExchangeParticles();
152 virtual void ClearParticles()
154 this->Active.clear();
155 this->Inactive.clear();
156 this->ParticleBlockIDsMap.clear();
159 DataSetIntegrator<DSIType, ParticleType>& GetDataSet(
viskores::Id id)
161 for (
auto& it : this->Blocks)
162 if (it.GetID() ==
id)
168 virtual void SetSeedArray(
const std::vector<ParticleType>& particles,
169 const std::vector<std::vector<viskores::Id>>& blockIds)
173 auto pit = particles.begin();
174 auto bit = blockIds.begin();
175 while (pit != particles.end() && bit != blockIds.end())
178 this->ParticleBlockIDsMap[pit->GetID()] = *bit;
179 if (this->Active.find(blockId0) == this->Active.end())
180 this->Active[blockId0] = { *pit };
182 this->Active[blockId0].emplace_back(*pit);
188 virtual bool GetActiveParticles(std::vector<ParticleType>& particles,
viskores::Id& blockId)
192 if (this->Active.empty())
196 if (this->Active.size() == 1)
198 blockId = this->Active.begin()->first;
199 particles = std::move(this->Active.begin()->second);
200 this->Active.clear();
205 std::size_t maxNum = 0;
206 auto maxIt = this->Active.end();
207 for (
auto it = this->Active.begin(); it != this->Active.end(); it++)
209 auto sz = it->second.size();
219 this->Active.clear();
223 blockId = maxIt->first;
224 particles = std::move(maxIt->second);
225 this->Active.erase(maxIt);
228 return !particles.empty();
231 void ExchangeParticles()
233 #ifndef VISKORES_ENABLE_MPI
234 this->SerialExchange();
237 if (this->NumRanks == 1)
238 this->SerialExchange();
241 std::vector<ParticleType> outgoing;
242 std::vector<viskores::Id> outgoingRanks;
244 this->GetOutgoingParticles(outgoing, outgoingRanks);
246 std::vector<ParticleType> incoming;
247 std::unordered_map<viskores::Id, std::vector<viskores::Id>> incomingBlockIDs;
249 this->Exchanger.Exchange(
250 outgoing, outgoingRanks, this->ParticleBlockIDsMap, incoming, incomingBlockIDs);
253 for (
const auto& p : outgoing)
254 this->ParticleBlockIDsMap.erase(p.GetID());
256 this->UpdateActive(incoming, incomingBlockIDs);
259 this->Terminator.Control(this->HaveWork());
263 void SerialExchange()
265 for (
const auto& p : this->Inactive)
267 const auto& bid = this->ParticleBlockIDsMap[p.GetID()];
269 this->Active[bid[0]].emplace_back(std::move(p));
271 this->Inactive.clear();
274 #ifdef VISKORES_ENABLE_MPI
275 void GetOutgoingParticles(std::vector<ParticleType>& outgoing,
276 std::vector<viskores::Id>& outgoingRanks)
279 outgoingRanks.clear();
281 outgoing.reserve(this->Inactive.size());
282 outgoingRanks.reserve(this->Inactive.size());
284 std::vector<ParticleType> particlesStaying;
285 std::unordered_map<viskores::Id, std::vector<viskores::Id>> particlesStayingBlockIDs;
287 for (
const auto& p : this->Inactive)
289 const auto& bid = this->ParticleBlockIDsMap[p.GetID()];
292 auto ranks = this->BoundsMap.FindRank(bid[0]);
296 if (ranks.size() == 1)
298 if (ranks[0] == this->Rank)
300 particlesStaying.emplace_back(p);
301 particlesStayingBlockIDs[p.GetID()] = this->ParticleBlockIDsMap[p.GetID()];
305 outgoing.emplace_back(p);
306 outgoingRanks.emplace_back(ranks[0]);
315 if (outRank == this->Rank)
317 particlesStayingBlockIDs[p.GetID()] = this->ParticleBlockIDsMap[p.GetID()];
318 particlesStaying.emplace_back(p);
322 outgoing.emplace_back(p);
323 outgoingRanks.emplace_back(outRank);
328 this->Inactive.clear();
331 VISKORES_ASSERT(particlesStaying.size() == particlesStayingBlockIDs.size());
332 if (!particlesStaying.empty())
333 this->UpdateActive(particlesStaying, particlesStayingBlockIDs);
337 virtual void UpdateActive(
338 const std::vector<ParticleType>& particles,
339 const std::unordered_map<
viskores::Id, std::vector<viskores::Id>>& idsMap)
343 if (!particles.empty())
345 for (
auto pit = particles.begin(); pit != particles.end(); pit++)
348 const auto& it = idsMap.find(particleID);
351 this->Active[blockId].emplace_back(*pit);
354 for (
const auto& it : idsMap)
355 this->ParticleBlockIDsMap[it.first] = it.second;
359 virtual void UpdateInactive(
360 const std::vector<ParticleType>& particles,
361 const std::unordered_map<
viskores::Id, std::vector<viskores::Id>>& idsMap)
365 this->Inactive.insert(this->Inactive.end(), particles.begin(), particles.end());
366 for (
const auto& it : idsMap)
367 this->ParticleBlockIDsMap[it.first] = it.second;
370 viskores::Id UpdateResult(
const DSIHelperInfo<ParticleType>& stuff)
372 this->UpdateActive(stuff.InBounds.Particles, stuff.InBounds.BlockIDs);
373 this->UpdateInactive(stuff.OutOfBounds.Particles, stuff.OutOfBounds.BlockIDs);
379 for (
const auto&
id : stuff.TermID)
380 this->ParticleBlockIDsMap.erase(
id);
388 std::unordered_map<viskores::Id, std::vector<ParticleType>> Active;
389 std::vector<DSIType> Blocks;
390 viskores::filter::flow::internal::BoundsMap BoundsMap;
392 #ifdef VISKORES_ENABLE_MPI
393 ParticleExchanger<ParticleType> Exchanger;
394 AdvectAlgorithmTerminator Terminator;
396 std::vector<ParticleType> Inactive;
400 std::unordered_map<viskores::Id, std::vector<viskores::Id>> ParticleBlockIDsMap;
410 #endif //viskores_filter_flow_internal_AdvectAlgorithm_h