Files

401 lines
11 KiB
C
Raw Permalink Normal View History

2025-12-17 10:53:43 +08:00
#ifndef UTILS_H
#define UTILS_H
#include <iostream>
#include <math.h>
#include <string.h>
#include <fstream>
#include <sys/stat.h>
#include <iomanip>
#include <sstream>
#include <cmath>
#include <new> // for std::bad_alloc
#include <cstdlib> // for std::exit
// chec if compiler is gcc 7.5 or older
//#if __GNUC__ == 7 && __GNUC_MINOR__ <= 5
//#include <experimental/filesystem>
//#define GNUC_7_5
//#elif __cplusplus > 201402L // compilers supporting c++17
//#include <filesystem>
//#endif
#include "config.h"
inline int mkpath(std::string s,mode_t mode) {
size_t pos=0;
std::string dir;
int mdret = 0;
if(s[s.size()-1]!='/'){
// force trailing / so we can handle everything in loop
s+='/';
}
while((pos=s.find_first_of('/',pos))!=std::string::npos){
dir=s.substr(0,pos++);
if(dir.size()==0) continue; // if leading / first time is 0 length
if((mdret=mkdir(dir.c_str(),mode)) && errno!=EEXIST){
return mdret;
}
}
return mdret;
}
inline void create_output_dir(std::string dir_path){
// create output directory if not exists (directories tree)
if (world_rank == 0) {
//#if __cplusplus > 201402L && !defined(GNUC_7_5)
// // this function requires c++17
// if (!std::filesystem::exists(dir_path)){
// std::filesystem::create_directories(dir_path);
// } else {
// std::cout << "Output directory already exists. Overwriting..." << std::endl;
// }
//#else // compilers not supporting std++17
// check if directory exists
struct stat info;
if (stat(dir_path.c_str(), &info) != 0){
// directory does not exist
// create directory
int status = mkpath(dir_path, 0755);
if (status != 0){
std::cout << "Error: cannot create output directory" << std::endl;
std::cout << "Exiting..." << std::endl;
exit(1);
}
} else {
// directory exists
std::cout << "Output directory already exists. Overwriting..." << std::endl;
}
//#endif
}
}
inline bool is_file_exist(const char* fileName)
{
return static_cast<bool>(std::ifstream(fileName));
}
inline void stdout_by_main(char const* str){
if (sim_rank == 0 && inter_sub_rank == 0 && sub_rank == 0 && id_sim == 0)
std::cout << str << std::endl;
}
inline void stdout_by_rank_zero(char const* str){
if(world_rank == 0)
std::cout << str << std::endl;
}
inline void parse_options(int argc, char* argv[]){
bool input_file_found = false;
for (int i = 1; i < argc; i++){
if(strcmp(argv[i], "-v") == 0)
if_verbose = true;
else if (strcmp(argv[i],"-i") == 0){
input_file = argv[i+1];
input_file_found = true;
}
else if (strcmp(argv[i], "-h") == 0){
stdout_by_main("usage: mpirun -np 4 TOMOATT -i input_params.yaml");
exit(EXIT_SUCCESS);
}
}
// error if input_file is not found
if(!input_file_found){
stdout_by_main("usage: mpirun -np 4 TOMOATT -i input_params.yaml");
std::cout << "Error: input parameter file not found" << std::endl;
exit(EXIT_FAILURE);
}
}
inline void parse_options_srcrec_weight(int argc, char* argv[]){
bool input_file_found = false;
for (int i = 1; i < argc; i++){
if(strcmp(argv[i], "-v") == 0)
if_verbose = true;
else if (strcmp(argv[i],"-i") == 0){
input_file = argv[i+1];
input_file_found = true;
} else if (strcmp(argv[i],"-r") == 0){
// reference value
ref_value = atof(argv[i+1]);
} else if (strcmp(argv[i], "-o") == 0){
// get output filename
output_file_weight = argv[i+1];
}
}
// error if input_file is not found
if(!input_file_found){
stdout_by_main("usage: ./SrcRecWeight -i srcrec_file.txt -r 10.0 -o srcrec_weight.txt");
std::cout << argc << std::endl;
exit(EXIT_FAILURE);
}
}
template <typename T>
inline int check_data_type(T const& data){
if (std::is_same<T,bool>::value){
return 0;
} else if (std::is_same<T, int>::value){
return 1;
} else if (std::is_same<T, float>::value){
return 2;
} else if (std::is_same<T, double>::value){
return 3;
} else {
std::cout << "Error: custom real type is not float or double" << std::endl;
std::cout << "Please check the definition of CUSTOMREAL in io.h" << std::endl;
std::cout << "Exiting..." << std::endl;
exit(1);
}
}
template <typename T>
inline T my_square(T const& a){
return a * a;
}
// defined function is more than 2 times slower than inline function
//#define my_square(a) (a * a)
template <typename T>
T* allocateMemory(size_t size, int allocationID) {
try {
T* ptr = new T[size];
return ptr;
} catch (const std::bad_alloc& e) {
// Handle memory allocation failure
std::cerr << "Memory allocation failed for ID " << allocationID << ": " << e.what() << std::endl;
std::exit(EXIT_FAILURE); // Exit the program on allocation failure
}
}
inline void RLonLat2xyz(CUSTOMREAL lon, CUSTOMREAL lat, CUSTOMREAL R, CUSTOMREAL& x, CUSTOMREAL& y, CUSTOMREAL& z){
/*
lon : longitude in radian
lat : latitude in radian
R : radius
x : x coordinate in m
y : y coordinate in m
z : z coordinate in m
*/
//x = R*cos(lat*DEG2RAD)*cos(lon*DEG2RAD);
//y = R*cos(lat*DEG2RAD)*sin(lon*DEG2RAD);
//z = R*sin(lat*DEG2RAD);
x = R*cos(lat)*cos(lon);
y = R*cos(lat)*sin(lon);
z = R*sin(lat);
}
// calculate epicentral distance in radian from lon lat in radian
inline void Epicentral_distance_sphere(const CUSTOMREAL lat1, const CUSTOMREAL lon1, \
const CUSTOMREAL lat2, const CUSTOMREAL lon2, \
CUSTOMREAL& dist) {
// calculate epicentral distance in radian
//dist = std::abs(acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon2-lon1)));
CUSTOMREAL lon_dif = lon2 - lon1;
dist = std::atan2(std::sqrt((my_square(std::cos(lat2) * std::sin(lon_dif)) + \
my_square(std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_dif)))), \
std::sin(lat1) * std::sin(lat2) + std::cos(lat1) * std::cos(lat2) * std::cos(lon_dif));
}
//calculate azimuth
inline void Azimuth_sphere(CUSTOMREAL lat1, CUSTOMREAL lon1, \
CUSTOMREAL lat2, CUSTOMREAL lon2, \
CUSTOMREAL& azi) {
if (isZero(my_square((lat1-lat2)) \
&& + my_square((lon1-lon2)))){
azi = _0_CR;
} else {
azi = atan2(sin(lon2-lon1)*cos(lat2), \
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1));
if (azi < _0_CR)
azi += _2_CR * PI;
}
}
inline void WGS84ToCartesian(CUSTOMREAL& lon, CUSTOMREAL& lat, CUSTOMREAL R, \
CUSTOMREAL& x, CUSTOMREAL& y, CUSTOMREAL& z, \
CUSTOMREAL& lon_center, CUSTOMREAL& lat_center){
// equatorial radius WGS84 major axis
const static CUSTOMREAL equRadius = R_earth; // in m in this function
const static CUSTOMREAL flattening = 1.0 / 298.257222101;
const static CUSTOMREAL sqrEccentricity = flattening * (2.0 - flattening);
const CUSTOMREAL lat_rad = lat - lat_center; // input should be already in radian
const CUSTOMREAL lon_rad = lon - lon_center;
const CUSTOMREAL alt = R - equRadius; // altitude (height above sea level)
const CUSTOMREAL sinLat = sin(lat_rad);
const CUSTOMREAL cosLat = cos(lat_rad);
const CUSTOMREAL sinLon = sin(lon_rad);
const CUSTOMREAL cosLon = cos(lon_rad);
// Normalized radius
const CUSTOMREAL normRadius = equRadius / sqrt(1.0 - sqrEccentricity * sinLat * sinLat);
x = (normRadius + alt) * cosLat * cosLon;
y = (normRadius + alt) * cosLat * sinLon;
z = (normRadius * (1.0 - sqrEccentricity) + alt) * sinLat;
}
template <typename T>
inline T dot_product(T const* const a, T const* const b, int const& n){
CUSTOMREAL result = _0_CR;
for (int i = 0; i < n; i++){
result += a[i] * b[i];
}
return result;
}
template <typename T>
inline T find_max(T const* const a, int const& n){
T max = a[0];
for (int i = 1; i < n; i++){
if (a[i] > max){
max = a[i];
}
}
return max;
}
template <typename T>
inline T find_absmax(T const* const a, int const& n){
T max = fabs(a[0]);
for (int i = 1; i < n; i++){
if (fabs(a[i]) > max){
max = fabs(a[i]);
}
}
return max;
}
template <typename T>
inline T calc_l2norm(T const* const a, int const& n){
T result = _0_CR;
for (int i = 0; i < n; i++){
result += a[i] * a[i];
}
return result;
}
inline std::string int2string_zero_fill(int i) {
std::stringstream ss;
ss << std::setfill('0') << std::setw(4) << i;
return ss.str();
}
inline bool in_between(CUSTOMREAL const& a, CUSTOMREAL const& b, CUSTOMREAL const& c){
// check if a is between b and c
if ((a-b)*(a-c) <= _0_CR){
return true;
} else {
return false;
}
}
inline CUSTOMREAL calc_ratio_between(CUSTOMREAL const& a, CUSTOMREAL const& b, CUSTOMREAL const& c){
// calculate ratio of a between b and c
//if (b < c)
return (a - b) / (c - b);
//else
// return (a - b) / (b - c);
}
inline void linear_interpolation_1d_sorted(const CUSTOMREAL* x1, const CUSTOMREAL* y1, const int& n1, const CUSTOMREAL* x2, CUSTOMREAL* y2, const int& n2){
// linear interpolation for sorted 1d array (monotonely increasing)
// x1 : positions of the first array
// y1 : values of the first array
// n1 : size of the first array
// x2 : positions of the second array
// y2 : values of the second array
// n2 : size of the second array
int start = 0;
for(int pt2=0; pt2<n2; pt2++){ // x2[pt2] <= x1[0]
if (x2[pt2] <= x1[0]){
y2[pt2] = y1[0];
} else if (x2[pt2] >= x1[n1-1]){ // x2[pt2] >= x1[n1-1]
y2[pt2] = y1[n1-1];
} else { // x1[0] < x2[pt2] < x1[n1-1]
for(int pt1=start; pt1<n1-1; pt1++){
if (x2[pt2] >= x1[pt1] && x2[pt2] <= x1[pt1+1]){
y2[pt2] = y1[pt1] + (y1[pt1+1] - y1[pt1]) * (x2[pt2] - x1[pt1]) / (x1[pt1+1] - x1[pt1]);
start = pt1;
break;
}
}
}
}
}
template<typename T>
std::vector<CUSTOMREAL> linspace(T start_in, T end_in, int num_in)
{
std::vector<CUSTOMREAL> linspaced;
double start = static_cast<CUSTOMREAL>(start_in);
double end = static_cast<CUSTOMREAL>(end_in);
double num = static_cast<CUSTOMREAL>(num_in);
if (num == 0) { return linspaced; }
if (num == 1)
{
linspaced.push_back(start);
return linspaced;
}
double delta = (end - start) / (num - 1);
for(int i=0; i < num-1; ++i)
{
linspaced.push_back(start + delta * i);
}
linspaced.push_back(end); // I want to ensure that start and end
// are exactly the same as the input
return linspaced;
}
#endif // UTILS_H