File indexing completed on 2026-05-27 07:23:56
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/definitions/algebra.hpp"
0013 #include "detray/definitions/containers.hpp"
0014 #include "detray/definitions/units.hpp"
0015 #include "detray/geometry/concepts.hpp"
0016 #include "detray/geometry/mask.hpp"
0017 #include "detray/geometry/shapes.hpp"
0018 #include "detray/utils/grid/axis.hpp"
0019 #include "detray/utils/grid/concepts.hpp"
0020 #include "detray/utils/grid/detail/axis_helpers.hpp"
0021 #include "detray/utils/grid/grid.hpp"
0022 #include "detray/utils/grid/grid_collection.hpp"
0023 #include "detray/utils/grid/populators.hpp"
0024 #include "detray/utils/grid/serializers.hpp"
0025
0026
0027 #include <vecmem/memory/memory_resource.hpp>
0028
0029
0030 #include <cassert>
0031 #include <iostream>
0032 #include <string>
0033 #include <type_traits>
0034
0035 namespace detray {
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 template <typename bin_t, template <std::size_t> class serializer_t,
0049 concepts::algebra algebra_t>
0050 class grid_factory {
0051 public:
0052
0053 static constexpr bool is_owning = true;
0054
0055 using bin_type = bin_t;
0056 template <typename grid_shape_t>
0057 using grid_type = grid<algebra_t, axes<grid_shape_t>, bin_type, serializer_t>;
0058 template <typename grid_shape_t>
0059 using loc_bin_index = typename grid_type<grid_shape_t>::loc_bin_index;
0060
0061 using scalar_type = dscalar<algebra_t>;
0062 template <typename T>
0063 using vector_type = host_container_types::template vector_type<T>;
0064 using algebra_type = algebra_t;
0065
0066 grid_factory() = default;
0067
0068
0069 explicit grid_factory(vecmem::memory_resource &resource)
0070 : m_resource(&resource) {}
0071
0072
0073
0074
0075 template <
0076 typename r_bounds = axis::closed<axis::label::e_r>,
0077 typename phi_bounds = axis::circular<>,
0078 typename r_binning = axis::regular<scalar_type, host_container_types>,
0079 typename phi_binning = axis::regular<scalar_type, host_container_types>>
0080 requires std::is_enum_v<decltype(r_bounds::label)>
0081 auto new_grid(const mask<annulus2D, algebra_type> &grid_bounds,
0082 const darray<std::size_t, 2UL> n_bins,
0083 const std::vector<std::pair<loc_bin_index<annulus2D>, dindex>>
0084 &bin_capacities = {},
0085 const darray<std::vector<scalar_type>, 2UL> &bin_edges =
0086 darray<std::vector<scalar_type>, 2UL>(),
0087 const darray<std::vector<scalar_type>, 2UL> &axis_spans =
0088 darray<std::vector<scalar_type>, 2UL>()) const {
0089 static_assert(
0090 std::is_same_v<phi_bounds, axis::circular<>>,
0091 "Phi axis bounds need to be circular for stereo annulus shape");
0092
0093
0094 using boundary = annulus2D::boundaries;
0095 using axes_t = axes<annulus2D>::template type<algebra_t>;
0096 using local_frame = typename axes_t::template frame<algebra_t>;
0097
0098 constexpr auto e_r_axis = static_cast<dindex>(axes_t::label0);
0099 constexpr auto e_phi_axis = static_cast<dindex>(axes_t::label1);
0100
0101 auto b_values = grid_bounds.values();
0102
0103 if (!axis_spans[0UL].empty()) {
0104 assert(axis_spans[0UL].size() == 2UL);
0105 b_values[boundary::e_min_r] = axis_spans[0UL].at(0UL);
0106 b_values[boundary::e_max_r] = axis_spans[0UL].at(1UL);
0107 }
0108 scalar_type min_phi =
0109 b_values[boundary::e_average_phi] - b_values[boundary::e_min_phi_rel];
0110 scalar_type max_phi =
0111 b_values[boundary::e_average_phi] + b_values[boundary::e_max_phi_rel];
0112 if (!axis_spans[1UL].empty()) {
0113 assert(axis_spans[1UL].size() == 2UL);
0114 min_phi = axis_spans[1UL].at(0UL);
0115 max_phi = axis_spans[1UL].at(1UL);
0116 }
0117
0118 return new_grid<local_frame>(
0119 {b_values[boundary::e_min_r], b_values[boundary::e_max_r], min_phi,
0120 max_phi},
0121 {n_bins[e_r_axis], n_bins[e_phi_axis]}, bin_capacities,
0122 {bin_edges[e_r_axis], bin_edges[e_phi_axis]},
0123 types::list<r_bounds, phi_bounds>{},
0124 types::list<r_binning, phi_binning>{});
0125 }
0126
0127
0128
0129
0130 template <
0131 typename x_bounds = axis::closed<axis::label::e_x>,
0132 typename y_bounds = axis::closed<axis::label::e_y>,
0133 typename z_bounds = axis::closed<axis::label::e_z>,
0134 typename x_binning = axis::regular<scalar_type, host_container_types>,
0135 typename y_binning = axis::regular<scalar_type, host_container_types>,
0136 typename z_binning = axis::regular<scalar_type, host_container_types>>
0137 requires std::is_enum_v<decltype(x_bounds::label)>
0138 auto new_grid(const mask<cuboid3D, algebra_type> &grid_bounds,
0139 const darray<std::size_t, 3UL> n_bins,
0140 const std::vector<std::pair<loc_bin_index<cuboid3D>, dindex>>
0141 &bin_capacities = {},
0142 const darray<std::vector<scalar_type>, 3UL> &bin_edges =
0143 darray<std::vector<scalar_type>, 3UL>(),
0144 const darray<std::vector<scalar_type>, 3UL> &axis_spans =
0145 darray<std::vector<scalar_type>, 3UL>()) const {
0146
0147 using boundary = cuboid3D::boundaries;
0148 using axes_t = axes<cuboid3D>::template type<algebra_t>;
0149 using local_frame = typename axes_t::template frame<algebra_t>;
0150
0151 constexpr auto e_x_axis = static_cast<dindex>(axes_t::label0);
0152 constexpr auto e_y_axis = static_cast<dindex>(axes_t::label1);
0153 constexpr auto e_z_axis = static_cast<dindex>(axes_t::label2);
0154
0155
0156 auto b_values = grid_bounds.values();
0157 if (!axis_spans[0UL].empty()) {
0158 assert(axis_spans[0UL].size() == 2UL);
0159 b_values[boundary::e_min_x] = axis_spans[0UL].at(0UL);
0160 b_values[boundary::e_max_x] = axis_spans[0UL].at(1UL);
0161 }
0162 if (!axis_spans[1UL].empty()) {
0163 assert(axis_spans[1UL].size() == 2UL);
0164 b_values[boundary::e_min_y] = axis_spans[1UL].at(0UL);
0165 b_values[boundary::e_max_y] = axis_spans[1UL].at(1UL);
0166 }
0167 if (!axis_spans[2UL].empty()) {
0168 assert(axis_spans[2UL].size() == 2UL);
0169 b_values[boundary::e_min_z] = axis_spans[2UL].at(0UL);
0170 b_values[boundary::e_max_z] = axis_spans[2UL].at(1UL);
0171 }
0172
0173 return new_grid<local_frame>(
0174 {b_values[boundary::e_min_x], b_values[boundary::e_max_x],
0175 b_values[boundary::e_min_y], b_values[boundary::e_max_y],
0176 b_values[boundary::e_min_z], b_values[boundary::e_max_z]},
0177 {n_bins[e_x_axis], n_bins[e_y_axis], n_bins[e_z_axis]}, bin_capacities,
0178 {bin_edges[e_x_axis], bin_edges[e_y_axis], bin_edges[e_z_axis]},
0179 types::list<x_bounds, y_bounds, z_bounds>{},
0180 types::list<x_binning, y_binning, z_binning>{});
0181 }
0182
0183
0184
0185
0186 template <
0187 typename rphi_bounds = axis::circular<axis::label::e_rphi>,
0188 typename z_bounds = axis::closed<axis::label::e_cyl_z>,
0189 typename rphi_binning = axis::regular<scalar_type, host_container_types>,
0190 typename z_binning = axis::regular<scalar_type, host_container_types>>
0191 requires std::is_enum_v<decltype(rphi_bounds::label)>
0192 auto new_grid(const mask<cylinder2D, algebra_type> &grid_bounds,
0193 const darray<std::size_t, 2UL> n_bins,
0194 const std::vector<std::pair<loc_bin_index<cylinder2D>, dindex>>
0195 &bin_capacities = {},
0196 const darray<std::vector<scalar_type>, 2UL> &bin_edges =
0197 darray<std::vector<scalar_type>, 2UL>(),
0198 const darray<std::vector<scalar_type>, 2UL> &axis_spans =
0199 darray<std::vector<scalar_type>, 2UL>()) const {
0200 static_assert(
0201 std::is_same_v<rphi_bounds, axis::circular<axis::label::e_rphi>>,
0202 "Phi axis bounds need to be circular for cylinder2D shape");
0203
0204
0205 using boundary = cylinder2D::boundaries;
0206 using axes_t = axes<cylinder2D>::template type<algebra_t>;
0207 using local_frame = typename axes_t::template frame<algebra_t>;
0208
0209 constexpr auto e_rphi_axis = static_cast<dindex>(axes_t::label0);
0210 constexpr auto e_z_axis = static_cast<dindex>(axes_t::label1);
0211
0212 auto b_values = grid_bounds.values();
0213 if (!axis_spans[1UL].empty()) {
0214 assert(axis_spans[1UL].size() == 2UL);
0215 b_values[boundary::e_lower_z] = axis_spans[1UL].at(0UL);
0216 b_values[boundary::e_upper_z] = axis_spans[1UL].at(1UL);
0217 }
0218 return new_grid<local_frame>(
0219 {-constant<scalar_type>::pi, constant<scalar_type>::pi,
0220 b_values[boundary::e_lower_z], b_values[boundary::e_upper_z]},
0221 {n_bins[e_rphi_axis], n_bins[e_z_axis]}, bin_capacities,
0222 {bin_edges[e_rphi_axis], bin_edges[e_z_axis]},
0223 types::list<rphi_bounds, z_bounds>{},
0224 types::list<rphi_binning, z_binning>{});
0225 }
0226
0227
0228
0229
0230 template <
0231 typename rphi_bounds = axis::circular<axis::label::e_rphi>,
0232 typename z_bounds = axis::closed<axis::label::e_cyl_z>,
0233 typename rphi_binning = axis::regular<scalar_type, host_container_types>,
0234 typename z_binning = axis::regular<scalar_type, host_container_types>>
0235 requires std::is_enum_v<decltype(rphi_bounds::label)>
0236 auto new_grid(
0237 const mask<concentric_cylinder2D, algebra_type> &grid_bounds,
0238 const darray<std::size_t, 2UL> n_bins,
0239 const std::vector<std::pair<loc_bin_index<concentric_cylinder2D>, dindex>>
0240 &bin_capacities = {},
0241 const darray<std::vector<scalar_type>, 2UL> &bin_edges =
0242 darray<std::vector<scalar_type>, 2UL>(),
0243 const darray<std::vector<scalar_type>, 2UL> &axis_spans =
0244 darray<std::vector<scalar_type>, 2UL>()) const {
0245 static_assert(
0246 std::is_same_v<rphi_bounds, axis::circular<axis::label::e_rphi>>,
0247 "Phi axis bounds need to be circular for cylinder2D portal shape");
0248
0249
0250 using boundary = concentric_cylinder2D::boundaries;
0251 using axes_t = axes<concentric_cylinder2D>::template type<algebra_t>;
0252 using local_frame = typename axes_t::template frame<algebra_t>;
0253
0254 constexpr auto e_rphi_axis = static_cast<dindex>(axes_t::label0);
0255 constexpr auto e_z_axis = static_cast<dindex>(axes_t::label1);
0256
0257 auto b_values = grid_bounds.values();
0258 if (!axis_spans[1UL].empty()) {
0259 assert(axis_spans[1UL].size() == 2UL);
0260 b_values[boundary::e_lower_z] = axis_spans[1UL].at(0UL);
0261 b_values[boundary::e_upper_z] = axis_spans[1UL].at(1UL);
0262 }
0263
0264 return new_grid<local_frame>(
0265 {-constant<scalar_type>::pi, constant<scalar_type>::pi,
0266 b_values[boundary::e_lower_z], b_values[boundary::e_upper_z]},
0267 {n_bins[e_rphi_axis], n_bins[e_z_axis]}, bin_capacities,
0268 {bin_edges[e_rphi_axis], bin_edges[e_z_axis]},
0269 types::list<rphi_bounds, z_bounds>{},
0270 types::list<rphi_binning, z_binning>{});
0271 }
0272
0273
0274
0275
0276 template <
0277 typename r_bounds = axis::closed<axis::label::e_r>,
0278 typename phi_bounds = axis::circular<>,
0279 typename z_bounds = axis::closed<axis::label::e_z>,
0280 typename r_binning = axis::regular<scalar_type, host_container_types>,
0281 typename phi_binning = axis::regular<scalar_type, host_container_types>,
0282 typename z_binning = axis::regular<scalar_type, host_container_types>>
0283 requires std::is_enum_v<decltype(r_bounds::label)>
0284 auto new_grid(const mask<cylinder3D, algebra_type> &grid_bounds,
0285 const darray<std::size_t, 3UL> n_bins,
0286 const std::vector<std::pair<loc_bin_index<cylinder3D>, dindex>>
0287 &bin_capacities = {},
0288 const darray<std::vector<scalar_type>, 3UL> &bin_edges =
0289 darray<std::vector<scalar_type>, 3UL>(),
0290 const darray<std::vector<scalar_type>, 3UL> &axis_spans =
0291 darray<std::vector<scalar_type>, 3UL>()) const {
0292 static_assert(std::is_same_v<phi_bounds, axis::circular<>>,
0293 "Phi axis bounds need to be circular for cylinder3D shape");
0294
0295
0296 using boundary = cylinder3D::boundaries;
0297 using axes_t = axes<cylinder3D>::template type<algebra_t>;
0298 using local_frame = typename axes_t::template frame<algebra_t>;
0299
0300 constexpr auto e_r_axis = static_cast<dindex>(axes_t::label0);
0301 constexpr auto e_phi_axis = static_cast<dindex>(axes_t::label1);
0302 constexpr auto e_z_axis = static_cast<dindex>(axes_t::label2);
0303
0304 auto b_values = grid_bounds.values();
0305
0306
0307 if (!axis_spans[0UL].empty()) {
0308 assert(axis_spans[0UL].size() == 2UL);
0309 b_values[boundary::e_min_r] = axis_spans[0UL].at(0UL);
0310 b_values[boundary::e_max_r] = axis_spans[0UL].at(1UL);
0311 }
0312 scalar_type min_phi = -constant<scalar_type>::pi;
0313 scalar_type max_phi = constant<scalar_type>::pi;
0314 if (!axis_spans[1UL].empty()) {
0315 assert(axis_spans[1UL].size() == 2UL);
0316 min_phi = axis_spans[1UL].at(0UL);
0317 max_phi = axis_spans[1UL].at(1UL);
0318 }
0319 if (!axis_spans[2UL].empty()) {
0320 assert(axis_spans[2UL].size() == 2UL);
0321 b_values[boundary::e_min_z] = axis_spans[2UL].at(0UL);
0322 b_values[boundary::e_max_z] = axis_spans[2UL].at(1UL);
0323 }
0324
0325 return new_grid<local_frame>(
0326 {b_values[boundary::e_min_r], b_values[boundary::e_max_r], min_phi,
0327 max_phi, -b_values[boundary::e_min_z], b_values[boundary::e_max_z]},
0328 {n_bins[e_r_axis], n_bins[e_phi_axis], n_bins[e_z_axis]},
0329 bin_capacities,
0330 {bin_edges[e_r_axis], bin_edges[e_phi_axis], bin_edges[e_z_axis]},
0331 types::list<r_bounds, phi_bounds, z_bounds>{},
0332 types::list<r_binning, phi_binning, z_binning>{});
0333 }
0334
0335
0336
0337
0338 template <
0339 typename r_bounds = axis::closed<axis::label::e_r>,
0340 typename phi_bounds = axis::circular<>,
0341 typename r_binning = axis::regular<scalar_type, host_container_types>,
0342 typename phi_binning = axis::regular<scalar_type, host_container_types>>
0343 requires std::is_enum_v<decltype(r_bounds::label)>
0344 auto new_grid(const mask<ring2D, algebra_type> &grid_bounds,
0345 const darray<std::size_t, 2UL> n_bins,
0346 const std::vector<std::pair<loc_bin_index<ring2D>, dindex>>
0347 &bin_capacities = {},
0348 const darray<std::vector<scalar_type>, 2UL> &bin_edges =
0349 darray<std::vector<scalar_type>, 2UL>(),
0350 const darray<std::vector<scalar_type>, 2UL> &axis_spans =
0351 darray<std::vector<scalar_type>, 2UL>()) const {
0352 static_assert(std::is_same_v<phi_bounds, axis::circular<>>,
0353 "Phi axis bounds need to be circular for ring shape");
0354
0355
0356 using boundary = ring2D::boundaries;
0357 using axes_t = axes<ring2D>::template type<algebra_t>;
0358 using local_frame = typename axes_t::template frame<algebra_t>;
0359
0360 constexpr auto e_r_axis = static_cast<dindex>(axes_t::label0);
0361 constexpr auto e_phi_axis = static_cast<dindex>(axes_t::label1);
0362
0363 auto b_values = grid_bounds.values();
0364
0365 if (!axis_spans[0UL].empty()) {
0366 assert(axis_spans[0UL].size() == 2UL);
0367 b_values[boundary::e_inner_r] = axis_spans[0UL].at(0UL);
0368 b_values[boundary::e_outer_r] = axis_spans[0UL].at(1UL);
0369 }
0370
0371 return new_grid<local_frame>(
0372 {b_values[boundary::e_inner_r], b_values[boundary::e_outer_r],
0373 -constant<scalar_type>::pi, constant<scalar_type>::pi},
0374 {n_bins[e_r_axis], n_bins[e_phi_axis]}, bin_capacities,
0375 {bin_edges[e_r_axis], bin_edges[e_phi_axis]},
0376 types::list<r_bounds, phi_bounds>{},
0377 types::list<r_binning, phi_binning>{});
0378 }
0379
0380
0381
0382
0383 template <
0384 typename x_bounds = axis::closed<axis::label::e_x>,
0385 typename y_bounds = axis::closed<axis::label::e_y>,
0386 typename x_binning = axis::regular<scalar_type, host_container_types>,
0387 typename y_binning = axis::regular<scalar_type, host_container_types>>
0388 requires std::is_enum_v<decltype(x_bounds::label)>
0389 auto new_grid(const mask<rectangle2D, algebra_type> &grid_bounds,
0390 const darray<std::size_t, 2UL> n_bins,
0391 const std::vector<std::pair<loc_bin_index<rectangle2D>, dindex>>
0392 &bin_capacities = {},
0393 const darray<std::vector<scalar_type>, 2UL> &bin_edges =
0394 darray<std::vector<scalar_type>, 2UL>(),
0395 const darray<std::vector<scalar_type>, 2UL> &axis_spans =
0396 darray<std::vector<scalar_type>, 2UL>()) const {
0397
0398 using boundary = rectangle2D::boundaries;
0399 using axes_t = axes<rectangle2D>::template type<algebra_t>;
0400 using local_frame = typename axes_t::template frame<algebra_t>;
0401
0402 constexpr auto e_x_axis = static_cast<dindex>(axes_t::label0);
0403 constexpr auto e_y_axis = static_cast<dindex>(axes_t::label1);
0404
0405 auto b_values = grid_bounds.values();
0406
0407 if (!axis_spans[0UL].empty()) {
0408 assert(axis_spans[0UL].size() == 2UL);
0409 b_values[boundary::e_half_x] = axis_spans[0UL].at(1UL);
0410 }
0411 if (!axis_spans[1UL].empty()) {
0412 assert(axis_spans[1UL].size() == 2UL);
0413 b_values[boundary::e_half_y] = axis_spans[1UL].at(1UL);
0414 }
0415
0416 return new_grid<local_frame>(
0417 {-b_values[boundary::e_half_x], b_values[boundary::e_half_x],
0418 -b_values[boundary::e_half_y], b_values[boundary::e_half_y]},
0419 {n_bins[e_x_axis], n_bins[e_y_axis]}, bin_capacities,
0420 {bin_edges[e_x_axis], bin_edges[e_y_axis]},
0421 types::list<x_bounds, y_bounds>{}, types::list<x_binning, y_binning>{});
0422 }
0423
0424
0425
0426
0427 template <
0428 typename x_bounds = axis::closed<axis::label::e_x>,
0429 typename y_bounds = axis::closed<axis::label::e_y>,
0430 typename x_binning = axis::regular<scalar_type, host_container_types>,
0431 typename y_binning = axis::regular<scalar_type, host_container_types>>
0432 requires std::is_enum_v<decltype(x_bounds::label)>
0433 auto new_grid(const mask<trapezoid2D, algebra_type> &grid_bounds,
0434 const darray<std::size_t, 2UL> n_bins,
0435 const std::vector<std::pair<loc_bin_index<trapezoid2D>, dindex>>
0436 &bin_capacities = {},
0437 const darray<std::vector<scalar_type>, 2UL> &bin_edges =
0438 darray<std::vector<scalar_type>, 2UL>(),
0439 const darray<std::vector<scalar_type>, 2UL> &axis_spans =
0440 darray<std::vector<scalar_type>, 2UL>()) const {
0441
0442 using boundary = trapezoid2D::boundaries;
0443 using axes_t = axes<trapezoid2D>::template type<algebra_t>;
0444 using local_frame = typename axes_t::template frame<algebra_t>;
0445
0446 constexpr auto e_x_axis = static_cast<dindex>(axes_t::label0);
0447 constexpr auto e_y_axis = static_cast<dindex>(axes_t::label1);
0448
0449 auto b_values = grid_bounds.values();
0450
0451 if (!axis_spans[0UL].empty()) {
0452 assert(axis_spans[0UL].size() == 2UL);
0453 b_values[boundary::e_half_length_1] = axis_spans[0UL].at(1UL);
0454 }
0455 if (!axis_spans[1UL].empty()) {
0456 assert(axis_spans[1UL].size() == 2UL);
0457 b_values[boundary::e_half_length_2] = axis_spans[1UL].at(1UL);
0458 }
0459
0460 return new_grid<local_frame>(
0461 {-b_values[boundary::e_half_length_1],
0462 b_values[boundary::e_half_length_1],
0463 -b_values[boundary::e_half_length_2],
0464 b_values[boundary::e_half_length_2]},
0465 {n_bins[e_x_axis], n_bins[e_y_axis]}, bin_capacities,
0466 {bin_edges[e_x_axis], bin_edges[e_y_axis]},
0467 types::list<x_bounds, y_bounds>{}, types::list<x_binning, y_binning>{});
0468 }
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485 template <concepts::coordinate_frame grid_frame_t, typename... bound_ts,
0486 typename... binning_ts>
0487 auto new_grid(
0488 const std::vector<scalar_type> &spans,
0489 const std::vector<std::size_t> &n_bins,
0490 const std::vector<std::pair<axis::multi_bin<sizeof...(bound_ts)>, dindex>>
0491 &bin_capacities = {},
0492 const std::vector<std::vector<scalar_type>> &ax_bin_edges = {},
0493 const types::list<bound_ts...> & = {},
0494 const types::list<binning_ts...> & = {}) const {
0495 static_assert(sizeof...(bound_ts) == sizeof...(binning_ts),
0496 "number of axis bounds and binning types has to match");
0497
0498
0499 using axes_t = axis::multi_axis<is_owning, grid_frame_t,
0500 axis::single_axis<bound_ts, binning_ts>...>;
0501 using grid_t = grid<algebra_t, axes_t, bin_t, serializer_t>;
0502
0503 return new_grid<grid_t>(spans, n_bins, bin_capacities, ax_bin_edges);
0504 }
0505
0506
0507 template <typename grid_shape_t, typename... bound_ts, typename... binning_ts>
0508 requires concepts::shape<grid_shape_t, algebra_t>
0509 auto new_grid(
0510 const std::vector<scalar_type> &spans,
0511 const std::vector<std::size_t> &n_bins,
0512 const std::vector<std::pair<axis::multi_bin<sizeof...(bound_ts)>, dindex>>
0513 &bin_capacities = {},
0514 const std::vector<std::vector<scalar_type>> &ax_bin_edges = {},
0515 const types::list<bound_ts...> &bounds = {},
0516 const types::list<binning_ts...> &binnings = {}) const {
0517 return new_grid<
0518 typename grid_shape_t::template local_frame_type<algebra_t>>(
0519 spans, n_bins, bin_capacities, ax_bin_edges, bounds, binnings);
0520 }
0521
0522
0523
0524 template <concepts::grid grid_t, typename grid_shape_t>
0525 requires concepts::shape<grid_shape_t, algebra_t>
0526 auto new_grid(
0527 const mask<grid_shape_t, algebra_type> &m,
0528 const darray<std::size_t, grid_t::dim> &n_bins,
0529 const std::vector<std::pair<typename grid_t::loc_bin_index, dindex>>
0530 &bin_capacities = {},
0531 const darray<std::vector<scalar_type>, grid_t::dim> &ax_bin_edges = {})
0532 const {
0533 return new_grid(m, n_bins, bin_capacities, ax_bin_edges,
0534 typename grid_t::axes_type::bounds{},
0535 typename grid_t::axes_type::binnings{});
0536 }
0537
0538
0539
0540 template <typename grid_shape_t, typename... bound_ts, typename... binning_ts>
0541 requires concepts::shape<grid_shape_t, algebra_t>
0542 auto new_grid(
0543 const mask<grid_shape_t, algebra_type> &m,
0544 const darray<std::size_t, grid_shape_t::dim> &n_bins,
0545 const std::vector<std::pair<axis::multi_bin<sizeof...(bound_ts)>, dindex>>
0546 &bin_capacities = {},
0547 const darray<std::vector<scalar_type>, grid_shape_t::dim> &ax_bin_edges =
0548 {},
0549 const types::list<bound_ts...> & = {},
0550 const types::list<binning_ts...> & = {}) const {
0551 return new_grid<bound_ts..., binning_ts...>(m, n_bins, bin_capacities,
0552 ax_bin_edges);
0553 }
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565 template <concepts::grid grid_t>
0566 auto new_grid(
0567 const std::vector<scalar_type> &spans,
0568 const std::vector<std::size_t> &n_bins,
0569 [[maybe_unused]] const std::vector<
0570 std::pair<typename grid_t::loc_bin_index, dindex>> &bin_capacities =
0571 {},
0572 const std::vector<std::vector<scalar_type>> &ax_bin_edges = {}) const {
0573 using owning_grid_t = typename grid_t::template type<true>;
0574 using axes_t = typename owning_grid_t::axes_type;
0575
0576
0577 vector_type<dsized_index_range> axes_data{};
0578 vector_type<scalar_type> bin_edges{};
0579
0580
0581 unroll_axis_init<typename axes_t::binnings>(
0582 spans, n_bins, ax_bin_edges, axes_data, bin_edges,
0583 std::make_index_sequence<axes_t::dim>{});
0584
0585
0586 axes_t axes(std::move(axes_data), std::move(bin_edges));
0587
0588 typename owning_grid_t::bin_container_type bin_data{};
0589
0590
0591 if constexpr (std::is_same_v<bin_t, bins::dynamic_array<
0592 typename grid_t::value_type>>) {
0593
0594 bin_data.bins.resize(axes.nbins());
0595
0596 if (!bin_capacities.empty()) {
0597
0598 typename grid_t::template serializer_type<grid_t::dim> serializer{};
0599 dindex total_cap{0u};
0600 for (const auto &capacity : bin_capacities) {
0601
0602 auto &data = bin_data.bins[serializer(axes, capacity.first)];
0603
0604 data.offset = total_cap;
0605 data.capacity = capacity.second;
0606 data.size = 0u;
0607
0608 total_cap += data.capacity;
0609 }
0610 assert(total_cap > 0);
0611 bin_data.entries.resize(
0612 total_cap, detail::invalid_value<typename grid_t::value_type>());
0613 }
0614 } else {
0615
0616 bin_data.resize(axes.nbins(), bin_type{});
0617 }
0618
0619 return owning_grid_t(std::move(bin_data), std::move(axes));
0620 }
0621
0622 private:
0623
0624
0625 template <std::size_t I, typename binnings>
0626 auto axis_init([[maybe_unused]] const std::vector<scalar_type> &spans,
0627 [[maybe_unused]] const std::vector<std::size_t> &n_bins,
0628 [[maybe_unused]] const std::vector<std::vector<scalar_type>>
0629 &ax_bin_edges,
0630 vector_type<dsized_index_range> &axes_data,
0631 vector_type<scalar_type> &bin_edges) const {
0632 if constexpr (std::is_same_v<
0633 types::at<binnings, I>,
0634 axis::regular<scalar_type, host_container_types>>) {
0635 axes_data.push_back({static_cast<dindex>(bin_edges.size()),
0636 static_cast<dindex>(n_bins.at(I))});
0637 bin_edges.push_back(spans.at(I * 2u));
0638 bin_edges.push_back(spans.at(I * 2u + 1u));
0639 } else {
0640 const auto &bin_edges_loc = ax_bin_edges.at(I);
0641 axes_data.push_back({static_cast<dindex>(bin_edges.size()),
0642 static_cast<dindex>(bin_edges_loc.size() - 1u)});
0643 bin_edges.insert(bin_edges.end(), bin_edges_loc.begin(),
0644 bin_edges_loc.end());
0645 }
0646 }
0647
0648
0649 template <typename binnings, std::size_t... I>
0650 auto unroll_axis_init(
0651 const std::vector<scalar_type> &spans,
0652 const std::vector<std::size_t> &n_bins,
0653 const std::vector<std::vector<scalar_type>> &ax_bin_edges,
0654 vector_type<dsized_index_range> &axes_data,
0655 vector_type<scalar_type> &bin_edges,
0656 std::index_sequence<I...> ) const {
0657 (axis_init<I, binnings>(spans, n_bins, ax_bin_edges, axes_data, bin_edges),
0658 ...);
0659 }
0660
0661 vecmem::memory_resource *m_resource{};
0662 };
0663
0664
0665 template <concepts::grid grid_t>
0666 using grid_factory_type =
0667 grid_factory<typename grid_t::bin_type,
0668 simple_serializer ,
0669 typename grid_t::algebra_type>;
0670
0671 }