Gyselalib++
 
Loading...
Searching...
No Matches
edge_transformation.hpp
1// SPDX-License-Identifier: MIT
2
3#pragma once
4
5#include <numeric>
6
7#include <ddc/ddc.hpp>
8
9#include "ddc_aliases.hpp"
10#include "ddc_helper.hpp"
11#include "edge.hpp"
12#include "interface.hpp"
13
14
33template <class Interface>
35{
36 static_assert(
37 !std::is_same_v<
38 typename Interface::Edge1,
39 OutsideEdge> && !std::is_same_v<typename Interface::Edge2, OutsideEdge>,
40 "The interface cannot be an interface with the outside domain.");
41
42
43 using EdgeGrid1 = typename Interface::Edge1::parallel_grid;
44 using EdgeGrid2 = typename Interface::Edge2::parallel_grid;
45
46 using EdgeDim1 = typename EdgeGrid1::continuous_dimension_type;
47 using EdgeDim2 = typename EdgeGrid2::continuous_dimension_type;
48
49 using IdxRangeEdge1 = IdxRange<EdgeGrid1>;
50 using IdxRangeEdge2 = IdxRange<EdgeGrid2>;
51
52 using IdxEdge1 = Idx<EdgeGrid1>;
53 using IdxEdge2 = Idx<EdgeGrid2>;
54
55 IdxRangeEdge1 const& m_idx_range_patch_1;
56 IdxRangeEdge2 const& m_idx_range_patch_2;
57
58
59public:
66 IdxRangeEdge1 const& idx_range_patch_1,
67 IdxRangeEdge2 const& idx_range_patch_2)
68 : m_idx_range_patch_1(idx_range_patch_1)
69 , m_idx_range_patch_2(idx_range_patch_2)
70 {
71 }
72
73 ~EdgeTransformation() = default;
74
75
88 template <class CurrentDim>
89 Coord<std::conditional_t<std::is_same_v<CurrentDim, EdgeDim1>, EdgeDim2, EdgeDim1>> operator()(
90 Coord<CurrentDim> const& current_coord) const
91 {
92 // The other continuous dimension
93 using TargetDim
94 = std::conditional_t<std::is_same_v<CurrentDim, EdgeDim1>, EdgeDim2, EdgeDim1>;
95
96 // The index range of CurrentDim
97 using IdxRangeCurrent = std::
98 conditional_t<std::is_same_v<CurrentDim, EdgeDim1>, IdxRangeEdge1, IdxRangeEdge2>;
99 // The index range of other dimension
100 using IdxRangeTarget = std::
101 conditional_t<std::is_same_v<CurrentDim, EdgeDim1>, IdxRangeEdge2, IdxRangeEdge1>;
102
103 // Get min and length on each 1D index ranges:
104 IdxRange<EdgeGrid1, EdgeGrid2> const
105 combined_idx_range(m_idx_range_patch_1, m_idx_range_patch_2);
106 IdxRangeCurrent const current_idx_range(combined_idx_range);
107 IdxRangeTarget const target_idx_range(combined_idx_range);
108
109 Coord<CurrentDim> const current_min = ddc::coordinate(current_idx_range.front());
110 double const current_length = ddcHelper::total_interval_length(current_idx_range);
111
112 Coord<TargetDim> const target_min = ddc::coordinate(target_idx_range.front());
113 double const target_length = ddcHelper::total_interval_length(target_idx_range);
114
115 double rescale_x = (current_coord - current_min) / current_length * target_length;
116
117 bool constexpr orientations_agree = Interface::orientations_agree;
118 if constexpr (!orientations_agree) {
119 rescale_x = target_length - rescale_x;
120 }
121 return target_min + rescale_x;
122 }
123
124
125
144 template <class CurrentIdx>
145 auto operator()(CurrentIdx const& current_idx) const
146 {
147 using IdxTarget
148 = std::conditional_t<std::is_same_v<CurrentIdx, IdxEdge1>, IdxEdge2, IdxEdge1>;
149 IdxTarget target_idx;
150 [[maybe_unused]] bool is_equivalent_idx_found = search_for_match(target_idx, current_idx);
151 assert(is_equivalent_idx_found);
152 return target_idx;
153 }
154
155
156
175 template <class CurrentIdx>
176 bool is_match_available(CurrentIdx const& current_idx) const
177 {
178 using IdxTarget
179 = std::conditional_t<std::is_same_v<CurrentIdx, IdxEdge1>, IdxEdge2, IdxEdge1>;
180 IdxTarget potential_target_idx;
181 return search_for_match(potential_target_idx, current_idx);
182 }
183
184
185
213 template <class CurrentGrid, class TargetGrid>
214 bool search_for_match(Idx<TargetGrid>& target_idx, Idx<CurrentGrid> const& current_idx) const
215 {
216 static_assert(
217 std::is_same_v<CurrentGrid, EdgeGrid1> || std::is_same_v<CurrentGrid, EdgeGrid2>,
218 "Current index must be associated with one of the edges.");
219 static_assert(
220 std::is_same_v<TargetGrid, EdgeGrid1> || std::is_same_v<TargetGrid, EdgeGrid2>,
221 "Target index must be associated with one of the edges.");
222 static_assert(
223 !std::is_same_v<TargetGrid, CurrentGrid>,
224 "The types of the indices should be different");
225
226 // Index range of CurrentIdx.
227 using IdxRangeCurrent = IdxRange<CurrentGrid>;
228 // Index range of other dimension.
229 using IdxRangeTarget = IdxRange<TargetGrid>;
230 // Coordinate on the discontinuous dimension of the current grid.
231 using CurrentCoord = Coord<typename CurrentGrid::continuous_dimension_type>;
232 // Index on the target grid
233 using IdxTarget = typename IdxRangeTarget::discrete_element_type;
234 // Index step on the target grid
235 using IdxStepTarget = typename IdxRangeTarget::discrete_vector_type;
236
237
238 bool is_equivalent_idx = false;
239
240 // Get the 1D index range corresponding to the current and target domains.
241 IdxRange<EdgeGrid1, EdgeGrid2> const
242 combined_idx_range(m_idx_range_patch_1, m_idx_range_patch_2);
243 IdxRangeCurrent const current_idx_range(combined_idx_range);
244 IdxRangeTarget const target_idx_range(combined_idx_range);
245
246 int const n_cells_current = current_idx_range.size() - 1;
247 int const n_cells_target = target_idx_range.size() - 1;
248
249 if constexpr ( // Uniform case
250 ddc::is_uniform_point_sampling_v<
251 EdgeGrid1> && ddc::is_uniform_point_sampling_v<EdgeGrid2>) {
252 // Get greatest common divisor
253 int const gcd_cells = std::gcd(n_cells_current, n_cells_target);
254
255 int const current_idx_value = (current_idx - current_idx_range.front()).value();
256 /*
257 There is an equivalent index if the current index is a multiple of
258 (number of current cells / gcd). If gcd == 1 then this condition is
259 only true if the current index represents an extremity
260 (current_idx_value == 0 or current_idx_value == n_cells_current).
261 */
262 is_equivalent_idx = (current_idx_value % (n_cells_current / gcd_cells) == 0);
263
264 // If there is an equivalent index, update target_idx.
265 if (is_equivalent_idx) {
266 double const rescaling_factor = double(n_cells_current) / double(n_cells_target);
267 IdxStepTarget target_idx_step_rescaled(int(current_idx_value / rescaling_factor));
268 target_idx = IdxTarget(target_idx_range.front());
269 target_idx += target_idx_step_rescaled;
270
271 if constexpr (!Interface::orientations_agree) {
272 IdxStepTarget target_idx_step = IdxTarget(target_idx_range.back()) - target_idx;
273 target_idx = IdxTarget(target_idx_range.front());
274 target_idx += target_idx_step;
275 }
276 }
277 } else { // Non uniform case
278 // Dichotomy method comparing the coordinates of indexes of the target edge.
279 target_idx = get_target_idx(target_idx_range, current_idx);
280 CurrentCoord const current_coord(ddc::coordinate(current_idx));
281 CurrentCoord const target_equivalent_coord((*this)(ddc::coordinate(target_idx)));
282 is_equivalent_idx = (abs(current_coord - target_equivalent_coord) < 1e-14);
283 }
284
285 return is_equivalent_idx;
286 }
287
288
289
290private:
292 template <class IdxType>
293 IdxType const get_mid(IdxType const& idx_1, IdxType const& idx_2) const
294 {
295 return idx_1 + (idx_2 - idx_1) / 2;
296 }
297
299 template <class TargetGrid, class CurrentGrid>
300 Idx<TargetGrid> const get_target_idx(
301 IdxRange<TargetGrid> const& target_idx_range,
302 Idx<CurrentGrid> const& current_idx) const
303 {
304 // Coordinate on the discontinuous dimension of the current grid.
305 using CurrentCoord = Coord<typename CurrentGrid::continuous_dimension_type>;
306 // Index on the target grid
307 using IdxTarget = Idx<TargetGrid>;
308 // Index step on the target grid
309 using IdxStepTarget = IdxStep<TargetGrid>;
310
311 // Dichotomy method
312 CurrentCoord const current_coord(ddc::coordinate(current_idx));
313
314 IdxTarget target_idx_min(target_idx_range.front());
315 IdxTarget target_idx_max(target_idx_range.back());
316 IdxTarget target_idx_mid = get_mid(target_idx_min, target_idx_max);
317
318 IdxStepTarget target_idx_step_diff = target_idx_max - target_idx_min;
319 while (target_idx_step_diff != IdxStepTarget(1)) {
320 CurrentCoord target_equivalent_coord_mid((*this)(ddc::coordinate(target_idx_mid)));
321
322 if ((current_coord > target_equivalent_coord_mid && Interface::orientations_agree)
323 || (current_coord <= target_equivalent_coord_mid
325 target_idx_min = target_idx_mid;
326 } else {
327 target_idx_max = target_idx_mid;
328 }
329
330 target_idx_mid = get_mid(target_idx_min, target_idx_max);
331 target_idx_step_diff = target_idx_max - target_idx_min;
332 }
333
334 CurrentCoord target_coord_min((*this)(ddc::coordinate(target_idx_min)));
335 CurrentCoord target_coord_max((*this)(ddc::coordinate(target_idx_max)));
336 if (abs(current_coord - target_coord_min) < abs(current_coord - target_coord_max)) {
337 return target_idx_min;
338 } else {
339 return target_idx_max;
340 }
341 }
342};
Transform a coordinate or an index from one edge to the one on the other edge.
Definition edge_transformation.hpp:35
bool search_for_match(Idx< TargetGrid > &target_idx, Idx< CurrentGrid > const &current_idx) const
Check if a given index has an equivalent index and transform an index on the edge in the dimension of...
Definition edge_transformation.hpp:214
Coord< std::conditional_t< std::is_same_v< CurrentDim, EdgeDim1 >, EdgeDim2, EdgeDim1 > > operator()(Coord< CurrentDim > const &current_coord) const
Transform a coordinate on the edge in the dimension of the current patch to the analogous coordinate ...
Definition edge_transformation.hpp:89
EdgeTransformation(IdxRangeEdge1 const &idx_range_patch_1, IdxRangeEdge2 const &idx_range_patch_2)
Instantiate an EdgeTransformation.
Definition edge_transformation.hpp:65
bool is_match_available(CurrentIdx const &current_idx) const
Check if a given index has an equivalent index on the other patch of an interface.
Definition edge_transformation.hpp:176
auto operator()(CurrentIdx const &current_idx) const
Transform an index on the edge in the dimension of the current patch to the analogous index on the ta...
Definition edge_transformation.hpp:145
Edge1Type Edge1
Edge type of the first patch.
Definition interface.hpp:27
static constexpr bool orientations_agree
If True, the parametrisations of the physical edge have the same orientation.
Definition interface.hpp:45
Define an edge for the outside index range.
Definition edge.hpp:47