moment_index.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra portage project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/portage/blob/master/LICENSE
5 */
6 #ifndef WONTON_SUPPORT_MOMENT_INDEX_
7 #define WONTON_SUPPORT_MOMENT_INDEX_
8 
9 #include <array>
10 #include <cassert>
11 #include <cmath>
12 #include <utility>
13 
61 
62 namespace Wonton {
63 
64  // ==========================================================================
65 
69  template<int D>
70  constexpr int moment_to_index(
71  int const order, std::array<int,D> const exponents);
72 
73  template<>
74  constexpr int moment_to_index<3>(
75  int const order, std::array<int,3> const exponents) {
76  int constexpr D = 3;
77  int exponent_sum = 0;
78  for (int d = 0; d < D; ++d) {
79  assert(exponents[d] >= 0);
80  exponent_sum += exponents[d];
81  }
82  assert(exponent_sum == order);
83  int index = 0;
84  index += (order+2) * (order+1) * order / 6;
85  int order1 = order - exponents[0];
86  index += (order1+1) * order1 / 2;
87  index += order1 - exponents[1];
88  return(index);
89  }
90 
91  template<>
92  constexpr int moment_to_index<2>(
93  int const order, std::array<int,2> const exponents) {
94  int constexpr D = 2;
95  int exponent_sum = 0;
96  for (int d = 0; d < D; ++d) {
97  assert(exponents[d] >= 0);
98  exponent_sum += exponents[d];
99  }
100  assert(exponent_sum == order);
101  int index = 0;
102  index += (order+1) * order / 2;
103  index += order - exponents[0];
104  return(index);
105  }
106 
107  template<>
108  constexpr int moment_to_index<1>(
109  int const order, std::array<int,1> const exponents) {
110  int constexpr D = 1;
111  int exponent_sum = 0;
112  for (int d = 0; d < D; ++d) {
113  assert(exponents[d] >= 0);
114  exponent_sum += exponents[d];
115  }
116  assert(exponent_sum == order);
117  int index = 0;
118  index += order;
119  return(index);
120  }
121 
122  // ==========================================================================
123 
126  template<int D>
127  constexpr int count_moments(int const order);
128 
129  template<>
130  constexpr int count_moments<3>(int const order) {
131  return (order+3) * (order+2) * (order+1) / 6;
132  }
133 
134  template<>
135  constexpr int count_moments<2>(int const order) {
136  return (order+2) * (order+1) / 2;
137  }
138 
139  template<>
140  constexpr int count_moments<1>(int const order) {
141  return order+1;
142  }
143 
144  // ==========================================================================
145  // TODO: We can't get a non-const reference to a std::array element in a
146  // constexpr function until C++17. Thus these routines cannot be
147  // constexpr until Wonton starts using C++17. Once these become
148  // constexpr the inline specifier is redundant.
149 
152  template<int D>
153  inline std::pair<int,std::array<int,D>> index_to_moment(int const index);
154 
155  template<>
156  inline std::pair<int,std::array<int,3>> index_to_moment<3>(
157  int const index) {
158  int constexpr D = 3;
159  int n = index;
160  // Declare the output variables
161  int order = 0;
162  std::array<int,D> exponents = {};
163  // Find order
164  // While this could be done analytically, the expression is ugly and
165  // involves cube roots and complex numbers. With only a small number of
166  // orders, this should be plenty fast enough (and possibly faster than the
167  // ugly expression).
168  while (true) {
169  if (n < (order+2)*(order+1)*order/6)
170  break;
171  order++;
172  }
173  order--;
174  // Skip the lower-order moments
175  n -= (order+2)*(order+1)*order/6;
176  // Find the first exponent
177  exponents[0] = order - (int) floor((sqrt((double)8*n+1) - 1) / 2);
178  auto order1 = order - exponents[0];
179  // Skip moments with wrong first exponent
180  n -= (order1+1) * order1 / 2;
181  // Find the second exponent
182  exponents[1] = order1 - n;
183  // Find the third exponent
184  exponents[2] = n;
185  // Verify results
186  int exponent_sum = 0;
187  for (int d = 0; d < D; ++d) {
188  assert(exponents[d] >= 0);
189  exponent_sum += exponents[d];
190  }
191  assert(exponent_sum == order);
192  // Return
193  return std::make_pair(order,exponents);
194  }
195 
196  template<>
197  inline std::pair<int,std::array<int,2>> index_to_moment<2>(
198  int const index) {
199  int constexpr D = 2;
200  int n = index;
201  // Declare the output variables
202  int order = 0;
203  std::array<int,D> exponents = {};
204  // Find order
205  order = (int) floor((sqrt((double)8*n+1) - 1) / 2);
206  // Skip the lower-order moments
207  n -= (order+1) * order / 2;
208  // Find the first exponent
209  exponents[0] = order - n;
210  // Find the second exponent
211  exponents[1] = n;
212  // Verify results
213  int exponent_sum = 0;
214  for (int d = 0; d < D; ++d) {
215  assert(exponents[d] >= 0);
216  exponent_sum += exponents[d];
217  }
218  assert(exponent_sum == order);
219  // Return
220  return std::make_pair(order,exponents);
221  }
222 
223  template<>
224  inline std::pair<int,std::array<int,1>> index_to_moment<1>(
225  int const index) {
226  int constexpr D = 1;
227  // Declare the output variables
228  int order = 0;
229  std::array<int,D> exponents = {};
230  // Find order
231  order = index;
232  // Find the first exponent
233  exponents[0] = index;
234  // Verify results
235  int exponent_sum = 0;
236  for (int d = 0; d < D; ++d) {
237  assert(exponents[d] >= 0);
238  exponent_sum += exponents[d];
239  }
240  assert(exponent_sum == order);
241  // Return
242  return std::make_pair(order,exponents);
243  }
244 
245 } // namespace Wonton
246 
247 #endif // WONTON_SUPPORT_MOMENT_INDEX_
std::pair< int, std::array< int, 1 > > index_to_moment< 1 >(int const index)
Definition: moment_index.h:224
constexpr int moment_to_index(int const order, std::array< int, D > const exponents)
constexpr int count_moments< 1 >(int const order)
Definition: moment_index.h:140
Factorize a number N into D equal (or nearly equal) factors.
Definition: adaptive_refinement_mesh.h:31
constexpr int moment_to_index< 3 >(int const order, std::array< int, 3 > const exponents)
Definition: moment_index.h:74
constexpr int moment_to_index< 2 >(int const order, std::array< int, 2 > const exponents)
Definition: moment_index.h:92
constexpr int count_moments(int const order)
constexpr int count_moments< 3 >(int const order)
Definition: moment_index.h:130
std::pair< int, std::array< int, D > > index_to_moment(int const index)
std::pair< int, std::array< int, 2 > > index_to_moment< 2 >(int const index)
Definition: moment_index.h:197
std::pair< int, std::array< int, 3 > > index_to_moment< 3 >(int const index)
Definition: moment_index.h:156
constexpr int count_moments< 2 >(int const order)
Definition: moment_index.h:135
constexpr int moment_to_index< 1 >(int const order, std::array< int, 1 > const exponents)
Definition: moment_index.h:108