39 if (fname.length() >= fext.length()) {
40 return (fname.rfind(fext) == (fname.length() - fext.length()));
46 const std::vector<std::string>& strings,
47 const std::string& delimiter
49 std::ostringstream oss;
50 for (
auto it = strings.begin(); it != strings.end(); ++it) {
52 if (std::next(it) != strings.end()) {
60 const std::string& str,
61 const std::string& delimiter
66 if (delimiter.empty()) {
70 std::string fullstr = {str};
72 std::size_t dlpos = 0;
74 std::vector<std::string> strings;
75 while ((dlpos = fullstr.find(delimiter)) != std::string::npos) {
76 substr = fullstr.substr(0, dlpos);
77 fullstr.erase(0, dlpos + delimiter.length());
78 strings.push_back(substr);
80 if (!fullstr.empty()) {
81 strings.push_back(fullstr);
119#if defined(TRV_USE_HIP)
120double worksize_in_gb(
123 int nx,
int ny,
int nz,
124 std::vector<int> gpus
126 std::vector<std::size_t> worksizes(gpus.size());
127 HIPFFT_EXEC(hipfftGetSize3d(plan, nx, ny, nz, ffttype, worksizes.data()));
129 std::size_t totsize = 0;
130 for (std::size_t
id = 0;
id < gpus.size(); ++id) {
131 totsize += worksizes[id];
134 const double BYTES_PER_GBYTES = 1073741824.;
135 double worksize_gb = double(totsize) / BYTES_PER_GBYTES;
139#elif defined(TRV_USE_CUDA)
140double worksize_in_gb(
143 int nx,
int ny,
int nz,
144 std::size_t* worksizes,
145 std::vector<int> gpus
147 std::size_t totsize = 0;
148 if (gpus.size() == 1) {
149 CUFFT_EXEC(cufftGetSize3d(plan, nx, ny, nz, ffttype, &totsize));
151 CUFFT_EXEC(cufftGetSize3d(plan, nx, ny, nz, ffttype, worksizes));
153 for (std::size_t
id = 0;
id < gpus.size(); ++id) {
154 totsize += worksizes[id];
158 const double BYTES_PER_GBYTES = 1073741824.;
159 double worksize_gb = double(totsize) / BYTES_PER_GBYTES;
191 auto now = std::chrono::system_clock::now();
192 auto timenow = std::chrono::system_clock::to_time_t(now);
198 buffer,
sizeof(buffer),
"%Y-%m-%dT%H:%M:%SZ", std::gmtime(&timenow)
202 buffer,
sizeof(buffer),
"%Y-%m-%d %H:%M:%S", std::localtime(&timenow)
207 std::string timestamp = std::string(buffer);
214 int time = int(elapsed_time_in_seconds);
217 std::string h = std::to_string(time / 3600);
218 std::string m = std::to_string((time % 3600) / 60);
219 std::string s = std::to_string(time % 60);
223 if (h.length() < 2) {
224 hh = std::string(2 - h.length(),
'0') + h;
229 std::string mm = std::string(2 - m.length(),
'0') + m;
230 std::string ss = std::string(2 - s.length(),
'0') + s;
233 std::string elapsed_time = hh +
":" + mm +
":" + ss;
240 double elapsed_time = double(
241 std::chrono::duration_cast<std::chrono::seconds>(
247 char timestamp_[128];
249 timestamp_,
sizeof(timestamp_),
"%s (+%s)",
253 std::string timestamp(timestamp_);
260#if defined(TRV_USE_HIP)
261 HIP_EXEC(hipGetDeviceCount(&num_gpus));
262#elif defined(TRV_USE_CUDA)
263 CUDA_EXEC(cudaGetDeviceCount(&num_gpus));
270 int max_gpus = num_gpus;
272 char* env_gpu_maxnum = std::getenv(
"TRV_GPU_MAXNUM");
273 if (env_gpu_maxnum !=
nullptr) {
274 std::string gpu_maxnum(env_gpu_maxnum);
275 std::regex re_int(
"^[0-9]+$");
276 if (std::regex_match(gpu_maxnum, re_int)) {
277 max_gpus = std::stoi(gpu_maxnum);
281 return num_gpus > max_gpus ? max_gpus : num_gpus;
285 std::vector<int> gpu_ids;
287 gpu_ids.push_back(i);
303 char* env_gpu_mode = std::getenv(
"TRV_GPU_MODE");
304 if (env_gpu_mode !=
nullptr) {
305 std::string gpu_mode(env_gpu_mode);
328 std::cout <<
"\n\033[1;37;41mFATAL\033[0m: " << msg << std::endl;
330 std::cout <<
"\nFATAL: " << msg << std::endl;
333 std::exit(EXIT_FAILURE);
353 std::string log_type,
const char* fmt_string, std::va_list args
355 char log_mesg_buf[4096];
356 std::vsnprintf(log_mesg_buf,
sizeof(log_mesg_buf), fmt_string, args);
358 if (log_type.empty()) {
374 Logger::log(
static_cast<int>(entry_level), fmt_string);
382 std::string log_type;
386 switch (level_entry) {
391 log_type =
"\033[0;36mDBUG\033[0m";
394 log_type =
"\033[0;34mSTAT\033[0m";
397 log_type =
"\033[0;32mINFO\033[0m";
400 log_type =
"\033[0;33mWARN\033[0m";
403 log_type =
"\033[0;31mERRO\033[0m";
410 switch (level_entry) {
435 va_start(args, fmt_string);
436 Logger::emit(log_type, fmt_string, args);
444 va_start(args, fmt_string);
446 Logger::emit(
"\033[0;36mDBUG\033[0m", fmt_string, args);
448 Logger::emit(
"DBUG", fmt_string, args);
457 va_start(args, fmt_string);
459 Logger::emit(
"\033[0;34mSTAT\033[0m", fmt_string, args);
461 Logger::emit(
"STAT", fmt_string, args);
470 va_start(args, fmt_string);
472 Logger::emit(
"\033[0;32mINFO\033[0m", fmt_string, args);
474 Logger::emit(
"INFO", fmt_string, args);
483 va_start(args, fmt_string);
485 Logger::emit(
"\033[0;33mWARN\033[0m", fmt_string, args);
487 Logger::emit(
"WARN", fmt_string, args);
496 va_start(args, fmt_string);
498 Logger::emit(
"\033[1;31mERRO\033[0m", fmt_string, args);
500 Logger::emit(
"ERRO", fmt_string, args);
507 char* ev_term = std::getenv(
"TERM");
508 char* ev_interactive = std::getenv(
"TRV_INTERACTIVE");
509 if (ev_term ==
nullptr || ev_interactive ==
nullptr) {
512 if (std::strstr(ev_term,
"color") ==
nullptr) {
515 std::string str_interactive = std::string(ev_interactive);
517 str_interactive ==
"true" ||
518 str_interactive ==
"yes" ||
519 str_interactive ==
"1" ||
520 str_interactive ==
"on"
529 "Progress bar must count at least one task in total."
534 this->set_default_pcpt_nodes();
541 this->bar_width = width;
545 if (nodes.size() < 1) {
547 "Progress bar nodes must have at least one element."
556 "Progress bar task index must be non-negative and "
557 "within the total task count."
562 float progress = float(this->task_idx) / float(this->task_count);
569 "Progress bar progress must be within the range [0, 1]."
574 this->next_node_idx = 0;
575 while (this->progress > this->nodes[this->next_node_idx]) {
576 this->next_node_idx += 1;
583 this->
update(progress_now);
590 if (this->
progress >= this->nodes[this->next_node_idx]) {
591 int pos = this->bar_width * this->
progress;
597 std::cout <<
" \033[0;34mSTAT\033[0m";
599 std::cout <<
" STAT";
606 std::cout <<
"\033[0;34m";
608 for (
int ichar = 0; ichar < this->bar_width; ichar++) {
619 std::cout <<
"\033[0m";
621 std::cout <<
"] " << int(
progress * 100.) <<
"%";
624 if (this->
name !=
"") {
625 std::cout <<
" < " << this->
name;
632 this->next_node_idx += 1;
636 "Progress bar has already completed: progress %f > 1.", this->
progress
639 if (this->
progress == 1.) {std::cout << std::endl;}
642void ProgressBar::set_default_pcpt_nodes() {
643 this->nodes.resize(101, 0.);
644 for (
int pcpt = 0; pcpt <= 100; ++pcpt) {
645 this->nodes.push_back(
float(pcpt) / 100.);
651 std::stof(interval_str);
652 }
catch (
const std::invalid_argument& e) {
654 "Progress bar interval must be a float number."
658 float interval = std::stof(interval_str);
659 if (!(0. < interval && interval < 100.)) {
661 "Progress bar interval must be in (0, 100) interval."
666 std::vector<float> nodes = {interval};
667 while (nodes.back() < 1.) {
668 if (nodes.back() + interval < 1.) {
669 nodes.push_back(nodes.back() + interval);
685 "Unimplemented error."
689 char err_mesg_buf[4096];
690 va_start(args, fmt_string);
691 std::vsnprintf(err_mesg_buf,
sizeof(err_mesg_buf), fmt_string, args);
694 this->
err_mesg = std::string(err_mesg_buf);
706 char err_mesg_buf[4096];
707 va_start(args, fmt_string);
708 std::vsnprintf(err_mesg_buf,
sizeof(err_mesg_buf), fmt_string, args);
711 this->
err_mesg = std::string(err_mesg_buf);
717std::invalid_argument(
718 "Invalid parameter error."
722 char err_mesg_buf[4096];
723 va_start(args, fmt_string);
724 std::vsnprintf(err_mesg_buf,
sizeof(err_mesg_buf), fmt_string, args);
727 this->
err_mesg = std::string(err_mesg_buf);
736 "Invalid data error."
740 char err_mesg_buf[4096];
741 va_start(args, fmt_string);
742 std::vsnprintf(err_mesg_buf,
sizeof(err_mesg_buf), fmt_string, args);
745 this->
err_mesg = std::string(err_mesg_buf);
759 auto convert_month_from_name_to_num = [](
const std::string& month) ->
int {
760 if (month ==
"Jan")
return 1;
761 if (month ==
"Feb")
return 2;
762 if (month ==
"Mar")
return 3;
763 if (month ==
"Apr")
return 4;
764 if (month ==
"May")
return 5;
765 if (month ==
"Jun")
return 6;
766 if (month ==
"Jul")
return 7;
767 if (month ==
"Aug")
return 8;
768 if (month ==
"Sep")
return 9;
769 if (month ==
"Oct")
return 10;
770 if (month ==
"Nov")
return 11;
771 if (month ==
"Dec")
return 12;
776 std::string month_str = std::string(__DATE__).substr(0, 3);
777 int month = convert_month_from_name_to_num(month_str);
779 int day = std::stoi(std::string(__DATE__).substr(4, 2));
780 int year = std::stoi(std::string(__DATE__).substr(7, 4));
782 int hour = std::stoi(std::string(__TIME__).substr(0, 2));
783 int minute = std::stoi(std::string(__TIME__).substr(3, 2));
784 int second = std::stoi(std::string(__TIME__).substr(6, 2));
786 int hour_tzoffset = 0;
787 int minute_tzoffset = 0;
788 int status_tzoffset = 0;
791 std::strlen(__TZOFFSET__) == 5
792 && (__TZOFFSET__[0] ==
'+' || __TZOFFSET__[0] ==
'-')
794 int _tzos_sign = (__TZOFFSET__[0] ==
'-') ? -1 : 1;
795 int _hr_tzoffset = std::stoi(std::string(__TZOFFSET__).substr(1, 2));
796 int _min_tzoffset = std::stoi(std::string(__TZOFFSET__).substr(3, 2));
798 0 <= hour_tzoffset && hour_tzoffset < 24
799 && 0 <= minute_tzoffset && minute_tzoffset < 60
801 hour_tzoffset = _tzos_sign * _hr_tzoffset;
802 minute_tzoffset = _tzos_sign * _min_tzoffset;
809 }
catch (
const std::invalid_argument& e) {
811 }
catch (
const std::out_of_range& e) {
815 if (status_tzoffset == 0) {
816 hour -= hour_tzoffset;
817 minute -= minute_tzoffset;
838 bdtm.tm_year = year - 1900;
839 bdtm.tm_mon = month - 1;
842 bdtm.tm_min = minute;
843 bdtm.tm_sec = second;
847 if (status_tzoffset == 0) {
848 std::strftime(bdt,
sizeof(bdt),
"%Y-%m-%dT%H:%M:%SZ", &bdtm);
850 std::strftime(bdt,
sizeof(bdt),
"%Y-%m-%dT%H:%M:%S", &bdtm);
853 return std::string(bdt);
858 "Triumvirate: Three-Point Clustering Measurements in LSS\n"
860 "\033[1mUsage:\033[0m triumvirate [-h] [-V] <parameter-ini-file>\n"
862 "\033[1mPositional arguments:\033[0m\n"
863 " <parameter-ini-file> path to the parameter INI file\n"
865 "\033[1mOptions:\033[0m\n"
866 " -h, --help show help message and exit\n"
867 " -V, --version show version and licensing information and exit\n"
874 " //\\ ___ __ __ ___ ___ \n"
875 " // \\ | |__) | | | |\\/| \\ / | |__) /\\ | |__ \n"
876 " // \\ | | \\ | \\__/ | | \\/ | | \\ /~~\\ | |___ \n"
882 "• \033[1mThree-Point Clustering Measurements in LSS\033[0m • \n"
885 std::printf(
"• Three-Point Clustering Measurements in LSS • \n");
891 std::printf(
"Copyright (C) 2023 Mike S Wang & Naonori S Sugiyama\n");
895 std::printf(
"\033[1mLICENCE NOTICE\033[0m >\n\n");
897 std::printf(
"LICENCE NOTICE >\n\n");
900 "This program comes with ABSOLUTELY NO WARRANTY. This is \n"
901 "free software, and you are welcome to redistribute it under \n"
902 "certain conditions; run `triumvirate --version` for details.\n"
906 std::printf(
"\033[1mLICENCE\033[0m >\n\n");
907 std::printf(
"\033[2mGPL-3.0-or-later\033[0m\n\n");
909 std::printf(
"LICENCE >\n\n");
910 std::printf(
"GPL-3.0-or-later\n\n");
913 "This program is free software: you can redistribute it and/or modify \n"
914 "it under the terms of the GNU General Public License as published by \n"
915 "the Free Software Foundation, either version 3 of the License, or \n"
916 "(at your option) any later version. \n"
918 "This program is distributed in the hope that it will be useful, but \n"
919 "WITHOUT ANY WARRANTY; without even the implied warranty of \n"
920 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU \n"
921 "General Public License for more details. \n"
923 "You should have received a copy of the GNU General Public License \n"
924 "along with this program. If not, see <https://www.gnu.org/licenses/>.\n"
933 std::printf(
"\033[1mRUNTIME INFORMATION\033[0m >\n\n");
935 std::printf(
"RUNTIME INFORMATION >\n\n");
939 std::printf(
"\033[1mPROGRAM INFORMATION\033[0m >\n\n");
941 std::printf(
"PROGRAM INFORMATION >\n\n");
945 std::printf(
"Triumvirate version: %s\n", __TRV_VERSION__);
947 std::printf(
"GSL version: %s\n", GSL_VERSION);
949#if defined(TRV_USE_HIP)
950 std::string hipfft_version =
951 std::to_string(HIPFFT_MAJOR_VERSION) +
"." +
952 std::to_string(HIPFFT_MINOR_VERSION) +
"." +
953 std::to_string(HIPFFT_PATCH_LEVEL);
954 std::printf(
"hipFFT version: %s\n", hipfft_version.c_str());
955#elif defined(TRV_USE_CUDA)
956 std::string cufft_version =
957 std::to_string(CUFFT_VER_MAJOR) +
"." +
958 std::to_string(CUFFT_VER_MINOR) +
"." +
959 std::to_string(CUFFT_VER_PATCH) +
"." +
960 std::to_string(CUFFT_VER_BUILD);
961 std::printf(
"cuFFT version: %s\n", cufft_version.c_str());
963 std::printf(
"FFTW version: %s\n", fftw_version);
966 std::printf(
"OpenMP version: %s\n", _OMP_VERSION.c_str());
969 unsigned hdf5_major, hdf5_minor, hdf5_release;
970 H5get_libversion(&hdf5_major, &hdf5_minor, &hdf5_release);
972 "HDF5 version: %d.%d.%d\n", hdf5_major, hdf5_minor, hdf5_release
979 std::printf(
"CPU thread count: %d\n", _OMP_NTHREADS);
981 std::string gpu_mode =
" (unavailable)";
986 "GPU device count: %d%s\n",
998 std::printf(
"\033[1mPROGRAM LOG\033[0m >\n\n");
1000 std::printf(
"PROGRAM LOG >\n\n");
1003 if (endpoint == 1) {
1007 "Invalid endpoint for log bars: %d.", endpoint
1013 std::regex envar_pattern(R
"(\$\{([^}]+)\})");
1014 std::smatch matches;
1016 auto search_start = path_str.cbegin();
1018 std::regex_search(search_start, path_str.cend(), matches, envar_pattern)
1020 std::string var_name = matches[1].str();
1021 const char* var_value = std::getenv(var_name.c_str());
1023 if (var_value !=
nullptr) {
1025 auto start_pos = matches.prefix().second - path_str.cbegin();
1027 matches.prefix().second, matches.suffix().first, var_value
1031 search_start = path_str.cbegin() + start_pos + std::strlen(var_value);
1034 search_start = matches.suffix().first;
IOError(const char *fmt_string,...)
Construct an trv::sys::IOError exception.
std::string err_mesg
error message
virtual const char * what() const noexcept
Exception string representation.
Exception raised when the data to be operated on are invalid.
std::string err_mesg
error message
virtual const char * what() const noexcept
Exception string representation.
InvalidDataError(const char *fmt_string,...)
Construct an trv::sys::InvalidDataError exception.
Exception raised when parameters are invalid.
InvalidParameterError(const char *fmt_string,...)
Construct an trv::sys::InvalidParameterError exception.
virtual const char * what() const noexcept
Exception string representation.
std::string err_mesg
error message
Logger with logging level differentiation.
Logger(LogLevel level)
Construct the logger with the specified threshold level.
void info(const char *fmt_string,...)
Emit a information-level message.
void debug(const char *fmt_string,...)
Emit a debugging-level message.
void error(const char *fmt_string,...)
Emit a warning-level message.
void warn(const char *fmt_string,...)
Emit a warning-level message.
void stat(const char *fmt_string,...)
Emit a status-level message.
int level_limit
logger threshold level
void log(LogLevel level_entry, const char *fmt_string,...)
Log a message at the specified level.
void reset_level(LogLevel level)
Reset the logger threshold level.
float progress
progress value in [0, 1] interval
int task_count
total task count
ProgressBar(int task_count, std::string name="")
Construct a progress bar.
void set_task_idx(int task_idx)
Set current (or initial) task index.
void set_nodes(std::vector< float > nodes)
Set progress bar width.
void set_bar_width(int bar_width)
Set progress bar width.
std::string name
progress bar name
void update(int task_idx_now)
Update the progress bar.
void set_progress(float progress)
Set current (or initial) progress value.
virtual const char * what() const noexcept
Exception string representation.
std::string err_mesg
error message
UnimplementedError(const char *fmt_string,...)
Construct an trv::sys::UnimplementedError exception.
Provide tracking of program resources and exceptions.
double gbytesMem
current memory usage in gibibytes
bool has_extension(const std::string &fname, const std::string &fext)
Check if a file has a given extension.
void display_help()
Display help message in stdout.
void update_maxmem(bool gpu=false)
Update the maximum memory usage estimate.
std::string show_timestamp()
Return the timestamp string including the elapsed time.
auto clockStart
program starting time
void expand_envar_in_path(std::string &path_str)
Expand environment variables in a path string.
std::vector< int > get_gpu_ids()
Get the indices of GPUs available for use.
bool fftw_wisdom_b_imported
wisdom import status for backward transform
bool is_gpu_enabled()
Check if GPU mode is enabled.
bool is_gpu_available()
Check if GPUs are available in the system.
void display_prog_logo()
Display program logo in stdout.
bool fftw_wisdom_f_imported
wisdom import status for forward transform
float max_count_grid
maximum number of grids
Logger logger
default logger (at NSET logging level)
int max_count_rgrid
maximum number of 3-d real grids
std::string show_current_datetime(bool utc=false)
Return the current datetime string.
float count_grid
number of grids
void display_prog_licence(bool brief=false)
Display program licence in stdout.
double gbytesMemGPU
current (GPU) memory usage in gibibytes
double gbytesMaxMemGPU
maximum (GPU) memory usage in gibibytes
int max_count_cgrid
maximum number of 3-d complex grids
void display_prog_logbars(int endpoint)
Display program log bars in stdout.
std::vector< float > set_nodes_by_str(std::string interval_str)
Set a node list possibly from a string.
int get_gpu_count(bool sys=false)
Get the number of GPUs available.
bool is_gpu_single()
Check if in single-GPU mode.
int count_fft
number of FFTs
int count_cgrid
number of 3-d complex grids
double gbytesMaxMem
maximum memory usage in gibibytes
std::vector< std::string > split_string(const std::string &str, const std::string &delimiter)
Split a string into a vector of strings.
int count_rgrid
number of 3-d real grids
std::string join_strings(const std::vector< std::string > &strings, const std::string &delimiter)
Join a vector of strings with a delimiter.
int count_ifft
number of IFFTs
void update_maxcntgrid()
Update the maximum 3-d grid counts.
void display_prog_info(bool runtime=false)
Display program information in stdout.
void exit_fatal(const std::string &msg)
Terminate the program with exit status EXIT_FAILURE.
bool is_colourable()
Check if the program stdout is colourable.
std::string show_elapsed_time(double duration_in_seconds)
Return the elapsed-time string in 'HH:MM:SS' format.
std::string get_build_datetime()
Return the build datetime string in ISO 8601–like format.