22 static std::ostream &operator<<(std::ostream &out, const std::vector<T> &v) {
23 auto column = out.tellp();
25 for (
const auto &x : v) {
26 if (out.tellp() - column >= 100) {
36 static std::ostream &operator<<(std::ostream &out,
37 const std::initializer_list<T> &v) {
38 auto column = out.tellp();
40 for (
const auto &x : v) {
41 if (out.tellp() - column >= 100) {
50 template <
typename T, std::
size_t N>
51 static std::ostream &operator<<(std::ostream &out, const std::array<T, N> &a) {
52 auto column = out.tellp();
54 for (
const auto &x : a) {
55 if (out.tellp() - column >= 100) {
70 std::pair<std::array<double, 3>, std::array<double, 3>>
72 std::pair<std::array<double, 3>, std::array<double, 3>> r;
73 auto &min_position = r.first;
74 auto &length = r.second;
79 min_position = {{first_position[1], first_position[2], first_position[3]}};
80 auto max_position = min_position;
81 for (
const auto &
p : particles) {
82 const auto &pos =
p.position();
83 min_position[0] = std::min(min_position[0], pos[1]);
84 min_position[1] = std::min(min_position[1], pos[2]);
85 min_position[2] = std::min(min_position[2], pos[3]);
86 max_position[0] = std::max(max_position[0], pos[1]);
87 max_position[1] = std::max(max_position[1], pos[2]);
88 max_position[2] = std::max(max_position[2], pos[3]);
90 length[0] = max_position[0] - min_position[0];
91 length[1] = max_position[1] - min_position[1];
92 length[2] = max_position[2] - min_position[2];
99 template <Gr
idOptions O>
102 const Particles &particles,
double max_interaction_length,
104 : length_(min_and_length.second) {
105 const auto min_position = min_and_length.first;
109 if (O == GridOptions::Normal && strategy == CellSizeStrategy::Largest) {
110 number_of_cells_ = {1, 1, 1};
131 const int max_cells =
132 (O == GridOptions::Normal)
133 ? std::cbrt(particle_count)
134 : std::max(2, static_cast<int>(std::cbrt(particle_count)));
138 std::array<double, 3> index_factor = {1. / max_interaction_length,
139 1. / max_interaction_length,
140 1. / max_interaction_length};
141 for (std::size_t i = 0; i < number_of_cells_.size(); ++i) {
142 number_of_cells_[i] =
143 (strategy == CellSizeStrategy::Largest)
145 : static_cast<int>(std::floor(length_[i] * index_factor[i])) +
156 (O == GridOptions::Normal ? 1 : 0);
160 if (number_of_cells_[i] > max_cells) {
161 number_of_cells_[i] = max_cells;
162 index_factor[i] = number_of_cells_[i] / length_[i];
163 while (index_factor[i] * length_[i] >= number_of_cells_[i]) {
164 index_factor[i] = std::nextafter(index_factor[i], 0.);
166 assert(index_factor[i] * length_[i] < number_of_cells_[i]);
167 }
else if (O == GridOptions::PeriodicBoundaries) {
168 if (number_of_cells_[i] == 1) {
169 number_of_cells_[i] = 2;
171 index_factor[i] = number_of_cells_[i] / length_[i];
172 while (index_factor[i] * length_[i] >= number_of_cells_[i]) {
173 index_factor[i] = std::nextafter(index_factor[i], 0.);
175 assert(index_factor[i] * length_[i] < number_of_cells_[i]);
179 const auto &log = logger<LogArea::Grid>();
180 if (O == GridOptions::Normal &&
188 log.debug(
"There would only be ", number_of_cells_,
189 " cells. Therefore the Grid falls back to a single cell / " 191 number_of_cells_ = {1, 1, 1};
193 cells_.front().reserve(particles.
size());
194 std::copy_if(particles.
begin(), particles.
end(),
195 std::back_inserter(cells_.front()), [](
const ParticleData &
p) {
196 return p.xsec_scaling_factor() > 0.0;
200 log.debug(
"min: ", min_position,
"\nlength: ", length_,
201 "\ncells: ", number_of_cells_,
"\nindex_factor: ", index_factor);
205 cells_.resize(number_of_cells_[0] * number_of_cells_[1] *
206 number_of_cells_[2]);
214 std::floor((
p.position()[1] - min_position[0]) * index_factor[0]),
215 std::floor((
p.position()[2] - min_position[1]) * index_factor[1]),
216 std::floor((
p.position()[3] - min_position[2]) * index_factor[2]));
219 for (
const auto &
p : particles) {
220 if (
p.xsec_scaling_factor() > 0.0) {
221 const auto idx = cell_index_for(
p);
223 if (idx >=
SizeType(cells_.size())) {
226 "\nan out-of-bounds access would be necessary for the " 228 p,
"\nfor a grid with the following parameters:\nmin: ",
229 min_position,
"\nlength: ", length_,
230 "\ncells: ", number_of_cells_,
"\nindex_factor: ", index_factor,
231 "\ncells_.size: ", cells_.size(),
"\nrequested index: ", idx);
232 throw std::runtime_error(
"out-of-bounds grid access on construction");
235 cells_[idx].push_back(
p);
243 template <Gr
idOptions Options>
246 return (z * number_of_cells_[1] + y) * number_of_cells_[0] + x;
252 const std::function<
void(
const ParticleList &)> &search_cell_callback,
253 const std::function<
void(
const ParticleList &,
const ParticleList &)>
254 &neighbor_cell_callback)
const {
255 std::array<SizeType, 3> search_index;
260 for (z = 0; z < number_of_cells_[2]; ++z) {
261 for (y = 0; y < number_of_cells_[1]; ++y) {
262 for (x = 0; x < number_of_cells_[0]; ++x, ++search_cell_index) {
263 assert(search_cell_index == make_index(search_index));
264 assert(search_cell_index >= 0);
265 assert(search_cell_index <
SizeType(cells_.size()));
266 const ParticleList &search = cells_[search_cell_index];
267 search_cell_callback(search);
269 const auto dz_list = z == number_of_cells_[2] - 1
270 ? std::initializer_list<SizeType>{0}
271 : std::initializer_list<SizeType>{0, 1};
273 number_of_cells_[1] == 1
274 ? std::initializer_list<SizeType>{0}
275 : y == 0 ? std::initializer_list<SizeType>{0, 1}
276 : y == number_of_cells_[1] - 1
277 ? std::initializer_list<SizeType>{-1, 0}
278 : std::initializer_list<SizeType>{-1, 0, 1};
280 number_of_cells_[0] == 1
281 ? std::initializer_list<SizeType>{0}
282 : x == 0 ? std::initializer_list<SizeType>{0, 1}
283 : x == number_of_cells_[0] - 1
284 ? std::initializer_list<SizeType>{-1, 0}
285 : std::initializer_list<SizeType>{-1, 0, 1};
289 const auto di = make_index(dx, dy, dz);
291 neighbor_cell_callback(search, cells_[search_cell_index + di]);
322 const std::function<
void(
const ParticleList &)> &search_cell_callback,
323 const std::function<
void(
const ParticleList &,
const ParticleList &)>
324 &neighbor_cell_callback)
const {
325 const auto &log = logger<LogArea::Grid>();
327 std::array<SizeType, 3> search_index;
334 std::array<NeighborLookup, 2> dz_list;
335 std::array<NeighborLookup, 3> dy_list;
336 std::array<NeighborLookup, 3> dx_list;
338 assert(number_of_cells_[2] >= 2);
339 assert(number_of_cells_[1] >= 2);
340 assert(number_of_cells_[0] >= 2);
342 for (z = 0; z < number_of_cells_[2]; ++z) {
343 dz_list[0].index = z;
344 dz_list[1].index = z + 1;
345 if (dz_list[1].index == number_of_cells_[2]) {
346 dz_list[1].index = 0;
348 dz_list[1].wrap = NeedsToWrap::MinusLength;
350 for (y = 0; y < number_of_cells_[1]; ++y) {
351 dy_list[0].index = y;
352 dy_list[1].index = y - 1;
353 dy_list[2].index = y + 1;
354 dy_list[2].wrap = NeedsToWrap::No;
356 dy_list[1] = dy_list[2];
357 dy_list[2].index = number_of_cells_[1] - 1;
358 dy_list[2].wrap = NeedsToWrap::PlusLength;
359 }
else if (dy_list[2].index == number_of_cells_[1]) {
360 dy_list[2].index = 0;
361 dy_list[2].wrap = NeedsToWrap::MinusLength;
363 for (x = 0; x < number_of_cells_[0]; ++x, ++search_cell_index) {
364 dx_list[0].index = x;
365 dx_list[1].index = x - 1;
366 dx_list[2].index = x + 1;
367 dx_list[2].wrap = NeedsToWrap::No;
369 dx_list[1] = dx_list[2];
370 dx_list[2].index = number_of_cells_[0] - 1;
371 dx_list[2].wrap = NeedsToWrap::PlusLength;
372 }
else if (dx_list[2].index == number_of_cells_[0]) {
373 dx_list[2].index = 0;
374 dx_list[2].wrap = NeedsToWrap::MinusLength;
377 assert(search_cell_index == make_index(search_index));
378 assert(search_cell_index >= 0);
379 assert(search_cell_index <
SizeType(cells_.size()));
380 ParticleList search = cells_[search_cell_index];
381 search_cell_callback(search);
383 auto virtual_search_index = search_index;
385 auto current_wrap_vector = wrap_vector;
387 for (
const auto &dz : dz_list) {
388 if (dz.wrap == NeedsToWrap::MinusLength) {
390 wrap_vector[2] = -length_[2];
391 virtual_search_index[2] = -1;
393 for (
const auto &dy : dy_list) {
395 if (dy.wrap == NeedsToWrap::MinusLength) {
396 wrap_vector[1] = -length_[1];
397 virtual_search_index[1] = -1;
398 }
else if (dy.wrap == NeedsToWrap::PlusLength) {
399 wrap_vector[1] = length_[1];
400 virtual_search_index[1] = number_of_cells_[1];
402 for (
const auto &dx : dx_list) {
404 if (dx.wrap == NeedsToWrap::MinusLength) {
405 wrap_vector[0] = -length_[0];
406 virtual_search_index[0] = -1;
407 }
else if (dx.wrap == NeedsToWrap::PlusLength) {
408 wrap_vector[0] = length_[0];
409 virtual_search_index[0] = number_of_cells_[0];
411 assert(dx.index >= 0);
412 assert(dx.index < number_of_cells_[0]);
413 assert(dy.index >= 0);
414 assert(dy.index < number_of_cells_[1]);
415 assert(dz.index >= 0);
416 assert(dz.index < number_of_cells_[2]);
417 const auto neighbor_cell_index =
418 make_index(dx.index, dy.index, dz.index);
419 assert(neighbor_cell_index >= 0);
420 assert(neighbor_cell_index <
SizeType(cells_.size()));
421 if (neighbor_cell_index <= make_index(virtual_search_index)) {
425 if (wrap_vector != current_wrap_vector) {
426 log.debug(
"translating search cell by ",
427 wrap_vector - current_wrap_vector);
429 p =
p.translated(wrap_vector - current_wrap_vector);
431 current_wrap_vector = wrap_vector;
433 neighbor_cell_callback(search, cells_[neighbor_cell_index]);
435 virtual_search_index[0] = search_index[0];
438 virtual_search_index[1] = search_index[1];
447 const std::pair<std::array<double, 3>, std::array<double, 3>>
449 const Particles &particles,
double max_interaction_length,
452 const std::pair<std::array<double, 3>, std::array<double, 3>>
454 const Particles &particles,
double max_interaction_length,
NeedsToWrap
The options determining what to do if a particle flies out of the grids PlusLength: Used if a periodi...
The ThreeVector class represents a physical three-vector with the components .
const FourVector & position() const
Get the particle's position in Minkowski space.
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
Generic algorithms on containers and ranges.
int SizeType
A type to store the sizes.
ParticleList copy_to_vector() const
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
UnaryFunction for_each(Container &&c, UnaryFunction &&f)
Convenience wrapper for std::for_each that operates on a complete container.
A strust containing the informations needed to search the neighboring cell.
static std::pair< std::array< double, 3 >, std::array< double, 3 > > find_min_and_length(const Particles &particles)
CellSizeStrategy
Indentifies the strategy of determining the cell size.
The Particles class abstracts the storage and manipulation of particles.
Grid(const Particles &particles, double min_cell_length, CellSizeStrategy strategy=CellSizeStrategy::Optimal)
Constructs a grid from the given particle list particles.
Abstracts a list of cells that partition the particles in the experiment into regions of space that c...
ParticleData contains the dynamic information of a certain particle.