Alexandria  2.16
Please provide a description of the project.
GridContainerToTable.icpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2020 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 #include <type_traits>
20 #include <vector>
21 #include <boost/algorithm/string.hpp>
22 
23 namespace Euclid {
24 namespace GridContainer {
25 
26 /**
27  * Template class to help on the recursive traversal of the grid
28  * @tparam I
29  * Handle the axis stored on the (I-1)th position on the GridContainer::AxesTuple
30  */
31 template<size_t I, typename GridCellManager, typename ...Axes>
32 struct GridToFitsHelper {
33 
34  /**
35  * Generate recursively the column description for each *knot* on the grid. The order on the tuples
36  * is reversed, so the 0th tuple element is inserted on the last position.
37  * @param grid
38  * An instance of a grid
39  * @param description
40  * A vector where to emplace the description
41  */
42  static void addColumnDescriptions(const GridContainer<GridCellManager, Axes...>& grid,
43  std::vector<Table::ColumnDescription>& description) {
44  auto& axis = grid.template getAxis<I - 1>();
45  using knot_t = typename std::remove_reference<decltype(axis)>::type::data_type;
46  auto name = axis.name();
47  boost::replace_all(name, " ", "_");
48  description.emplace_back(name, typeid(typename GridAxisToTable<knot_t>::table_cell_t));
49 
50  GridToFitsHelper<I - 1, GridCellManager, Axes...>::addColumnDescriptions(grid, description);
51  }
52 
53  /**
54  * Iterate over the elements of the (I-1)th axis, and for each one call recursively unfold on the next axis.
55  * @tparam Args
56  * Used to keep track of the types of the knots of the previous axes
57  * @param grid
58  * An instance of a grid
59  * @param column_info
60  * As populated by getColumnDescriptions
61  * @param rows
62  * Grid cells will be inserted on this vector
63  * @param axes
64  * Used to keep track of the values of the knots of the previous axis
65  */
66  template<typename ...Args>
67  static void
68  unfold(const GridContainer<GridCellManager, Axes...>& grid, const std::shared_ptr<Table::ColumnInfo>& column_info,
69  std::vector<Table::Row>& rows, std::pair<size_t, Args>... axes) {
70  auto& axis = grid.template getAxis<I - 1>();
71  for (size_t i = 0; i < axis.size(); ++i) {
72  GridToFitsHelper<I - 1, GridCellManager, Axes...>::unfold(grid, column_info, rows, std::make_pair(i, axis[i]),
73  axes...);
74  }
75  }
76 
77  /**
78  * Same as before, but without the book-keeping data, since this is the entry point
79  */
80  static void
81  unfold(const GridContainer<GridCellManager, Axes...>& grid, const std::shared_ptr<Table::ColumnInfo>& column_info,
82  std::vector<Table::Row>& rows) {
83  auto& axis = grid.template getAxis<I - 1>();
84  for (size_t i = 0; i < axis.size(); ++i) {
85  GridToFitsHelper<I - 1, GridCellManager, Axes...>::unfold(grid, column_info, rows, std::make_pair(i, axis[i]));
86  }
87  }
88 };
89 
90 /**
91  * Base class for the recursive traversal of the grid
92  */
93 template<typename GridCellManager, typename ...Axes>
94 struct GridToFitsHelper<0, GridCellManager, Axes...> {
95  /**
96  * There are no more axis, so do nothing for the columns
97  */
98  static void addColumnDescriptions(const GridContainer<GridCellManager, Axes...>&,
99  std::vector<Table::ColumnDescription>&) {}
100 
101  /**
102  * Insert into the row vector the cell value plus the axes values that brought us here
103  */
104  template<typename ...Args>
105  static void
106  unfold(const GridContainer<GridCellManager, Axes...>& grid, const std::shared_ptr<Table::ColumnInfo>& column_info,
107  std::vector<Table::Row>& rows, std::pair<size_t, Args> ...axes) {
108  using GridType = GridContainer<GridCellManager, Axes...>;
109 
110  std::vector<Table::Row::cell_type> row_content{GridAxisToTable<Args>::serialize(axes.second)...};
111  std::reverse(row_content.begin(), row_content.end());
112 
113  GridCellToTable<typename GridType::cell_type> cell_traits;
114  cell_traits.addCells(grid.at(axes.first...), row_content);
115 
116  rows.emplace_back(row_content, column_info);
117  }
118 };
119 
120 /**
121  * Transform a GridContainer into a Table, with an entry for each
122  * cell. The content will be unfolded, so the knot values will be repeated.
123  */
124 template<typename GridCellManager, typename ...AxesTypes>
125 Table::Table gridContainerToTable(const GridContainer<GridCellManager, AxesTypes...>& grid) {
126  using GridType = GridContainer<GridCellManager, AxesTypes...>;
127  using Helper = GridToFitsHelper<std::tuple_size<typename GridType::AxesTuple>::value, GridCellManager, AxesTypes...>;
128 
129  std::vector<Table::ColumnDescription> columns;
130  Helper::addColumnDescriptions(GridContainer<GridCellManager, AxesTypes...>{grid.getAxesTuple()}, columns);
131 
132  GridCellToTable<typename GridType::cell_type> cell_trais;
133  cell_trais.addColumnDescriptions(*grid.begin(), columns);
134 
135  auto column_info = std::make_shared<Table::ColumnInfo>(std::move(columns));
136 
137  std::vector<Table::Row> rows;
138  rows.reserve(grid.size());
139 
140  Helper::unfold(grid, column_info, rows);
141 
142  return Table::Table{std::move(rows)};
143 }
144 
145 } // end of namespace GridContainer
146 } // end of namespace Euclid