27 static std::ostream &operator<<(std::ostream &out,
const std::vector<T> &v) {
28 auto column = out.tellp();
30 for (
const auto &x : v) {
31 if (out.tellp() - column >= 100) {
46 static std::ostream &operator<<(std::ostream &out,
47 const std::initializer_list<T> &v) {
48 auto column = out.tellp();
50 for (
const auto &x : v) {
51 if (out.tellp() - column >= 100) {
65 template <
typename T, std::
size_t N>
66 static std::ostream &operator<<(std::ostream &out,
const std::array<T, N> &a) {
67 auto column = out.tellp();
69 for (
const auto &x : a) {
70 if (out.tellp() - column >= 100) {
81 static constexpr
int LGrid = LogArea::Grid::id;
86 std::pair<std::array<double, 3>, std::array<double, 3>>
88 std::pair<std::array<double, 3>, std::array<double, 3>> r;
89 auto &min_position = r.first;
90 auto &length = r.second;
95 min_position = {{first_position[1], first_position[2], first_position[3]}};
96 auto max_position = min_position;
97 for (
const auto &
p : particles) {
98 const auto &pos =
p.position();
99 min_position[0] = std::min(min_position[0], pos[1]);
100 min_position[1] = std::min(min_position[1], pos[2]);
101 min_position[2] = std::min(min_position[2], pos[3]);
102 max_position[0] = std::max(max_position[0], pos[1]);
103 max_position[1] = std::max(max_position[1], pos[2]);
104 max_position[2] = std::max(max_position[2], pos[3]);
106 length[0] = max_position[0] - min_position[0];
107 length[1] = max_position[1] - min_position[1];
108 length[2] = max_position[2] - min_position[2];
115 template <Gr
idOptions O>
118 const Particles &particles,
double max_interaction_length,
121 : length_(min_and_length.second) {
122 const auto min_position = min_and_length.first;
142 const int max_cells =
144 ? std::cbrt(particle_count)
145 : std::max(2,
static_cast<int>(std::cbrt(particle_count)));
150 std::array<double, 3> index_factor = {1. / max_interaction_length,
151 1. / max_interaction_length,
152 1. / max_interaction_length};
157 std::numeric_limits<int>::max() / index_factor[i])) {
158 throw std::overflow_error(
159 "An integer overflow would occur constructing the system grid.\n"
160 "Impossible to (further) simulate the provided system using "
162 "Refer to the user guide for more information (see the Modi "
166 static_cast<int>(std::floor(
length_[i] * index_factor[i]));
178 std::string error_box_too_small =
179 "Input error: With the chosen time step (Delta_Time), your box is\n"
180 "too small for the grid. Using the provided time step, the minimal\n"
181 "length of the box should be " +
182 std::to_string(2 * max_interaction_length) +
183 "fm. Using a smaller time step\n"
184 "will reduce the minimal needed box size. The use of test particles\n"
185 "also helps reducing the minimum needed size. Have a look to the\n"
186 "user guide (e.g. box modus page) for further information.\n"
187 "Please, adjust your config file and run SMASH again.";
188 throw std::runtime_error(error_box_too_small);
196 if (
length_[i] >= max_interaction_length) {
201 index_factor[i] = std::nextafter(index_factor[i], 0.);
217 " cells. Therefore the Grid falls back to a single cell / "
221 if (include_unformed_particles) {
229 std::copy_if(particles.
begin(), particles.
end(),
230 std::back_inserter(
cells_.front()),
231 [&](
const ParticleData &
p) {
232 return p.xsec_scaling_factor(timestep_duration) > 0.0;
245 "\nindex_factor: ", index_factor);
256 auto &&cell_index_for = [&](
const ParticleData &
p) {
258 std::floor((
p.position()[1] - min_position[0]) * index_factor[0]),
259 std::floor((
p.position()[2] - min_position[1]) * index_factor[1]),
260 std::floor((
p.position()[3] - min_position[2]) * index_factor[2]));
262 for (
const auto &
p : particles) {
263 if (!include_unformed_particles &&
264 (
p.xsec_scaling_factor(timestep_duration) <= 0.0)) {
267 const auto idx = cell_index_for(
p);
272 "\nan out-of-bounds access would be necessary for the "
275 "\nfor a grid with the following parameters:\nmin: ", min_position,
277 "\nindex_factor: ", index_factor,
"\ncells_.size: ",
cells_.size(),
278 "\nrequested index: ", idx);
279 throw std::runtime_error(
"out-of-bounds grid access on construction");
289 template <Gr
idOptions Options>
292 return (z * number_of_cells_[1] + y) * number_of_cells_[0] + x;
295 static const std::initializer_list<GridBase::SizeType>
ZERO{0};
296 static const std::initializer_list<GridBase::SizeType>
ZERO_ONE{0, 1};
304 const std::function<
void(
const ParticleList &)> &search_cell_callback,
305 const std::function<
void(
const ParticleList &,
const ParticleList &)>
306 &neighbor_cell_callback)
const {
307 std::array<SizeType, 3> search_index;
312 for (z = 0; z < number_of_cells_[2]; ++z) {
313 for (y = 0; y < number_of_cells_[1]; ++y) {
314 for (x = 0; x < number_of_cells_[0]; ++x, ++search_cell_index) {
315 assert(search_cell_index == make_index(search_index));
316 assert(search_cell_index >= 0);
317 assert(search_cell_index <
SizeType(cells_.size()));
318 const ParticleList &search = cells_[search_cell_index];
319 search_cell_callback(search);
321 const auto &dz_list = z == number_of_cells_[2] - 1 ?
ZERO :
ZERO_ONE;
322 const auto &dy_list = number_of_cells_[1] == 1 ?
ZERO
324 : y == number_of_cells_[1] - 1
327 const auto &dx_list = number_of_cells_[0] == 1 ?
ZERO
329 : x == number_of_cells_[0] - 1
335 const auto di = make_index(dx, dy, dz);
337 neighbor_cell_callback(search, cells_[search_cell_index + di]);
368 const std::function<
void(
const ParticleList &)> &search_cell_callback,
369 const std::function<
void(
const ParticleList &,
const ParticleList &)>
370 &neighbor_cell_callback)
const {
371 std::array<SizeType, 3> search_index;
378 std::array<NeighborLookup, 2> dz_list;
379 std::array<NeighborLookup, 3> dy_list;
380 std::array<NeighborLookup, 3> dx_list;
382 assert(number_of_cells_[2] >= 2);
383 assert(number_of_cells_[1] >= 2);
384 assert(number_of_cells_[0] >= 2);
386 for (z = 0; z < number_of_cells_[2]; ++z) {
387 dz_list[0].index = z;
388 dz_list[1].index = z + 1;
389 if (dz_list[1].index == number_of_cells_[2]) {
390 dz_list[1].index = 0;
392 dz_list[1].wrap = NeedsToWrap::MinusLength;
394 for (y = 0; y < number_of_cells_[1]; ++y) {
395 dy_list[0].index = y;
396 dy_list[1].index = y - 1;
397 dy_list[2].index = y + 1;
398 dy_list[2].wrap = NeedsToWrap::No;
400 dy_list[1] = dy_list[2];
401 dy_list[2].index = number_of_cells_[1] - 1;
402 dy_list[2].wrap = NeedsToWrap::PlusLength;
403 }
else if (dy_list[2].index == number_of_cells_[1]) {
404 dy_list[2].index = 0;
405 dy_list[2].wrap = NeedsToWrap::MinusLength;
407 for (x = 0; x < number_of_cells_[0]; ++x, ++search_cell_index) {
408 dx_list[0].index = x;
409 dx_list[1].index = x - 1;
410 dx_list[2].index = x + 1;
411 dx_list[2].wrap = NeedsToWrap::No;
413 dx_list[1] = dx_list[2];
414 dx_list[2].index = number_of_cells_[0] - 1;
415 dx_list[2].wrap = NeedsToWrap::PlusLength;
416 }
else if (dx_list[2].index == number_of_cells_[0]) {
417 dx_list[2].index = 0;
418 dx_list[2].wrap = NeedsToWrap::MinusLength;
421 assert(search_cell_index == make_index(search_index));
422 assert(search_cell_index >= 0);
423 assert(search_cell_index <
SizeType(cells_.size()));
424 ParticleList search = cells_[search_cell_index];
425 search_cell_callback(search);
427 auto virtual_search_index = search_index;
429 auto current_wrap_vector = wrap_vector;
431 for (
const auto &dz : dz_list) {
432 if (dz.wrap == NeedsToWrap::MinusLength) {
434 wrap_vector[2] = -length_[2];
435 virtual_search_index[2] = -1;
437 for (
const auto &dy : dy_list) {
439 if (dy.wrap == NeedsToWrap::MinusLength) {
440 wrap_vector[1] = -length_[1];
441 virtual_search_index[1] = -1;
442 }
else if (dy.wrap == NeedsToWrap::PlusLength) {
443 wrap_vector[1] = length_[1];
444 virtual_search_index[1] = number_of_cells_[1];
446 for (
const auto &dx : dx_list) {
448 if (dx.wrap == NeedsToWrap::MinusLength) {
449 wrap_vector[0] = -length_[0];
450 virtual_search_index[0] = -1;
451 }
else if (dx.wrap == NeedsToWrap::PlusLength) {
452 wrap_vector[0] = length_[0];
453 virtual_search_index[0] = number_of_cells_[0];
455 assert(dx.index >= 0);
456 assert(dx.index < number_of_cells_[0]);
457 assert(dy.index >= 0);
458 assert(dy.index < number_of_cells_[1]);
459 assert(dz.index >= 0);
460 assert(dz.index < number_of_cells_[2]);
461 const auto neighbor_cell_index =
462 make_index(dx.index, dy.index, dz.index);
463 assert(neighbor_cell_index >= 0);
464 assert(neighbor_cell_index <
SizeType(cells_.size()));
465 if (neighbor_cell_index <= make_index(virtual_search_index)) {
469 if (wrap_vector != current_wrap_vector) {
470 logg[
LGrid].debug(
"translating search cell by ",
471 wrap_vector - current_wrap_vector);
473 p =
p.translated(wrap_vector - current_wrap_vector);
475 current_wrap_vector = wrap_vector;
477 neighbor_cell_callback(search, cells_[neighbor_cell_index]);
479 virtual_search_index[0] = search_index[0];
482 virtual_search_index[1] = search_index[1];
491 const std::pair<std::array<double, 3>, std::array<double, 3>>
493 const Particles &particles,
double max_interaction_length,
497 const std::pair<std::array<double, 3>, std::array<double, 3>>
499 const Particles &particles,
double max_interaction_length,
Generic algorithms on containers and ranges.
int SizeType
A type to store the sizes.
static std::pair< std::array< double, 3 >, std::array< double, 3 > > find_min_and_length(const Particles &particles)
Abstracts a list of cells that partition the particles in the experiment into regions of space that c...
const std::array< double, 3 > length_
The 3 lengths of the complete grid. Used for periodic boundary wrapping.
std::array< int, 3 > number_of_cells_
The number of cells in x, y, and z direction.
double cell_volume_
The volume of a single cell.
std::vector< ParticleList > cells_
The cell storage.
Grid(const Particles &particles, double min_cell_length, double timestep_duration, CellNumberLimitation limit, const bool include_unformed_particles=false, CellSizeStrategy strategy=CellSizeStrategy::Optimal)
Constructs a grid from the given particle list particles.
void iterate_cells(const std::function< void(const ParticleList &)> &search_cell_callback, const std::function< void(const ParticleList &, const ParticleList &)> &neighbor_cell_callback) const
Iterates over all cells in the grid and calls the callback arguments with a search cell and 0 to 13 n...
SizeType make_index(SizeType x, SizeType y, SizeType z) const
ParticleData contains the dynamic information of a certain particle.
const FourVector & position() const
Get the particle's position in Minkowski space.
The Particles class abstracts the storage and manipulation of particles.
ParticleList copy_to_vector() const
The ThreeVector class represents a physical three-vector with the components .
#define SMASH_SOURCE_LOCATION
Hackery that is required to output the location in the source code where the log statement occurs.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
#define unlikely(x)
Tell the branch predictor that this expression is likely false.
static const std::initializer_list< GridBase::SizeType > ZERO_ONE
UnaryFunction for_each(Container &&c, UnaryFunction &&f)
Convenience wrapper for std::for_each that operates on a complete container.
NeedsToWrap
The options determining what to do if a particle flies out of the grids PlusLength: Used if a periodi...
CellNumberLimitation
Identifies whether the number of cells should be limited.
@ ParticleNumber
Limit the number of cells to the number of particles.
bool all_of(Container &&c, UnaryPredicate &&p)
Convenience wrapper for std::all_of that operates on a complete container.
@ Normal
Without ghost cells.
@ PeriodicBoundaries
With ghost cells for periodic boundaries.
static const std::initializer_list< GridBase::SizeType > MINUS_ONE_ZERO
static const std::initializer_list< GridBase::SizeType > ZERO
static constexpr int LGrid
CellSizeStrategy
Indentifies the strategy of determining the cell size.
@ Largest
Make cells as large as possible.
static const std::initializer_list< GridBase::SizeType > MINUS_ONE_ZERO_ONE
A strust containing the informations needed to search the neighboring cell.
Grid< GridOptions::PeriodicBoundaries >::SizeType index
Index of the cell.
NeedsToWrap wrap
Option to determine the neighbors of the cells on the boundary.