3535
3636# include < boost/mpl/placeholders.hpp>
3737
38+ # include < algorithm>
3839# include < cassert>
3940# include < stdexcept>
41+ # include < utility>
4042
4143# include < openPMD/openPMD.hpp>
4244
@@ -101,7 +103,7 @@ namespace picongpu
101103
102104 auto numRanks = gc.getGlobalSize ();
103105
104- size_t patchIdx = getPatchIdx (params, particleSpecies, numRanks );
106+ size_t patchIdx = getPatchIdx (params, particleSpecies);
105107
106108 std::shared_ptr<uint64_t > fullParticlesInfoShared
107109 = particleSpecies.particlePatches [" numParticles" ][::openPMD::RecordComponent::SCALAR]
@@ -186,6 +188,27 @@ namespace picongpu
186188 }
187189
188190 private:
191+ // o: offset, e: extent, u: upper corner (= o+e)
192+ static std::pair<DataSpace<simDim>, DataSpace<simDim>> intersect (
193+ DataSpace<simDim> const & o1,
194+ DataSpace<simDim> const & e1 ,
195+ DataSpace<simDim> const & o2,
196+ DataSpace<simDim> const & e2 )
197+ {
198+ // Convert extents into upper coordinates
199+ auto u1 = o1 + e1 ;
200+ auto u2 = o2 + e2 ;
201+
202+ DataSpace<simDim> intersect_o, intersect_u, intersect_e;
203+ for (unsigned d = 0 ; d < simDim; ++d)
204+ {
205+ intersect_o[d] = std::max (o1[d], o2[d]);
206+ intersect_u[d] = std::min (u1[d], u2[d]);
207+ intersect_e[d] = intersect_u[d] > intersect_o[d] ? intersect_u[d] - intersect_o[d] : 0 ;
208+ }
209+ return {intersect_o, intersect_e};
210+ }
211+
189212 /* * get index for particle data within the openPMD patch data
190213 *
191214 * It is not possible to assume that we can use the MPI rank to load the particle data.
@@ -197,13 +220,14 @@ namespace picongpu
197220 *
198221 * @return index of the particle patch within the openPMD data
199222 */
200- HINLINE size_t
201- getPatchIdx (ThreadParams* params, ::openPMD::ParticleSpecies particleSpecies, size_t numRanks)
223+ HINLINE size_t getPatchIdx (ThreadParams* params, ::openPMD::ParticleSpecies particleSpecies)
202224 {
203225 std::string const name_lookup[] = {" x" , " y" , " z" };
204226
205- std::vector<DataSpace<simDim>> offsets (numRanks);
206- std::vector<DataSpace<simDim>> extents (numRanks);
227+ size_t patches = particleSpecies.particlePatches [" numParticles" ].getExtent ()[0 ];
228+
229+ std::vector<DataSpace<simDim>> offsets (patches);
230+ std::vector<DataSpace<simDim>> extents (patches);
207231
208232 // transform openPMD particle patch data into PIConGPU data objects
209233 for (uint32_t d = 0 ; d < simDim; ++d)
@@ -213,7 +237,7 @@ namespace picongpu
213237 std::shared_ptr<uint64_t > patchExtentsInfoShared
214238 = particleSpecies.particlePatches [" extent" ][name_lookup[d]].load <uint64_t >();
215239 particleSpecies.seriesFlush ();
216- for (size_t i = 0 ; i < numRanks ; ++i)
240+ for (size_t i = 0 ; i < patches ; ++i)
217241 {
218242 offsets[i][d] = patchOffsetsInfoShared.get ()[i];
219243 extents[i][d] = patchExtentsInfoShared.get ()[i];
@@ -235,18 +259,53 @@ namespace picongpu
235259 DataSpace<simDim> const patchTotalOffset
236260 = localToTotalDomainOffset + params->localWindowToDomainOffset ;
237261 DataSpace<simDim> const patchExtent = params->window .localDimensions .size ;
262+ math::Vector<bool , simDim> true_;
263+ for (unsigned d = 0 ; d < simDim; ++d)
264+ {
265+ true_[d] = true ;
266+ }
238267
239268 // search the patch index based on the offset and extents of local domain size
240- for (size_t i = 0 ; i < numRanks; ++i)
269+ std::deque<size_t > fullMatches;
270+ std::deque<size_t > partialMatches;
271+ size_t noMatches = 0 ;
272+ for (size_t i = 0 ; i < patches; ++i)
241273 {
242- if (patchTotalOffset == offsets[i] && patchExtent == extents[i])
243- return i;
274+ // std::cout << "Comp.: " << patchTotalOffset << " - " << (patchTotalOffset + patchExtent)
275+ // << "\tAGAINST " << offsets[i] << " - " << (offsets[i] + extents[i])
276+ // << "\toffsets: " << (patchTotalOffset <= offsets[i])
277+ // << ", extents: " << ((offsets[i] + extents[i]) <= (patchTotalOffset + patchExtent)) <<
278+ // '\n';
279+ if ((patchTotalOffset <= offsets[i]) == true_
280+ && ((offsets[i] + extents[i]) <= (patchTotalOffset + patchExtent)) == true_)
281+ {
282+ fullMatches.emplace_back (i);
283+ }
284+ else if (
285+ intersect (offsets[i], extents[i], patchTotalOffset, patchExtent).second .productOfComponents ()
286+ != 0 )
287+ {
288+ partialMatches.emplace_back (i);
289+ }
290+ else
291+ {
292+ ++noMatches;
293+ }
244294 }
295+
296+ std::cout << " \n\n "
297+ << fullMatches.size () << " full matches, " << partialMatches.size () << " partial matches, "
298+ << noMatches << " unmatched." << std ::endl;
299+
245300 // If no patch fits the conditions, something went wrong before
246- throw std::runtime_error (
247- " Error while restarting: no particle patch matches the required offset and extent" );
248- // Fake return still needed to avoid warnings
249- return 0 ;
301+ if (fullMatches.empty ())
302+ {
303+ throw std::runtime_error (
304+ " Error while restarting: no particle patch matches the required offset and extent" );
305+ }
306+
307+ // For now, ignore all the others
308+ return *fullMatches.begin ();
250309 }
251310 };
252311
0 commit comments