GammaLib 2.2.0.dev
Loading...
Searching...
No Matches
GTools.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GTools.cpp - GammaLib tools *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2008-2026 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it 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. See the *
15 * 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 <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GTools.cpp
23 * @brief Gammalib tools implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <unistd.h> // geteuid(), access() functions
32#include <fcntl.h> // fcntl() functions
33#include <sys/stat.h>
34#include <sys/time.h> // timeval
35#include <sys/select.h> // select() function
36#include <sys/types.h>
37#include <sys/socket.h> // recv() function
38#include <netinet/in.h> // struct sockaddr_in, struct sockaddr
39#include <netdb.h> // struct hostent, gethostbyname
40#include <pwd.h> // getpwuid()
41#include <cmath>
42#include <cfloat>
43#include <cctype>
44#include <ctime>
45#include <cstdlib> // std::getenv() function
46#include <cstring> // std::strlen() and std::memcpy functions
47#include <iostream>
48#include <sstream>
49#include <algorithm>
50#include <cstdio> // sprintf
51#include "GTools.hpp"
52#include "GException.hpp"
53#include "GFits.hpp"
54#include "GEnergy.hpp"
55#include "GFilename.hpp"
56#include "GMath.hpp"
57#include "GXmlElement.hpp"
58#include "GXmlNode.hpp"
59#include "GXmlText.hpp"
60
61/* __ OpenMP section _____________________________________________________ */
62#ifdef _OPENMP
63#include <omp.h>
64#endif
65
66/* __ Includes for memory usage determination ____________________________ */
67#if defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
68#include <unistd.h>
69#include <sys/resource.h>
70#if defined(__APPLE__) && defined(__MACH__)
71#include <mach/mach.h>
72#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
73#include <fcntl.h>
74#include <procfs.h>
75#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
76#include <stdio.h>
77#endif
78#endif
79
80/* __ Compile options ____________________________________________________ */
81//#define G_CHECK_FOR_NAN
82//#define G_USE_CURL //!< Use curl in host_country()
83
84/* __ Function name definitions __________________________________________ */
85#define G_XML2STR "gammalib::xml2str(std::string&)"
86#define G_HTTP_QUERY "gammalib::http_query(str::string&, std::string&)"
87
88/* __ Coding definitions _________________________________________________ */
89#define G_PARFORMAT_LENGTH 29
90#define G_CHAR_BUFFER 256
91
92
93/***********************************************************************//**
94 * @brief Strip leading and trailing whitespace from string
95 *
96 * @param[in] arg String from which whitespace should be stripped.
97 * @return String with stripped whitespace.
98 ***************************************************************************/
99std::string gammalib::strip_whitespace(const std::string& arg)
100{
101 // Return result
102 return (strip_chars(arg, " "));
103}
104
105
106/***********************************************************************//**
107 * @brief Strip leading and trailing character from string
108 *
109 * @param[in] arg String from which character should be stripped.
110 * @param[in] chars Character(s) to be stripped.
111 * @return String with stripped characters.
112 ***************************************************************************/
113std::string gammalib::strip_chars(const std::string& arg,
114 const std::string& chars)
115{
116 // Initialise empty result string
117 std::string result;
118
119 // Continue only if argument is not empty
120 if (!arg.empty()) {
121
122 // Get start and stop
123 std::string::size_type start = arg.find_first_not_of(chars);
124 std::string::size_type stop = arg.find_last_not_of(chars);
125
126 // Continue only if start and stop are valid
127 if (start != std::string::npos && stop != std::string::npos) {
128
129 // Continue only if stop is larger then or equal to start
130 if (start <= stop) {
131 result = arg.substr(start, stop-start+1);
132 }
133
134 } // endif: start and stop were valid
135
136 } // endif: argument was not empty
137
138 // Return result
139 return result;
140}
141
142
143/***********************************************************************//**
144 * @brief Strip trailing character from string
145 *
146 * @param[in] arg String from which character should be stripped.
147 * @param[in] chars Character(s) to be stripped.
148 * @return String with stripped characters.
149 ***************************************************************************/
150std::string gammalib::rstrip_chars(const std::string& arg,
151 const std::string& chars)
152{
153 // Initialise empty result string
154 std::string result;
155
156 // Continue only if argument is not empty
157 if (!arg.empty()) {
158
159 // Get stop
160 std::string::size_type stop = arg.find_last_not_of(chars);
161
162 // Continue only if stop is valid
163 if (stop != std::string::npos) {
164 result = arg.substr(0, stop+1);
165 }
166
167 } // endif: argument was not empty
168
169 // Return result
170 return result;
171}
172
173
174/***********************************************************************//**
175 * @brief Replace string segment in string
176 *
177 * @param[in] arg String in which character segements are to be replaced
178 * @param[in] segment String segment to be replaced.
179 * @param[in] replacement Replacement string.
180 * @return String with replaced segements.
181 *
182 * Replaces string segments by a replacement string in a given string.
183 *
184 * If the input string @p arg is "Wonderful", the @p segment is "onder" and
185 * the @p replacement is "ish" the method will return "Wishful".
186 ***************************************************************************/
187std::string gammalib::replace_segment(const std::string& arg,
188 const std::string& segment,
189 const std::string& replacement)
190{
191 // Initialise result string by argument
192 std::string result = arg;
193
194 // Initialise character pointer
195 std::string::size_type pos = 0;
196 std::string::size_type start = 0;
197
198 // Loop over string
199 while (start != std::string::npos) {
200 start = result.find(segment, pos);
201 if (start != std::string::npos) {
202 result = result.replace(start, segment.length(), replacement);
203 pos = start + replacement.length();
204 }
205 }
206
207 // Return result
208 return result;
209}
210
211
212/***********************************************************************//**
213 * @brief Expand environment variables in string
214 *
215 * @param[in] arg String.
216 * @return String with expected environment variables.
217 *
218 * Expands any environment variable that is found in a string. Valid
219 * delimiters for environment variables are $ENV{<name>}, $ENV(<name>),
220 * ${<name>}, $(<name>) and $<name> (in the last case the terminating
221 * delimiter is either a / or a blank character or the end of the string).
222 * Environment variables occuring within single quotes (') are ignored.
223 * Environment variables that do not exist will be kept as specified.
224 *
225 * The method also replaces ~ or ~user by the user's home directory, ~+
226 * by the value of the PWD environment variable and ~- by the value of the
227 * OLDPWD variable. If the user or the PWD or OLDPWD variable are not found,
228 * no replacement is done.
229 *
230 * This function has been inspired by the function ape_util_expand_env_var
231 * from ape_util.c in the ape software developed at HEASARC.
232 ***************************************************************************/
233std::string gammalib::expand_env(const std::string& arg)
234{
235 // Set environment variable delimiters
236 static const char* begin_delim[] = { "$ENV{", "$ENV(", "${", "$(", "$", "~" };
237 static const char* end_delim[] = { "}", ")", "}", ")", "/", "/" };
238 static const int num_delim = 6;
239
240 // Initialise result with argument
241 std::string result = arg;
242
243 // Initialise parse parameters
244 size_t index = 0;
245 bool in_quote = false;
246
247 // Loop over string
248 while (index < result.length()) {
249
250 // If we have an escaped character then skip the current character
251 // and the next one
252 if (result[index] == '\\') {
253 index += 2;
254 continue;
255 }
256
257 // If we have a single quote then toggle the quote state
258 if (result[index] == '\'') {
259 in_quote = !in_quote;
260 index++;
261 continue;
262 }
263
264 // Don't expand environment variables inside single quotes. Note
265 // that double quotes are ok.
266 if (in_quote) {
267 index++;
268 continue;
269 }
270
271 // Find delimiter which indicates beginning of an environment variable
272 size_t begin_length = 0;
273 int delim_idx = 0;
274 for (; delim_idx < num_delim; ++delim_idx) {
275 size_t len = std::strlen(begin_delim[delim_idx]);
276 if (result.compare(index, len, begin_delim[delim_idx]) == 0) {
277 begin_length = len;
278 break;
279 }
280 }
281
282 // If we found a delimiter then process the environment variable
283 if (begin_length > 0) {
284
285 // Search for the termination delimiter of the environment
286 // variable. There is a special case for delimiters 4 and 5:
287 // It has always an end_length of zero as the / is not a real
288 // delimiter, but just an indicator that the environment variable
289 // ends. Another indicator is a blank. If the end of the
290 // string has been reached this is also acceptable.
291 size_t i_start = index + begin_length;
292 size_t i_end = i_start;
293 size_t end_length = 0;
294 if (delim_idx == 4 || delim_idx == 5) {
295 while (i_end < result.length() &&
296 result.compare(i_end, 1, "/") != 0 &&
297 result.compare(i_end, 1, " ") != 0) {
298 i_end++;
299 }
300 }
301 else {
302 end_length = std::strlen(end_delim[delim_idx]);
303 while (i_end < result.length() &&
304 result.compare(i_end, end_length, end_delim[delim_idx]) != 0) {
305 i_end++;
306 }
307 }
308
309 // If termination delimiter has been found then expand the
310 // environment variable
311 if (i_end < result.length() || delim_idx == 4) {
312
313 // Extract environment variable name
314 std::string name = result.substr(i_start, i_end-i_start);
315 size_t name_length = name.length();
316
317 // Initialise pointer on environment variable
318 const char* env = NULL;
319
320 // Handle ~
321 if (delim_idx == 5) {
322 if (name_length == 0) {
323 if ((env = std::getenv("HOME")) == NULL) {
324 struct passwd *pw = getpwuid(getuid());
325 if (pw != NULL) {
326 env = pw->pw_dir;
327 }
328 }
329 }
330 else {
331 if (name == "+") {
332 env = std::getenv("PWD");
333 }
334 else if (name == "-") {
335 env = std::getenv("OLDPWD");
336 }
337 else {
338 struct passwd *pw = getpwnam(name.c_str());
339 if (pw != NULL) {
340 env = pw->pw_dir;
341 }
342 }
343 }
344 }
345
346 // ... otherwise get the environment variable
347 else {
348 env = std::getenv(name.c_str());
349 }
350
351 // If the environment variable has been found then replace
352 // it by its value
353 if (env != NULL) {
354
355 // Erase delimiters and environment variable
356 result.erase(index, begin_length+name_length+end_length);
357
358 // Set replacement string and its length
359 std::string replace(env);
360 size_t replace_length = replace.length();
361
362 // Insert replacement string
363 result.insert(index, replace);
364
365 // Advance pointer
366 index += replace_length;
367
368 } // endif: environment variable has been found
369
370 // If no environment variable has been found then set
371 // index=i_end+1
372 else {
373 index = i_end + 1;
374 }
375
376 } // endif: termination delimiter found
377
378 // If no environment variable has been found then set index=i_end+1
379 else {
380 index = i_end + 1;
381 }
382
383 } // endif: we found an environment variable delimiter
384
385 // ... otherwise advance to next character
386 else {
387 index++;
388 }
389
390 } // endwhile: looped over string
391
392 // Return result
393 return result;
394}
395
396
397/***********************************************************************//**
398 * @brief Build file path from path name and file name
399 *
400 * @param[in] pathname Path name.
401 * @param[in] filename File name.
402 * @return File path.
403 *
404 * Builds a file path by combining the @p pathname and the @p filename
405 * following
406 *
407 * filepath = pathname/filename
408 *
409 * If @p pathname is an empty string, the method simply returns the
410 * @p filename.
411 ***************************************************************************/
412std::string gammalib::filepath(const std::string& pathname,
413 const std::string& filename)
414{
415 // Initialise filepath
416 std::string filepath;
417
418 // If path name is empty, simply return the file name
419 if (pathname.empty()) {
420 filepath = filename;
421 }
422
423 // ... otherwise combine both
424 else {
425 filepath = pathname + "/" + filename;
426 }
427
428 // Return the file path
429 return filepath;
430}
431
432
433/***********************************************************************//**
434 * @brief Return temporary file name
435 *
436 * @return Temporary file name.
437 *
438 * Returns a temporary file name.
439 ***************************************************************************/
440std::string gammalib::tmpnam(void)
441{
442 // Set default temporary directory
443 char default_tmpdir[] = "/tmp";
444
445 // Get pointer to name of temporary directory by searching various
446 // possible environment variables
447 char *tmpdir = NULL;
448 if ((tmpdir = std::getenv("TEMP")) == NULL) {
449 if ((tmpdir = std::getenv("TMP")) == NULL) {
450 if ((tmpdir = std::getenv("TMPDIR")) == NULL) {
451 tmpdir = default_tmpdir;
452 }
453 }
454 }
455
456 // Allocate empty filename
457 char filename[256];
458 filename[0] = '\0';
459
460 // Combine temporary directory with temporary filename
461 strcat(filename, tmpdir);
462 strcat(filename, "/gammalibXXXXXX");
463
464 // Create temporary file
465 int fd = mkstemp(filename);
466 std::string tmpname(filename);
467 close(fd);
468 unlink(filename);
469
470 // Return temporary file name
471 return tmpname;
472}
473
474
475/***********************************************************************//**
476 * @brief Return value of environment variable
477 *
478 * @param[in] arg Environment variable
479 * @return Value of environment variable.
480 *
481 * Returns the value of an environment variable @p arg. If the environment
482 * variable is not found an empty string will be returned.
483 ***************************************************************************/
484std::string gammalib::getenv(const std::string& arg)
485{
486 // Initialise environment variable
487 std::string env;
488
489 // Get pointer to environment variable string
490 const char* ptr = std::getenv(arg.c_str());
491
492 // If pointer is not NULL then extract value of environment variable
493 if (ptr != NULL) {
494 env = std::string(ptr);
495 }
496
497 // Return environment variable
498 return env;
499}
500
501
502/***********************************************************************//**
503 * @brief Convert unsigned short integer value into string
504 *
505 * @param[in] value Unsigned short integer to be converted into string.
506 * @return String with unsigned short integer value.
507 ***************************************************************************/
508std::string gammalib::str(const unsigned short int& value)
509{
510 std::ostringstream s_value;
511 s_value << value;
512 return s_value.str();
513}
514
515
516/***********************************************************************//**
517 * @brief Convert unsigned integer value into string
518 *
519 * @param[in] value Unsigned integer to be converted into string.
520 * @return String with unsigned integer value.
521 ***************************************************************************/
522std::string gammalib::str(const unsigned int& value)
523{
524 std::ostringstream s_value;
525 s_value << value;
526 return s_value.str();
527}
528
529
530/***********************************************************************//**
531 * @brief Convert unsigned long integer value into string
532 *
533 * @param[in] value Unsigned long integer to be converted into string.
534 * @return String with unsigned long integer value.
535 ***************************************************************************/
536std::string gammalib::str(const unsigned long int& value)
537{
538 std::ostringstream s_value;
539 s_value << value;
540 return s_value.str();
541}
542
543
544/***********************************************************************//**
545 * @brief Convert unsigned long long integer value into string
546 *
547 * @param[in] value Unsigned long long integer to be converted into string.
548 * @return String with unsigned long long integer value.
549 ***************************************************************************/
550std::string gammalib::str(const unsigned long long int& value)
551{
552 std::ostringstream s_value;
553 s_value << value;
554 return s_value.str();
555}
556
557
558/***********************************************************************//**
559 * @brief Convert short integer value into string
560 *
561 * @param[in] value Short integer to be converted into string.
562 * @return String with short integer value.
563 ***************************************************************************/
564std::string gammalib::str(const short int& value)
565{
566 std::ostringstream s_value;
567 s_value << value;
568 return s_value.str();
569}
570
571
572/***********************************************************************//**
573 * @brief Convert integer value into string
574 *
575 * @param[in] value Integer to be converted into string.
576 * @param[in] fmt Format string.
577 * @return String with integer value.
578 ***************************************************************************/
579std::string gammalib::str(const int& value, const std::string& fmt)
580{
581 // Allocate character buffer
582 char buffer[G_CHAR_BUFFER];
583
584 // Put integer into buffer (not C-98 compliant)
585 gammalib_snprintf(buffer, G_CHAR_BUFFER, fmt.c_str(), value);
586
587 // Convert buffer into string
588 std::string str_buffer(buffer);
589
590 // Return string buffer
591 return str_buffer;
592}
593
594
595/***********************************************************************//**
596 * @brief Convert long integer value into string
597 *
598 * @param[in] value Long integer to be converted into string.
599 * @return String with long integer value.
600 ***************************************************************************/
601std::string gammalib::str(const long int& value)
602{
603 std::ostringstream s_value;
604 s_value << value;
605 return s_value.str();
606}
607
608
609/***********************************************************************//**
610 * @brief Convert long long integer value into string
611 *
612 * @param[in] value Long long integer to be converted into string.
613 * @return String with long long integer value.
614 ***************************************************************************/
615std::string gammalib::str(const long long int& value)
616{
617 std::ostringstream s_value;
618 s_value << value;
619 return s_value.str();
620}
621
622
623/***********************************************************************//**
624 * @brief Convert single precision value into string
625 *
626 * @param[in] value Single precision value to be converted into string.
627 * @param[in] precision Floating point precision.
628 * @return String with single precision value.
629 *
630 * Converts a single precision value into a string. Any positive
631 * @p precision argument specifies the exact number of digits after the
632 * comma.
633 ***************************************************************************/
634std::string gammalib::str(const float& value, const int& precision)
635{
636 // Allocate output stream
637 std::ostringstream s_value;
638
639 // If specified then set the requested fixed point precision. Otherwise
640 // use a precision that should be sufficient for floating point values.
641 if (precision > 0) {
642 s_value.precision(precision);
643 s_value.setf(std::ios::fixed, std::ios::floatfield);
644 }
645 else {
646 s_value.precision(7);
647 }
648
649 // Put floating point value in stream
650 s_value << value;
651
652 // Convert to a string
653 std::string result = s_value.str();
654
655 // Return result
656 return result;
657}
658
659
660/***********************************************************************//**
661 * @brief Convert double precision value into string
662 *
663 * @param[in] value Double precision value to be converted into string.
664 * @param[in] precision Floating point precision.
665 * @return String with double precision value.
666 *
667 * Converts a double precision value into a string. Any positive
668 * @p precision argument specifies the exact number of digits after the
669 * comma.
670 ***************************************************************************/
671std::string gammalib::str(const double& value, const int& precision)
672{
673 // Allocate output stream
674 std::ostringstream s_value;
675
676 // If specified then set the requested fixed point precision. Otherwise
677 // use a precision that should be sufficient for floating point values.
678 if (precision > 0) {
679 s_value.precision(precision);
680 s_value.setf(std::ios::fixed, std::ios::floatfield);
681 }
682 else {
683 s_value.precision(15);
684 }
685
686 // Put double precision floating point value in stream
687 s_value << value;
688
689 // Convert to a string
690 std::string result = s_value.str();
691
692 // Return result
693 return result;
694}
695
696
697/***********************************************************************//**
698 * @brief Convert complex value into string
699 *
700 * @param[in] value Complex value to be converted into string.
701 * @param[in] precision Floating point precision.
702 * @return String with complex value.
703 *
704 * Converts a complex value into a string. Any positive @p precision argument
705 * specifies the exact number of digits after the comma.
706 ***************************************************************************/
707std::string gammalib::str(const std::complex<double>& value,
708 const int& precision)
709{
710 // Allocate output stream
711 std::ostringstream s_value;
712
713 // If specified then set the requested fixed point precision. Otherwise
714 // use a precision that should be sufficient for floating point values.
715 if (precision > 0) {
716 s_value.precision(precision);
717 s_value.setf(std::ios::fixed, std::ios::floatfield);
718 }
719 else {
720 s_value.precision(15);
721 }
722
723 // Put double precision floating point value in stream
724 s_value << value.real();
725 if (value.imag() < 0.0) {
726 s_value << "-";
727 }
728 else {
729 s_value << "+";
730 }
731 s_value << std::abs(value.imag()) << "j";
732
733 // Convert to a string
734 std::string result = s_value.str();
735
736 // Return result
737 return result;
738}
739
740
741/***********************************************************************//**
742 * @brief Return current date
743 *
744 * Returns the current date as string in the format yyyy-mm-ddThh:mm:ss.
745 ***************************************************************************/
746std::string gammalib::strdate(void)
747{
748 // Allocate variables
749 struct std::tm timeStruct;
750 std::time_t now;
751 char buffer[100];
752
753 // Get time
754 now = std::time(NULL);
755 #ifdef HAVE_GMTIME_R
756 std::gmtime_r(&now, &timeStruct);
757 #else
758 std::memcpy(&timeStruct, gmtime(&now), sizeof(struct tm));
759 #endif
760
761 // Write message type, time and task name to buffer
762 std::snprintf(buffer, 100, "%04d-%02d-%02dT%02d:%02d:%02d",
763 timeStruct.tm_year + 1900,
764 timeStruct.tm_mon + 1,
765 timeStruct.tm_mday,
766 timeStruct.tm_hour,
767 timeStruct.tm_min,
768 timeStruct.tm_sec);
769
770 // Build string from buffer
771 std::string date = buffer;
772
773 // Return date
774 return date;
775}
776
777
778/***********************************************************************//**
779 * @brief Convert string into short value
780 *
781 * @param[in] arg String to be converted.
782 * @return Short value.
783 ***************************************************************************/
784short gammalib::toshort(const std::string& arg)
785{
786 std::istringstream iss(arg);
787 short result;
788 iss >> std::dec >> result;
789 return result;
790}
791
792
793/***********************************************************************//**
794 * @brief Convert string into unsigned short value
795 *
796 * @param[in] arg String to be converted.
797 * @return Unsigned short value.
798 ***************************************************************************/
799unsigned short gammalib::toushort(const std::string& arg)
800{
801 std::istringstream iss(arg);
802 unsigned short result;
803 iss >> std::dec >> result;
804 return result;
805}
806
807
808/***********************************************************************//**
809 * @brief Convert string into integer value
810 *
811 * @param[in] arg String to be converted.
812 * @return Integer value.
813 ***************************************************************************/
814int gammalib::toint(const std::string& arg)
815{
816 std::istringstream iss(arg);
817 int result;
818 iss >> std::dec >> result;
819 return result;
820}
821
822
823/***********************************************************************//**
824 * @brief Convert string into unsigned integer value
825 *
826 * @param[in] arg String to be converted.
827 * @return Unsigned integer value.
828 ***************************************************************************/
829unsigned int gammalib::touint(const std::string& arg)
830{
831 std::istringstream iss(arg);
832 unsigned int result;
833 iss >> std::dec >> result;
834 return result;
835}
836
837
838/***********************************************************************//**
839 * @brief Convert string into long value
840 *
841 * @param[in] arg String to be converted.
842 * @return Long value.
843 ***************************************************************************/
844long gammalib::tolong(const std::string& arg)
845{
846 std::istringstream iss(arg);
847 long result;
848 iss >> std::dec >> result;
849 return result;
850}
851
852
853/***********************************************************************//**
854 * @brief Convert string into unsigned long value
855 *
856 * @param[in] arg String to be converted.
857 * @return Unsigned long value.
858 ***************************************************************************/
859unsigned long gammalib::toulong(const std::string& arg)
860{
861 std::istringstream iss(arg);
862 unsigned long result;
863 iss >> std::dec >> result;
864 return result;
865}
866
867
868/***********************************************************************//**
869 * @brief Convert string into long long value
870 *
871 * @param[in] arg String to be converted.
872 * @return Long long value.
873 ***************************************************************************/
874long long gammalib::tolonglong(const std::string& arg)
875{
876 std::istringstream iss(arg);
877 long long result;
878 iss >> std::dec >> result;
879 return result;
880}
881
882
883/***********************************************************************//**
884 * @brief Convert string into unsigned long long value
885 *
886 * @param[in] arg String to be converted.
887 * @return Unsigned long long value.
888 ***************************************************************************/
889unsigned long long gammalib::toulonglong(const std::string& arg)
890{
891 std::istringstream iss(arg);
892 unsigned long long result;
893 iss >> std::dec >> result;
894 return result;
895}
896
897
898/***********************************************************************//**
899 * @brief Convert string into single precision value
900 *
901 * @param[in] arg String to be converted.
902 * @return Single precision value.
903 ***************************************************************************/
904float gammalib::tofloat(const std::string& arg)
905{
906 std::istringstream iss(arg);
907 float result;
908 iss >> std::dec >> result;
909 return result;
910}
911
912
913/***********************************************************************//**
914 * @brief Convert string into double precision value
915 *
916 * @param[in] arg String to be converted.
917 * @return Double precision value.
918 ***************************************************************************/
919double gammalib::todouble(const std::string& arg)
920{
921 std::istringstream iss(arg);
922 double result;
923 iss >> std::dec >> result;
924 return result;
925}
926
927
928/***********************************************************************//**
929 * @brief Convert string to upper case
930 *
931 * @param[in] arg String to be converted to upper case.
932 * @return String converted to upper case.
933 ***************************************************************************/
934std::string gammalib::toupper(const std::string& arg)
935{
936 std::string s = arg;
937 std::transform(s.begin(), s.end(), s.begin(), ::toupper);
938 return s;
939}
940
941
942/***********************************************************************//**
943 * @brief Convert string to lower case
944 *
945 * @param[in] arg String to be converted to upper case.
946 * @return String converted to lower case.
947 ***************************************************************************/
948std::string gammalib::tolower(const std::string& arg)
949{
950 std::string s = arg;
951 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
952 return s;
953}
954
955
956/***********************************************************************//**
957 * @brief Split string
958 *
959 * @param[in] s String to be splitted.
960 * @param[in] sep Separator(s).
961 * @return Vector of split strings.
962 *
963 * Splits a string on the basis of one or multiple separator characters. The
964 * separator characters are provided by the @p sep argument. Subsequent
965 * separator characters that are not seperated by some other characters will
966 * lead to an empty string element, except for a blank separator where
967 * subsequent blanks are takens as a single separator. Below a few examples
968 * that illustrate how the function will split a given string.
969 *
970 * "Name;RA;DEC" => ["Name","RA","DEC"] (sep=";")
971 * "My house is red" => ["My","house","is","red"] (sep=" ")
972 * "IRF::FRONT" => ["IRF","","FRONT"] (sep=":")
973 * "Fields;RA,DEC,Flux" => ["Fields","RA","DEC","Flux"] (sep=";,")
974 * "Last;Field;" => ["Last","Field",""] (sep=";")
975 ***************************************************************************/
976std::vector<std::string> gammalib::split(const std::string& s,
977 const std::string& sep)
978{
979 // Allocate result string vector
980 std::vector<std::string> result;
981
982 // Initialise counters
983 std::size_t pos = 0;
984 std::size_t len = s.length();
985
986 // Loop over string
987 while (pos < len && pos != std::string::npos) {
988
989 // Get index of first separator occurence and preset the length
990 // of the substring to the end of the string
991 std::size_t index = s.find_first_of(sep, pos);
992 std::size_t n = std::string::npos;
993
994 // If we did not reach the end then compute now the length of the
995 // substring
996 if (index != std::string::npos) {
997 n = index-pos;
998 }
999
1000 // If we have no whitespace separator and the length of the
1001 // substring is zero then push back an empty string. If the
1002 // length of the substring is positive then push back the
1003 // substring.
1004 if (sep != " " && n == 0) {
1005 result.push_back("");
1006 }
1007 else if (n > 0) {
1008 result.push_back(s.substr(pos, n));
1009 }
1010
1011 // Go to the string position after the last separator
1012 pos = (index != std::string::npos) ? index + 1 : std::string::npos;
1013
1014 // If the position is pointing right beyong the last string
1015 // character we terminated with a separator, hence we need to push
1016 // back one more empty string before we leave
1017 if (sep != " " && pos == len) {
1018 result.push_back("");
1019 }
1020
1021 } // endwhile: there were still characters in the string
1022
1023 // Return result
1024 return result;
1025}
1026
1027
1028/***********************************************************************//**
1029 * @brief Fill string with n strings of same type
1030 *
1031 * @param[in] s String to be filled.
1032 * @param[in] n Number of fillings.
1033 * @return Filled strings.
1034 *
1035 * Replicates a given string n time.
1036 ***************************************************************************/
1037std::string gammalib::fill(const std::string& s, const int& n)
1038{
1039 // Initialise result
1040 std::string result = "";
1041
1042 // Replicate string
1043 for (int i = 0; i < n; ++i) {
1044 result.append(s);
1045 }
1046
1047 // Return result
1048 return result;
1049}
1050
1051
1052/***********************************************************************//**
1053 * @brief Left justify string to achieve a length of n characters
1054 *
1055 * @param[in] s String to be left justified.
1056 * @param[in] n Requested total width.
1057 * @param[in] c Fill character.
1058 * @return Left justified string.
1059 *
1060 * Left justify string by adding @p c to the right to achieve a length of
1061 * @p n characters.
1062 ***************************************************************************/
1063std::string gammalib::left(const std::string& s, const int& n, const char& c)
1064{
1065 // Compute number of characters to fill right
1066 int n_right = n - s.length();
1067
1068 // Set result
1069 std::string result = s + fill(std::string(1,c), n_right);
1070
1071 // Return result
1072 return result;
1073}
1074
1075
1076/***********************************************************************//**
1077 * @brief Right justify string to achieve a length of n characters
1078 *
1079 * @param[in] s String to be right justified.
1080 * @param[in] n Requested total width.
1081 * @param[in] c Fill character.
1082 * @return Right justified string.
1083 *
1084 * Right justify string by adding @p c to the left to achieve a length of
1085 * @p n characters.
1086 ***************************************************************************/
1087std::string gammalib::right(const std::string& s, const int& n, const char& c)
1088{
1089 // Compute number of characters to fill right
1090 int n_left = n - s.length();
1091
1092 // Set result
1093 std::string result = fill(std::string(1,c), n_left) + s;
1094
1095 // Return result
1096 return result;
1097}
1098
1099
1100/***********************************************************************//**
1101 * @brief Centre string to achieve a length of n characters
1102 *
1103 * @param[in] s String to be centred.
1104 * @param[in] n Requested total width.
1105 * @param[in] c Fill character.
1106 * @return Centred string.
1107 *
1108 * Centre string by adding @p c to the left and the right to achieve a length
1109 * of @p n characters.
1110 ***************************************************************************/
1111std::string gammalib::centre(const std::string& s, const int& n, const char& c)
1112{
1113 // Compute number of characters to fill left and right
1114 int n_right = (n-s.length()) / 2;
1115 int n_left = n - s.length() - n_right;
1116
1117 // Set result
1118 std::string result = fill(std::string(1,c), n_left) + s +
1119 fill(std::string(1,c), n_right);
1120
1121 // Return result
1122 return result;
1123}
1124
1125
1126/***********************************************************************//**
1127 * @brief Convert string in parameter format
1128 *
1129 * @param[in] s String to be converted.
1130 * @param[in] indent Indentation of parameter.
1131 * @return Parameter string.
1132 *
1133 * Converts and string into the parameter format of type "s ......: " with a
1134 * total length of G_PARFORMAT_LENGTH.
1135 ***************************************************************************/
1136std::string gammalib::parformat(const std::string& s, const int& indent)
1137{
1138 // Compute number of characters to fill right. Do not clip the string if
1139 // it is too long since we do not want to loose information.
1140 int n_right = G_PARFORMAT_LENGTH - s.length() - 3 - indent;
1141
1142 // Set result
1143 std::string result = " " + s + " " + fill(".", n_right) + ": ";
1144
1145 // Return result
1146 return result;
1147}
1148
1149
1150/***********************************************************************//**
1151 * @brief Convert singular noun into number noun
1152 *
1153 * @param[in] noun Singular noun.
1154 * @param[in] number Number of instance of noun.
1155 * @return Converted noun.
1156 *
1157 * Converts a singular noun into a number noun by appending a "s" to the
1158 * noun if the @p number of the instances of the noun is not one.
1159 ***************************************************************************/
1160std::string gammalib::number(const std::string& noun, const int& number)
1161{
1162 // Copy input noun
1163 std::string result(noun);
1164
1165 // Append "s" if number if not one
1166 if (number != 1) {
1167 result += "s";
1168 }
1169
1170 // Return result
1171 return result;
1172}
1173
1174
1175/***********************************************************************//**
1176 * @brief Convert number into order noun
1177 *
1178 * @param[in] number Number.
1179 * @return Order string derived from number.
1180 *
1181 * Converts a number into an order string, such as "0th", "1st", "2nd",
1182 * "3rd", "4th", etc. This function only works correctly on non-negative
1183 * numbers. No checking is done on whether the number is non-negative.
1184 ***************************************************************************/
1185std::string gammalib::order(const int& number)
1186{
1187 // Initialise result
1188 std::string result;
1189
1190 // Set results
1191 if (number == 0) {
1192 result = "0th";
1193 }
1194 else if (number == 1) {
1195 result = "1st";
1196 }
1197 else if (number == 2) {
1198 result = "2nd";
1199 }
1200 else if (number == 3) {
1201 result = "3rd";
1202 }
1203 else {
1204 result = gammalib::str(number)+"th";
1205 }
1206
1207 // Return result
1208 return result;
1209}
1210
1211
1212/***********************************************************************//**
1213 * @brief Compute photon flux between two energies for a power law
1214 *
1215 * @param[in] emin Minimum energy.
1216 * @param[in] emax Maximum energy.
1217 * @param[in] epivot Pivot energy.
1218 * @param[in] gamma Spectral index.
1219 * @return Photon flux under power law.
1220 *
1221 * Analytically computes
1222 * \f[\int_{E_{\rm min}}^{E_{\rm max}}
1223 * \left( E/E_{\rm pivot} \right)^{\gamma} dE\f]
1224 * where
1225 * \f$E_{\rm min}\f$ and \f$E_{\rm max}\f$ are the minimum and maximum
1226 * energy, respectively, and
1227 * \f$E_{\rm pivot}\f$ is the pivot energy, and
1228 * \f$\gamma\f$ is the spectral index.
1229 ***************************************************************************/
1230double gammalib::plaw_photon_flux(const double& emin, const double& emax,
1231 const double& epivot, const double& gamma)
1232{
1233 // Initialise flux
1234 double flux = 0.0;
1235
1236 // Continue only if emax > emin
1237 if (emax > emin) {
1238
1239 // Compute photon flux. Computations dependend on the exponent. We
1240 // add here a kluge to assure numerical accuracy.
1241 double exponent = gamma + 1.0;
1242 if (std::abs(exponent) > 1.0e-11) {
1243 double xmin = emin / epivot;
1244 double xmax = emax / epivot;
1245 flux = epivot / exponent * (std::pow(xmax, exponent) -
1246 std::pow(xmin, exponent));
1247 }
1248 else {
1249 double ratio = emax / emin;
1250 flux = epivot * std::log(ratio);
1251 }
1252
1253 } // endif: emax > emin
1254
1255 // Return result
1256 return flux;
1257}
1258
1259
1260/***********************************************************************//**
1261 * @brief Compute energy flux between two energies for a power law
1262 *
1263 * @param[in] emin Minimum energy.
1264 * @param[in] emax Maximum energy.
1265 * @param[in] epivot Pivot energy.
1266 * @param[in] gamma Spectral index.
1267 * @return Energy flux under power law.
1268 *
1269 * Analytically computes
1270 * \f[\int_{E_{\rm min}}^{E_{\rm max}}
1271 * \left( E/E_{\rm pivot} \right)^{\gamma} E dE\f]
1272 * where
1273 * \f$E_{\rm min}\f$ and \f$E_{\rm max}\f$ are the minimum and maximum
1274 * energy, respectively, and
1275 * \f$E_{\rm pivot}\f$ is the pivot energy, and
1276 * \f$\gamma\f$ is the spectral index.
1277 ***************************************************************************/
1278double gammalib::plaw_energy_flux(const double& emin, const double& emax,
1279 const double& epivot, const double& gamma)
1280{
1281 // Initialise flux
1282 double flux = 0.0;
1283
1284 // Continue only if emax > emin
1285 if (emax > emin) {
1286
1287 // Compute energy flux. Computations dependend on the exponent. We
1288 // add here a kluge to assure numerical accuracy.
1289 double exponent = gamma + 2.0;
1290 double epivot2 = epivot * epivot;
1291 if (std::abs(exponent) > 1.0e-11) {
1292 double xmin = emin / epivot;
1293 double xmax = emax / epivot;
1294 flux = epivot2 / exponent * (std::pow(xmax, exponent) -
1295 std::pow(xmin, exponent));
1296 }
1297 else {
1298 double ratio = emax / emin;
1299 flux = epivot2 * (std::log(ratio));
1300 }
1301
1302 } // endif: emax > emin
1303
1304 // Return result
1305 return flux;
1306}
1307
1308
1309/***********************************************************************//**
1310 * @brief Computes log mean energy
1311 *
1312 * @param[in] a First energy.
1313 * @param[in] b Second energy.
1314 * @return Log mean energy.
1315 *
1316 * Computes the logarithmic mean energy
1317 * \f$10^{0.5 * (\log E_{\rm a} + \log E_{\rm b})}\f$
1318 * for two energies.
1319 ***************************************************************************/
1321{
1322 // Compute logarithmic mean energy
1324 double eloga = a.log10MeV();
1325 double elogb = b.log10MeV();
1326 elogmean.MeV(std::pow(10.0, 0.5 * (eloga + elogb)));
1327
1328 // Return
1329 return elogmean;
1330}
1331
1332
1333/***********************************************************************//**
1334 * @brief Checks if directory exists
1335 *
1336 * @param[in] dirname Directory name.
1337 * @return True if directory exists, false otherwise.
1338 *
1339 * Checks if a directory exists. The function expands any environment
1340 * variable prior to checking.
1341 ***************************************************************************/
1342bool gammalib::dir_exists(const std::string& dirname)
1343{
1344 // Initialise result
1345 bool result = false;
1346
1347 // Allocate file information structure
1348 struct stat info;
1349
1350 // Get file information structure
1351 int ret = stat(gammalib::expand_env(dirname).c_str(), &info);
1352
1353 // Check if we have a directory
1354 if (ret == 0 && S_ISDIR(info.st_mode)) {
1355 result = true;
1356 }
1357
1358 // Return result
1359 return result;
1360}
1361
1362
1363/***********************************************************************//**
1364 * @brief Checks if a substring is in a string
1365 *
1366 * @param[in] str String you want to search in.
1367 * @param[in] substring String you are looking for in @p str.
1368 * @return True if a string contains a sub string.
1369 *
1370 * Checks if substring is contained in str
1371 ***************************************************************************/
1372bool gammalib::contains(const std::string& str, const std::string& substring)
1373{
1374 // Initialise result
1375 bool result = false;
1376
1377 // checks if substring is in str
1378 if (str.find(substring) != std::string::npos) {
1379 result = true;
1380 }
1381
1382 // Return result
1383 return result;
1384}
1385
1386
1387/***********************************************************************//**
1388 * @brief Checks if a string is contained in a vector of strings
1389 *
1390 * @param[in] strings Vector of strings you want to search in.
1391 * @param[in] string string you are looking for in strings.
1392 * @return True if a string is contained a vector.
1393 *
1394 * Checks if a string is contained in a vector of strings
1395 ***************************************************************************/
1396bool gammalib::contains(const std::vector<std::string>& strings,
1397 const std::string& string)
1398{
1399 // Compute result
1400 bool result = std::find(strings.begin(), strings.end(), string) !=
1401 strings.end();
1402
1403 // Return result
1404 return result;
1405}
1406
1407
1408/***********************************************************************//**
1409 * @brief Emits warning
1410 *
1411 * @param[in] origin Name of method that emits warning.
1412 * @param[in] message Warning message.
1413 *
1414 * Writes a warning to the console.
1415 ***************************************************************************/
1416void gammalib::warning(const std::string& origin,
1417 const std::string& message)
1418{
1419 // Compile option: enable/disable warnings
1420 #if defined(G_WARNINGS)
1421
1422 // Set warning message
1423 std::string warning = "+++ WARNING in " + origin + ": " + message;
1424
1425 // Writes warning to the console
1426 std::cout << warning << std::endl;
1427
1428 // End of compile option
1429 #endif
1430
1431 // Return
1432 return;
1433}
1434
1435
1436/***********************************************************************//**
1437 * @brief Convert XML character references in string to characters
1438 *
1439 * @param[in] arg String containing XML character references.
1440 * @return String with character reference replaced by respective characters.
1441 *
1442 * @exception GException::invalid_argument
1443 * Could not extract number from numerical character reference.
1444 *
1445 * Converts all character references found in a string in their respective
1446 * characters. For more information about XML character references read
1447 * http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
1448 ***************************************************************************/
1449std::string gammalib::xml2str(const std::string& arg)
1450{
1451 // Initialise string
1452 std::string result;
1453
1454 // Initialise position, lengths and flags
1455 size_t length = arg.length();
1456 size_t pos = 0;
1457 size_t start = 0;
1458 size_t stop = 0;
1459 size_t len = 0; // Length of string preceeding char. reference
1460 bool found = false;
1461
1462 // Loop over string
1463 while (pos < length) {
1464
1465 // If we have not yet found a character reference then search for
1466 // the next one. If we did not find one we break here.
1467 if (!found) {
1468 start = arg.find("&", pos);
1469 if (start != std::string::npos) {
1470 len = start - pos;
1471 pos = start;
1472 found = true;
1473 }
1474 else {
1475 break;
1476 }
1477 }
1478
1479 // If we have found a character reference then attach the string
1480 // that is preceeding the character reference to the result and
1481 // search for the end character of the character reference.
1482 if (found) {
1483
1484 // Initialse successful decoding flag
1485 bool decoded = false;
1486
1487 // Attach preceeding string to the result
1488 if (len > 0) {
1489 result += arg.substr(start-len, len);
1490 }
1491
1492 // Search for the end character
1493 stop = arg.find(";", pos);
1494
1495 // If the end character was found then try decoding it
1496 if (stop != std::string::npos) {
1497
1498 // Extract the sequence between start and end character as
1499 // the character reference
1500 std::string cref = arg.substr(start+1, stop-start-1);
1501 len = cref.length();
1502
1503 // Check whether we have numerical character reference
1504 //TODO: Check that there are only valid characters in
1505 // numerical field
1506 if (len >= 2 && cref[0] == '#') {
1507 int number = -1;
1508 if (cref[1] == 'x') {
1509 number = (int)std::strtol(cref.substr(2,len-2).c_str(), NULL, 16);
1510 }
1511 else {
1512 number = toint(cref.substr(1,len-1));
1513 }
1514 if (number != -1) {
1515 result.push_back((char)number);
1516 decoded = true;
1517 }
1518 else {
1519 std::string msg = "Could not extract number from "
1520 "numerical character reference &"+
1521 cref+";";
1523 }
1524 }
1525
1526 // ... otherwise check for a character entity reference.
1527 // If we found out then push back the corresponding character
1528 // to the result string
1529 else {
1530 if (cref == "quot") {
1531 result.push_back((char)34);
1532 decoded = true;
1533 }
1534 else if (cref == "amp") {
1535 result.push_back((char)38);
1536 decoded = true;
1537 }
1538 else if (cref == "apos") {
1539 result.push_back((char)39);
1540 decoded = true;
1541 }
1542 else if (cref == "lt") {
1543 result.push_back((char)60);
1544 decoded = true;
1545 }
1546 else if (cref == "gt") {
1547 result.push_back((char)62);
1548 decoded = true;
1549 }
1550 } // endelse: checked for character entity reference
1551
1552 // If decoding was successful then skip the character
1553 // reference, otherwise add ampersand to result and
1554 // continue searching for an ampersand
1555 if (decoded) {
1556 found = false;
1557 pos = stop + 1;
1558 }
1559 else {
1560 found = false;
1561 result += "&";
1562 pos++;
1563 }
1564
1565 } // endif: end of character reference found
1566
1567 // ... otherwise add ampersand to result and continue
1568 // searching for an ampersand
1569 else {
1570 found = false;
1571 result += "&";
1572 pos++;
1573 }
1574
1575 } // endelse: search for end of character reference
1576
1577 } // endwhile
1578
1579 // Append any pending string to the result
1580 if (pos < length) {
1581 len = length - pos;
1582 result += arg.substr(pos, len);
1583 }
1584
1585 // Return result
1586 return result;
1587}
1588
1589
1590/***********************************************************************//**
1591 * @brief Convert special characters in string to XML character references
1592 *
1593 * @param[in] arg String.
1594 * @return String with special characters replaced by character references.
1595 *
1596 * Converts all special characters found in a string into character
1597 * references. For more information about XML character references read
1598 * http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
1599 ***************************************************************************/
1600std::string gammalib::str2xml(const std::string& arg)
1601{
1602 // Initialise string
1603 std::string result;
1604
1605 // Loop over string
1606 for (int i = 0; i < arg.length(); ++i) {
1607
1608 // Initialize string to add
1609 std::string character = arg.substr(i, 1);
1610
1611 // Replace special characters
1612 if (character == "\"") {
1613 character = "&quot;";
1614 }
1615 else if (character == "&") {
1616 character = "&amp;";
1617 }
1618 else if (character == "'") {
1619 character = "&apos;";
1620 }
1621 else if (character == "<") {
1622 character = "&lt;";
1623 }
1624 else if (character == ">") {
1625 character = "&gt;";
1626 }
1627
1628 // Append character
1629 result += character;
1630
1631 }
1632
1633 // Return result
1634 return result;
1635}
1636
1637
1638/***********************************************************************//**
1639 * @brief Checks if parameter with given name in XML element exists
1640 *
1641 * @param[in] xml XML element.
1642 * @param[in] name Parameter name.
1643 * @return True if parameter exists, false otherwise.
1644 *
1645 * Checks whether a parameter with given @p name exists in XML element.
1646 ***************************************************************************/
1647bool gammalib::xml_has_par(const GXmlElement& xml, const std::string& name)
1648{
1649 // Initialize flag
1650 bool found = false;
1651
1652 // Get number of elements
1653 int n = xml.elements("parameter");
1654
1655 // Search for parameter with given name
1656 for (int i = 0; i < n; ++i) {
1657 const GXmlElement* element = xml.element("parameter", i);
1658 if (element->attribute("name") == name) {
1659 found = true;
1660 break;
1661 }
1662 }
1663
1664 // Return
1665 return found;
1666}
1667
1668
1669/***********************************************************************//**
1670 * @brief Return pointer to parameter with given name in XML element
1671 *
1672 * @param[in] origin Method requesting parameter.
1673 * @param[in] xml XML element.
1674 * @param[in] name Parameter name.
1675 * @return Pointer to parameter XML element.
1676 *
1677 * @exception GException::invalid_value
1678 * Invalid XML format encountered.
1679 *
1680 * Returns pointer to parameter with given @p name in XML element. If the
1681 * @p name is not found, a parameter with the given @p name is added. In
1682 * that respect the function differs from xml_get_par which does not add a
1683 * parameter element.
1684 *
1685 * The function checks for multiple occurences of a parameter and throws an
1686 * exception in case that more than one parameter with a given name is found.
1687 ***************************************************************************/
1688GXmlElement* gammalib::xml_need_par(const std::string& origin,
1689 GXmlElement& xml,
1690 const std::string& name)
1691{
1692 // Initialize XML element pointer
1693 GXmlElement* par = NULL;
1694
1695 // Number of elements
1696 int number = 0;
1697
1698 // Get number of elements in XML element
1699 int n = xml.elements("parameter");
1700
1701 // Search for parameter with given name
1702 for (int i = 0; i < n; ++i) {
1703 GXmlElement* element = xml.element("parameter", i);
1704 if (element->attribute("name") == name) {
1705 par = element;
1706 number++;
1707 }
1708 }
1709
1710 // Create parameter if none was found
1711 if (number == 0) {
1712 par = static_cast<GXmlElement*>(xml.append(GXmlElement("parameter name=\""+name+"\"")));
1713 number++;
1714 }
1715
1716 // Check that there are no multiple parameters
1717 gammalib::xml_check_par(origin, name, number);
1718
1719 // Return
1720 return par;
1721}
1722
1723
1724/***********************************************************************//**
1725 * @brief Return pointer to parameter with given name in XML element
1726 *
1727 * @param[in] origin Method requesting parameter.
1728 * @param[in] xml XML element.
1729 * @param[in] name Parameter name.
1730 * @return Pointer to parameter XML element.
1731 *
1732 * @exception GException::invalid_value
1733 * Invalid XML format encountered.
1734 *
1735 * Returns pointer to parameter with given @p name in XML element. The
1736 * function checks whether the parameter has been found and throws an
1737 * exception if no parameter or multiple occurences of a parameter with given
1738 * @p name are found.
1739 ***************************************************************************/
1740const GXmlElement* gammalib::xml_get_par(const std::string& origin,
1741 const GXmlElement& xml,
1742 const std::string& name)
1743{
1744 // Initialize XML element pointer
1745 const GXmlElement* par = NULL;
1746
1747 // Number of elements
1748 int number = 0;
1749
1750 // Get number of elements in XML element
1751 int n = xml.elements("parameter");
1752
1753 // Search for parameter with given name
1754 for (int i = 0; i < n; ++i) {
1755 const GXmlElement* element = xml.element("parameter", i);
1756 if (element->attribute("name") == name) {
1757 par = element;
1758 number++;
1759 }
1760 }
1761
1762 // Check that there is at least one parameter and that there are no
1763 // multiple parameters
1764 gammalib::xml_check_par(origin, name, number);
1765
1766 // Return
1767 return par;
1768}
1769
1770
1771/***********************************************************************//**
1772 * @brief Return attribute value for a given parameter in XML element
1773 *
1774 * @param[in] origin Method requesting parameter.
1775 * @param[in] xml XML element.
1776 * @param[in] name Parameter name.
1777 * @param[in] attribute Attribute name.
1778 * @return Value of attribute.
1779 *
1780 * @exception GException::invalid_value
1781 * Attribute not found.
1782 *
1783 * Returns the value of @p attribute of parameter @p name in XML element.
1784 * The function checks whether the parameter has been found and throws an
1785 * exception if no parameter or multiple occurences of a parameter with given
1786 * @p name are found. The function furthermore checks whether the attribute
1787 * exists.
1788 ***************************************************************************/
1789std::string gammalib::xml_get_attr(const std::string& origin,
1790 const GXmlElement& xml,
1791 const std::string& name,
1792 const std::string& attribute)
1793{
1794 // Initialise attribute value
1795 std::string value = "";
1796
1797 // Get parameter
1798 const GXmlElement* par = gammalib::xml_get_par(origin, xml, name);
1799
1800 // Throw an exception if a parameter has not the requested attribute
1801 if (!par->has_attribute(attribute)) {
1802 std::string msg = "Attribute \""+attribute+"\" not found in XML "
1803 "parameter \""+name+"\". Please verify the XML "
1804 "format.";
1805 throw GException::invalid_value(origin, msg);
1806 }
1807
1808 // Extract attribute
1809 value = par->attribute(attribute);
1810
1811 // Return attribute value
1812 return value;
1813}
1814
1815
1816/***********************************************************************//**
1817 * @brief Checks number of parameters
1818 *
1819 * @param[in] origin Method performing the check.
1820 * @param[in] xml XML element.
1821 * @param[in] number Expected number of parameters.
1822 *
1823 * @exception GException::invalid_value
1824 * Invalid XML format encountered.
1825 *
1826 * Checks the number of parameter in an XML element.
1827 ***************************************************************************/
1828void gammalib::xml_check_parnum(const std::string& origin,
1829 const GXmlElement& xml,
1830 const int& number)
1831{
1832 // Throw exception if number of elements does not correspond to the
1833 // expected number
1834 if (xml.elements() != number) {
1835 std::string msg = "Number of "+gammalib::str(xml.elements())+
1836 " child elements in XML file does not correspond "
1837 "to expected number of "+gammalib::str(number)+
1838 " elements. Please verify the XML format.";
1839 throw GException::invalid_value(origin, msg);
1840 }
1841
1842 // Throw exception if number of "parameter" elements does not correspond
1843 // to the xpected number
1844 int npars = xml.elements("parameter");
1845 if (npars != number) {
1846 std::string msg = "Number of "+gammalib::str(npars)+" \"parameter\" "
1847 "child elements in XML file does not correspond to "
1848 "expected number of "+gammalib::str(number)+
1849 " elements. Please verify the XML format.";
1850 throw GException::invalid_value(origin, msg);
1851 }
1852
1853 // Return
1854 return;
1855}
1856
1857
1858/***********************************************************************//**
1859 * @brief Checks the model type
1860 *
1861 * @param[in] origin Method performing the check.
1862 * @param[in,out] xml XML element.
1863 * @param[in] type Expected model typeN.
1864 *
1865 * @exception GException::invalid_value
1866 * Invalid XML format encountered.
1867 *
1868 * Checks the number of parameter in an XML element.
1869 ***************************************************************************/
1870void gammalib::xml_check_type(const std::string& origin,
1871 GXmlElement& xml,
1872 const std::string& type)
1873{
1874 // If XML element has no model type then set model type
1875 if (xml.attribute("type") == "") {
1876 xml.attribute("type", type);
1877 }
1878
1879 // Throw an exception if the model type is not the expected one
1880 if (xml.attribute("type") != type) {
1881 std::string msg = "Model type \""+xml.attribute("type")+"\" is not "
1882 "the expected type \""+type+"\". Please verify "
1883 "the XML format.";
1884 throw GException::invalid_value(origin, msg);
1885 }
1886
1887 // Return
1888 return;
1889}
1890
1891
1892/***********************************************************************//**
1893 * @brief Checks whether a parameter has occured once
1894 *
1895 * @param[in] origin Method performing the check.
1896 * @param[in] name Parameter name.
1897 * @param[in] number Number of occurences of parameter.
1898 *
1899 * @exception GException::invalid_value
1900 * Invalid XML format encountered.
1901 *
1902 * Throws an exception if a given parameter has not exactly occured once.
1903 * The exception text is adapted to the case that none or multiple parameters
1904 * have been found.
1905 ***************************************************************************/
1906void gammalib::xml_check_par(const std::string& origin,
1907 const std::string& name,
1908 const int& number)
1909{
1910 // Throw case dependent exception
1911 if (number < 1) {
1912 std::string msg = "Parameter \""+name+"\" not found in XML element."
1913 " Please verify the XML format.";
1914 throw GException::invalid_value(origin, msg);
1915 }
1916 else if (number > 1) {
1917 std::string msg = "Parameter \""+name+"\" found "+
1918 gammalib::str(number)+" times in XML element."
1919 " Please verify the XML format.";
1920 throw GException::invalid_value(origin, msg);
1921 }
1922
1923 // Return
1924 return;
1925}
1926
1927
1928/***********************************************************************//**
1929 * @brief Expand file name provided as XML attribute for loading
1930 *
1931 * @param[in] xml XML element.
1932 * @param[in] filename File name.
1933 * @return Expanded file name.
1934 *
1935 * Expands file name provided as XML attribute for loading. The XML file
1936 * access path will be prepended to the file name access path if the file
1937 * name has not an absolute path and if the file name access path does not
1938 * start with the XML file access path.
1939 ***************************************************************************/
1941 const std::string& filename)
1942{
1943 // Set file name
1944 GFilename fname(filename);
1945
1946 // If the file name is not empty and is not an absolute path then we
1947 // assume that the filename is a relative file name with respect to the
1948 // XML file access path and we therefore prepend the XML file access path
1949 // to the file name
1950 if (!fname.is_empty()) {
1951 size_t access_length = fname.path().length();
1952 size_t xml_length = xml.filename().path().length();
1953
1954 // If filename has no access path and the XML file has an access path
1955 // then preprend the XML file access path
1956 if (access_length == 0) {
1957 if (xml_length > 0) {
1958 fname = xml.filename().path() + fname;
1959 }
1960 }
1961
1962 // If filename assess path is not absolute then continue ...
1963 else if (fname.path()[0] != '/') {
1964
1965 // If XML file access path is not contained in file name access
1966 // path then prepend the XML file access path
1967 if (access_length >= xml_length) {
1968 if (fname.path().compare(0, xml_length, xml.filename().path()) != 0) {
1969 fname = xml.filename().path() + fname;
1970 }
1971 }
1972
1973 // If file name access pass is shorter than XML file access path
1974 // then prepend the XML file access path
1975 else {
1976 fname = xml.filename().path() + fname;
1977 }
1978 }
1979 }
1980
1981 // Return file name
1982 return fname;
1983}
1984
1985
1986/***********************************************************************//**
1987 * @brief Reduce file name provided for writing as XML attribute
1988 *
1989 * @param[in] xml XML element.
1990 * @param[in] filename File name.
1991 * @return Reduced file name.
1992 *
1993 * Reduces file name provided for writing as XML attribute. If the file name
1994 * is not empty and its access path starts has the same access path as the
1995 * XML file the XML file access path is stripped from the file name.
1996 ***************************************************************************/
1998 const std::string& filename)
1999{
2000 // Set file name
2001 GFilename fname(filename);
2002
2003 // If the file name is not empty and the access path starts with the
2004 // same characters as the XML file access path then we assume that the
2005 // access path has been added and hence we strip it now
2006 if (!fname.is_empty()) {
2007 size_t access_length = fname.path().length();
2008 size_t xml_length = xml.filename().path().length();
2009 if (xml_length > 0) {
2010 if (access_length == xml_length) {
2011 if (fname.path() == xml.filename().path()) {
2012 fname = fname.file();
2013 }
2014 }
2015 else if (access_length > xml_length) {
2016 if (fname.path().compare(0, xml_length, xml.filename().path()) == 0) {
2017 std::string relpath = fname.path().substr(xml_length, access_length-xml_length);
2018 fname = GFilename(relpath + fname.file());
2019 }
2020 }
2021 }
2022 }
2023
2024 // Return file name
2025 return fname;
2026}
2027
2028
2029/***********************************************************************//**
2030 * @brief Extract name / value pair from XML node
2031 *
2032 * @param[in] node Pointer to XML node.
2033 * @param[out] name Name string.
2034 * @param[out] value Value string.
2035 *
2036 * Extracts a name / value pair from a XML node. If the XML node pointer is
2037 * NULL, the name and value strings will be empty.
2038 ***************************************************************************/
2040 std::string& name,
2041 std::string& value)
2042{
2043 // Clear name and value strings
2044 name.clear();
2045 value.clear();
2046
2047 // Continue only if node is valid
2048 if (node != NULL) {
2049
2050 // Get name node and extract text content
2051 const GXmlNode* ptr = node->element("name", 0);
2052 if (ptr != NULL) {
2053 const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]);
2054 if (text != NULL) {
2055 name = text->text();
2056 }
2057 }
2058
2059 // Get value node and extract text content
2060 ptr = node->element("value", 0);
2061 if (ptr != NULL) {
2062 const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]);
2063 if (text != NULL) {
2064 value = text->text();
2065 }
2066 }
2067 }
2068
2069 // Return
2070 return;
2071}
2072
2073
2074/***********************************************************************//**
2075 * @brief Return XML element for a given tag and name/value attribute
2076 *
2077 * @param[in] element Pointer to XML element in which to search for element.
2078 * @param[in] tag Tag of element to search for.
2079 * @param[in] name Attribute name of element to search for.
2080 * @param[in] value Attribute value of element to search for.
2081 * @return Pointer to XML element.
2082 *
2083 * Searches the XML structure from the specified @p element on for a given
2084 * @p tag that contains an attribute with @p name and @p value. This function
2085 * works recursevely down the entire XML structure and stops once the first
2086 * element with a given name/value attribute was found.
2087 ***************************************************************************/
2089 const std::string& tag,
2090 const std::string& name,
2091 const std::string& value)
2092{
2093 // Initialise result element
2094 const GXmlElement* result = NULL;
2095
2096 // First check if element is the one searched for
2097 if (element->name() == tag) {
2098 if (element->has_attribute(name)) {
2099 if (element->attribute(name) == value) {
2100 result = element;
2101 }
2102 }
2103 }
2104
2105 // If we have no result then search all childern
2106 if (result == NULL) {
2107
2108 // Get number of elements in element
2109 int elements = element->elements();
2110
2111 // Loop over elements
2112 for (int i = 0; i < elements; ++i) {
2113
2114 // Get child element
2115 const GXmlElement* child = element->element(i);
2116
2117 // Search in child element
2118 result = xml_get_element_by_attribute(child, tag, name, value);
2119
2120 // If element was found then break
2121 if (result != NULL) {
2122 break;
2123 }
2124
2125 } // endfor: looped over elements
2126
2127 } // endif: searched all children
2128
2129 // Return result element
2130 return result;
2131}
2132
2133
2134/***********************************************************************//**
2135 * @brief Checks whether a parameter has occured once
2136 *
2137 * @param[in] fd Socket file descriptor.
2138 * @param[out] buffer Buffer to hold data.
2139 * @param[in] len Maximum number of bytes to recv().
2140 * @param[in] flags Flags (as the fourth param to recv() ).
2141 * @param[in] timeout Timeout in milliseconds.
2142 * @return recv() error code, -2 == timeout
2143 *
2144 * This function implements the recv() function with a timeout. The timeout
2145 * is specified in milliseconds.
2146 ***************************************************************************/
2147int gammalib::recv(int fd, char *buffer, int len, int flags, int timeout)
2148{
2149 // Initialise error code with time out
2150 int error = -2;
2151
2152 // Initialize the set
2153 fd_set readset;
2154 FD_ZERO(&readset);
2155 FD_SET(fd, &readset);
2156
2157 // Initialize time out struct
2158 struct timeval tv;
2159 if (timeout >= 1000) {
2160 tv.tv_sec = timeout/1000;
2161 tv.tv_usec = 0;
2162 }
2163 else {
2164 tv.tv_sec = 0;
2165 tv.tv_usec = timeout*1000;
2166 }
2167
2168 // select()
2169 int result = select(fd+1, &readset, NULL, NULL, &tv);
2170
2171 // Check status
2172 if (result < 0) {
2173 error = -1;
2174 }
2175 else if (result > 0 && FD_ISSET(fd, &readset)) {
2176
2177 // Initialise flags
2178 int iof = -1;
2179
2180 // Set non-blocking mode
2181 if ((iof = fcntl(fd, F_GETFL, 0)) != -1) {
2182 fcntl(fd, F_SETFL, iof | O_NONBLOCK);
2183 }
2184
2185 // Receive data
2186 result = ::recv(fd, buffer, len, flags);
2187
2188 // Set as before
2189 if (iof != -1) {
2190 fcntl(fd, F_SETFL, iof);
2191 }
2192
2193 // Set error
2194 error = result;
2195 }
2196
2197 // Return error
2198 return error;
2199}
2200
2201
2202/***********************************************************************//**
2203 * @brief Returns length of circular arc within circular ROI
2204 *
2205 * @param[in] rad Circle radius in radians (<pi).
2206 * @param[in] dist Circle centre distance to ROI centre (<pi).
2207 * @param[in] cosdist Cosine of circle centre distance to ROI centre.
2208 * @param[in] sindist Sinus of circle centre distance to ROI centre.
2209 * @param[in] roi Radius of ROI in radians.
2210 * @param[in] cosroi Cosine of ROI radius.
2211 *
2212 * This method returns the arclength in radians of a circle of radius 'rad'
2213 * with a centre that is offset by 'dist' from the ROI centre, where the ROI
2214 * radius is given by 'roi'. To speed-up computations, the cosines and sinus
2215 * of 'roi' and 'psf' should be calculated by the client and be passed to
2216 * the method.
2217 ***************************************************************************/
2218double gammalib::roi_arclength(const double& rad, const double& dist,
2219 const double& cosdist, const double& sindist,
2220 const double& roi, const double& cosroi)
2221{
2222 // Declare arclength
2223 double arclength;
2224
2225 // Handle special case that circle centre matches ROI centre
2226 if (dist == 0.0) {
2227 if (rad > roi) arclength = 0.0; // Circle outside ROI
2228 else arclength = gammalib::twopi; // Circle inside ROI
2229 }
2230
2231 // ... otherwise circle and ROI centres are not identical
2232 else {
2233
2234 // Handle special case that we evaluate exactly at the circle
2235 // centre. In this case we have in fact a point, and if this point
2236 // falls within the ROI it has a formal arclength of 2pi.
2237 //
2238 if (rad == 0.0) {
2239 if (dist > roi) arclength = 0.0; // Circle centre outside ROI
2240 else arclength = gammalib::twopi; // Circle centre inside ROI
2241 }
2242
2243 // ... otherwise we have to handle the general case
2244 else {
2245 double d = roi - dist;
2246 if (-rad >= d) {
2247 arclength = 0.0;
2248 }
2249 else if (rad <= d) {
2250 arclength = gammalib::twopi;
2251 }
2252 else {
2253 double cosrad = std::cos(rad);
2254 double sinrad = std::sin(rad);
2255 double cosang = (cosroi - cosdist*cosrad) / (sindist*sinrad);
2256 arclength = 2.0 * gammalib::acos(cosang);
2257 #if defined(G_CHECK_FOR_NAN)
2258 if (gammalib::is_infinite(arclength) ||
2259 gammalib::is_notanumber(arclength)) {
2260 std::cout << "roi_arclength: NaN occured";
2261 std::cout << " rad=" << rad;
2262 std::cout << " sinrad=" << sinrad;
2263 std::cout << " cosrad=" << cosrad;
2264 std::cout << " sindist=" << sindist;
2265 std::cout << " cosdist=" << cosdist;
2266 std::cout << " cosang=" << cosang;
2267 std::cout << std::endl;
2268 }
2269 #endif
2270 }
2271 }
2272
2273 } // endelse: Circle and ROI centres were not identical
2274
2275 // Return arclength
2276 return arclength;
2277}
2278
2279
2280/***********************************************************************//**
2281 * @brief Compare two floating point values with tolerance
2282 *
2283 * @param[in] a First floating point value.
2284 * @param[in] b Second floating point value.
2285 * @param[in] tol Relative tolerance.
2286 * @return True if both floating point values are identical within
2287 * the tolerance.
2288 *
2289 * This method tests whether @p a is identical to @p b within a given
2290 * relative tolerance @p tol. The test verifies whether
2291 *
2292 * \f[|a - b| \le |a \times tol|\f]
2293 *
2294 * for \f$a \ne 0\f$ or whether
2295 *
2296 * \f[|a - b| \le |b \times tol|\f]
2297 *
2298 * for \f$b \ne 0\f$. If both \f$a = 0\f$ and \f$b = 0\f$ the method
2299 * returns true.
2300 ***************************************************************************/
2301bool gammalib::compare(const double& a, const double& b, const double& tol)
2302{
2303 // Initialise identity
2304 bool identity = false;
2305
2306 // Case A: a is not zero
2307 if (a != 0.0) {
2308 identity = std::abs(a - b) <= std::abs(a * tol);
2309 }
2310
2311 // Case B: b is not zero
2312 else if (b != 0.0) {
2313 identity = std::abs(a - b) <= std::abs(b * tol);
2314 }
2315
2316 // Case C: a and b are zero
2317 else {
2318 identity = true;
2319 }
2320
2321 // Return identity
2322 return identity;
2323}
2324
2325
2326/***********************************************************************//**
2327 * @brief Return response to a HTTP query
2328 *
2329 * @param[in] host Host address.
2330 * @param[in] query Query string.
2331 * @return Response to a HTTP query.
2332 *
2333 * @exception GException::runtime_error
2334 * Unable to open or to connect to socket.
2335 * @exception GException::invalid_argument
2336 * Host not found.
2337 *
2338 * Returns response to a HTTP query. Be aware that this method will not
2339 * work for https servers.
2340 ***************************************************************************/
2341std::string gammalib::http_query(const std::string& host, const std::string& query)
2342{
2343 // Set constants
2344 const int portno = 80;
2345
2346 // Initialise buffers
2347 char message[1024];
2348 char response[4096];
2349 memset(message, 0, sizeof(message));
2350 memset(response, 0, sizeof(response));
2351
2352 // Build message string (C++98 compliant)
2353 #if ((defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || \
2354 (defined __cplusplus && __cplusplus >= 201103L))
2355 std::snprintf(message, sizeof(message), "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n",
2356 query.c_str(), host.c_str());
2357 #else
2358 std::sprintf(message, "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n",
2359 query.c_str(), host.c_str());
2360 #endif
2361
2362 // Create the socket
2363 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
2364 if (sockfd < 0) {
2365 std::string msg = "Unable to open socket.";
2367 }
2368
2369 // Lookup IP address
2370 struct hostent* server = gethostbyname(host.c_str());
2371 if (server == NULL) {
2372 std::string msg = "Unable to find host \""+host+"\".";
2374 }
2375
2376 // Fill in structure
2377 struct sockaddr_in serveraddr;
2378 memset(&serveraddr, 0, sizeof(serveraddr));
2379 serveraddr.sin_family = AF_INET;
2380 memcpy(&serveraddr.sin_addr.s_addr, server->h_addr, server->h_length);
2381 serveraddr.sin_port = htons(portno);
2382
2383 // Connect the socket
2384 if (connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) {
2385 std::string msg = "Unable to connect to socket for host \""+host+"\".";
2387 }
2388
2389 // Send request
2390 write(sockfd, message, strlen(message));
2391
2392 // Receive response
2393 read(sockfd, response, sizeof(response)-1);
2394
2395 // Close socket
2396 close(sockfd);
2397
2398 // Return response
2399 return std::string(response);
2400}
2401
2402
2403#if defined(G_USE_CURL)
2404/***********************************************************************//**
2405 * @brief Return two-digit host country code
2406 *
2407 * @param[in] force_query Force query of host country code?
2408 * @return Host two-digit host country code.
2409 *
2410 * Returns two-digit host country code, either by reading the code from the
2411 * $HOME/.gamma/host-country file, or if the file does not exist, by using
2412 * the http query
2413 * http://ip-api.com/line/?fields=countryCode.
2414 *
2415 * The result is saved in a static variable, hence once the country code is
2416 * retrieved no queries will be executed anymore. The http query is issued
2417 * using the curl tool with a timeout of one second. If the query fails,
2418 * or the curl tool is not available, the method returns an empty string.
2419 *
2420 * If no host-country file exists and the method retrieved a two-digit
2421 * country code it will write the results into a host-country file.
2422 ***************************************************************************/
2423#else
2424/***********************************************************************//**
2425 * @brief Return two-digit host country code
2426 *
2427 * @param[in] force_query Force query of host country code?
2428 * @return Host two-digit host country code.
2429 *
2430 * Returns two-digit host country code, either by reading the code from the
2431 * $HOME/.gamma/host-country file, or if the file does not exist, by using
2432 * the http query
2433 * http://ip-api.com/line/?fields=countryCode.
2434 *
2435 * The result is saved in a static variable, hence once the country code is
2436 * retrieved no queries will be executed anymore. The http query is issued
2437 * using the http_query() method. If the query fails the method returns an
2438 * empty string.
2439 *
2440 * If no host-country file exists and the method retrieved a two-digit
2441 * country code it will write the results into a host-country file.
2442 ***************************************************************************/
2443#endif
2444std::string gammalib::host_country(const bool& force_query)
2445{
2446 // Initialise country as static variable
2447 static std::string country;
2448
2449 // Continue only if host country is empty
2450 if (country.empty()) {
2451
2452 // Attempt to get host country from $HOME/.gamma/host-country file
2453 GFilename filename = gammalib::gamma_filename("host-country");
2454
2455 // Continue only if file exists
2456 if ((!force_query) && (access(filename.url().c_str(), R_OK) == 0)) {
2457
2458 // OpenMP critical zone to read host-country file
2459 #pragma omp critical(GammaLib_host_country)
2460 {
2461
2462 // Get file lock. Continue only in case of success.
2463 struct flock lock;
2464 lock.l_type = F_RDLCK; // Want a read lock
2465 lock.l_whence = SEEK_SET; // Want beginning of file
2466 lock.l_start = 0; // No offset, lock entire file ...
2467 lock.l_len = 0; // ... to the end
2468 lock.l_pid = getpid(); // Current process ID
2469 int fd = open(filename.url().c_str(), O_RDONLY);
2470 if (fd != -1) {
2471
2472 // Lock file
2473 fcntl(fd, F_SETLKW, &lock);
2474
2475 // Open host-country file. Continue only if opening was
2476 // successful.
2477 FILE* fptr = fopen(filename.url().c_str(), "r");
2478 if (fptr != NULL) {
2479
2480 // Allocate line buffer
2481 const int n = 1000;
2482 char line[n];
2483
2484 // Read line
2485 fgets(line, n-1, fptr);
2486
2487 // Close file
2488 fclose(fptr);
2489
2490 // Extract country string
2491 country = gammalib::strip_chars(std::string(line), "\n");
2492
2493 } // endif: host-country file opened successfully
2494
2495 // Unlock file
2496 lock.l_type = F_UNLCK;
2497 fcntl(fd, F_SETLK, &lock);
2498 close(fd);
2499
2500 } // endif: file locking successful
2501
2502 } // end of OMP critial zone
2503
2504 } // endif: file existed
2505
2506 // ... otherwise there is no host-country file then get the
2507 // information from a geolocalisation web site
2508 else {
2509
2510 // If curl should be used, the curl tool is available and the
2511 // country code is not set then determine the country code
2512 // from a geolocalisation web site
2513 #if defined(G_USE_CURL)
2514 #if defined(G_HAS_CURL)
2515 // If curl is available then use curl to infer the country code
2516 char command[256];
2517
2518 // Setup curl command with timeout if possible to avoid lock up
2519 #if defined(G_HAS_PERL)
2520 sprintf(command, "a=$(perl -e 'alarm shift; exec \"curl --silent"
2521 " http://ip-api.com/line/?fields=countryCode"
2522 " 2>/dev/null\"' \"1\";);echo $a");
2523 #elif defined(G_HAS_TIMEOUT)
2524 sprintf(command, "timeout 1s curl --silent http://ip-api.com/line/"
2525 "?fields=countryCode 2>/dev/null");
2526 #else
2527 sprintf(command, "curl --silent http://ip-api.com/line/?fields=countryCode"
2528 " 2>/dev/null");
2529 #endif
2530
2531 // Open the process with given 'command' for reading
2532 FILE* file = popen(command, "r");
2533
2534 // Retrieve curl output
2535 char output[1024];
2536 if (fgets(output, sizeof(output)-1, file) != NULL) {
2537 country = strip_chars(std::string(output), "\n");
2538 }
2539
2540 // Close process
2541 pclose(file);
2542 #endif
2543
2544 // ... otherwise use the http_query method. Catch any exceptions.
2545 #else
2546 try {
2547 std::string response = http_query("ip-api.com", "line/?fields=countryCode");
2548 std::vector<std::string> lines = split(response, "\n");
2549 bool body = false;
2550 for (int i = 0; i < lines.size(); ++i) {
2551 if (body) {
2552 country = lines[i];
2553 break;
2554 }
2555 if ((lines[i] == "\n") || (lines[i] == "\r") || (lines[i] == " ")) {
2556 body = true;
2557 }
2558 }
2559 } // endtry
2560 catch (const std::exception& e) {
2561 //
2562 }
2563 #endif
2564
2565 // If we have a two-digit country code then write the code into
2566 // host-country file
2567 if (country.length() == 2) {
2568
2569 // OpenMP critical zone to write host-country file
2570 #pragma omp critical(GammaLib_host_country)
2571 {
2572
2573 // Open host-country file, and in case of success, write
2574 // country
2575 FILE* fptr = fopen(filename.url().c_str(), "w");
2576 if (fptr != NULL) {
2577 fprintf(fptr, "%s\n", country.c_str());
2578 fclose(fptr);
2579 }
2580
2581 } // end of OMP critial zone
2582
2583 } // endif: had no two digit country code
2584
2585 } // endelse: there was no host country file
2586
2587 } // endif: host country was empty
2588
2589 // Return country
2590 return country;
2591}
2592
2593
2594/***********************************************************************//**
2595 * @brief Returns filename in .gamma directory
2596 *
2597 * @param[in] name Name of file in .gamma directory.
2598 * @return Filename in .gamma directory.
2599 *
2600 * Returns the filename of the name of a file in the .gamma directory.
2601 ***************************************************************************/
2602GFilename gammalib::gamma_filename(const std::string& name)
2603{
2604 // Initialise lock filename
2605 GFilename filename;
2606
2607 // First try accessing the user ID to get the home directory
2608 uid_t uid = geteuid();
2609 struct passwd* pw = getpwuid(uid);
2610 if (pw != NULL) {
2611 filename = std::string(pw->pw_dir) + "/.gamma/" + name;
2612 }
2613
2614 // ... otherwise try using the $HOME environment variable
2615 else {
2616
2617 // First attempt fetching $HOME environment variable
2618 char* home_ptr = std::getenv("HOME");
2619 if (home_ptr != NULL) {
2620 filename = std::string(home_ptr) + "/.gamma/" + name;
2621 }
2622
2623 // ... otherwise use ~ as home directory
2624 else {
2625 filename = "~/.gamma/" + name;
2626 }
2627 }
2628
2629 // Return filename
2630 return filename;
2631}
2632
2633
2634/***********************************************************************//**
2635 * @brief Get current resident set size (physical memory use) in Bytes
2636 *
2637 * @return Physical memory use in Bytes.
2638 ***************************************************************************/
2640{
2641 // Initialize resident set size
2642 size_t rss = 0;
2643
2644 // Determine resident set size (architecture dependent)
2645 // OSX
2646 #if defined(__APPLE__) && defined(__MACH__)
2647 #ifdef MACH_TASK_BASIC_INFO
2648 struct mach_task_basic_info info;
2649 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
2650 if (task_info(mach_task_self( ), MACH_TASK_BASIC_INFO,
2651 (task_info_t)&info, &infoCount) == KERN_SUCCESS) {
2652 rss = (size_t)info.resident_size;
2653 }
2654 #else
2655 struct task_basic_info info;
2656 mach_msg_type_number_t info_count = TASK_BASIC_INFO_COUNT;
2657 if (task_info(mach_task_self(), TASK_BASIC_INFO,
2658 (task_info_t)&info, &info_count) == KERN_SUCCESS) {
2659 rss = (size_t)info.resident_size;
2660 }
2661 #endif
2662 // Linux
2663 #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
2664 FILE* fp = NULL;
2665 if ((fp = fopen( "/proc/self/statm", "r" )) != NULL) {
2666 if (fscanf( fp, "%*s%ld", &rss ) == 1) {
2667 rss *= (size_t)sysconf(_SC_PAGESIZE);
2668 }
2669 fclose(fp);
2670 }
2671 // AIX, BSD, Solaris, and Unknown OS
2672 #else
2673 rss = 0;
2674 #endif
2675
2676 // Return resident set size
2677 return rss;
2678}
2679
2680
2681/***********************************************************************//**
2682 * @brief Get current clock in seconds
2683 *
2684 * @return Current clock in seconds.
2685 ***************************************************************************/
2687{
2688 // Get current clock in seconds
2689 #ifdef _OPENMP
2690 double time = omp_get_wtime();
2691 #else
2692 double time = double(clock()) / (double)CLOCKS_PER_SEC;
2693 #endif
2694
2695 // Return time
2696 return time;
2697}
Energy value class definition.
Exception handler interface definition.
Filename class interface definition.
FITS file class interface definition.
Mathematical function definitions.
#define G_CHAR_BUFFER
Definition GTools.cpp:90
#define G_XML2STR
Definition GTools.cpp:85
#define G_PARFORMAT_LENGTH
Definition GTools.cpp:89
#define G_HTTP_QUERY
Definition GTools.cpp:86
Gammalib tools definition.
#define gammalib_snprintf(O, S, F, A)
Definition GTools.hpp:45
XML element node class interface definition.
Abstract XML node base class interface definition.
XML text node class interface definition.
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:342
double log10MeV(void) const
Return log10 of energy in MeV.
Definition GEnergy.cpp:458
Filename class.
Definition GFilename.hpp:62
std::string path(void) const
Return access path.
std::string file(void) const
Return name of file.
std::string url(void) const
Return Uniform Resource Locator (URL)
bool is_empty(void) const
Signal if filename is empty.
XML element node class.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
const std::string & name(void) const
Return XML element name.
Abstract XML node base class.
Definition GXmlNode.hpp:57
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition GXmlNode.cpp:287
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition GXmlNode.cpp:640
GFilename filename(void) const
Return filename of XML file.
Definition GXmlNode.cpp:546
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition GXmlNode.cpp:586
XML text node class.
Definition GXmlText.hpp:43
const std::string & text(void) const
Return text.
Definition GXmlText.hpp:97
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1136
std::string number(const std::string &noun, const int &number)
Convert singular noun into number noun.
Definition GTools.cpp:1160
GFilename gamma_filename(const std::string &name)
Returns filename in .gamma directory.
Definition GTools.cpp:2602
bool is_infinite(const double &x)
Signal if argument is infinite.
Definition GTools.hpp:203
double plaw_photon_flux(const double &emin, const double &emax, const double &epivot, const double &gamma)
Compute photon flux between two energies for a power law.
Definition GTools.cpp:1230
std::string strdate(void)
Return current date.
Definition GTools.cpp:746
std::string http_query(const std::string &host, const std::string &query)
Return response to a HTTP query.
Definition GTools.cpp:2341
bool is_notanumber(const double &x)
Signal if argument is not a number.
Definition GTools.hpp:220
GEnergy elogmean(const GEnergy &a, const GEnergy &b)
Computes log mean energy.
Definition GTools.cpp:1320
long tolong(const std::string &arg)
Convert string into long value.
Definition GTools.cpp:844
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508
const GXmlElement * xml_get_par(const std::string &origin, const GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1740
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:919
std::string xml_get_attr(const std::string &origin, const GXmlElement &xml, const std::string &name, const std::string &attribute)
Return attribute value for a given parameter in XML element.
Definition GTools.cpp:1789
std::string order(const int &number)
Convert number into order noun.
Definition GTools.cpp:1185
std::string left(const std::string &s, const int &n, const char &c=' ')
Left justify string to achieve a length of n characters.
Definition GTools.cpp:1063
bool compare(const double &a, const double &b, const double &tol)
Compare two floating point values with tolerance.
Definition GTools.cpp:2301
std::string right(const std::string &s, const int &n, const char &c=' ')
Right justify string to achieve a length of n characters.
Definition GTools.cpp:1087
std::string replace_segment(const std::string &arg, const std::string &segment, const std::string &replacement)
Replace string segment in string.
Definition GTools.cpp:187
std::string filepath(const std::string &pathname, const std::string &filename)
Build file path from path name and file name.
Definition GTools.cpp:412
std::string tolower(const std::string &s)
Convert string to lower case.
Definition GTools.cpp:948
unsigned long long toulonglong(const std::string &arg)
Convert string into unsigned long long value.
Definition GTools.cpp:889
int toint(const std::string &arg)
Convert string into integer value.
Definition GTools.cpp:814
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1688
std::string rstrip_chars(const std::string &arg, const std::string &chars)
Strip trailing character from string.
Definition GTools.cpp:150
std::string xml2str(const std::string &arg)
Convert XML character references in string to characters.
Definition GTools.cpp:1449
GFilename xml_file_reduce(const GXmlElement &xml, const std::string &filename)
Reduce file name provided for writing as XML attribute.
Definition GTools.cpp:1997
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:99
std::string str2xml(const std::string &arg)
Convert special characters in string to XML character references.
Definition GTools.cpp:1600
double roi_arclength(const double &rad, const double &dist, const double &cosdist, const double &sindist, const double &roi, const double &cosroi)
Returns length of circular arc within circular ROI.
Definition GTools.cpp:2218
float tofloat(const std::string &arg)
Convert string into single precision value.
Definition GTools.cpp:904
std::string expand_env(const std::string &arg)
Expand environment variables in string.
Definition GTools.cpp:233
unsigned long toulong(const std::string &arg)
Convert string into unsigned long value.
Definition GTools.cpp:859
bool dir_exists(const std::string &dirname)
Checks if directory exists.
Definition GTools.cpp:1342
unsigned int touint(const std::string &arg)
Convert string into unsigned integer value.
Definition GTools.cpp:829
bool contains(const std::string &str, const std::string &substring)
Checks if a substring is in a string.
Definition GTools.cpp:1372
std::string host_country(const bool &force_query=false)
Return two-digit host country code.
Definition GTools.cpp:2444
short toshort(const std::string &arg)
Convert string into short value.
Definition GTools.cpp:784
double get_current_clock(void)
Get current clock in seconds.
Definition GTools.cpp:2686
double acos(const double &arg)
Computes acos by avoiding NaN due to rounding errors.
Definition GMath.cpp:69
std::string centre(const std::string &s, const int &n, const char &c=' ')
Centre string to achieve a length of n characters.
Definition GTools.cpp:1111
void xml_check_parnum(const std::string &origin, const GXmlElement &xml, const int &number)
Checks number of parameters.
Definition GTools.cpp:1828
std::string tmpnam(void)
Return temporary file name.
Definition GTools.cpp:440
void xml_get_name_value_pair(const GXmlNode *node, std::string &name, std::string &value)
Extract name / value pair from XML node.
Definition GTools.cpp:2039
void warning(const std::string &origin, const std::string &message)
Emits warning.
Definition GTools.cpp:1416
const GXmlElement * xml_get_element_by_attribute(const GXmlElement *element, const std::string &tag, const std::string &name, const std::string &value)
Return XML element for a given tag and name/value attribute.
Definition GTools.cpp:2088
const double twopi
Definition GMath.hpp:36
unsigned short toushort(const std::string &arg)
Convert string into unsigned short value.
Definition GTools.cpp:799
double plaw_energy_flux(const double &emin, const double &emax, const double &epivot, const double &gamma)
Compute energy flux between two energies for a power law.
Definition GTools.cpp:1278
std::string fill(const std::string &s, const int &n)
Fill string with n strings of same type.
Definition GTools.cpp:1037
std::string getenv(const std::string &arg)
Return value of environment variable.
Definition GTools.cpp:484
bool xml_has_par(const GXmlElement &xml, const std::string &name)
Checks if parameter with given name in XML element exists.
Definition GTools.cpp:1647
void xml_check_par(const std::string &origin, const std::string &name, const int &number)
Checks whether a parameter has occured once.
Definition GTools.cpp:1906
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition GTools.cpp:976
int recv(int fd, char *buffer, int len, int flags, int timeout)
Checks whether a parameter has occured once.
Definition GTools.cpp:2147
std::string toupper(const std::string &s)
Convert string to upper case.
Definition GTools.cpp:934
GFilename xml_file_expand(const GXmlElement &xml, const std::string &filename)
Expand file name provided as XML attribute for loading.
Definition GTools.cpp:1940
long long tolonglong(const std::string &arg)
Convert string into long long value.
Definition GTools.cpp:874
void xml_check_type(const std::string &origin, GXmlElement &xml, const std::string &type)
Checks the model type.
Definition GTools.cpp:1870
std::string strip_chars(const std::string &arg, const std::string &chars)
Strip leading and trailing character from string.
Definition GTools.cpp:113
size_t get_current_rss(void)
Get current resident set size (physical memory use) in Bytes.
Definition GTools.cpp:2639