chombo-discharge
CD_LookupTable1DImplem.H
1 /* chombo-discharge
2  * Copyright © 2021 SINTEF Energy Research.
3  * Please refer to Copyright.txt and LICENSE in the chombo-discharge root directory.
4  */
5 
12 #ifndef CD_LookupTableImplem_H
13 #define CD_LookupTableImplem_H
14 
15 // Std includes
16 #include <algorithm>
17 #include <math.h>
18 #include <iomanip>
19 #include <fstream>
20 #include <limits>
21 
22 // Our includes
23 #include <CD_LookupTable1D.H>
24 
25 template <typename T, size_t N, typename I>
27 {
28  this->reset();
29 }
30 
31 template <typename T, size_t N, typename I>
32 inline void
34 {
35  m_isGood = false;
36  m_grid = std::make_tuple(LookupTable::Spacing::Uniform, 0, -1.0, -1.0, -1.0);
37  m_rangeStrategyLo = LookupTable::OutOfRangeStrategy::Constant;
38  m_rangeStrategyHi = LookupTable::OutOfRangeStrategy::Constant;
39 
40  m_rawData.clear();
41  m_structuredData.clear();
42 }
43 
44 template <typename T, size_t N, typename I>
45 template <typename... Ts>
46 inline void
47 LookupTable1D<T, N, I>::addData(const Ts&... x) noexcept
48 {
49  std::array<T, sizeof...(Ts)> arr = {(T)x...};
50 
51  m_rawData.emplace_back(arr);
52 }
53 
54 template <typename T, size_t N, typename I>
55 inline void
56 LookupTable1D<T, N, I>::addData(const std::array<T, N + 1>& x) noexcept
57 {
58  m_rawData.emplace_back(x);
59 }
60 
61 template <typename T, size_t N, typename I>
62 inline void
63 LookupTable1D<T, N, I>::swap(const size_t a_columnOne, const size_t a_columnTwo) noexcept
64 {
65  for (auto& r : m_rawData) {
66  const auto tmp = r[a_columnOne];
67 
68  r[a_columnOne] = r[a_columnTwo];
69  r[a_columnTwo] = tmp;
70  }
71 
72  for (auto& r : m_structuredData) {
73  const auto tmp = r[a_columnOne];
74 
75  r[a_columnOne] = r[a_columnTwo];
76  r[a_columnTwo] = tmp;
77  }
78 
79  if (m_isGood) {
80  if (a_columnOne == std::get<4>(m_grid)) {
81  std::get<4>(m_grid) = a_columnOne;
82  }
83  else if (a_columnTwo == std::get<4>(m_grid)) {
84  std::get<4>(m_grid) = a_columnTwo;
85  }
86  }
87 }
88 
89 template <typename T, size_t N, typename I>
90 template <size_t K>
91 inline void
92 LookupTable1D<T, N, I>::scale(const T& a_scale) noexcept
93 {
94  for (auto& r : m_rawData) {
95  r[K] *= a_scale;
96  }
97 
98  for (auto& r : m_structuredData) {
99  r[K] *= a_scale;
100  }
101 
102  if (m_isGood && K == std::get<2>(m_grid)) {
103  std::get<4>(m_grid) *= a_scale;
104  }
105 }
106 
107 template <typename T, size_t N, typename I>
108 inline void
109 LookupTable1D<T, N, I>::truncate(const T& a_min, const T& a_max, const size_t a_column) noexcept
110 {
111  std::vector<std::array<T, N + 1>> truncatedData;
112 
113  for (const auto& xy : m_rawData) {
114  if (xy[a_column] >= a_min || xy[a_column] <= a_max) {
115  truncatedData.emplace_back(xy);
116  }
117  }
118 
119  m_rawData = truncatedData;
120 }
121 
122 template <typename T, size_t N, typename I>
123 inline void
125 {
126  m_rangeStrategyLo = a_strategy;
127 }
128 
129 template <typename T, size_t N, typename I>
130 inline void
132 {
133  m_rangeStrategyHi = a_strategy;
134 }
135 
136 template <typename T, size_t N, typename I>
137 inline void
138 LookupTable1D<T, N, I>::prepareTable(const size_t& a_independentVariable,
139  const size_t& a_numPoints,
140  const LookupTable::Spacing& a_spacing)
141 {
142 
143  const std::string baseError = "LookupTable1D<T,N,I>::prepareTable";
144 
145  if (a_numPoints <= 1) {
146  throw std::runtime_error(baseError + " - must have 'a_numPoints > 1'");
147  }
148 
149  // Sort the raw data along the specified column.
150  using Values = std::array<T, N + 1>;
151  std::vector<Values> sortedData = m_rawData;
152 
153  std::sort(sortedData.begin(),
154  sortedData.end(),
155  [i = a_independentVariable](const Values& X1, const Values& X2) -> bool {
156  return X1[i] < X2[i];
157  });
158 
159  // Set up the 1D grid
160  T xmin;
161  T xmax;
162  T delta;
163 
164  xmin = sortedData.front()[a_independentVariable];
165  xmax = sortedData.back()[a_independentVariable];
166 
167  std::vector<T> coords(a_numPoints);
168 
169  switch (a_spacing) {
170  case LookupTable::Spacing::Uniform: {
171  delta = (xmax - xmin) / (a_numPoints - 1);
172 
173  for (size_t i = 0; i < a_numPoints; i++) {
174  coords[i] = xmin + i * delta;
175  }
176 
177  break;
178  }
179  case LookupTable::Spacing::Exponential: {
180  if (xmin <= std::numeric_limits<T>::min()) {
181  throw std::runtime_error(baseError + " - but must have all 'x > 0.0' for logarithmic grid");
182  }
183 
184  else {
185  delta = log10(xmax / xmin) / (a_numPoints - 1);
186 
187  for (int i = 0; i < a_numPoints; i++) {
188  coords[i] = xmin * std::pow(10.0, i * delta);
189  }
190 
191  break;
192  }
193  }
194  default: {
195  throw std::runtime_error(baseError + " - logic bust (unsupported table spacing system)");
196 
197  break;
198  }
199  }
200 
201  m_structuredData.clear();
202 
203  size_t curRow = 0;
204 
205  for (const auto& x : coords) {
206  while (curRow < m_rawData.size() - 1) {
207  const auto& row1 = m_rawData[curRow];
208  const auto& row2 = m_rawData[curRow + 1];
209 
210  const auto x1 = row1[a_independentVariable];
211  const auto x2 = row2[a_independentVariable];
212 
213  if (x >= x1 && x <= x2) {
214  const auto t = (x - x1) / (x2 - x1);
215 
216  std::array<T, N + 1> interpRow;
217 
218  for (size_t i = 0; i <= N; i++) {
219  interpRow[i] = row1[i] + t * (row2[i] - row1[i]);
220  }
221 
222  m_structuredData.emplace_back(interpRow);
223 
224  break;
225  }
226 
227  curRow++;
228  }
229  }
230 
231  m_grid = std::make_tuple(a_spacing, a_independentVariable, xmin, xmax, delta);
232 
233  m_isGood = true;
234 }
235 
236 template <typename T, size_t N, typename I>
237 inline std::vector<std::array<T, N + 1>>&
239 {
240  return (m_rawData);
241 }
242 
243 template <typename T, size_t N, typename I>
244 inline std::vector<std::array<T, N + 1>>&
246 {
247  return (m_structuredData);
248 }
249 
250 template <typename T, size_t N, typename I>
251 inline const std::vector<std::array<T, N + 1>>&
253 {
254  return (m_rawData);
255 }
256 
257 template <typename T, size_t N, typename I>
258 inline const std::vector<std::array<T, N + 1>>&
260 {
261  return (m_structuredData);
262 }
263 
264 template <typename T, size_t N, typename I>
265 inline void
266 LookupTable1D<T, N, I>::writeRawData(const std::string& a_file) const noexcept
267 {
268  this->writeToFile(a_file, m_rawData);
269 }
270 
271 template <typename T, size_t N, typename I>
272 inline void
273 LookupTable1D<T, N, I>::writeStructuredData(const std::string& a_file) const noexcept
274 {
275  this->writeToFile(a_file, m_structuredData);
276 }
277 
278 template <typename T, size_t N, typename I>
279 inline void
280 LookupTable1D<T, N, I>::outputRawData(std::ostream& a_ostream) const noexcept
281 {
282  this->outputData(a_ostream, m_rawData);
283 }
284 
285 template <typename T, size_t N, typename I>
286 inline void
287 LookupTable1D<T, N, I>::outputStructuredData(std::ostream& a_ostream) const noexcept
288 {
289  this->outputData(a_ostream, m_structuredData);
290 }
291 
292 template <typename T, size_t N, typename I>
293 inline void
294 LookupTable1D<T, N, I>::outputData(std::ostream& a_ostream,
295  const std::vector<std::array<T, N + 1>>& a_data) const noexcept
296 {
297  for (const auto& r : a_data) {
298  for (const auto& c : r) {
299  a_ostream << std::left << std::setw(14) << c;
300  }
301  a_ostream << "\n";
302  }
303 }
304 
305 template <typename T, size_t N, typename I>
306 inline void
307 LookupTable1D<T, N, I>::writeToFile(const std::string& a_file,
308  const std::vector<std::array<T, N + 1>>& a_data) const noexcept
309 {
310 
311 #ifdef CH_MPI
312  if (procID() == 0) {
313 #endif
314  std::ofstream file;
315 
316  file.open(a_file);
317  this->outputData(file, a_data);
318  file.close();
319 #ifdef CH_MPI
320  }
321 #endif
322 }
323 
324 template <typename T, size_t N, typename I>
325 inline size_t
327 {
328  const LookupTable::Spacing& spacing = std::get<0>(m_grid);
329  const T& x0 = std::get<2>(m_grid);
330  const T& delta = std::get<4>(m_grid);
331 
332  size_t idxLo;
333 
334  switch (spacing) {
335  case LookupTable::Spacing::Uniform: {
336  idxLo = std::floor((a_x - x0) / delta);
337 
338  break;
339  }
340  case LookupTable::Spacing::Exponential: {
341  idxLo = std::floor(log10(a_x / x0) / delta);
342 
343  break;
344  }
345  default: {
346  throw std::runtime_error("LookupTable1D<T,N,I>::getIndexLo - logic bust (unsupported table spacing system)");
347  }
348  }
349 
350  return idxLo;
351 }
352 
353 template <typename T, size_t N, typename I>
354 inline std::array<T, N + 1>
356 {
357  if (!m_isGood) {
358  throw std::runtime_error("LookupTable1D<T, N, I>::interpolate(array) but need to call 'prepareTable first'");
359  }
360 
361  const size_t& indVar = std::get<1>(m_grid);
362  const T& xmin = std::get<2>(m_grid);
363  const T& xmax = std::get<3>(m_grid);
364 
365  std::array<T, N + 1> ret;
366 
367  if (a_x < xmin) {
368  switch (m_rangeStrategyLo) {
369  case LookupTable::OutOfRangeStrategy::Constant: {
370  ret = m_structuredData.front();
371 
372  break;
373  }
374  case LookupTable::OutOfRangeStrategy::Interpolate: {
375  const T diffDx = m_structuredData[1][indVar] - m_structuredData[0][indVar];
376  const T extrapDx = m_structuredData[0][indVar] - a_x;
377 
378  ret = m_structuredData.front();
379 
380  for (size_t i = 0; i < N + 1; i++) {
381  const T slope = (m_structuredData[1][i] - m_structuredData[0][i]) / diffDx;
382 
383  ret[i] -= slope * extrapDx;
384  }
385 
386  break;
387  }
388  default: {
389  throw std::runtime_error("LookupTable1D<T, N, I>::interpolate(array) unsupported range strategy at low end");
390 
391  break;
392  }
393  }
394  }
395  else if (a_x > xmax) {
396  switch (m_rangeStrategyHi) {
397  case LookupTable::OutOfRangeStrategy::Constant: {
398  ret = m_structuredData.back();
399 
400  break;
401  }
402  case LookupTable::OutOfRangeStrategy::Interpolate: {
403  const size_t& size = m_structuredData.size();
404 
405  const T diffDx = m_structuredData[size - 1][indVar] - m_structuredData[size - 2][indVar];
406  const T extrapDx = a_x - m_structuredData[size - 1][indVar];
407 
408  ret = m_structuredData.back();
409 
410  for (size_t i = 0; i < N + 1; i++) {
411  const T slope = (m_structuredData[size - 1][i] - m_structuredData[size - 2][i]) / diffDx;
412 
413  ret[i] += slope * extrapDx;
414  }
415 
416  break;
417  }
418  default: {
419  throw std::runtime_error("LookupTable1D<T, N, I>::interpolate(array) unsupported range strategy at low end");
420 
421  break;
422  }
423  }
424  }
425  else {
426  const size_t idx = this->getIndexLo(a_x);
427 
428  const T diffDx = m_structuredData[idx + 1][indVar] - m_structuredData[idx][indVar];
429  const T interpDx = a_x - m_structuredData[idx][indVar];
430 
431  ret = m_structuredData[idx];
432 
433  for (size_t i = 0; i < N + 1; i++) {
434  const T slope = (m_structuredData[idx + 1][i] - m_structuredData[idx][i]) / diffDx;
435 
436  ret[i] += slope * interpDx;
437  }
438  }
439 
440  return ret;
441 }
442 
443 template <typename T, size_t N, typename I>
444 template <size_t K>
445 inline T
447 {
448  return std::get<K>(this->interpolate(a_x));
449 }
450 
451 template <typename T, size_t N, typename I>
452 template <size_t M, typename... Ts>
454 LookupTable1D<T, N, I>::slice(const Ts&... a_columns) const noexcept
455 {
456  static_assert(M <= N, "LookupTable1D<T, N,I>::slice must have have 'M <= N'");
457 
458  std::array<size_t, sizeof...(Ts)> arr = {(size_t)a_columns...};
459 
461 
462  for (const auto& r : m_rawData) {
463  std::array<T, M + 1> slicedData;
464 
465  for (size_t i = 0; i < M + 1; i++) {
466  slicedData[i] = r[arr[i]];
467  }
468 
469  ret.addData(slicedData);
470  }
471 
472  return ret;
473 }
474 
475 #endif
Declaration of a lookup table in one independent variable.
OutOfRangeStrategy
Strategy for obtaining data when requesting data that is out of range. We can use either constant (i....
Definition: CD_LookupTable.H:29
Spacing
Enum for classifying the coordinate system.
Definition: CD_LookupTable.H:38
Class for interpolation of f = f(x) data in one independent variable x.
Definition: CD_LookupTable1D.H:30
std::vector< std::array< T, N+1 > > & getStructuredData() noexcept
Access function for structured data.
Definition: CD_LookupTable1DImplem.H:245
T interpolate(const T &a_x) const
Interpolation function for specific dependent variable K.
Definition: CD_LookupTable1DImplem.H:446
void addData(const Ts &... x) noexcept
Add entry.
Definition: CD_LookupTable1DImplem.H:47
void setRangeStrategyLo(const LookupTable::OutOfRangeStrategy &a_strategy) noexcept
Set the out-of-range strategy on the low end.
Definition: CD_LookupTable1DImplem.H:124
void outputData(std::ostream &a_ostream, const std::vector< std::array< T, N+1 >> &a_data) const noexcept
Utility function for outputting data.
Definition: CD_LookupTable1DImplem.H:294
size_t getIndexLo(const T &a_x) const
Get the lower index that brackets the input variable between two data points in the structured grid.
Definition: CD_LookupTable1DImplem.H:326
void swap(const size_t a_columnOne, const size_t a_columnTwo) noexcept
Utility function for swapping columns.
Definition: CD_LookupTable1DImplem.H:63
void truncate(const T &a_min, const T &a_max, const size_t a_column) noexcept
Utility function for truncating raw data along one of the variables (either dependent or independent)...
Definition: CD_LookupTable1DImplem.H:109
void setRangeStrategyHi(const LookupTable::OutOfRangeStrategy &a_strategy) noexcept
Set the out-of-range strategy on the high end.
Definition: CD_LookupTable1DImplem.H:131
LookupTable1D() noexcept
Default constructor. Creates a table without any entries.
Definition: CD_LookupTable1DImplem.H:26
void writeRawData(const std::string &a_file) const noexcept
Dump raw table data to file.
Definition: CD_LookupTable1DImplem.H:266
void outputStructuredData(std::ostream &a_ostream=std::cout) const noexcept
Dump structured table data to file.
Definition: CD_LookupTable1DImplem.H:287
void reset() noexcept
Reset everything.
Definition: CD_LookupTable1DImplem.H:33
void writeToFile(const std::string &a_file, const std::vector< std::array< T, N+1 >> &a_data) const noexcept
Utility function for outputting data to a file.
Definition: CD_LookupTable1DImplem.H:307
void outputRawData(std::ostream &a_ostream=std::cout) const noexcept
Dump raw table data to output stream.
Definition: CD_LookupTable1DImplem.H:280
void prepareTable(const size_t &a_independentVariable, const size_t &a_numPoints, const LookupTable::Spacing &a_spacing)
Turn the raw data into uniform data for fast lookup.
Definition: CD_LookupTable1DImplem.H:138
void scale(const T &a_scale) noexcept
Utility function which scales one of the columns (either dependent or independent variable)
Definition: CD_LookupTable1DImplem.H:92
void writeStructuredData(const std::string &a_file) const noexcept
Dump structured table data to file.
Definition: CD_LookupTable1DImplem.H:273
LookupTable1D< T, M, I > slice(const Ts &... a_columns) const noexcept
Slice this table, keeping only the user-specified columns.
Definition: CD_LookupTable1DImplem.H:454
std::vector< std::array< T, N+1 > > & getRawData() noexcept
Access function for raw data.
Definition: CD_LookupTable1DImplem.H:238
Real min(const Real &a_input) noexcept
Get the minimum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:58
constexpr Real c
Speed of light.
Definition: CD_Units.H:39