Triumvirate C++ API 0.5.0.post1.dev301+g026f21751
Three-point clustering measurements in large-scale structure analyses.
Loading...
Searching...
No Matches
arrayops.cpp
Go to the documentation of this file.
1// Triumvirate: Three-Point Clustering Measurements in LSS
2//
3// Copyright (C) 2023 Mike S Wang & Naonori S Sugiyama [GPL-3.0-or-later]
4//
5// This file is part of the Triumvirate program. See the COPYRIGHT
6// and LICENCE files at the top-level directory of this distribution
7// for details of copyright and licensing.
8//
9// This program is free software: you can redistribute it and/or modify it
10// under the terms of the GNU General Public License as published by
11// the Free Software Foundation, either version 3 of the License, or
12// (at your option) any later version.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17// See the GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this program. If not, see <https://www.gnu.org/licenses/>.
21
28
29#include "arrayops.hpp"
30
31namespace trvs = trv::sys;
32
33namespace trv {
34
35// ***********************************************************************
36// Extrapolation
37// ***********************************************************************
38
39namespace sys {
40
41ExtrapError::ExtrapError(const char* fmt_string, ...) : std::runtime_error(
42 "Extrapolation error." // mandatory default error message
43) {
44 std::va_list args;
45
46 char err_mesg_buf[4096];
47 va_start(args, fmt_string);
48 std::vsnprintf(err_mesg_buf, sizeof(err_mesg_buf), fmt_string, args);
49 va_end(args);
50
51 this->err_mesg = std::string(err_mesg_buf);
52}
53
54const char* ExtrapError::what() const noexcept {return this->err_mesg.c_str();}
55
56} // namespace trv::sys
57
58namespace array {
59
61 std::vector<double>& a, bool check_lin, bool check_loglin, bool check_sign
62) {
63 std::size_t N = a.size();
64
65 if (check_lin) {
66 std::vector<double> diff_a(N - 1);
67 for (std::size_t i = 0; i < N - 1; i++) {
68 diff_a[i] = a[i + 1] - a[i];
69 }
70 if (!check_isclose(diff_a, diff_a[0])) {return 1;}
71 }
72
73 if (check_loglin) {
74 std::vector<double> diff_loga(N - 1);
75 std::feclearexcept(FE_ALL_EXCEPT);
76 for (std::size_t i = 0; i < N - 1; i++) {
77 diff_loga[i] = std::log(a[i + 1] / a[i]);
78 if (std::fetestexcept(FE_DIVBYZERO) || std::fetestexcept(FE_INVALID)) {
79 return 3;
80 }
81 }
82 if (!check_isclose(diff_loga, diff_loga[0])) {return 2;}
83 }
84
85 if (check_sign) {
86 for (std::size_t i = 0; i < N - 1; i++) {
87 if (a[i] * a[i + 1] <= 0.0) {return 3;}
88 }
89 }
90
91 return 0;
92}
93
95 std::vector<double>& a, int N_ext, std::vector<double>& a_ext
96) {
97 // Prepare arrays.
98 int N = a.size();
99 int N_notch_left = N_ext;
100 int N_notch_right = N_ext + N;
101 int N_extrap = N_ext + N + N_ext;
102
103 a_ext.resize(N_extrap);
104
105 // Extrapolate the lower end.
106 double da_left = a[1] - a[0];
107 for (int i = 0; i < N_notch_left; i++) {
108 a_ext[i] = a.front() + (i - N_notch_left) * da_left;
109 }
110
111 // Fill in the middle part.
112 for (int i = N_notch_left; i < N_notch_right; i++) {
113 a_ext[i] = a[i - N_notch_left];
114 }
115
116 // Extrapolate the upper end.
117 double da_right = a[N - 1] - a[N - 2];
118 for (int i = N_notch_right; i < N_extrap; i++) {
119 a_ext[i] = a.back() + (i - (N_notch_right - 1)) * da_right;
120 }
121}
122
124 std::vector<double>& a, int N_ext, std::vector<double>& a_ext
125) {
126 std::feclearexcept(FE_ALL_EXCEPT);
127
128 // Prepare arrays.
129 int N = a.size();
130 int N_notch_left = N_ext;
131 int N_notch_right = N_ext + N;
132 int N_extrap = N_ext + N + N_ext;
133
134 if (check_1d_array(a, false, false, true) != 0) {
135 throw std::invalid_argument(
136 "Sign change or zeros detected in the input array."
137 );
138 }
139
140 a_ext.resize(N_extrap);
141
142 // Extrapolate the lower end.
143 double dlna_left = std::log(a[1] / a[0]);
144 if (std::isnan(dlna_left)) {
145 throw std::invalid_argument(
146 "NaN detected at lower-end log-linear spacing."
147 );
148 }
149
150 for (int i = 0; i < N_notch_left; i++) {
151 a_ext[i] = a.front() * std::exp((i - N_notch_left) * dlna_left);
152 if (std::fetestexcept(FE_DIVBYZERO) || std::fetestexcept(FE_INVALID)) {
153 throw std::invalid_argument(
154 "NaN detected at lower-end log-linear extrapolation."
155 );
156 }
157 }
158
159 // Fill in the middle part.
160 for (int i = N_notch_left; i < N_notch_right; i++) {
161 a_ext[i] = a[i - N_ext];
162 }
163
164 // Extrapolate the upper end.
165 double dlna_right = std::log(a[N - 1] / a[N - 2]);
166 if (std::isnan(dlna_right)) {
167 throw std::invalid_argument(
168 "NaN detected at upper-end log-linear spacing."
169 );
170 }
171
172 for (int i = N_notch_right; i < N_extrap; i++) {
173 a_ext[i] = a.back() * std::exp((i - (N_notch_right - 1)) * dlna_right);
174 if (std::fetestexcept(FE_DIVBYZERO) || std::fetestexcept(FE_INVALID)) {
175 throw std::invalid_argument(
176 "NaN detected at upper-end log-linear extrapolation."
177 );
178 }
179 }
180}
181
183 std::vector<double>& a,
184 int N_ext, double c_lower, double c_upper,
185 std::vector<double>& a_ext
186) {
187 int N = a.size();
188 int N_notch_left = N_ext;
189 int N_notch_right = N_ext + N;
190 int N_extrap = N_ext + N + N_ext;
191
192 a_ext.resize(N_extrap);
193
194 for (int i = 0; i < N_notch_left; i++) {
195 a_ext[i] = c_lower;
196 }
197 for (int i = N_notch_left; i < N_notch_right; i++) {
198 a_ext[i] = a[i - N_notch_left];
199 }
200 for (int i = N_notch_right; i < N_extrap; i++) {
201 a_ext[i] = c_upper;
202 }
203}
204
206 std::vector< std::vector<double> >& a,
207 int N_row_ext, int N_col_ext,
208 std::vector< std::vector<double> >& a_ext
209) {
210 // FUTURE: Implement this function.
212 "Function `extrap2d_lin` is not yet implemented in the C++ backend."
213 );
214}
215
217 std::vector< std::vector<double> >& a,
218 int N_row_ext, int N_col_ext,
219 std::vector< std::vector<double> >& a_ext
220) {
221 // FUTURE: Implement this function.
223 "Function `extrap2d_loglin` is not yet implemented in the C++ backend."
224 );
225}
226
228 std::vector< std::vector<double> >& a,
229 int N_row_ext, int N_col_ext,
230 double c_row_lower, double c_row_upper,
231 double c_col_lower, double c_col_upper,
232 std::vector< std::vector<double> >& a_ext
233) {
234 // FUTURE: Implement this function.
236 "Function `extrap2d_pad` is not yet implemented in the C++ backend."
237 );
238}
239
240
241// ***********************************************************************
242// Sorting
243// ***********************************************************************
244
245std::vector<int> get_sorted_indices(std::vector<int> sorting_vector) {
246 // Create an index vector to store the indices of the elements.
247 std::vector<int> indices(sorting_vector.size());
248
249#ifdef TRV_USE_OMP
250#if defined(__GNUC__) && !defined(__clang__)
251#pragma omp parallel for simd
252#else // !__GNUC__ || __clang__
253#pragma omp parallel for
254#endif // __GNUC__ && !__clang__
255#endif // TRV_USE_OMP
256 for (std::size_t i = 0; i < sorting_vector.size(); i++) {
257 indices[i] = i;
258 }
259
260 // Sort the index vector based on the sorting vector.
261 std::sort(indices.begin(), indices.end(), [&](std::size_t a, std::size_t b) {
262 return sorting_vector[a] < sorting_vector[b];;
263 });
264
265 return indices;
266}
267
268
269// ***********************************************************************
270// Memory management
271// ***********************************************************************
272
273#if defined(TRV_USE_HIP)
274void copy_complex_array_dtoh(
275 fft_double_complex* d_arr, fftw_complex* arr, std::size_t length
276) {
277 HIP_EXEC(hipMemcpy(
278 arr,
279 d_arr,
280 sizeof(fft_double_complex) * length,
281 hipMemcpyDeviceToHost
282 ));
283}
284
285void copy_complex_array_htod(
286 fftw_complex* arr, fft_double_complex* d_arr, std::size_t length
287) {
288 HIP_EXEC(hipMemcpy(
289 d_arr,
290 arr,
291 sizeof(fftw_complex) * length,
292 hipMemcpyHostToDevice
293 ));
294}
295
296#elif defined(TRV_USE_CUDA) // !TRV_USE_HIP && TRV_USE_CUDA
297void copy_complex_array_dtoh(
298 fft_double_complex* d_arr, fftw_complex* arr, std::size_t length
299) {
300 CUDA_EXEC(cudaMemcpy(
301 reinterpret_cast<void*>(arr),
302 reinterpret_cast<void*>(d_arr),
303 sizeof(fft_double_complex) * length,
304 cudaMemcpyDeviceToHost
305 ));
306}
307
308void copy_complex_array_htod(
309 fftw_complex* arr, fft_double_complex* d_arr, std::size_t length
310) {
311 CUDA_EXEC(cudaMemcpy(
312 reinterpret_cast<void*>(d_arr),
313 reinterpret_cast<void*>(arr),
314 sizeof(fftw_complex) * length,
315 cudaMemcpyHostToDevice
316 ));
317}
318#endif // TRV_USE_HIP
319
320#if defined(TRV_USE_HIP)
321#elif defined(TRV_USE_CUDA) // !TRV_USE_HIP && TRV_USE_CUDA
322void copy_complex_array_dtoh_mgpu(
323 fftHandle plan, libXtDesc* libxt_desc, fftw_complex* arr
324) {
325 CUFFT_EXEC(cufftXtMemcpy(
326 plan,
327 reinterpret_cast<void*>(arr),
328 reinterpret_cast<void*>(libxt_desc),
329 CUFFT_COPY_DEVICE_TO_HOST
330 ));
331}
332
333void copy_complex_array_htod_mgpu(
334 fftHandle plan, libXtDesc* libxt_desc, fftw_complex* arr
335) {
336 CUFFT_EXEC(cufftXtMemcpy(
337 plan,
338 reinterpret_cast<void*>(libxt_desc),
339 reinterpret_cast<void*>(arr),
340 CUFFT_COPY_HOST_TO_DEVICE
341 ));
342}
343#endif // TRV_USE_HIP
344} // namespace trv::array
345
346} // namespace trv
Array operations.
ExtrapError(const char *fmt_string,...)
Construct an trv::sys::ExtrapError exception.
Definition arrayops.cpp:41
std::string err_mesg
error message
Definition arrayops.hpp:76
virtual const char * what() const noexcept
Exception string representation.
Definition arrayops.cpp:54
Exception raised when a function or method is unimplemented.
Definition monitor.hpp:683
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:60
std::vector< int > get_sorted_indices(std::vector< int > sorting_vector)
Get the sorted indices.
Definition arrayops.cpp:245
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:121
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:216
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:123
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:227
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:205
void extrap_lin(std::vector< double > &a, int N_ext, std::vector< double > &a_ext)
Extrapolate a 1-d array linearly.
Definition arrayops.cpp:94
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:182