Triumvirate C++ API 0.5.0
Three-point clustering measurements in large-scale structure analyses.
Loading...
Searching...
No Matches
arrayops.cpp
Go to the documentation of this file.
1// Copyright (C) [GPLv3 Licence]
2//
3// This file is part of the Triumvirate program. See the COPYRIGHT
4// and LICENCE files at the top-level directory of this distribution
5// for details of copyright and licensing.
6//
7// This program is free software: you can redistribute it and/or modify it
8// under the terms of the GNU General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15// See the GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <https://www.gnu.org/licenses/>.
19
27#include "arrayops.hpp"
28
29namespace trvs = trv::sys;
30
31namespace trv {
32
33// ***********************************************************************
34// Extrapolation
35// ***********************************************************************
36
37namespace sys {
38
39ExtrapError::ExtrapError(const char* fmt_string, ...) : std::runtime_error(
40 "Extrapolation error." // mandatory default error message
41) {
42 std::va_list args;
43
44 char err_mesg_buf[4096];
45 va_start(args, fmt_string);
46 std::vsnprintf(err_mesg_buf, sizeof(err_mesg_buf), fmt_string, args);
47 va_end(args);
48
49 this->err_mesg = std::string(err_mesg_buf);
50}
51
52const char* ExtrapError::what() const noexcept {return this->err_mesg.c_str();}
53
54} // namespace trv::sys
55
56namespace array {
57
59 std::vector<double>& a, bool check_lin, bool check_loglin, bool check_sign
60) {
61 std::size_t N = a.size();
62
63 if (check_lin) {
64 std::vector<double> diff_a(N - 1);
65 for (std::size_t i = 0; i < N - 1; i++) {
66 diff_a[i] = a[i + 1] - a[i];
67 }
68 if (!check_isclose(diff_a, diff_a[0])) {return 1;}
69 }
70
71 if (check_loglin) {
72 std::vector<double> diff_loga(N - 1);
73 std::feclearexcept(FE_ALL_EXCEPT);
74 for (std::size_t i = 0; i < N - 1; i++) {
75 diff_loga[i] = std::log(a[i + 1] / a[i]);
76 if (std::fetestexcept(FE_DIVBYZERO) || std::fetestexcept(FE_INVALID)) {
77 return 3;
78 }
79 }
80 if (!check_isclose(diff_loga, diff_loga[0])) {return 2;}
81 }
82
83 if (check_sign) {
84 for (std::size_t i = 0; i < N - 1; i++) {
85 if (a[i] * a[i + 1] <= 0.0) {return 3;}
86 }
87 }
88
89 return 0;
90}
91
93 std::vector<double>& a, int N_ext, std::vector<double>& a_ext
94) {
95 // Prepare arrays.
96 int N = a.size();
97 int N_notch_left = N_ext;
98 int N_notch_right = N_ext + N;
99 int N_extrap = N_ext + N + N_ext;
100
101 a_ext.resize(N_extrap);
102
103 // Extrapolate the lower end.
104 double da_left = a[1] - a[0];
105 for (int i = 0; i < N_notch_left; i++) {
106 a_ext[i] = a.front() + (i - N_notch_left) * da_left;
107 }
108
109 // Fill in the middle part.
110 for (int i = N_notch_left; i < N_notch_right; i++) {
111 a_ext[i] = a[i - N_notch_left];
112 }
113
114 // Extrapolate the upper end.
115 double da_right = a[N - 1] - a[N - 2];
116 for (int i = N_notch_right; i < N_extrap; i++) {
117 a_ext[i] = a.back() + (i - (N_notch_right - 1)) * da_right;
118 }
119}
120
122 std::vector<double>& a, int N_ext, std::vector<double>& a_ext
123) {
124 std::feclearexcept(FE_ALL_EXCEPT);
125
126 // Prepare arrays.
127 int N = a.size();
128 int N_notch_left = N_ext;
129 int N_notch_right = N_ext + N;
130 int N_extrap = N_ext + N + N_ext;
131
132 if (check_1d_array(a, false, false, true) != 0) {
133 throw std::invalid_argument(
134 "Sign change or zeros detected in the input array."
135 );
136 }
137
138 a_ext.resize(N_extrap);
139
140 // Extrapolate the lower end.
141 double dlna_left = std::log(a[1] / a[0]);
142 if (std::isnan(dlna_left)) {
143 throw std::invalid_argument(
144 "NaN detected at lower-end log-linear spacing."
145 );
146 }
147
148 for (int i = 0; i < N_notch_left; i++) {
149 a_ext[i] = a.front() * std::exp((i - N_notch_left) * dlna_left);
150 if (std::fetestexcept(FE_DIVBYZERO) || std::fetestexcept(FE_INVALID)) {
151 throw std::invalid_argument(
152 "NaN detected at lower-end log-linear extrapolation."
153 );
154 }
155 }
156
157 // Fill in the middle part.
158 for (int i = N_notch_left; i < N_notch_right; i++) {
159 a_ext[i] = a[i - N_ext];
160 }
161
162 // Extrapolate the upper end.
163 double dlna_right = std::log(a[N - 1] / a[N - 2]);
164 if (std::isnan(dlna_right)) {
165 throw std::invalid_argument(
166 "NaN detected at upper-end log-linear spacing."
167 );
168 }
169
170 for (int i = N_notch_right; i < N_extrap; i++) {
171 a_ext[i] = a.back() * std::exp((i - (N_notch_right - 1)) * dlna_right);
172 if (std::fetestexcept(FE_DIVBYZERO) || std::fetestexcept(FE_INVALID)) {
173 throw std::invalid_argument(
174 "NaN detected at upper-end log-linear extrapolation."
175 );
176 }
177 }
178}
179
181 std::vector<double>& a,
182 int N_ext, double c_lower, double c_upper,
183 std::vector<double>& a_ext
184) {
185 int N = a.size();
186 int N_notch_left = N_ext;
187 int N_notch_right = N_ext + N;
188 int N_extrap = N_ext + N + N_ext;
189
190 a_ext.resize(N_extrap);
191
192 for (int i = 0; i < N_notch_left; i++) {
193 a_ext[i] = c_lower;
194 }
195 for (int i = N_notch_left; i < N_notch_right; i++) {
196 a_ext[i] = a[i - N_notch_left];
197 }
198 for (int i = N_notch_right; i < N_extrap; i++) {
199 a_ext[i] = c_upper;
200 }
201}
202
204 std::vector< std::vector<double> >& a,
205 int N_row_ext, int N_col_ext,
206 std::vector< std::vector<double> >& a_ext
207) {
208 // FUTURE: Implement this function.
210 "Function `extrap2d_lin` is not yet implemented in the C++ backend."
211 );
212}
213
215 std::vector< std::vector<double> >& a,
216 int N_row_ext, int N_col_ext,
217 std::vector< std::vector<double> >& a_ext
218) {
219 // FUTURE: Implement this function.
221 "Function `extrap2d_loglin` is not yet implemented in the C++ backend."
222 );
223}
224
226 std::vector< std::vector<double> >& a,
227 int N_row_ext, int N_col_ext,
228 double c_row_lower, double c_row_upper,
229 double c_col_lower, double c_col_upper,
230 std::vector< std::vector<double> >& a_ext
231) {
232 // FUTURE: Implement this function.
234 "Function `extrap2d_pad` is not yet implemented in the C++ backend."
235 );
236}
237
238
239// ***********************************************************************
240// Sorting
241// ***********************************************************************
242
243std::vector<int> get_sorted_indices(std::vector<int> sorting_vector) {
244 // Create an index vector to store the indices of the elements.
245 std::vector<int> indices(sorting_vector.size());
246
247#ifdef TRV_USE_OMP
248#if defined(__GNUC__) && !defined(__clang__)
249#pragma omp parallel for simd
250#else // !__GNUC__ || __clang__
251#pragma omp parallel for
252#endif // __GNUC__ && !__clang__
253#endif // TRV_USE_OMP
254 for (int i = 0; i < int(sorting_vector.size()); i++) {
255 indices[i] = i;
256 }
257
258 // Sort the index vector based on the sorting vector.
259 std::sort(indices.begin(), indices.end(), [&](int a, int b) {
260 return sorting_vector[a] < sorting_vector[b];;
261 });
262
263 return indices;
264}
265
266} // namespace trv::array
267
268} // namespace trv
Array operations.
ExtrapError(const char *fmt_string,...)
Construct an trv::sys::ExtrapError exception.
Definition arrayops.cpp:39
std::string err_mesg
error message
Definition arrayops.hpp:57
virtual const char * what() const noexcept
Exception string representation.
Definition arrayops.cpp:52
Exception raised when a function or method is unimplemented.
Definition monitor.hpp:384
int check_1d_array(std::vector< double > &a, bool check_lin, bool check_loglin, bool check_sign)
Check the linearity or log-linearity of a 1-d array.
Definition arrayops.cpp:58
std::vector< int > get_sorted_indices(std::vector< int > sorting_vector)
Get the sorted indices.
Definition arrayops.cpp:243
bool check_isclose(const std::vector< T > &arr, const T val, T atol=1.e-8, T rtol=1.e-5)
Check if all elements of a 1-d array are close to a given value.
Definition arrayops.hpp:103
void extrap2d_loglin(std::vector< std::vector< double > > &a, int N_row_ext, int N_col_ext, std::vector< std::vector< double > > &a_ext)
Extrapolate a 2-d array bi-exponentially (i.e. log-bilinearly).
Definition arrayops.cpp:214
void extrap_loglin(std::vector< double > &a, int N_ext, std::vector< double > &a_ext)
Extrapolate a 1-d array exponentially (i.e. log-linearly).
Definition arrayops.cpp:121
void extrap2d_pad(std::vector< std::vector< double > > &a, int N_row_ext, int N_col_ext, double c_row_lower, double c_row_upper, double c_col_lower, double c_col_upper, std::vector< std::vector< double > > &a_ext)
Extrapolate a 2-d array by constant padding.
Definition arrayops.cpp:225
void extrap2d_lin(std::vector< std::vector< double > > &a, int N_row_ext, int N_col_ext, std::vector< std::vector< double > > &a_ext)
Extrapolate a 2-d array bi-linearly.
Definition arrayops.cpp:203
void extrap_lin(std::vector< double > &a, int N_ext, std::vector< double > &a_ext)
Extrapolate a 1-d array linearly.
Definition arrayops.cpp:92
void extrap_pad(std::vector< double > &a, int N_ext, double c_lower, double c_upper, std::vector< double > &a_ext)
Extrapolate a 1-d array by constant padding.
Definition arrayops.cpp:180