Alexandria  2.27.0
SDC-CH common library for the Euclid project
GridContainer.icpp
Go to the documentation of this file.
1 /**
2  * Copyright (C) 2012-2022 Euclid Science Ground Segment
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 3.0 of the License, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /**
20  * @file GridContainer/_impl/GridContainer.icpp
21  * @date May 13, 2014
22  * @author Nikolaos Apostolakos
23  */
24 
25 #include "ElementsKernel/Exception.h"
26 #include "GridConstructionHelper.h"
27 
28 namespace Euclid {
29 namespace GridContainer {
30 
31 template <typename GridCellManager, typename... AxesTypes>
32 GridContainer<GridCellManager, AxesTypes...>::GridContainer(GridAxis<AxesTypes>... axes) : m_axes{std::move(axes)...} {
33  m_cell_manager =
34  GridCellManagerTraits<GridCellManager>::factory(GridConstructionHelper<AxesTypes...>::getAxisIndexFactor(
35  m_axes, TemplateLoopCounter<sizeof...(AxesTypes) - 1>{}));
36 }
37 
38 template <typename GridCellManager, typename... AxesTypes>
39 GridContainer<GridCellManager, AxesTypes...>::GridContainer(std::tuple<GridAxis<AxesTypes>...> axes_tuple)
40  : m_axes{std::move(axes_tuple)} {
41  m_cell_manager =
42  GridCellManagerTraits<GridCellManager>::factory(GridConstructionHelper<AxesTypes...>::getAxisIndexFactor(
43  m_axes, TemplateLoopCounter<sizeof...(AxesTypes) - 1>{}));
44 }
45 
46 template <typename GridCellManager, typename... AxesTypes>
47 template <typename... Args>
48 GridContainer<GridCellManager, AxesTypes...>::GridContainer(std::tuple<GridAxis<AxesTypes>...> axes_tuple,
49  Args&&... args)
50  : m_axes{std::move(axes_tuple)} {
51  m_cell_manager = GridCellManagerTraits<GridCellManager>::factory(
52  GridConstructionHelper<AxesTypes...>::getAxisIndexFactor(m_axes, TemplateLoopCounter<sizeof...(AxesTypes) - 1>{}),
53  std::forward<Args>(args)...);
54 }
55 
56 template <typename... AxesTypes>
57 std::tuple<GridAxis<AxesTypes>...> fixAxis(const std::tuple<GridAxis<AxesTypes>...>& original, size_t axis,
58  size_t index) {
59  std::tuple<GridAxis<AxesTypes>...> result{original};
60  GridConstructionHelper<AxesTypes...>::template findAndFixAxis(result, axis, index, TemplateLoopCounter<0>{});
61  return result;
62 }
63 
64 template <typename GridCellManager, typename... AxesTypes>
65 GridContainer<GridCellManager, AxesTypes...>::GridContainer()
66  : m_cell_manager{
67  GridCellManagerTraits<GridCellManager>::factory(GridConstructionHelper<AxesTypes...>::getAxisIndexFactor(
68  m_axes, TemplateLoopCounter<sizeof...(AxesTypes) - 1>{}))} {}
69 
70 template <typename GridCellManager, typename... AxesTypes>
71 GridContainer<GridCellManager, AxesTypes...>::GridContainer(const GridContainer<GridCellManager, AxesTypes...>& other,
72  size_t axis, size_t index)
73  : m_axes{other.m_axes}
74  , m_axes_fixed{fixAxis(other.m_axes, axis, index)}
75  , m_fixed_indices{other.m_fixed_indices}
76  , m_cell_manager{other.m_cell_manager} {
77  // Update the fixed indices
78  if (m_fixed_indices.find(axis) != m_fixed_indices.end()) {
79  throw Elements::Exception() << "Axis " << axis << " is already fixed";
80  }
81  m_fixed_indices[axis] = index;
82 }
83 
84 template <typename GridCellManager, typename... AxesTypes>
85 auto GridContainer<GridCellManager, AxesTypes...>::copy() const -> GridContainer {
86  GridContainer clone{m_axes};
87  std::copy(begin(), end(), std::begin(clone));
88  return clone;
89 }
90 
91 template <typename GridCellManager, typename... AxesTypes>
92 template <int I>
93 auto GridContainer<GridCellManager, AxesTypes...>::getOriginalAxis() const -> const GridAxis<axis_type<I>>& {
94  return std::get<I>(m_axes);
95 }
96 
97 template <typename GridCellManager, typename... AxesTypes>
98 constexpr size_t GridContainer<GridCellManager, AxesTypes...>::axisNumber() {
99  return std::tuple_size<decltype(m_axes_fixed)>::value;
100 }
101 
102 template <typename GridCellManager, typename... AxesTypes>
103 template <int I>
104 auto GridContainer<GridCellManager, AxesTypes...>::getAxis() const -> const GridAxis<axis_type<I>>& {
105  return std::get<I>(m_axes_fixed);
106 }
107 
108 template <typename GridCellManager, typename... AxesTypes>
109 const std::tuple<GridAxis<AxesTypes>...>& GridContainer<GridCellManager, AxesTypes...>::getAxesTuple() const {
110  return m_axes_fixed;
111 }
112 
113 template <typename GridCellManager, typename... AxesTypes>
114 auto GridContainer<GridCellManager, AxesTypes...>::begin() -> iterator {
115  iterator result{*this, GridCellManagerTraits<GridCellManager>::begin(*m_cell_manager)};
116  GridConstructionHelper<AxesTypes...>::fixIteratorAxes(result, m_fixed_indices, TemplateLoopCounter<0>{});
117  return result;
118 }
119 
120 template <typename GridCellManager, typename... AxesTypes>
121 auto GridContainer<GridCellManager, AxesTypes...>::begin() const -> const_iterator {
122  const_iterator result{*this, GridCellManagerTraits<GridCellManager>::begin(*m_cell_manager)};
123  GridConstructionHelper<AxesTypes...>::fixIteratorAxes(result, m_fixed_indices, TemplateLoopCounter<0>{});
124  return result;
125 }
126 
127 template <typename GridCellManager, typename... AxesTypes>
128 auto GridContainer<GridCellManager, AxesTypes...>::cbegin() -> const_iterator {
129  const_iterator result{*this, GridCellManagerTraits<GridCellManager>::begin(*m_cell_manager)};
130  GridConstructionHelper<AxesTypes...>::fixIteratorAxes(result, m_fixed_indices, TemplateLoopCounter<0>{});
131  return result;
132 }
133 
134 template <typename GridCellManager, typename... AxesTypes>
135 auto GridContainer<GridCellManager, AxesTypes...>::end() -> iterator {
136  return iterator{*this, GridCellManagerTraits<GridCellManager>::end(*m_cell_manager)};
137 }
138 
139 template <typename GridCellManager, typename... AxesTypes>
140 auto GridContainer<GridCellManager, AxesTypes...>::end() const -> const_iterator {
141  return const_iterator{*this, GridCellManagerTraits<GridCellManager>::end(*m_cell_manager)};
142 }
143 
144 template <typename GridCellManager, typename... AxesTypes>
145 auto GridContainer<GridCellManager, AxesTypes...>::cend() -> const_iterator {
146  return const_iterator{*this, GridCellManagerTraits<GridCellManager>::end(*m_cell_manager)};
147 }
148 
149 template <typename GridCellManager, typename... AxesTypes>
150 size_t GridContainer<GridCellManager, AxesTypes...>::size() const {
151  return m_index_helper_fixed.m_axes_index_factors.back();
152 }
153 
154 template <typename GridCellManager, typename... AxesTypes>
155 auto GridContainer<GridCellManager, AxesTypes...>::operator()(
156  decltype(std::declval<GridAxis<AxesTypes>>().size())... indices) const -> const reference_type {
157  size_t total_index = m_index_helper.totalIndex(indices...);
158  // If we have fixed axes we need to move the index accordingly
159  for (auto& pair : m_fixed_indices) {
160  total_index += pair.second * m_index_helper.m_axes_index_factors[pair.first];
161  }
162  return (*m_cell_manager)[total_index];
163 }
164 
165 template <typename GridCellManager, typename... AxesTypes>
166 auto GridContainer<GridCellManager, AxesTypes...>::operator()(
167  decltype(std::declval<GridAxis<AxesTypes>>().size())... indices) -> reference_type {
168  size_t total_index = m_index_helper.totalIndex(indices...);
169  // If we have fixed axes we need to move the index accordingly
170  for (auto& pair : m_fixed_indices) {
171  total_index += pair.second * m_index_helper.m_axes_index_factors[pair.first];
172  }
173  return (*m_cell_manager)[total_index];
174 }
175 
176 template <typename GridCellManager, typename... AxesTypes>
177 auto GridContainer<GridCellManager, AxesTypes...>::at(
178  decltype(std::declval<GridAxis<AxesTypes>>().size())... indices) const -> const reference_type {
179  return const_cast<GridContainer*>(this)->at(indices...);
180 }
181 
182 template <typename GridCellManager, typename... AxesTypes>
183 auto GridContainer<GridCellManager, AxesTypes...>::at(decltype(std::declval<GridAxis<AxesTypes>>().size())... indices)
184  -> reference_type {
185  // First make a check that all the fixed axes are zero
186  m_index_helper.checkAllFixedAreZero(m_fixed_indices, indices...);
187  size_t total_index = m_index_helper.totalIndexChecked(indices...);
188  // If we have fixed axes we need to move the index accordingly
189  for (auto& pair : m_fixed_indices) {
190  total_index += pair.second * m_index_helper.m_axes_index_factors[pair.first];
191  }
192  return (*m_cell_manager)[total_index];
193 }
194 
195 template <std::size_t I>
196 struct InfimumHelper {
197  template <typename>
198  using Index = std::size_t;
199 
200  template <typename... AxesType>
201  static std::tuple<Index<AxesType>...> getIndex(const std::tuple<AxesType...>& coords,
202  const std::tuple<GridAxis<AxesType>...>& axes) {
203  std::tuple<Index<AxesType>...> index;
204  getIndex(coords, axes, index);
205  return index;
206  }
207 
208  template <typename IndexTuple, typename... AxesType>
209  static void getIndex(const std::tuple<AxesType...>& coords, const std::tuple<GridAxis<AxesType>...>& axes,
210  IndexTuple& index) {
211  auto& axn = std::get<I>(axes);
212  std::get<I>(index) = axn.infimum(std::get<I>(coords)) - axn.begin();
213  InfimumHelper<I - 1>::getIndex(coords, axes, index);
214  }
215 };
216 
217 template <>
218 struct InfimumHelper<0> {
219  template <typename>
220  using Index = std::size_t;
221 
222  template <typename... AxesType>
223  static std::tuple<std::size_t> getIndex(const std::tuple<AxesType...>& coords,
224  const std::tuple<GridAxis<AxesType>...>& axes) {
225  auto i0 = std::get<0>(axes).infimum(std::get<0>(coords));
226  return std::make_tuple(i0);
227  }
228 
229  template <typename IndexTuple, typename... AxesType>
230  static void getIndex(const std::tuple<AxesType...>& coords, const std::tuple<GridAxis<AxesType>...>& axes,
231  IndexTuple& index) {
232  auto& ax0 = std::get<0>(axes);
233  std::get<0>(index) = ax0.infimum(std::get<0>(coords)) - ax0.begin();
234  }
235 };
236 
237 template <typename GridCellManager, typename... AxesTypes>
238 auto GridContainer<GridCellManager, AxesTypes...>::infimum(const AxesTypes... coordinates) const
239  -> std::tuple<decltype(std::declval<GridAxis<AxesTypes>>().size())...> {
240  return infimum(std::make_tuple(coordinates...));
241 }
242 
243 template <typename GridCellManager, typename... AxesTypes>
244 auto GridContainer<GridCellManager, AxesTypes...>::infimum(const std::tuple<AxesTypes...>& coords) const
245  -> std::tuple<decltype(std::declval<GridAxis<AxesTypes>>().size())...> {
246  return InfimumHelper<sizeof...(AxesTypes) - 1>::getIndex(coords, m_axes);
247 }
248 
249 template <typename GridCellManager, typename... AxesTypes>
250 template <int I>
251 GridContainer<GridCellManager, AxesTypes...>
252 GridContainer<GridCellManager, AxesTypes...>::fixAxisByIndex(size_t index) {
253  if (index >= getOriginalAxis<I>().size()) {
254  throw Elements::Exception() << "Index (" << index << ") out of axis " << getOriginalAxis<I>().name() << " size ("
255  << getOriginalAxis<I>().size() << ")";
256  }
257  return GridContainer<GridCellManager, AxesTypes...>(*this, I, index);
258 }
259 
260 template <typename GridCellManager, typename... AxesTypes>
261 template <int I>
262 const GridContainer<GridCellManager, AxesTypes...>
263 GridContainer<GridCellManager, AxesTypes...>::fixAxisByIndex(size_t index) const {
264  return const_cast<GridContainer<GridCellManager, AxesTypes...>*>(this)->fixAxisByIndex<I>(index);
265 }
266 
267 template <typename GridCellManager, typename... AxesTypes>
268 template <int I>
269 GridContainer<GridCellManager, AxesTypes...>
270 GridContainer<GridCellManager, AxesTypes...>::fixAxisByValue(const axis_type<I>& value) {
271  auto& axis = getOriginalAxis<I>();
272  auto found_axis = std::find(axis.begin(), axis.end(), value);
273  if (found_axis == axis.end()) {
274  throw Elements::Exception() << "Failed to fix axis " << getOriginalAxis<I>().name() << " (given value not found)";
275  }
276  return GridContainer<GridCellManager, AxesTypes...>(*this, I, found_axis - axis.begin());
277 }
278 
279 template <typename GridCellManager, typename... AxesTypes>
280 template <int I>
281 const GridContainer<GridCellManager, AxesTypes...>
282 GridContainer<GridCellManager, AxesTypes...>::fixAxisByValue(const axis_type<I>& value) const {
283  return const_cast<GridContainer<GridCellManager, AxesTypes...>*>(this)->fixAxisByValue<I>(value);
284 }
285 
286 } // end of namespace GridContainer
287 } // end of namespace Euclid