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>>
71 GridBase::find_min_and_length(
const Particles &particles) {
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;
132 const int max_cells =
134 ? std::cbrt(particle_count)
135 : std::max(2, static_cast<int>(std::cbrt(particle_count)));
139 std::array<double, 3> index_factor = {1. / max_interaction_length,
140 1. / max_interaction_length,
141 1. / max_interaction_length};
146 : static_cast<int>(std::floor(
length_[i] * index_factor[i])) +
159 throw std::runtime_error(
160 "Input error: Your Box is too small for the grid." 161 "\nThe minimal length of the box is given by:\n" +
162 std::to_string(max_interaction_length) +
163 " fm with your current timestep size dt.\n" 164 "If you have large timesteps please reduce them." 165 "\nPlease take a look at your config.");
173 index_factor[i] = std::nextafter(index_factor[i], 0.);
182 index_factor[i] = std::nextafter(index_factor[i], 0.);
192 const auto &log = logger<LogArea::Grid>();
202 " cells. Therefore the Grid falls back to a single cell / " 208 std::copy_if(particles.
begin(), particles.
end(),
209 std::back_inserter(
cells_.front()),
215 log.debug(
"min: ", min_position,
"\nlength: ",
length_,
217 "\nindex_factor: ", index_factor);
230 std::floor((
p.position()[1] - min_position[0]) * index_factor[0]),
231 std::floor((
p.position()[2] - min_position[1]) * index_factor[1]),
232 std::floor((
p.position()[3] - min_position[2]) * index_factor[2]));
235 for (
const auto &
p : particles) {
236 if (
p.xsec_scaling_factor(timestep_duration) > 0.0) {
237 const auto idx = cell_index_for(
p);
242 "\nan out-of-bounds access would be necessary for the " 244 p,
"\nfor a grid with the following parameters:\nmin: ",
245 min_position,
"\nlength: ",
length_,
246 "\ncells: ", number_of_cells_,
"\nindex_factor: ", index_factor,
247 "\ncells_.size: ",
cells_.size(),
"\nrequested index: ", idx);
248 throw std::runtime_error(
"out-of-bounds grid access on construction");
259 template <Gr
idOptions Options>
265 static const std::initializer_list<GridBase::SizeType>
ZERO{0};
266 static const std::initializer_list<GridBase::SizeType>
ZERO_ONE{0, 1};
274 const std::function<
void(
const ParticleList &)> &search_cell_callback,
275 const std::function<
void(
const ParticleList &,
const ParticleList &)>
276 &neighbor_cell_callback)
const {
277 std::array<SizeType, 3> search_index;
283 for (y = 0; y < number_of_cells_[1]; ++y) {
284 for (x = 0; x < number_of_cells_[0]; ++x, ++search_cell_index) {
285 assert(search_cell_index ==
make_index(search_index));
286 assert(search_cell_index >= 0);
288 const ParticleList &search =
cells_[search_cell_index];
289 search_cell_callback(search);
291 const auto &dz_list = z == number_of_cells_[2] - 1 ?
ZERO :
ZERO_ONE;
292 const auto &dy_list = number_of_cells_[1] == 1
295 : y == number_of_cells_[1] - 1
298 const auto &dx_list = number_of_cells_[0] == 1
301 : x == number_of_cells_[0] - 1
309 neighbor_cell_callback(search,
cells_[search_cell_index + di]);
340 const std::function<
void(
const ParticleList &)> &search_cell_callback,
341 const std::function<
void(
const ParticleList &,
const ParticleList &)>
342 &neighbor_cell_callback)
const {
343 const auto &log = logger<LogArea::Grid>();
345 std::array<SizeType, 3> search_index;
352 std::array<NeighborLookup, 2> dz_list;
353 std::array<NeighborLookup, 3> dy_list;
354 std::array<NeighborLookup, 3> dx_list;
361 dz_list[0].index = z;
362 dz_list[1].index = z + 1;
363 if (dz_list[1].index == number_of_cells_[2]) {
364 dz_list[1].index = 0;
368 for (y = 0; y < number_of_cells_[1]; ++y) {
369 dy_list[0].index = y;
370 dy_list[1].index = y - 1;
371 dy_list[2].index = y + 1;
374 dy_list[1] = dy_list[2];
375 dy_list[2].index = number_of_cells_[1] - 1;
377 }
else if (dy_list[2].index == number_of_cells_[1]) {
378 dy_list[2].index = 0;
381 for (x = 0; x < number_of_cells_[0]; ++x, ++search_cell_index) {
382 dx_list[0].index = x;
383 dx_list[1].index = x - 1;
384 dx_list[2].index = x + 1;
387 dx_list[1] = dx_list[2];
388 dx_list[2].index = number_of_cells_[0] - 1;
390 }
else if (dx_list[2].index == number_of_cells_[0]) {
391 dx_list[2].index = 0;
395 assert(search_cell_index ==
make_index(search_index));
396 assert(search_cell_index >= 0);
398 ParticleList search =
cells_[search_cell_index];
399 search_cell_callback(search);
401 auto virtual_search_index = search_index;
403 auto current_wrap_vector = wrap_vector;
405 for (
const auto &dz : dz_list) {
409 virtual_search_index[2] = -1;
411 for (
const auto &dy : dy_list) {
415 virtual_search_index[1] = -1;
418 virtual_search_index[1] = number_of_cells_[1];
420 for (
const auto &dx : dx_list) {
424 virtual_search_index[0] = -1;
427 virtual_search_index[0] = number_of_cells_[0];
429 assert(dx.index >= 0);
430 assert(dx.index < number_of_cells_[0]);
431 assert(dy.index >= 0);
432 assert(dy.index < number_of_cells_[1]);
433 assert(dz.index >= 0);
434 assert(dz.index < number_of_cells_[2]);
435 const auto neighbor_cell_index =
437 assert(neighbor_cell_index >= 0);
439 if (neighbor_cell_index <=
make_index(virtual_search_index)) {
443 if (wrap_vector != current_wrap_vector) {
444 log.debug(
"translating search cell by ",
445 wrap_vector - current_wrap_vector);
447 p = p.
translated(wrap_vector - current_wrap_vector);
449 current_wrap_vector = wrap_vector;
451 neighbor_cell_callback(search,
cells_[neighbor_cell_index]);
453 virtual_search_index[0] = search_index[0];
456 virtual_search_index[1] = search_index[1];
465 const std::pair<std::array<double, 3>, std::array<double, 3>>
467 const Particles &particles,
double max_interaction_length,
470 const std::pair<std::array<double, 3>, std::array<double, 3>>
472 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...
ParticleData translated(const ThreeVector &delta) const
Translate the particle position.
With ghost cells for periodic boundaries.
The ThreeVector class represents a physical three-vector with the components .
const FourVector & position() const
Get the particle's position in Minkowski space.
static const std::initializer_list< GridBase::SizeType > ZERO_ONE
std::vector< ParticleList > cells_
The cell storage.
ParticleList copy_to_vector() const
Grid(const Particles &particles, double min_cell_length, double timestep_duration, 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...
#define source_location
Hackery that is required to output the location in the source code where the log statement occurs...
double xsec_scaling_factor(double delta_time=0.) const
Return the cross section scaling factor at a given time.
Generic algorithms on containers and ranges.
std::array< int, 3 > number_of_cells_
The number of cells in x, y, and z direction.
int SizeType
A type to store the sizes.
double cell_volume_
The volume of a single cell.
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.
static const std::initializer_list< GridBase::SizeType > MINUS_ONE_ZERO
static const std::initializer_list< GridBase::SizeType > MINUS_ONE_ZERO_ONE
A strust containing the informations needed to search the neighboring cell.
static const std::initializer_list< GridBase::SizeType > ZERO
CellSizeStrategy
Indentifies the strategy of determining the cell size.
The Particles class abstracts the storage and manipulation of particles.
Abstracts a list of cells that partition the particles in the experiment into regions of space that c...
Make cells as large as possible.
SizeType make_index(SizeType x, SizeType y, SizeType z) const
const std::array< double, 3 > length_
The 3 lengths of the complete grid. Used for periodic boundary wrapping.
ParticleData contains the dynamic information of a certain particle.