Skip to content

Commit a5ec903

Browse files
committed
Select particle patches more finely when restarting
1 parent add37a9 commit a5ec903

File tree

1 file changed

+72
-13
lines changed

1 file changed

+72
-13
lines changed

include/picongpu/plugins/openPMD/restart/LoadSpecies.hpp

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
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

Comments
 (0)