diff --git a/ChangeLog b/ChangeLog index e0b8aa7..71c3330 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2015-12-18 Juergen Knoedlseder + + * Version 1.0.0 released + ========================= + + Ignore errors for El Capitan post processing (#1605) + Read only mandatory columns in GCTAEventList (#1600) + Remove extname arguments from classes (#1601) + Add GFilename class (#1599) + Check existence of files in CTA response loading (#1586) + GSkyMap::__getitem__ throw exception if out of bound (#1581) + Handle ~ in filenames (#1580) + Add GModel::has_ts() method (#1578) + Perform __init__.py creation only in build step (#1569) + Remove access by name methods from GSkyRegions (#1564) + Resolve Python test problem on El Capitan (#1563) + + 2015-10-28 Juergen Knoedlseder * Version 0.11.0 released diff --git a/NEWS b/NEWS index 779bc83..5befd62 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,8 @@ -New Features and Important Changes in GammaLib 0.11.0 +New Features and Important Changes in GammaLib 1.0.0 Author(s) : Juergen Knoedlseder -28 October 2015 +18 December 2015 1. Introduction @@ -13,33 +13,32 @@ made since the last release of GammaLib. 2. Public interface modifications --------------------------------- -The GOptimizerLM logger constructor now takes a pointer to a logger instead of -a reference. This allows setting of a NULL pointer, disabling the logging of the -optimizer. - -The GSkymap class has been renamed to GSkyMap to be consistent with the other -classes in the sky module. - -The small angle approximation has been removed from GModelSpatialRadialShell. +Remove optional extname arguments from the following classes: +- GEbounds +- GEnergies +- GGti +- GNodeArray +- GCTAPointing +- GMWLObservation +- GMWLSpectrum 3. Configuration ----------------- -None +The __init__.py file in the pyext/gammalib folder is now only created during +build but not during the install. This should avoid problems during installation +related to file access rights (#1569). + +A special post processing of the Python module libraries has been added for +Mac OS X 10.11 and higher (El Capitan). This post processing is a replacement for +setting DYLD_LIBRARY_PATH during unit testing since the environment variable is +ignored in certain circumstances by El Capitan. Any errors that occur during the +post processing will be ignored. 4. Application module --------------------- -GammaLib applications now only look for the application parameter file in the -users pfiles directory if the PFILES environment variable has been not set. This -assure that the PFILES environment variable will always take precedence over the -users pfiles directory, and if the paramter file is missing in the directory -pointed by the PFILES environment variable, it will be copied over from the -syspfiles directory. - -The GApplication class now has a need_help() method that returns true is the ---help option is specified on the command line. This allows the client to display -any help information. +None 5. Base module @@ -59,35 +58,8 @@ None 8. Model module --------------- -Implement a rejection method for Monte Carlo simulations of photons in -GModelSpatialDiffuseMap and GModelSpatialDiffuseCube. This assures that the -simulated photon distribution follows the intensity distribution of the skymap -as obtained using the sky direction access operator. - -The algorithm used to draw random numbers in GModelSpatialDiffuseConst::mc() -was wrong (sky directions were not distributed isotropically on the sky). This -has now been fixed (#1480). - -The small angle approximation has been removed from GModelSpatialRadialShell -as this complexifies the class and the approximation is not really needed. - -A GModelSpatialDiffuseMap::set_mc_cone method has been introduced to handle -correctly Monte Carlo simulations for unnormalized diffuse maps. This method -now computes the normalization for a map within the acceptance cone which is -then returned by the GModelSpatialDiffuseMap::mc_norm method. - -The GModelSpatial::norm method has been renamed to GModelSpatial::mc_norm so that -the usage of this method is now explicitly given by the method name. - -save() and write() methods have been added to GModelSpatialDiffuseCube that allow -the saving of a diffuse cube spatial model to disk or into a FITS objects. - -The computations in GModelSpatialDiffuseCube were not precise enough to allow -an accurate modelling of the simulated events. The eval() and eval_gradients() -methods now use a log-log interpolation. Furthermore, the map is selected -in mc() randomly based on the interpolation weights of th neighbouring maps. -And some bugs related to the map indexing and maximum map value computation -have been corrected. +Added GModel::has_ts() method that signals if a TS value has been computed +for a given model. 9. Numerics module @@ -97,49 +69,38 @@ None 10. Observation module ---------------------- -Integration in npred() is now done using a fixed number of Romberg iterations -instead of using the integration precision. This will assure that the log- -likelihood function is smooth. - -The number of integration iterations for the energy dispersion was changed from -4 to 5 to make it compatible with the default integration order. - -An interval constructor and the set_lin() and set_log() methods have been added -to the GEnergies class to allow quick creation of a linear or logarithmic series -of energies. +None 11. Optimization module ----------------------- -The gradient computation has been corrected. Instead of multiplying the gradient -factor with the scale factor we have to divide the gradient factor by the scale -factor. - -An logger() method has been added to GOptimizerLM to set the logger for an -optimizer (before, a logger could only be set during construction). +None 12. Sky module -------------- -Added the flux() method that provides estimates for the flux value of a pixel. The -flux is defined as the intensity (computed by bilinear interpolation over the pixel) -multiplied by the solid angle of the pixel. +Remove the following methods from GSkyRegions as we have not identified a use case +where this access is needed (#1564): +* set(std::string, GSkyRegion) +* insert(std::string, GSkyRegion) +* remove(std::string) +* operator[](std::string) +* contains(std::string) +* get_index(std::string) -The pixel containment check has been corrected. Before, the containment check returned -true even if the pixel was by one beyond the skymap limits. On of the unwanted side -effects in the sky map access operator was that pixels outside the valid sky map -array were accessed, leading to unpredictable results at the edge of the images. -This quite severe bug was now corrected. - -The GSkymap::operator/=(GSkymap) operator now sets all pixels to zero for which the -nominator is zero. No exception is thrown any longer. - -Add +, -, * and / binary operators to the GSkymap class. +The Python extension GSkyMap::__getitem__ now checks the validity of the index and +map number and throws an out_of_range exception if the parameters are not valid. +This is required on some platforms to properly catch the end in iterations (#1581). 13. Support module ------------------ -None +The gammalib::expand_env() function now handles ~, ~user, ~+ and ~- following the +logic implemented for the bash shell. + +The GFilename class has been added to deal with filenames in the future. This class +handles the decomposition of the string into a filename and an extension name in the +cfitsio style, allowing to specify the extension name, number and version. 14. XML module @@ -174,34 +135,11 @@ None 20. CTA interface ----------------- -All integrations are now done using a fixed number of Romberg iterations -instead of using the integration precision. This will assure that the log- -likelihood function is smooth. - -The number of integration iterations for the energy dispersion was changed from -4 to 5 to make it compatible with the default integration order. - -An is_valid() method has been added to GCTARoi that returns true if the ROI -has a positive radius. DS keywords are only written for a valid ROI into the -event list file. - -The OBJECT attribute of an event file is now stored in to m_object member of -GCTAObservation, and object() methods have been added to set and get the -attribute value. - -The deadtime correction has been removed from GCTAModelCubeBackground as the -background cube rates are already given per livetime. We formerly did the -correction twice (#1503). - -The GCTAModelAeffBackground class has been added to generate a background model -from the effective area information (#1525). The usage of this model is similar -to that of the IRF background model. The model type in the XML file is -"CTAAeffBackground". - -The precision for the IRF computation of radial shell models has been increased -to reduce a bias in the fitting of the model for unbinned analysis (#1521). There -is still a slight bias for the shell parameters in an unbinned analysis when the -width of the shell becomes comparable to the angular resolution. +The IRF loaders now check the existence of the file before loading, and now throws +appropriate error messages in case that the files do not exist (#1586). + +Only manadatory columns are read by GCTAEventsList, while any other columns will only +be stored for back writing in a FITS file. 21. COMPTEL interface diff --git a/README b/README index fb0b411..9a3f1b9 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ GammaLib information ==================== -Version: 0.11.0 (28 October 2015) +Version: 1.0.0 (18 December 2015) Author: Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu) @@ -41,8 +41,7 @@ data analysis framework that enables simultaneous multi-mission analysis. Web sites ========= -http://cta.irap.omp.eu/gammalib/ - for documentation -https://sourceforge.net/projects/gammalib/ - for downloads +http://cta.irap.omp.eu/gammalib/ - for end users https://cta-redmine.irap.omp.eu/projects/gammalib - for developers @@ -181,7 +180,7 @@ If everything works successfully you should see or ============================================================================ -Testsuite summary for gammalib 0.11.0 +Testsuite summary for gammalib 1.0.0 ============================================================================ # TOTAL: 20 # PASS: 20 diff --git a/configure.ac b/configure.ac index a19a178..86ad1ba 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ ############################################################################# # Initialisation # ############################################################################# -AC_INIT([gammalib], [0.11.0], [jurgen.knodlseder@irap.omp.eu], [gammalib]) +AC_INIT([gammalib], [1.0.0], [jurgen.knodlseder@irap.omp.eu], [gammalib]) AC_CONFIG_SRCDIR([src/support/GTools.cpp]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([gnu no-dependencies -Wno-portability subdir-objects]) @@ -39,13 +39,23 @@ AC_CONFIG_HEADER([config.h]) ############################################################################# -# Library versioning # +# Library versioning (current:revision:age) # # ------------------------------------------------------------------------- # -# See the libtool manual for an explanation. Currently, library versioning # -# is not yet used for GammaLib as we're still in the development cycle. # -# Users have to make sure that they link against the correct library. # -############################################################################# -GAMMALIB_LT_VERSION="0:0:0" +# Here are a set of rules to update your library version information: # +# 1. Update the version information only immediately before a public # +# release of your software. More frequent updates are unnecessary, # +# and only guarantee that the current interface number gets larger # +# faster. # +# 2. If the library source code has changed at all since the last update, # +# then increment revision. # +# 3. If any interfaces have been added, removed, or changed since the last # +# update, increment current, and set revision to 0. # +# 4. If any interfaces have been added since the last public release, then # +# increment age. # +# 5. If any interfaces have been removed or changed since the last public # +# release, then set age to 0. # +############################################################################# +GAMMALIB_LT_VERSION="1:0:0" AC_SUBST(GAMMALIB_LT_VERSION) @@ -90,18 +100,42 @@ AC_CANONICAL_HOST # # # A special kluge was added for Mac OS X >=10.7. As Apple switched to clang # # we search from this version on for the clang compiler. # +# # +# We also signal whether Mac OS X >=10.11 (El Capitan). # ############################################################################# +# Set default Mac OS X version flags +osx_lion=no +osx_el_capitan=no + # Set default compiler lists cxx_list="g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++" cc_list="gcc cc cl.exe clang" -# Check if we have Mac OS X >= 10.7 +# Check if we have Mac OS X >= 10.7 and >= 10.11 if test `uname -s` = "Darwin"; then - if test `sw_vers -productVersion | sed 's/\(10\.[[0-9]]*\).*/\1/'` '>' 10.6; then + version=`sw_vers -productVersion | sed 's/\(10\.[[0-9]]*\).*/\1/' | sed -e 's/\.//g'` + if [ test $version -ge 107 ]; then cxx_list="clang++ g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC" cc_list="clang gcc cc cl.exe" + osx_lion=yes + fi + if [ test $version -ge 1011 ]; then + osx_el_capitan=yes fi fi +AC_MSG_CHECKING([for Mac OS X >= 10.7]) +if [test "x$osx_lion" = "xyes"]; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING([for Mac OS X >= 10.11]) +if [test "x$osx_el_capitan" = "xyes"]; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(IS_ELCAPITAN, test "x$osx_el_capitan" = "xyes") # Our language is C++ AC_LANG(C++) diff --git a/dev/release_gammalib.sh b/dev/release_gammalib.sh index 35eb33e..3f4d07a 100755 --- a/dev/release_gammalib.sh +++ b/dev/release_gammalib.sh @@ -8,13 +8,11 @@ makelatex="no" echo "Checkout latest GammaLib" rm -rf gammalib -git clone -b release https://cta-git.irap.omp.eu/gammalib -#git clone -b devel https://cta-git.irap.omp.eu/gammalib +git clone -b release https://cta-gitlab.irap.omp.eu/gammalib/gammalib.git rm -rf gammalib/.git # Extract version number version=`cat gammalib/configure.ac | grep 'AC_INIT' | awk -F"[" '{print $3}' | sed 's/],//' | sed 's/\./ /g'` -#version=`printf "%2.2d-%2.2d-%2.2d" $version` version=`printf "%d.%d.%d" $version` echo "GammaLib version: "$version diff --git a/doc/Doxyfile b/doc/Doxyfile index adf2f10..7b4e713 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -32,7 +32,7 @@ PROJECT_NAME = GammaLib # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.11.0 +PROJECT_NUMBER = 1.0.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/doc/source/coding/design.rst b/doc/source/coding/design.rst index f865928..498bc6f 100644 --- a/doc/source/coding/design.rst +++ b/doc/source/coding/design.rst @@ -18,9 +18,11 @@ file: #include #endif -Note that **the ``config.h`` file should not be included in header files**, -since header files are used by the outside world without any knowledge -about ``config.h``. +.. warning:: + + **The config.h file should never be included in header files.** + The header files are used by the outside world without any knowledge + about ``config.h``. One of the most commonly used configuration options used throughout GammaLib is related to range checking. Range checks are usually @@ -305,11 +307,13 @@ following guidelines should be respected as far as possible: - Avoid as far as possible methods that are only defined in the derived class. -Also note that **for a derived class, ``init_members()``, -``copy_members(const &A a)`` and ``free_members()`` should only act on derived -class members but not on base class members**. Any exception from this -rule needs very careful documentation since it can easily be the source -of memory leaks. +.. warning:: + + **For a derived class, init_members(), copy_members(const &A a) and + free_members() should only act on derived class members but not on base + class members**. Any exception to this rule needs very careful + documentation since it can easily be the source of memory leaks. + Method naming conventions ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/coding/rules.rst b/doc/source/coding/rules.rst index 19537e3..a410f7b 100644 --- a/doc/source/coding/rules.rst +++ b/doc/source/coding/rules.rst @@ -8,7 +8,7 @@ C++ rules --------- All GammaLib C++ code must be compatible with ISO standard C++98. -Do not use C++11 features. +Do not use C++11 features (see `here `__ if you don't know what C++98 and C++11 is and note that C++03 is just a minor correction of C++98). @@ -189,16 +189,12 @@ Code semantics >>> import gammalib >>> energy = gammalib.GEnergy(10, 'TeV') - >>> import numpy as np - >>> import matplotlib.pyplot as plt In interactive sessions (`IPython `_ is recommended) to save typing you can use ``import *`` to import everything into your local namespace:: >>> from gammalib import * >>> energy = GEnergy(10, 'TeV') - >>> from numpy import * - >>> from matplotlib.pyplot import * Using ``import *`` in Python scripts is not recommended. Some reason are given in `this section `__ diff --git a/doc/source/conf.py b/doc/source/conf.py index ce7acb0..4b4c9b3 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -55,9 +55,10 @@ copyright = u'2006-2015, GammaLib developers' # built documents. # # The short X.Y version. -version = '0.11' +version = '1.0' + # The full version, including alpha/beta/rc tags. -release = '0.11.0' +release = '1.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/download.rst b/doc/source/download.rst index 5ebb803..0cf26c3 100644 --- a/doc/source/download.rst +++ b/doc/source/download.rst @@ -14,10 +14,11 @@ Releases -------- The latest GammaLib release is -`gammalib-0.11.0 `_ -(1 November 2015). +`gammalib-1.0.0 `_ +(18 December 2015). To download an older release, click on the corresponding release number: +`0.11.0 `_ `0.10.0 `_ `0.9.1 `_ `0.9.0 `_ diff --git a/doc/source/installation.rst b/doc/source/installation.rst index 938b59c..5274b41 100644 --- a/doc/source/installation.rst +++ b/doc/source/installation.rst @@ -5,8 +5,8 @@ Installation .. note :: - These installation instructions apply to gammalib-0.11.0 and - later. gammalib-0.11.0 has been built, installed and tested + These installation instructions apply to gammalib-1.0.0 and + later. gammalib-1.0.0 has been built, installed and tested successfully on Debian, Ubuntu, Mandriva, OpenSUSE, Scientific Linux, CentOS, Mac OS X, FreeBSD, and OpenSolaris (using gcc), so hopefully it also installs on your distribution. In case you encounter @@ -51,7 +51,7 @@ shared library by typing :: GammaLib can also benefit from the presence of the readline library that provides line-editing and history capabilities for text input (GammaLib -offers however also full functionality without having readline +offers however full functionality without having readline installed). readline (which depends on ncurses) is available on most system as a prebuilt library, so also here we recommend to use your package manager to install the libraries if they are not already there. @@ -83,7 +83,7 @@ Building GammaLib If you need the latest source code from the git repository that has not yet been released you may also clone the gammalib git repository using :: - $ git clone https://cta-git.irap.omp.eu/gammalib + $ git clone https://cta-gitlab.irap.omp.eu/gammalib/gammalib.git In case you encounter an SSL certificat problem, type :: @@ -95,7 +95,7 @@ Building GammaLib $ git checkout devel $ ./autogen.sh - This will make sure that you use the validated development trunk and + This will make sure that you use the development trunk. It also creates the configuration file that is needed to configure GammaLib before compilation. Continue then with the procedure below starting with ``./configure``. @@ -122,19 +122,19 @@ source files and builds the C++ library and Python module. Type ``./configure`` and not simply ``configure`` to ensure that the configuration script in the current directory is used and not some other system-wide configuration script. By default, the install directory is set to -``/usr/local/gamma``. To change the install directory an optional -``--prefix`` argument should be given, for example :: +``/usr/local/gamma``. To change the install directory, provide an optional +``--prefix`` argument, for example :: $ ./configure --prefix=/usr/local If cfitsio and/or readline is not installed in a standard location for -libraries (such as ``/usr/lib`` or ``/usr/local/lib``), the appropriate -location(s) can be specified using the ``LDFLAGS`` (for the library +libraries (such as ``/usr/lib`` or ``/usr/local/lib``), you can specify +the appropriate location(s) using the ``LDFLAGS`` (for the library directory) and ``CPPFLAGS`` (for the include directory) options:: $ ./configure LDFLAGS='-L/opt/local/lib' CPPFLAGS='-I/opt/local/include' -A full list of configuration options can be found using :: +You can find a full list of configuration options using :: $ ./configure --help diff --git a/doc/source/issues.rst b/doc/source/issues.rst index cf86216..4df70ef 100644 --- a/doc/source/issues.rst +++ b/doc/source/issues.rst @@ -7,7 +7,6 @@ Below you will find a list of known issues. - :ref:`Many (but not all) unit tests fail ` - :ref:`Python module does not work ` -- :ref:`Python unit test fails on El Capitan ` - :ref:`Mac OS X ` - :ref:`Solaris ` - :ref:`OpenSolaris ` @@ -73,16 +72,6 @@ Below you will find a list of known issues. If the ``Python.h`` header file does not exist then install the Python development package. -.. _issue_elcapitan: - -.. topic:: Python unit test fails on El Capitan - - On Mac OS X 10.11 (El Capitan) the Python unit tests fail when GammaLib - is not installed due to the way the ``DYLD_LIBRARY_PATH`` environment - variable is handled by the operating system. A (not very elegant) - workaround is to install GammaLib before running the unit test using - ``make check``. - .. _issue_macosx: .. topic:: Mac OS X diff --git a/doc/source/user_manual/getting.rst b/doc/source/user_manual/getting.rst index 0c1d7a4..0044435 100644 --- a/doc/source/user_manual/getting.rst +++ b/doc/source/user_manual/getting.rst @@ -148,15 +148,15 @@ from this site by selection the gammalib package from the table. Alternatively, the code can be downloaded and unpacked from the UNIX prompt using:: - $ wget --no-check-certificate http://cta.irap.omp.eu/ctools/releases/gammalib/gammalib-0.11.0.tar.gz - $ tar xfz gammalib-0.11.0.tar.gz + $ wget --no-check-certificate http://cta.irap.omp.eu/ctools/releases/gammalib/gammalib-1.0.0.tar.gz + $ tar xfz gammalib-1.0.0.tar.gz The GammaLib source code can also be cloned using git. This method is recommended if you plan to contribute to the development of the GammaLib library. Assuming that git is installed on your system, you may clone GammaLib using:: - $ git clone https://cta-git.irap.omp.eu/gammalib + $ git clone https://cta-gitlab.irap.omp.eu/gammalib/gammalib.git In case that you get: diff --git a/doc/source/user_manual/index.rst b/doc/source/user_manual/index.rst index 4d53c27..2b3a9f4 100644 --- a/doc/source/user_manual/index.rst +++ b/doc/source/user_manual/index.rst @@ -7,7 +7,6 @@ User Manual introduction getting - quickstart modules/index internals manual/index diff --git a/doc/source/user_manual/introduction.rst b/doc/source/user_manual/introduction.rst index f4cf922..a5823c8 100644 --- a/doc/source/user_manual/introduction.rst +++ b/doc/source/user_manual/introduction.rst @@ -43,7 +43,7 @@ are: * Issue tracker: https://cta-redmine.irap.omp.eu/projects/gammalib/issues * Documentation: http://cta.irap.omp.eu/gammalib/ -The present document applies to GammaLib version 0.11. +The present document applies to GammaLib version 1.0. GammaLib is designed to compile on any POSIX compliant platform. So far, GammaLib has been successfully compiled and tested on Mac OS X, OpenBSD, OpenSolaris diff --git a/doc/source/user_manual/modules/support.rst b/doc/source/user_manual/modules/support.rst index 8e9d358..39008da 100644 --- a/doc/source/user_manual/modules/support.rst +++ b/doc/source/user_manual/modules/support.rst @@ -38,10 +38,17 @@ and a string storage, respectively. As most of the classes are unrelated, they will be described individually in the following sections. -Column Separated Value tables +Bilinear interpolation +~~~~~~~~~~~~~~~~~~~~~~ + +The :doxy:`GBilinear` class handles bilinear interpolation of values in a +two-dimensional table. + + +Comma-Separated Value tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The :doxy:`GCsv` class handles column separated value tables. Column separated +The :doxy:`GCsv` class handles comma-separated value tables. Comma-separated value tables are ASCII files representing a table, where individual table columns a separated by a specific character (for example a whitespace or a comma). @@ -113,6 +120,37 @@ Runtime exceptions Usage =============================== ===== +Filename handling +~~~~~~~~~~~~~~~~~ + +The :doxy:`GFilename` class handles file names in GammaLib, including +extensions for FITS files in the cfitsio format. The following file name +formats are supported :: + + myfile.fits + myfile.fits[EVENTS] + myfile.fits[EVENTS,2] + myfile.fits[3,2] + +The class decomposes the input string into the filename and the extension. +The filename can be access using the :doxy:`GFilename::filename` +method, the extension name using the :doxy:`GFilename::extname` method, +the extension number using the :doxy:`GFilename::extno` method and the +extension version using the :doxy:`GFilename::extver` method. The latter +three methods take an argument that specifies the default value that +should be used in case that no extension information is specified. Below +a usage example that extracts by default the ``EBOUNDS`` table from a +FITS file: + +.. code-block:: cpp + :linenos: + + GFits file; + GFilename fname(filename); + file.open(fname.filename()); + const GFitsTable& table = *file.table(fname.extname("EBOUNDS")); + + Linear interpolation ~~~~~~~~~~~~~~~~~~~~ @@ -279,9 +317,11 @@ Function Description ``gammalib::plaw_energy_flux`` Compute energy flux under a power law. ``gammalib::elogmean`` Computes geometric mean of energy. ``gammalib::file_exists`` Check whether a file exists. +``gammalib::file_exists_gzip`` Check whether a file (or a gzipped version of it) exists. ``gammalib::dir_exists`` Check whether a directory exists. ``gammalib::is_infinite`` Check whether a double precision value is infinite. ``gammalib::is_notanumber`` Check whether a double precision value is not a number. +``gammalib::is_fits`` Check whether a file is a FITS file. ``gammalib::contains`` Check whether a string contains a sub-string. ``gammalib::warning`` Dump warning in console. ``gammalib::xml2str`` Converts XML to string. diff --git a/doc/source/user_manual/modules/uml_support.png b/doc/source/user_manual/modules/uml_support.png index 8c6faa6..b992b84 100644 --- a/doc/source/user_manual/modules/uml_support.png +++ b/doc/source/user_manual/modules/uml_support.png diff --git a/doc/source/user_manual/quickstart.rst b/doc/source/user_manual/quickstart.rst deleted file mode 100644 index 7def1ec..0000000 --- a/doc/source/user_manual/quickstart.rst +++ /dev/null @@ -1,25 +0,0 @@ -Getting started with GammaLib -============================= - -A quick GammaLib tutorial -------------------------- - -To be written ... - - -Using GammaLib from Python --------------------------- - -To be written ... - - -Programming guidelines ----------------------- - -To be written ... - - -Frequently asked questions --------------------------- - -To be written ... diff --git a/gammalib.pc.in b/gammalib.pc.in index d166008..afe8541 100644 --- a/gammalib.pc.in +++ b/gammalib.pc.in @@ -6,7 +6,7 @@ includedir=${prefix}/include Name: GammaLib Description: Versatile toolbox for analysis of astronomical gamma-ray data URL: http://cta.irap.omp.eu/gammalib/ -Version: 0.11.0 +Version: 1.0.0 Requires: Requires.private: @CFITSIO@ Conflicts: diff --git a/include/GCsv.hpp b/include/GCsv.hpp index d131cd6..74160b1 100644 --- a/include/GCsv.hpp +++ b/include/GCsv.hpp @@ -1,7 +1,7 @@ /*************************************************************************** - * GCsv.hpp - Column separated values table class * + * GCsv.hpp - Comma-separated values table class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2014 by Juergen Knoedlseder * + * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -20,7 +20,7 @@ ***************************************************************************/ /** * @file GCsv.hpp - * @brief Column separated values table class definition + * @brief Comma-separated values table class definition * @author Juergen Knoedlseder */ @@ -36,10 +36,10 @@ /***********************************************************************//** * @class GCsv * - * @brief Column separated values table class + * @brief Comma-separated values table class * * This class implements a table of std::string elements that is loaded - * from a column separated value ASCII file. The column separation string + * from a comma-separated value ASCII file. The comma-separation string * can be specified upon loading of the file (by default the class assumes * that elements are separated by a white space). * diff --git a/include/GEbounds.hpp b/include/GEbounds.hpp index 392e9b4..cf0df39 100644 --- a/include/GEbounds.hpp +++ b/include/GEbounds.hpp @@ -55,13 +55,12 @@ class GEbounds : public GContainer { public: // Constructors and destructors GEbounds(void); - GEbounds(const GEbounds& ebds); + explicit GEbounds(const std::string& filename); explicit GEbounds(const GXmlElement& xml); + GEbounds(const GEbounds& ebds); GEbounds(const GEnergy& emin, const GEnergy& emax); GEbounds(const int& num, const GEnergy& emin, const GEnergy& emax, const bool& log = true); - GEbounds(const std::string& filename, - const std::string& extname = "EBOUNDS"); virtual ~GEbounds(void); // Operators @@ -82,11 +81,9 @@ public: void extend(const GEbounds& ebds); void set_lin(const int& num, const GEnergy& emin, const GEnergy& emax); void set_log(const int& num, const GEnergy& emin, const GEnergy& emax); - void load(const std::string& filename, - const std::string& extname = "EBOUNDS"); + void load(const std::string& filename); void save(const std::string& filename, const bool& clobber = false, - const std::string& extname = "EBOUNDS", const std::string& unit = "keV") const; void read(const GFitsTable& table); void write(GFits& file, diff --git a/include/GEnergies.hpp b/include/GEnergies.hpp index 3b97cad..b245938 100644 --- a/include/GEnergies.hpp +++ b/include/GEnergies.hpp @@ -49,8 +49,7 @@ class GEnergies : public GContainer { public: // Constructors and destructors GEnergies(void); - GEnergies(const std::string& filename, - const std::string& extname = "ENERGIES"); + explicit GEnergies(const std::string& filename); GEnergies(const GEnergies& energies); GEnergies(const int& num, const GEnergy& emin, const GEnergy& emax, const bool& log = true); @@ -78,11 +77,9 @@ public: const GEnergy& emax); void set_log(const int& num, const GEnergy& emin, const GEnergy& emax); - void load(const std::string& filename, - const std::string& extname = "ENERGIES"); + void load(const std::string& filename); void save(const std::string& filename, - const bool& clobber = false, - const std::string& extname = "ENERGIES") const; + const bool& clobber = false) const; void read(const GFitsTable& table); void write(GFits& file, const std::string& extname = "ENERGIES") const; diff --git a/include/GFilename.hpp b/include/GFilename.hpp new file mode 100644 index 0000000..a25edbc --- /dev/null +++ b/include/GFilename.hpp @@ -0,0 +1,183 @@ +/*************************************************************************** + * GFilename.hpp - Filename class * + * ----------------------------------------------------------------------- * + * copyright (C) 2015 by Juergen Knoedlseder * + * ----------------------------------------------------------------------- * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ +/** + * @file GFilename.hpp + * @brief Filename class interface definition + * @author Juergen Knoedlseder + */ + +#ifndef GFILENAME_HPP +#define GFILENAME_HPP + +/* __ Includes ___________________________________________________________ */ +#include +#include "GBase.hpp" + + +/***********************************************************************//** + * @class GFilename + * + * @brief Filename class + * + * This class handles filenames. + ***************************************************************************/ +class GFilename : public GBase { + +public: + // Constructors and destructors + GFilename(void); + GFilename(const std::string& filename); + GFilename(const char* filename); + GFilename(const GFilename& filename); + virtual ~GFilename(void); + + // Operators + GFilename& operator=(const GFilename& filename); + + // Methods + void clear(void); + GFilename* clone(void) const; + std::string classname(void) const; + bool empty(void) const; + int size(void) const; + int length(void) const; + const std::string& filename(void) const; + std::string extname(const std::string& defaultname = "") const; + int extno(const int& defaultno = -1) const; + int extver(const int& defaultver = 0) const; + bool has_extname(void) const; + bool has_extno(void) const; + bool has_extver(void) const; + std::string print(const GChatter& chatter = NORMAL) const; + +protected: + // Protected methods + void init_members(void); + void copy_members(const GFilename& filename); + void free_members(void); + void set_filename(const std::string& filename); + + // Protected members + std::string m_filename; //!< Filename (with stripped extension info) + std::string m_extname; //!< Extension name ("": not set) + int m_extno; //!< Extension number (-1: not set) + int m_extver; //!< Extension version (0: not set) +}; + + +/***********************************************************************//** + * @brief Return class name + * + * @return String containing the class name ("GFilename"). + ***************************************************************************/ +inline +std::string GFilename::classname(void) const +{ + return ("GFilename"); +} + + +/***********************************************************************//** + * @brief Signal if filename is empty + * + * @return True if filename is empty, false otherwise. + ***************************************************************************/ +inline +bool GFilename::empty(void) const +{ + return (m_filename.empty()); +} + + +/***********************************************************************//** + * @brief Return size of filename + * + * @return Size of filename. + * + * The size of the file name is equal to its length. + ***************************************************************************/ +inline +int GFilename::size(void) const +{ + return (m_filename.size()); +} + + +/***********************************************************************//** + * @brief Return length of filename + * + * @return Length of filename. + ***************************************************************************/ +inline +int GFilename::length(void) const +{ + return (m_filename.length()); +} + + +/***********************************************************************//** + * @brief Return file name + * + * @return String containing file name. + ***************************************************************************/ +inline +const std::string& GFilename::filename(void) const +{ + return (m_filename); +} + + +/***********************************************************************//** + * @brief Signal if filename has an extension name + * + * @return True if filename has an extension name, false otherwise. + ***************************************************************************/ +inline +bool GFilename::has_extname(void) const +{ + return (!m_extname.empty()); +} + + +/***********************************************************************//** + * @brief Signal if filename has an extension number + * + * @return True if filename has an extension number, false otherwise. + ***************************************************************************/ +inline +bool GFilename::has_extno(void) const +{ + return (m_extno >= 0); +} + + +/***********************************************************************//** + * @brief Signal if filename has an extension version + * + * @return True if filename has an extension version, false otherwise. + ***************************************************************************/ +inline +bool GFilename::has_extver(void) const +{ + return (m_extver > 0); +} + +#endif /* GFILENAME_HPP */ diff --git a/include/GGti.hpp b/include/GGti.hpp index 1477d45..60e5eef 100644 --- a/include/GGti.hpp +++ b/include/GGti.hpp @@ -58,6 +58,7 @@ class GGti : public GContainer { public: // Constructors and destructors GGti(void); + explicit GGti(const std::string& filename); GGti(const GGti& gti); GGti(const GTime& tstart, const GTime& tstop); explicit GGti(const GXmlElement& xml); @@ -81,11 +82,9 @@ public: void remove(const int& index); void reserve(const int& num); void extend(const GGti& gti); - void load(const std::string& filename, - const std::string& extname = "GTI"); + void load(const std::string& filename); void save(const std::string& filename, - const bool& clobber = false, - const std::string& extname = "GTI") const; + const bool& clobber = false) const; void read(const GFitsTable& table); void write(GFits& file, const std::string& extname = "GTI") const; diff --git a/include/GModel.hpp b/include/GModel.hpp index 8eefb99..8f08348 100644 --- a/include/GModel.hpp +++ b/include/GModel.hpp @@ -139,6 +139,7 @@ public: void ts(const double& ts); const bool& tscalc(void) const; void tscalc(const bool& tscalc); + const bool& has_ts(void) const; std::string instruments(void) const; void instruments(const std::string& instruments); GModelPar scale(const std::string& instrument) const; @@ -314,7 +315,7 @@ void GModel::tscalc(const bool& tscalc) /***********************************************************************//** * @brief Signals that model has scales * - * @return True is model has scale factors. + * @return True if model has scale factors. ***************************************************************************/ inline bool GModel::has_scales(void) const @@ -322,4 +323,16 @@ bool GModel::has_scales(void) const return (!m_scales.empty()); } + +/***********************************************************************//** + * @brief Signals that model has Test Statistics value + * + * @return True if model has TS value. + ***************************************************************************/ +inline +const bool& GModel::has_ts(void) const +{ + return m_has_ts; +} + #endif /* GMODEL_HPP */ diff --git a/include/GNodeArray.hpp b/include/GNodeArray.hpp index 74d0d87..d764e0b 100644 --- a/include/GNodeArray.hpp +++ b/include/GNodeArray.hpp @@ -59,9 +59,10 @@ class GNodeArray : public GContainer { public: // Constructors and destructors GNodeArray(void); - GNodeArray(const int& num, const double* array); + explicit GNodeArray(const std::string& filename); explicit GNodeArray(const GVector& vector); explicit GNodeArray(const std::vector& vector); + GNodeArray(const int& num, const double* array); GNodeArray(const GNodeArray& array); virtual ~GNodeArray(void); @@ -93,10 +94,9 @@ public: const int& inx_right(void) const; const double& wgt_left(void) const; const double& wgt_right(void) const; - void load(const std::string& filename, - const std::string& extname = "NODES"); - void save(const std::string& filename, const bool& clobber = false, - const std::string& extname = "NODES") const; + void load(const std::string& filename); + void save(const std::string& filename, + const bool& clobber = false) const; void read(const GFitsTable& table); void write(GFits& file, const std::string& extname = "NODES") const; diff --git a/include/GSkyRegions.hpp b/include/GSkyRegions.hpp index 9086dc8..f935c35 100644 --- a/include/GSkyRegions.hpp +++ b/include/GSkyRegions.hpp @@ -63,8 +63,6 @@ public: GSkyRegions& operator=(const GSkyRegions& regions); GSkyRegion* operator[](const int& index); const GSkyRegion* operator[](const int& index) const; - GSkyRegion* operator[](const std::string& name); - const GSkyRegion* operator[](const std::string& name) const; // Methods void clear(void); @@ -75,15 +73,11 @@ public: int size(void) const; bool is_empty(void) const; GSkyRegion* set(const int& index, const GSkyRegion& region); - GSkyRegion* set(const std::string& name, const GSkyRegion& region); GSkyRegion* append(const GSkyRegion& region); GSkyRegion* insert(const int& index, const GSkyRegion& region); - GSkyRegion* insert(const std::string& name, const GSkyRegion& region); void remove(const int& index); - void remove(const std::string& name); void reserve(const int& num); void extend(const GSkyRegions& regions); - bool contains(const std::string& name) const; bool contains(const GSkyDir& dir) const; bool overlaps(const GSkyRegion& reg) const; void load(const std::string& filename); @@ -96,7 +90,6 @@ protected: void init_members(void); void copy_members(const GSkyRegions& regions); void free_members(void); - int get_index(const std::string& name) const; // Protected members mutable std::string m_filename; //!< Filename of origin diff --git a/include/GTools.hpp b/include/GTools.hpp index 62f5342..324784f 100644 --- a/include/GTools.hpp +++ b/include/GTools.hpp @@ -96,6 +96,7 @@ namespace gammalib { const double& gamma); GEnergy elogmean(const GEnergy& a, const GEnergy& b); bool file_exists(const std::string& filename); + bool file_exists_gzip(const std::string& filename); bool dir_exists(const std::string& dirname); bool is_infinite(const double& x); bool is_notanumber(const double& x); @@ -135,7 +136,7 @@ namespace gammalib { inline bool gammalib::is_infinite(const double& x) { - return (x < -DBL_MAX || x > DBL_MAX); + return (x < -DBL_MAX || x > DBL_MAX); } @@ -147,12 +148,12 @@ bool gammalib::is_infinite(const double& x) * * Signals if the argument @p x is not a number. * - * This function is a very simple kludge. It may not work on all systems. + * This function is a very simple kluge. It may not work on all systems. ***************************************************************************/ inline bool gammalib::is_notanumber(const double& x) { - return (x != x); + return (x != x); } #endif /* GTOOLS_HPP */ diff --git a/include/GVOHub.hpp b/include/GVOHub.hpp index 3ab9670..65e45cd 100644 --- a/include/GVOHub.hpp +++ b/include/GVOHub.hpp @@ -108,11 +108,14 @@ protected: // Low-level methods void create_samp_file(void) const; + void delete_samp_file(void) const; + int get_socket(void); void post_samp_ok(const socklen_t& sock) const; void post_samp_void(const socklen_t& sock) const; void post_string(const std::string& content, const socklen_t& sock) const; void notify(const std::string& url, const std::string& notification) const; std::string random_string(const size_t& length) const; + std::string hub_url(void) const; // Protected structure struct client { @@ -132,7 +135,6 @@ protected: // Protected members std::string m_secret; //!< Secret Hub key - std::string m_hub_url; //!< The XML-RPC endpoint for communication with the hub std::string m_hub_host; //!< Hub host std::string m_hub_port; //!< Hub port std::string m_hub_path; //!< Hub path diff --git a/include/GammaLib.hpp b/include/GammaLib.hpp index 9b92eb5..a9756fe 100644 --- a/include/GammaLib.hpp +++ b/include/GammaLib.hpp @@ -49,6 +49,7 @@ #include "GUrl.hpp" #include "GUrlFile.hpp" #include "GUrlString.hpp" +#include "GFilename.hpp" /* __ Linear algebra module ______________________________________________ */ #include "GVector.hpp" diff --git a/include/Makefile.am b/include/Makefile.am index a227a79..bd6fade 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -13,6 +13,7 @@ pkginclude_HEADERS = GammaLib.hpp \ GUrl.hpp \ GUrlFile.hpp \ GUrlString.hpp \ + GFilename.hpp \ GVector.hpp \ GMatrixBase.hpp \ GMatrix.hpp \ diff --git a/inst/cta/include/GCTAAeff2D.hpp b/inst/cta/include/GCTAAeff2D.hpp index 2fc2b89..56c4a90 100644 --- a/inst/cta/include/GCTAAeff2D.hpp +++ b/inst/cta/include/GCTAAeff2D.hpp @@ -75,8 +75,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; diff --git a/inst/cta/include/GCTAAeffArf.hpp b/inst/cta/include/GCTAAeffArf.hpp index 8e006a6..9fc76d5 100644 --- a/inst/cta/include/GCTAAeffArf.hpp +++ b/inst/cta/include/GCTAAeffArf.hpp @@ -85,7 +85,7 @@ public: const double& thetacut(void) const; void scale(const double& scale); const double& scale(void) const; - void read(const GFitsTable& hdu); + void read(const GFitsTable& table); void remove_thetacut(const GCTAResponseIrf& rsp); private: diff --git a/inst/cta/include/GCTABackground3D.hpp b/inst/cta/include/GCTABackground3D.hpp index 4e0df6d..c7a0242 100644 --- a/inst/cta/include/GCTABackground3D.hpp +++ b/inst/cta/include/GCTABackground3D.hpp @@ -75,8 +75,8 @@ public: bool is_valid(void) const; const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; diff --git a/inst/cta/include/GCTAEdisp2D.hpp b/inst/cta/include/GCTAEdisp2D.hpp index bb7d5a9..738d769 100644 --- a/inst/cta/include/GCTAEdisp2D.hpp +++ b/inst/cta/include/GCTAEdisp2D.hpp @@ -91,8 +91,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; private: diff --git a/inst/cta/include/GCTAEventAtom.hpp b/inst/cta/include/GCTAEventAtom.hpp index d6b106a..1c17fb8 100644 --- a/inst/cta/include/GCTAEventAtom.hpp +++ b/inst/cta/include/GCTAEventAtom.hpp @@ -72,10 +72,8 @@ public: // Other methods const int& index(void) const; const unsigned long& event_id(void) const; - const unsigned long& obs_id(void) const; const float& phase(void) const; void event_id(const unsigned long& id); - void obs_id(const unsigned long& id); void phase(const float& phase); protected: @@ -90,24 +88,6 @@ protected: GEnergy m_energy; //!< Event energy GTime m_time; //!< Event time unsigned long m_event_id; //!< Event identifier - unsigned long m_obs_id; //!< Observation identifier - int m_multip; //!< Multiplicity - char m_telmask; //!< Telescope mask - float m_dir_err; //!< Error on event direction - float m_alt; //!< Event altitude - float m_az; //!< Event azimuth - float m_corex; //!< Position on ground (m) - float m_corey; //!< Position on ground (m) - float m_core_err; //!< Error on core reconstruction - float m_xmax; //!< Position of shower max (g/cm2) - float m_xmax_err; //!< Error on shower max (g/cm2) - float m_shwidth; //!< Shower width (m) - float m_shlength; //!< Shower length (m) - float m_energy_err; //!< Error on event energy (MeV) - float m_hil_msw; //!< Hillas MSW - float m_hil_msw_err; //!< Hillas MSW error - float m_hil_msl; //!< Hillas MSL - float m_hil_msl_err; //!< Hillas MSL error float m_phase; //!< Optional phase }; @@ -226,18 +206,6 @@ const unsigned long& GCTAEventAtom::event_id(void) const /***********************************************************************//** - * @brief Return observation identifier - * - * @return Observation identifier. - ***************************************************************************/ -inline -const unsigned long& GCTAEventAtom::obs_id(void) const -{ - return (m_obs_id); -} - - -/***********************************************************************//** * @brief Return event phase * * @return Event phase. @@ -263,19 +231,6 @@ void GCTAEventAtom::event_id(const unsigned long& id) /***********************************************************************//** - * @brief Set observation identifier - * - * @param[in] id Observation identifier. - ***************************************************************************/ -inline -void GCTAEventAtom::obs_id(const unsigned long& id) -{ - m_obs_id = id; - return; -} - - -/***********************************************************************//** * @brief Set event phase * * @param[in] phase Event phase. diff --git a/inst/cta/include/GCTAEventList.hpp b/inst/cta/include/GCTAEventList.hpp index 53ea830..7b0917d 100644 --- a/inst/cta/include/GCTAEventList.hpp +++ b/inst/cta/include/GCTAEventList.hpp @@ -88,19 +88,18 @@ protected: void free_members(void); virtual void set_energies(void) { return; } virtual void set_times(void) { return; } - void read_events(const GFitsTable& hdu); - void read_events_v0(const GFitsTable& hdu); - void read_events_v1(const GFitsTable& hdu); - void read_events_hillas(const GFitsTable& hdu); - void write_events(GFitsBinTable& hdu) const; + void read_events(const GFitsTable& table); + void write_events(GFitsBinTable& table) const; void write_ds_keys(GFitsHDU& hdu) const; int irf_cache_init(const std::string& name) const; int irf_cache_index(const std::string& name) const; // Protected members - GCTARoi m_roi; //!< Region of interest - std::vector m_events; //!< Events - bool m_has_phase; //!< Signal presence of phase + GCTARoi m_roi; //!< Region of interest + std::vector m_events; //!< Events + std::vector m_columns; //!< Pointers to optional columns + bool m_has_phase; //!< Signal presence of phase + bool m_has_detxy; //!< Signal presence of detector coordinates // IRF cache for diffuse models mutable std::vector m_irf_names; //!< Model names diff --git a/inst/cta/include/GCTAPointing.hpp b/inst/cta/include/GCTAPointing.hpp index cc15738..e2e2904 100644 --- a/inst/cta/include/GCTAPointing.hpp +++ b/inst/cta/include/GCTAPointing.hpp @@ -61,8 +61,7 @@ public: GCTAPointing(void); explicit GCTAPointing(const GSkyDir& dir); explicit GCTAPointing(const GXmlElement& xml); - GCTAPointing(const std::string& filename, - const std::string& extname = "POINTING"); + explicit GCTAPointing(const std::string& filename); GCTAPointing(const GCTAPointing& pnt); virtual ~GCTAPointing(void); @@ -83,8 +82,7 @@ public: void zenith(const double& zenith); void azimuth(const double& azimuth); GHorizDir dir_horiz(const GTime& time) const; - void load(const std::string& filename, - const std::string& extname = "POINTING"); + void load(const std::string& filename); void read(const GFitsTable& table); void read(const GXmlElement& xml); void write(GXmlElement& xml) const; diff --git a/inst/cta/include/GCTAPsf2D.hpp b/inst/cta/include/GCTAPsf2D.hpp index e9d446e..5827642 100644 --- a/inst/cta/include/GCTAPsf2D.hpp +++ b/inst/cta/include/GCTAPsf2D.hpp @@ -96,8 +96,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; diff --git a/inst/cta/include/GCTAPsfKing.hpp b/inst/cta/include/GCTAPsfKing.hpp index 7480614..1c1b5af 100644 --- a/inst/cta/include/GCTAPsfKing.hpp +++ b/inst/cta/include/GCTAPsfKing.hpp @@ -94,8 +94,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; diff --git a/inst/cta/pyext/GCTAAeff2D.i b/inst/cta/pyext/GCTAAeff2D.i index 75e467e..23487c0 100644 --- a/inst/cta/pyext/GCTAAeff2D.i +++ b/inst/cta/pyext/GCTAAeff2D.i @@ -66,8 +66,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; }; diff --git a/inst/cta/pyext/GCTAAeffArf.i b/inst/cta/pyext/GCTAAeffArf.i index 5ea4870..4eb3f0c 100644 --- a/inst/cta/pyext/GCTAAeffArf.i +++ b/inst/cta/pyext/GCTAAeffArf.i @@ -71,7 +71,7 @@ public: const double& thetacut(void) const; void scale(const double& scale); const double& scale(void) const; - void read(const GFitsTable& hdu); + void read(const GFitsTable& table); void remove_thetacut(const GCTAResponseIrf& rsp); }; diff --git a/inst/cta/pyext/GCTABackground3D.i b/inst/cta/pyext/GCTABackground3D.i index c9f4c12..c6ad337 100644 --- a/inst/cta/pyext/GCTABackground3D.i +++ b/inst/cta/pyext/GCTABackground3D.i @@ -63,8 +63,8 @@ public: bool is_valid(void) const; const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; }; diff --git a/inst/cta/pyext/GCTAEdisp2D.i b/inst/cta/pyext/GCTAEdisp2D.i index 5008aa1..6dc97ec 100644 --- a/inst/cta/pyext/GCTAEdisp2D.i +++ b/inst/cta/pyext/GCTAEdisp2D.i @@ -77,8 +77,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; }; diff --git a/inst/cta/pyext/GCTAEventAtom.i b/inst/cta/pyext/GCTAEventAtom.i index 0c89247..3e653fa 100644 --- a/inst/cta/pyext/GCTAEventAtom.i +++ b/inst/cta/pyext/GCTAEventAtom.i @@ -55,10 +55,8 @@ public: // Other methods const int& index(void) const; const unsigned long& event_id(void) const; - const unsigned long& obs_id(void) const; const float& phase(void) const; void event_id(const unsigned long& id); - void obs_id(const unsigned long& id); void phase(const float& phase); }; diff --git a/inst/cta/pyext/GCTAPointing.i b/inst/cta/pyext/GCTAPointing.i index 9041191..a152e70 100644 --- a/inst/cta/pyext/GCTAPointing.i +++ b/inst/cta/pyext/GCTAPointing.i @@ -40,8 +40,7 @@ public: GCTAPointing(void); explicit GCTAPointing(const GSkyDir& dir); explicit GCTAPointing(const GXmlElement& xml); - GCTAPointing(const std::string& filename, - const std::string& extname = "POINTING"); + explicit GCTAPointing(const std::string& filename); GCTAPointing(const GCTAPointing& pnt); virtual ~GCTAPointing(void); @@ -59,8 +58,7 @@ public: void zenith(const double& zenith); void azimuth(const double& azimuth); GHorizDir dir_horiz(const GTime& time) const; - void load(const std::string& filename, - const std::string& extname = "POINTING"); + void load(const std::string& filename); void read(const GFitsTable& table); void read(const GXmlElement& xml); void write(GXmlElement& xml) const; diff --git a/inst/cta/pyext/GCTAPsf2D.i b/inst/cta/pyext/GCTAPsf2D.i index c6e152b..b5e219a 100644 --- a/inst/cta/pyext/GCTAPsf2D.i +++ b/inst/cta/pyext/GCTAPsf2D.i @@ -82,8 +82,8 @@ public: // Methods const GCTAResponseTable& table(void) const; void table(const GCTAResponseTable& table); - void read(const GFits& file); - void write(GFitsBinTable& hdu) const; + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; void save(const std::string& filename, const bool& clobber = false) const; diff --git a/inst/cta/pyext/GCTAPsfKing.i b/inst/cta/pyext/GCTAPsfKing.i index 6402505..660e822 100644 --- a/inst/cta/pyext/GCTAPsfKing.i +++ b/inst/cta/pyext/GCTAPsfKing.i @@ -81,6 +81,13 @@ public: const double& zenith = 0.0, const double& azimuth = 0.0, const bool& etrue = true) const; + // Methods + const GCTAResponseTable& table(void) const; + void table(const GCTAResponseTable& table); + void read(const GFitsTable& table); + void write(GFitsBinTable& table) const; + void save(const std::string& filename, + const bool& clobber = false) const; }; diff --git a/inst/cta/src/GCTAAeff2D.cpp b/inst/cta/src/GCTAAeff2D.cpp index 09cfddf..3d1ad9c 100644 --- a/inst/cta/src/GCTAAeff2D.cpp +++ b/inst/cta/src/GCTAAeff2D.cpp @@ -30,13 +30,14 @@ #endif #include "GTools.hpp" #include "GException.hpp" +#include "GFilename.hpp" #include "GFits.hpp" #include "GFitsBinTable.hpp" #include "GFitsTable.hpp" #include "GCTAAeff2D.hpp" /* __ Method name definitions ____________________________________________ */ -#define G_READ "GCTAAeff2D::read(GFits&)" +#define G_READ "GCTAAeff2D::read(GFitsTable&)" /* __ Macros _____________________________________________________________ */ @@ -71,8 +72,7 @@ GCTAAeff2D::GCTAAeff2D(void) : GCTAAeff() * * @param[in] filename FITS file name. * - * Construct instance by loading the effective area information from a FITS - * file. + * Constructs effective area from a FITS file. ***************************************************************************/ GCTAAeff2D::GCTAAeff2D(const std::string& filename) : GCTAAeff() { @@ -235,25 +235,23 @@ GCTAAeff2D* GCTAAeff2D::clone(void) const /***********************************************************************//** - * @brief Read effective area from FITS file + * @brief Read effective area from FITS table * - * @param[in] fits FITS file pointer. + * @param[in] table FITS table. * * @exception GException::invalid_value * FITS file format differs from expectation. * - * Reads the effective area form the FITS file extension "EFFECTIVE AREA". + * Reads the effective area form the FITS @p table. + * * The data are stored in m_aeff which is of type GCTAResponseTable. The * energy axis will be set to log10, the offset angle axis to radians. ***************************************************************************/ -void GCTAAeff2D::read(const GFits& fits) +void GCTAAeff2D::read(const GFitsTable& table) { // Clear response table m_aeff.clear(); - // Get effective area table - const GFitsTable& table = *fits.table("EFFECTIVE AREA"); - // Read effective area table m_aeff.read(table); @@ -289,23 +287,25 @@ void GCTAAeff2D::read(const GFits& fits) /***********************************************************************//** - * @brief Write CTA effective area table into FITS binary table object. + * @brief Write effective area into FITS binary table + * + * @param[in] table FITS binary table. * - * @param[in] hdu FITS binary table. + * Writes effective area into the FITS binary @p table. * - * @todo Add necessary keywords. + * @todo Add keywords. ***************************************************************************/ -void GCTAAeff2D::write(GFitsBinTable& hdu) const +void GCTAAeff2D::write(GFitsBinTable& table) const { // Create a copy of the response table - GCTAResponseTable table(m_aeff); + GCTAResponseTable aeff(m_aeff); // Convert area from cm2 to m2 - table.scale(0, 1.0e-4); - table.scale(1, 1.0e-4); + aeff.scale(0, 1.0e-4); + aeff.scale(1, 1.0e-4); // Write response table - table.write(hdu); + aeff.write(table); // Return return; @@ -315,20 +315,32 @@ void GCTAAeff2D::write(GFitsBinTable& hdu) const /***********************************************************************//** * @brief Load effective area from FITS file * - * @param[in] filename FITS file. + * @param[in] filename FITS file name. + * + * Loads the effective area from a FITS file. * - * This method loads the effective area information from a FITS file. + * If no extension name is provided, the effective area will be loaded from + * the "EFFECTIVE AREA" extension. ***************************************************************************/ void GCTAAeff2D::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; + // Open FITS file - GFits fits(filename); + file.open(fname.filename()); + + // Get effective area table + const GFitsTable& table = *file.table(fname.extname("EFFECTIVE AREA")); - // Read effective area from file - read(fits); + // Read effective area from table + read(table); // Close FITS file - fits.close(); + file.close(); // Store filename m_filename = filename; @@ -339,18 +351,24 @@ void GCTAAeff2D::load(const std::string& filename) /***********************************************************************//** - * @brief Save effectiva area table into FITS file + * @brief Save effectiva area into FITS file * - * @param[in] filename Effective area table FITS file name. - * @param[in] clobber Overwrite existing file? (true=yes) + * @param[in] filename FITS file name. + * @param[in] clobber Overwrite existing file? (default: false) + * + * Save the effectiva area into a FITS file. * - * Save the effectiva area table into a FITS file. + * If no extension name is provided, the effective area will be saved into + * the "EFFECTIVE AREA" extension. ***************************************************************************/ void GCTAAeff2D::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Create binary table GFitsBinTable table; - table.extname("EFFECTIVE AREA"); + table.extname(fname.extname("EFFECTIVE AREA")); // Write the Effective area table write(table); @@ -358,7 +376,7 @@ void GCTAAeff2D::save(const std::string& filename, const bool& clobber) const // Create FITS file, append table, and write into the file GFits fits; fits.append(table); - fits.saveto(filename, clobber); + fits.saveto(fname.filename(), clobber); // Return return; diff --git a/inst/cta/src/GCTAAeffArf.cpp b/inst/cta/src/GCTAAeffArf.cpp index 65e7840..b388b34 100644 --- a/inst/cta/src/GCTAAeffArf.cpp +++ b/inst/cta/src/GCTAAeffArf.cpp @@ -31,6 +31,7 @@ #include "GTools.hpp" #include "GMath.hpp" #include "GIntegral.hpp" +#include "GFilename.hpp" #include "GFitsTable.hpp" #include "GFitsTableCol.hpp" #include "GCTAAeffArf.hpp" @@ -74,8 +75,7 @@ GCTAAeffArf::GCTAAeffArf(void) : GCTAAeff() * * @param[in] filename ARF FITS file name. * - * Construct instance by loading the effective area information from an - * ARF FITS file. + * Constructs effective area from an ARF FITS file. ***************************************************************************/ GCTAAeffArf::GCTAAeffArf(const std::string& filename) : GCTAAeff() { @@ -238,25 +238,33 @@ GCTAAeffArf* GCTAAeffArf::clone(void) const /***********************************************************************//** - * @brief Load effective area from performance table + * @brief Load effective area from ARF FITS file * - * @param[in] filename Performance table file name. + * @param[in] filename ARF FITS file name. + * + * Loads the effective area from an ARF FITS file. * - * This method loads the effective area information from an ASCII - * performance table. + * If no extension name is provided, the effective area will be loaded from + * the "SPECRESP" extension. ***************************************************************************/ void GCTAAeffArf::load(const std::string& filename) { - // Open ARF FITS file - GFits file(filename); + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; + + // Open FITS file + file.open(fname.filename()); // Get ARF table - const GFitsTable& table = *file.table("SPECRESP"); + const GFitsTable& table = *file.table(fname.extname("SPECRESP")); - // Read ARF + // Read ARF from table read(table); - // Close ARF FITS file + // Close FITS file file.close(); // Store filename @@ -270,11 +278,12 @@ void GCTAAeffArf::load(const std::string& filename) /***********************************************************************//** * @brief Read CTA ARF vector * - * @param[in] hdu FITS table. + * @param[in] table FITS table. + * + * Reads a CTA ARF vector from the FITS @p table. * - * This method reads a CTA ARF vector from the FITS HDU. Note that the - * energies are converted to TeV and the effective area is converted to cm2. - * Conversion is done based on the units provided for the energy and + * The energies are converted to TeV and the effective area is converted to + * cm2. Conversion is done based on the units provided for the energy and * effective area columns. Units that are recognized are 'keV', 'MeV', 'GeV', * 'TeV', 'm^2', 'm2', 'cm^2' and 'cm^2' (case independent). * @@ -282,16 +291,16 @@ void GCTAAeffArf::load(const std::string& filename) * For appropriate theta angle assignment, we would need this * information in the response header. ***************************************************************************/ -void GCTAAeffArf::read(const GFitsTable& hdu) +void GCTAAeffArf::read(const GFitsTable& table) { // Clear arrays m_logE.clear(); m_aeff.clear(); // Get pointers to table columns - const GFitsTableCol* energy_lo = hdu["ENERG_LO"]; - const GFitsTableCol* energy_hi = hdu["ENERG_HI"]; - const GFitsTableCol* specresp = hdu["SPECRESP"]; + const GFitsTableCol* energy_lo = table["ENERG_LO"]; + const GFitsTableCol* energy_hi = table["ENERG_HI"]; + const GFitsTableCol* specresp = table["SPECRESP"]; // Determine unit conversion factors (default: TeV and cm^2) std::string u_energy_lo = gammalib::tolower(gammalib::strip_whitespace(energy_lo->unit())); diff --git a/inst/cta/src/GCTABackground3D.cpp b/inst/cta/src/GCTABackground3D.cpp index 90ddc12..b30649d 100644 --- a/inst/cta/src/GCTABackground3D.cpp +++ b/inst/cta/src/GCTABackground3D.cpp @@ -30,13 +30,14 @@ #endif #include "GTools.hpp" #include "GException.hpp" +#include "GFilename.hpp" #include "GMath.hpp" #include "GFits.hpp" #include "GFitsBinTable.hpp" #include "GCTABackground3D.hpp" /* __ Method name definitions ____________________________________________ */ -#define G_READ "GCTABackground3D::read(GFits&)" +#define G_READ "GCTABackground3D::read(GFitsTable&)" #define G_MC "GCTABackground3D::mc(GEnergy&, GTime&, GRan&)" #define G_INIT_MC_CACHE "GCTABackground3D::init_mc_cache()" @@ -76,7 +77,7 @@ GCTABackground3D::GCTABackground3D(void) : GCTABackground() * * @param[in] filename FITS file name. * - * Construct instance by loading the background information from a FITS file. + * Constructs background from a FITS file. ***************************************************************************/ GCTABackground3D::GCTABackground3D(const std::string& filename) : GCTABackground() @@ -303,26 +304,24 @@ GCTABackground3D* GCTABackground3D::clone(void) const /***********************************************************************//** - * @brief Read background from FITS file + * @brief Read background from FITS table * - * @param[in] fits FITS file pointer. + * @param[in] table FITS table. * * @exception GException::invalid_value * FITS file format differs from expectation. * - * Reads the background from the FITS file extension "BACKGROUND". The data - * are stored in m_background which is of type GCTAResponseTable. The DETX - * and DETY axes will be set to radians, the energy axis will be set to - * log10. + * Reads the background from the FITS @p table. + * + * The data are stored in m_background which is of type GCTAResponseTable. + * The DETX and DETY axes will be set to radians, the energy axis will be set + * to log10. ***************************************************************************/ -void GCTABackground3D::read(const GFits& fits) +void GCTABackground3D::read(const GFitsTable& table) { // Clear response table m_background.clear(); - // Get background table - const GFitsTable& table = *fits.table("BACKGROUND"); - // Read background table m_background.read(table); @@ -361,16 +360,18 @@ void GCTABackground3D::read(const GFits& fits) } /***********************************************************************//** - * @brief Write CTA background table into FITS binary table object. + * @brief Write background into FITS table * - * @param[in] hdu FITS binary table. + * @param[in] table FITS binary table. + * + * Writes background into a FITS binary @p table. * * @todo Add necessary keywords. ***************************************************************************/ -void GCTABackground3D::write(GFitsBinTable& hdu) const +void GCTABackground3D::write(GFitsBinTable& table) const { // Write background table - m_background.write(hdu); + m_background.write(table); // Return return; @@ -380,20 +381,32 @@ void GCTABackground3D::write(GFitsBinTable& hdu) const /***********************************************************************//** * @brief Load background from FITS file * - * @param[in] filename FITS file. + * @param[in] filename FITS file name. + * + * Loads the background from a FITS file. * - * This method loads the background information from a FITS file. + * If no extension name is provided, the background will be loaded from the + * "BACKGROUND" extension. ***************************************************************************/ void GCTABackground3D::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; + // Open FITS file - GFits fits(filename); + file.open(fname.filename()); + + // Get background table + const GFitsTable& table = *file.table(fname.extname("BACKGROUND")); - // Read background from file - read(fits); + // Read effective area from table + read(table); // Close FITS file - fits.close(); + file.close(); // Store filename m_filename = filename; @@ -404,18 +417,24 @@ void GCTABackground3D::load(const std::string& filename) /***********************************************************************//** - * @brief Save background table into FITS file + * @brief Save background into FITS file * * @param[in] filename background table FITS file name. - * @param[in] clobber Overwrite existing file? (true=yes) + * @param[in] clobber Overwrite existing file? (default: false) + * + * Save the background into a FITS file. * - * Save the background table into a FITS file. + * If no extension name is provided, the background will be saved into the + * "BACKGROUND" extension. ***************************************************************************/ void GCTABackground3D::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Create binary table GFitsBinTable table; - table.extname("BACKGROUND"); + table.extname(fname.extname("BACKGROUND")); // Write the background table write(table); @@ -423,7 +442,7 @@ void GCTABackground3D::save(const std::string& filename, const bool& clobber) co // Create FITS file, append table, and write into the file GFits fits; fits.append(table); - fits.saveto(filename, clobber); + fits.saveto(fname.filename(), clobber); // Return return; diff --git a/inst/cta/src/GCTAEdisp2D.cpp b/inst/cta/src/GCTAEdisp2D.cpp index 5251812..7018248 100644 --- a/inst/cta/src/GCTAEdisp2D.cpp +++ b/inst/cta/src/GCTAEdisp2D.cpp @@ -33,6 +33,7 @@ #include "GTools.hpp" #include "GMath.hpp" #include "GIntegral.hpp" +#include "GFilename.hpp" #include "GFits.hpp" #include "GFitsTable.hpp" #include "GFitsBinTable.hpp" @@ -73,8 +74,7 @@ GCTAEdisp2D::GCTAEdisp2D(void) : GCTAEdisp() * * @param[in] filename FITS file name. * - * Construct instance by loading the energy dispersion information from a - * FITS file. + * Constructs energy dispersion from a FITS file. ***************************************************************************/ GCTAEdisp2D::GCTAEdisp2D(const std::string& filename) : GCTAEdisp() { @@ -232,20 +232,32 @@ GCTAEdisp2D* GCTAEdisp2D::clone(void) const /***********************************************************************//** * @brief Load energy dispersion from FITS file * - * @param[in] filename FITS file. + * @param[in] filename FITS file name. + * + * Loads the energy dispersion from a FITS file. * - * This method loads the energy dispersion information from a FITS file. + * If no extension name is provided, the energy dispersion will be loaded + * from the "ENERGY DISPERSION" extension. ***************************************************************************/ void GCTAEdisp2D::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; + // Open FITS file - GFits fits(filename); + file.open(fname.filename()); - // Read energy dispersion from file - read(fits); + // Get energy dispersion table + const GFitsTable& table = *file.table(fname.extname("ENERGY DISPERSION")); + + // Read energy dispersion from table + read(table); // Close FITS file - fits.close(); + file.close(); // Store filename m_filename = filename; @@ -256,26 +268,22 @@ void GCTAEdisp2D::load(const std::string& filename) /***********************************************************************//** - * @brief Read energy dispersion from FITS file + * @brief Read energy dispersion from FITS table + * + * @param[in] table FITS table. * - * @param[in] fits FITS file pointer. + * Reads the energy dispersion form the FITS @p table. * - * Reads the energy dispersion form the FITS file extension - * "ENERGY DISPERSION". The data are stored in m_edisp which is of type - * GCTAResponseTable. The energy axis will be set to log10, the offset - * angle axis to radians. + * The data are stored in m_edisp which is of type GCTAResponseTable. The + * energy axis will be set to log10, the offset angle axis to radians. * - * The method assures that the energy dispersion information is properly - * normalised. + * The method assures that the energy dispersion is properly normalised. ***************************************************************************/ -void GCTAEdisp2D::read(const GFits& fits) +void GCTAEdisp2D::read(const GFitsTable& table) { // Clear response table m_edisp.clear(); - // Get energy dispersion table - const GFitsTable& table = *fits.table("ENERGY DISPERSION"); - // Read energy dispersion table m_edisp.read(table); @@ -373,16 +381,18 @@ void GCTAEdisp2D::read(const GFits& fits) /***********************************************************************//** - * @brief Write CTA energy dispersion table into FITS binary table object. + * @brief Write energy dispersion into FITS binary table + * + * @param[in] table FITS binary table. * - * @param[in] hdu FITS binary table. + * Writes the energy dispersion into the FITS binary @p table. * - * @todo Add necessary keywords. + * @todo Add keywords. ***************************************************************************/ -void GCTAEdisp2D::write(GFitsBinTable& hdu) const +void GCTAEdisp2D::write(GFitsBinTable& table) const { // Write background table - m_edisp.write(hdu); + m_edisp.write(table); // Return return; @@ -392,24 +402,30 @@ void GCTAEdisp2D::write(GFitsBinTable& hdu) const /***********************************************************************//** * @brief Save energy dispersion table into FITS file * - * @param[in] filename Energy dispersion table FITS file name. - * @param[in] clobber Overwrite existing file? (true=yes) + * @param[in] filename FITS file name. + * @param[in] clobber Overwrite existing file? (default: false) + * + * Save the energy dispersion table into FITS file. * - * Save the energy dispersion table into a FITS file. + * If no extension name is provided, the energy dispersion will be saved into + * the "ENERGY DISPERSION" extension. ***************************************************************************/ void GCTAEdisp2D::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Create binary table GFitsBinTable table; - table.extname("ENERGY DISPERSION"); + table.extname(fname.extname("ENERGY DISPERSION")); - // Write the Energy dispersion table + // Write the energy dispersion table write(table); // Create FITS file, append table, and write into the file GFits fits; fits.append(table); - fits.saveto(filename, clobber); + fits.saveto(fname.filename(), clobber); // Return return; diff --git a/inst/cta/src/GCTAEventAtom.cpp b/inst/cta/src/GCTAEventAtom.cpp index 8986469..5a4c776 100644 --- a/inst/cta/src/GCTAEventAtom.cpp +++ b/inst/cta/src/GCTAEventAtom.cpp @@ -207,27 +207,9 @@ void GCTAEventAtom::init_members(void) m_dir.clear(); m_time.clear(); m_energy.clear(); - m_index = 0; - m_event_id = 0; - m_obs_id = 0; - m_multip = 0; - m_telmask = 0; - m_dir_err = 0.0; - m_alt = 0.0; - m_az = 0.0; - m_corex = 0.0; - m_corey = 0.0; - m_core_err = 0.0; - m_xmax = 0.0; - m_xmax_err = 0.0; - m_shwidth = 0.0; - m_shlength = 0.0; - m_energy_err = 0.0; - m_hil_msw = 0.0; - m_hil_msw_err = 0.0; - m_hil_msl = 0.0; - m_hil_msl_err = 0.0; - m_phase = 0.0; + m_index = 0; + m_event_id = 0; + m_phase = 0.0; // Return return; @@ -242,30 +224,12 @@ void GCTAEventAtom::init_members(void) void GCTAEventAtom::copy_members(const GCTAEventAtom& atom) { // Copy members - m_dir = atom.m_dir; - m_time = atom.m_time; - m_energy = atom.m_energy; - m_index = atom.m_index; - m_event_id = atom.m_event_id; - m_obs_id = atom.m_obs_id; - m_multip = atom.m_multip; - m_telmask = atom.m_telmask; - m_dir_err = atom.m_dir_err; - m_alt = atom.m_alt; - m_az = atom.m_az; - m_corex = atom.m_corex; - m_corey = atom.m_corey; - m_core_err = atom.m_core_err; - m_xmax = atom.m_xmax; - m_xmax_err = atom.m_xmax_err; - m_shwidth = atom.m_shwidth; - m_shlength = atom.m_shlength; - m_energy_err = atom.m_energy_err; - m_hil_msw = atom.m_hil_msw; - m_hil_msw_err = atom.m_hil_msw_err; - m_hil_msl = atom.m_hil_msl; - m_hil_msl_err = atom.m_hil_msl_err; - m_phase = atom.m_phase; + m_dir = atom.m_dir; + m_time = atom.m_time; + m_energy = atom.m_energy; + m_index = atom.m_index; + m_event_id = atom.m_event_id; + m_phase = atom.m_phase; // Return return; diff --git a/inst/cta/src/GCTAEventCube.cpp b/inst/cta/src/GCTAEventCube.cpp index ccd01fd..1b3c7c4 100644 --- a/inst/cta/src/GCTAEventCube.cpp +++ b/inst/cta/src/GCTAEventCube.cpp @@ -436,8 +436,11 @@ int GCTAEventCube::number(void) const // Sum event cube if (size() > 0 && pixels != NULL) { - for (int i = 0; i < size(); ++i) - number += pixels[i]; + for (int i = 0; i < size(); ++i) { + if (pixels[i] > 0.0) { + number += pixels[i]; + } + } } // Return diff --git a/inst/cta/src/GCTAEventList.cpp b/inst/cta/src/GCTAEventList.cpp index 3622aed..758aeba 100644 --- a/inst/cta/src/GCTAEventList.cpp +++ b/inst/cta/src/GCTAEventList.cpp @@ -572,7 +572,9 @@ void GCTAEventList::init_members(void) // Initialise members m_roi.clear(); m_events.clear(); + m_columns.clear(); m_has_phase = false; + m_has_detxy = true; // Initialise cache m_irf_names.clear(); @@ -594,11 +596,18 @@ void GCTAEventList::copy_members(const GCTAEventList& list) m_roi = list.m_roi; m_events = list.m_events; m_has_phase = list.m_has_phase; + m_has_detxy = list.m_has_detxy; // Copy cache m_irf_names = list.m_irf_names; m_irf_values = list.m_irf_values; + // Copy column pointers + m_columns.clear(); + for (int i = 0; i < list.m_columns.size(); ++i) { + m_columns.push_back((list.m_columns[i]->clone())); + } + // Return return; } @@ -609,6 +618,12 @@ void GCTAEventList::copy_members(const GCTAEventList& list) ***************************************************************************/ void GCTAEventList::free_members(void) { + // Free columns + for (int i = 0; i < m_columns.size(); ++i) { + delete m_columns[i]; + m_columns[i] = NULL; + } + // Return return; } @@ -619,52 +634,26 @@ void GCTAEventList::free_members(void) * * @param[in] table FITS table. * - * This method reads the CTA event list from a FITS table HDU into memory. - * Depending on the columns existing in the file, it either selects v0 or - * v1 of the event list reader. - ***************************************************************************/ -void GCTAEventList::read_events(const GFitsTable& table) -{ - // Clear existing events - m_events.clear(); - - // Extract number of events in FITS file - int num = table.integer("NAXIS2"); - - // Continue only if there are events - if (num > 0) { - - // Read events for v1 - if (table.contains("SHWIDTH") && table.contains("SHLENGTH")) { - read_events_v1(table); - } - - // ... otherwise read events for v0 - else { - read_events_v0(table); - } - - // Read (optional) Hillas parameters - read_events_hillas(table); - - } // endif: there were events - - // Return - return; -} - - -/***********************************************************************//** - * @brief Read CTA events from FITS table (version 0) + * This method reads the CTA event list from a FITS table into memory. + * The following columns are mandatory in the FITS table: * - * @param[in] table FITS table. + * - EVENT_ID + * - TIME + * - RA + * - DEC + * - ENERGY + * + * Optionally, the * - * This method reads the CTA event list from a FITS table HDU into memory. - * It is a minimal event reader that is compliant with the initial data - * format distributed by Karl Kosack. Information that is not present in - * that format is set to 0. + * - DETX + * - DETY + * - PHASE + * + * columns are read. Any other columns present in the FITS table will also be + * read, and written into the FITS table when the write_events() method is + * called. ***************************************************************************/ -void GCTAEventList::read_events_v0(const GFitsTable& table) +void GCTAEventList::read_events(const GFitsTable& table) { // Clear existing events m_events.clear(); @@ -679,120 +668,25 @@ void GCTAEventList::read_events_v0(const GFitsTable& table) m_events.reserve(num); // Get column pointers - const GFitsTableCol* ptr_eid = table["EVENT_ID"]; - const GFitsTableCol* ptr_time = table["TIME"]; - const GFitsTableCol* ptr_multip = table["MULTIP"]; - const GFitsTableCol* ptr_ra = table["RA"]; - const GFitsTableCol* ptr_dec = table["DEC"]; - const GFitsTableCol* ptr_dir_err = table["DIR_ERR"]; - const GFitsTableCol* ptr_detx = table["DETX"]; - const GFitsTableCol* ptr_dety = table["DETY"]; - const GFitsTableCol* ptr_alt = table["ALT"]; - const GFitsTableCol* ptr_az = table["AZ"]; - const GFitsTableCol* ptr_corex = table["COREX"]; - const GFitsTableCol* ptr_corey = table["COREY"]; - const GFitsTableCol* ptr_core_err = table["CORE_ERR"]; - const GFitsTableCol* ptr_xmax = table["XMAX"]; - const GFitsTableCol* ptr_xmax_err = table["XMAX_ERR"]; - const GFitsTableCol* ptr_energy = table["ENERGY"]; - const GFitsTableCol* ptr_energy_err = table["ENERGY_ERR"]; - - // Check for phase column - const GFitsTableCol* ptr_phase; - if (table.contains("PHASE")) { - m_has_phase = true; - ptr_phase = table["PHASE"]; + const GFitsTableCol* ptr_eid = table["EVENT_ID"]; + const GFitsTableCol* ptr_time = table["TIME"]; + const GFitsTableCol* ptr_ra = table["RA"]; + const GFitsTableCol* ptr_dec = table["DEC"]; + const GFitsTableCol* ptr_energy = table["ENERGY"]; + + // Check for DETX and DETY columns + const GFitsTableCol* ptr_detx; + const GFitsTableCol* ptr_dety; + if (table.contains("DETX") && table.contains("DETY")) { + m_has_detxy = true; + ptr_detx = table["DETX"]; + ptr_dety = table["DETY"]; } else { - m_has_phase = false; - } - - // Copy data from columns into GCTAEventAtom objects - GCTAEventAtom event; - for (int i = 0; i < num; ++i) { - event.m_index = i; - event.m_time.set(ptr_time->real(i), m_gti.reference()); - event.m_dir.dir().radec_deg(ptr_ra->real(i), ptr_dec->real(i)); - event.m_dir.detx(ptr_detx->real(i)*gammalib::deg2rad); - event.m_dir.dety(ptr_dety->real(i)*gammalib::deg2rad); - event.m_energy.TeV(ptr_energy->real(i)); - event.m_event_id = ptr_eid->integer(i); - event.m_obs_id = 0; - event.m_multip = ptr_multip->integer(i); - event.m_telmask = 0; - event.m_dir_err = ptr_dir_err->real(i); - event.m_alt = ptr_alt->real(i); - event.m_az = ptr_az->real(i); - event.m_corex = ptr_corex->real(i); - event.m_corey = ptr_corey->real(i); - event.m_core_err = ptr_core_err->real(i); - event.m_xmax = ptr_xmax->real(i); - event.m_xmax_err = ptr_xmax_err->real(i); - event.m_shwidth = 0.0; - event.m_shlength = 0.0; - event.m_energy_err = ptr_energy_err->real(i); - - // Set pulse phase if available - if (m_has_phase) { - event.m_phase = ptr_phase->real(i); - } - - m_events.push_back(event); + m_has_detxy = false; } - } // endif: there were events - - // Return - return; -} - - -/***********************************************************************//** - * @brief Read CTA events from FITS table (version 1) - * - * @param[in] table FITS table. - * - * This method reads the CTA event list from a FITS table HDU into memory. - * - * @todo Implement agreed column format - ***************************************************************************/ -void GCTAEventList::read_events_v1(const GFitsTable& table) -{ - // Clear existing events - m_events.clear(); - - // Extract number of events in FITS file - int num = table.nrows(); - - // If there are events then load them - if (num > 0) { - - // Reserve data - m_events.reserve(num); - - // Get column pointers - const GFitsTableCol* ptr_eid = table["EVENT_ID"]; - const GFitsTableCol* ptr_oid = table["OBS_ID"]; - const GFitsTableCol* ptr_time = table["TIME"]; - const GFitsTableCol* ptr_multip = table["MULTIP"]; - const GFitsTableCol* ptr_ra = table["RA"]; - const GFitsTableCol* ptr_dec = table["DEC"]; - const GFitsTableCol* ptr_dir_err = table["DIR_ERR"]; - const GFitsTableCol* ptr_detx = table["DETX"]; - const GFitsTableCol* ptr_dety = table["DETY"]; - const GFitsTableCol* ptr_alt = table["ALT"]; - const GFitsTableCol* ptr_az = table["AZ"]; - const GFitsTableCol* ptr_corex = table["COREX"]; - const GFitsTableCol* ptr_corey = table["COREY"]; - const GFitsTableCol* ptr_core_err = table["CORE_ERR"]; - const GFitsTableCol* ptr_xmax = table["XMAX"]; - const GFitsTableCol* ptr_xmax_err = table["XMAX_ERR"]; - const GFitsTableCol* ptr_shw = table["SHWIDTH"]; - const GFitsTableCol* ptr_shl = table["SHLENGTH"]; - const GFitsTableCol* ptr_energy = table["ENERGY"]; - const GFitsTableCol* ptr_energy_err = table["ENERGY_ERR"]; - - // Check for phase column + // Check for PHASE column const GFitsTableCol* ptr_phase; if (table.contains("PHASE")) { m_has_phase = true; @@ -805,98 +699,57 @@ void GCTAEventList::read_events_v1(const GFitsTable& table) // Copy data from columns into GCTAEventAtom objects GCTAEventAtom event; for (int i = 0; i < num; ++i) { - event.m_index = i; + + // Set mandatory information event.m_time.set(ptr_time->real(i), m_gti.reference()); event.m_dir.dir().radec_deg(ptr_ra->real(i), ptr_dec->real(i)); - event.m_dir.detx(ptr_detx->real(i)*gammalib::deg2rad); - event.m_dir.dety(ptr_dety->real(i)*gammalib::deg2rad); event.m_energy.TeV(ptr_energy->real(i)); - event.m_event_id = ptr_eid->integer(i); - event.m_obs_id = ptr_oid->integer(i); - event.m_multip = ptr_multip->integer(i); - event.m_telmask = 0; - event.m_dir_err = ptr_dir_err->real(i); - event.m_alt = ptr_alt->real(i); - event.m_az = ptr_az->real(i); - event.m_corex = ptr_corex->real(i); - event.m_corey = ptr_corey->real(i); - event.m_core_err = ptr_core_err->real(i); - event.m_xmax = ptr_xmax->real(i); - event.m_xmax_err = ptr_xmax_err->real(i); - event.m_shwidth = ptr_shw->real(i); - event.m_shlength = ptr_shl->real(i); - event.m_energy_err = ptr_energy_err->real(i); - - // Set phase if available + event.m_event_id = ptr_eid->integer(i); + event.m_index = i; + + // If available, set detector coordinates in radians + if (m_has_detxy) { + event.m_dir.detx(ptr_detx->real(i)*gammalib::deg2rad); + event.m_dir.dety(ptr_dety->real(i)*gammalib::deg2rad); + } + + // If available, set pulse phase if (m_has_phase) { event.m_phase = ptr_phase->real(i); } + // Append event m_events.push_back(event); - } - } // endif: there were events + } // endfor: looped over all events - // Return - return; -} + // Loop over table and find optional columns + for (int i = 0; i < table.ncols(); ++i) { + // Get column pointer + const GFitsTableCol* col = table[i]; -/***********************************************************************//** - * @brief Read Hillas information for CTA events from FITS table - * - * @param[in] table FITS table. - * - * This method reads the Hillas reconstruction information for CTA events - * from an EVENTS file. It searches for the columns HIL_MSW, HIL_MSW_ERR, - * HIL_MSL, and HIL_MSL_ERR in the FITS table and extracts the relevant - * columns from the FITS file. If a column is not found, no action is - * performed. - * - * @todo Verify consistency of event list size - ***************************************************************************/ -void GCTAEventList::read_events_hillas(const GFitsTable& table) -{ - // Extract number of events in FITS file - int num = table.nrows(); + // Get column name + const std::string name = col->name(); - //TODO: Make sure that dimension is consistent with existing event - // list - - // Continue only if there are events - if (num > 0) { - - // HIL_MSW - if (table.contains("HIL_MSW")) { - const GFitsTableCol* ptr = table["HIL_MSW"]; - for (int i = 0; i < num; ++i) { - m_events[i].m_hil_msw = ptr->real(i); - } - } - - // HIL_MSW_ERR - if (table.contains("HIL_MSW_ERR")) { - const GFitsTableCol* ptr = table["HIL_MSW_ERR"]; - for (int i = 0; i < num; ++i) { - m_events[i].m_hil_msw_err = ptr->real(i); + // If column was mandatory or optional then skip it ... + if (name == "EVENT_ID" || + name == "TIME" || + name == "RA" || + name == "DEC" || + name == "ENERGY" || + name == "DETX" || + name == "DETY" || + name == "PHASE") { + continue; } - } - // HIL_MSL - if (table.contains("HIL_MSL")) { - const GFitsTableCol* ptr = table["HIL_MSL"]; - for (int i = 0; i < num; ++i) { - m_events[i].m_hil_msl = ptr->real(i); + // ... otherwise keep a copy + else { + m_columns.push_back(col->clone()); } - } - // HIL_MSL_ERR - if (table.contains("HIL_MSL_ERR")) { - const GFitsTableCol* ptr = table["HIL_MSL_ERR"]; - for (int i = 0; i < num; ++i) { - m_events[i].m_hil_msl_err = ptr->real(i); - } - } + } // endfor: loop over optional columns } // endif: there were events @@ -908,12 +761,26 @@ void GCTAEventList::read_events_hillas(const GFitsTable& table) /***********************************************************************//** * @brief Write CTA events into FITS table * - * @param[in] hdu FITS table HDU. + * @param[in] hdu FITS binary table. * - * Write the CTA event list into FITS table. + * Write the CTA event list into a FITS binary table. * - * @todo The TELMASK column is allocated with a dummy length of 100. - * @todo Implement agreed column format + * The following mandatory columns will be written into the FITS table: + * + * - EVENT_ID + * - TIME + * - RA + * - DEC + * - ENERGY + * + * If available, also the + * + * - DETX + * - DETY + * - PHASE + * + * columns are written. Any other columns that were read by the read_events() + * method will be also written into the table. ***************************************************************************/ void GCTAEventList::write_events(GFitsBinTable& hdu) const { @@ -923,109 +790,55 @@ void GCTAEventList::write_events(GFitsBinTable& hdu) const // If there are events then write them now if (size() > 0) { - // Allocate columns - GFitsTableULongCol col_eid = GFitsTableULongCol("EVENT_ID", size()); - GFitsTableULongCol col_oid = GFitsTableULongCol("OBS_ID", size()); - GFitsTableDoubleCol col_time = GFitsTableDoubleCol("TIME", size()); - GFitsTableDoubleCol col_live = GFitsTableDoubleCol("TLIVE", size()); - GFitsTableShortCol col_multip = GFitsTableShortCol("MULTIP", size()); - GFitsTableBitCol col_telmask = GFitsTableBitCol("TELMASK", size(), 100); - GFitsTableFloatCol col_ra = GFitsTableFloatCol("RA", size()); - GFitsTableFloatCol col_dec = GFitsTableFloatCol("DEC", size()); - GFitsTableFloatCol col_direrr = GFitsTableFloatCol("DIR_ERR", size()); - GFitsTableFloatCol col_detx = GFitsTableFloatCol("DETX", size()); - GFitsTableFloatCol col_dety = GFitsTableFloatCol("DETY", size()); - GFitsTableFloatCol col_alt = GFitsTableFloatCol("ALT", size()); - GFitsTableFloatCol col_az = GFitsTableFloatCol("AZ", size()); - GFitsTableFloatCol col_corex = GFitsTableFloatCol("COREX", size()); - GFitsTableFloatCol col_corey = GFitsTableFloatCol("COREY", size()); - GFitsTableFloatCol col_core_err = GFitsTableFloatCol("CORE_ERR", size()); - GFitsTableFloatCol col_xmax = GFitsTableFloatCol("XMAX", size()); - GFitsTableFloatCol col_xmax_err = GFitsTableFloatCol("XMAX_ERR", size()); - GFitsTableFloatCol col_shw = GFitsTableFloatCol("SHWIDTH", size()); - GFitsTableFloatCol col_shl = GFitsTableFloatCol("SHLENGTH", size()); - GFitsTableFloatCol col_energy = GFitsTableFloatCol("ENERGY", size()); - GFitsTableFloatCol col_energy_err = GFitsTableFloatCol("ENERGY_ERR", size()); - GFitsTableFloatCol col_hil_msw = GFitsTableFloatCol("HIL_MSW", size()); - GFitsTableFloatCol col_hil_msw_err = GFitsTableFloatCol("HIL_MSW_ERR", size()); - GFitsTableFloatCol col_hil_msl = GFitsTableFloatCol("HIL_MSL", size()); - GFitsTableFloatCol col_hil_msl_err = GFitsTableFloatCol("HIL_MSL_ERR", size()); - - // Create phase column if required - GFitsTableFloatCol col_phase; - if (m_has_phase) { - col_phase = GFitsTableFloatCol("PHASE", size()); - } + // Allocate mandatory columns + GFitsTableULongCol col_eid = GFitsTableULongCol("EVENT_ID", size()); + GFitsTableDoubleCol col_time = GFitsTableDoubleCol("TIME", size()); + GFitsTableFloatCol col_ra = GFitsTableFloatCol("RA", size()); + GFitsTableFloatCol col_dec = GFitsTableFloatCol("DEC", size()); + GFitsTableFloatCol col_energy = GFitsTableFloatCol("ENERGY", size()); - // Fill columns + // Fill mandatory columns for (int i = 0; i < size(); ++i) { - col_eid(i) = m_events[i].m_event_id; - col_oid(i) = m_events[i].m_obs_id; - col_time(i) = m_events[i].time().convert(m_gti.reference()); - col_live(i) = 0.0; - col_multip(i) = 0; - //col_telmask - col_ra(i) = m_events[i].dir().dir().ra_deg(); - col_dec(i) = m_events[i].dir().dir().dec_deg(); - col_direrr(i) = m_events[i].m_dir_err; - col_detx(i) = m_events[i].dir().detx() * gammalib::rad2deg; - col_dety(i) = m_events[i].dir().dety() * gammalib::rad2deg; - col_alt(i) = m_events[i].m_alt; - col_az(i) = m_events[i].m_az; - col_corex(i) = m_events[i].m_corex; - col_corey(i) = m_events[i].m_corey; - col_core_err(i) = m_events[i].m_core_err; - col_xmax(i) = m_events[i].m_xmax; - col_xmax_err(i) = m_events[i].m_xmax_err; - col_shw(i) = m_events[i].m_shwidth; - col_shl(i) = m_events[i].m_shlength; - col_energy(i) = m_events[i].energy().TeV(); - col_energy_err(i) = m_events[i].m_energy_err; - col_hil_msw(i) = m_events[i].m_hil_msw; - col_hil_msw_err(i) = m_events[i].m_hil_msw_err; - col_hil_msl(i) = m_events[i].m_hil_msl; - col_hil_msl_err(i) = m_events[i].m_hil_msl_err; - - // Optionally fill pulse phase column - if (m_has_phase) { - col_phase(i) = m_events[i].m_phase; - } - - } // endfor: looped over rows + col_eid(i) = m_events[i].m_event_id; + col_time(i) = m_events[i].time().convert(m_gti.reference()); + col_ra(i) = m_events[i].dir().dir().ra_deg(); + col_dec(i) = m_events[i].dir().dir().dec_deg(); + col_energy(i) = m_events[i].energy().TeV(); + } - // Append columns to table + // Append mandatory columns to table hdu.append(col_eid); - hdu.append(col_oid); hdu.append(col_time); - hdu.append(col_live); - hdu.append(col_multip); - hdu.append(col_telmask); hdu.append(col_ra); hdu.append(col_dec); - hdu.append(col_direrr); - hdu.append(col_detx); - hdu.append(col_dety); - hdu.append(col_alt); - hdu.append(col_az); - hdu.append(col_corex); - hdu.append(col_corey); - hdu.append(col_core_err); - hdu.append(col_xmax); - hdu.append(col_xmax_err); - hdu.append(col_shw); - hdu.append(col_shl); hdu.append(col_energy); - hdu.append(col_energy_err); - hdu.append(col_hil_msw); - hdu.append(col_hil_msw_err); - hdu.append(col_hil_msl); - hdu.append(col_hil_msl_err); - // Optionally write phase column + // If available, add detector coordinates in degrees + if (m_has_detxy) { + GFitsTableFloatCol col_detx = GFitsTableFloatCol("DETX", size()); + GFitsTableFloatCol col_dety = GFitsTableFloatCol("DETY", size()); + for (int i = 0; i < size(); ++i) { + col_detx(i) = m_events[i].dir().detx() * gammalib::rad2deg; + col_dety(i) = m_events[i].dir().dety() * gammalib::rad2deg; + } + hdu.append(col_detx); + hdu.append(col_dety); + } + + // If available, add event phase if (m_has_phase) { + GFitsTableFloatCol col_phase = GFitsTableFloatCol("PHASE", size()); + for (int i = 0; i < size(); ++i) { + col_phase(i) = m_events[i].m_phase; + } hdu.append(col_phase); } + // Append other columns to table + for (int i = 0; i < m_columns.size(); ++i) { + hdu.append(*m_columns[i]); + } + } // endif: there were events to write // Return diff --git a/inst/cta/src/GCTAPointing.cpp b/inst/cta/src/GCTAPointing.cpp index dc6e411..ebad18e 100644 --- a/inst/cta/src/GCTAPointing.cpp +++ b/inst/cta/src/GCTAPointing.cpp @@ -28,8 +28,9 @@ #ifdef HAVE_CONFIG_H #include #endif -#include "GCTAPointing.hpp" #include "GTools.hpp" +#include "GFilename.hpp" +#include "GCTAPointing.hpp" #include "GFits.hpp" #include "GHorizDir.hpp" @@ -107,21 +108,19 @@ GCTAPointing::GCTAPointing(const GXmlElement& xml) /***********************************************************************//** - * @brief Pointing table constructor + * @brief FITS file constructor * - * @param[in] filename Pointing table file. - * @param[in] extname Pointing extension name (defaults to "POINTING") + * @param[in] filename FITS file. * - * Construct CTA pointing from a pointing table file. + * Construct CTA pointing from a pointing table FITS file. ***************************************************************************/ -GCTAPointing::GCTAPointing(const std::string& filename, - const std::string& extname) +GCTAPointing::GCTAPointing(const std::string& filename) { // Initialise members init_members(); // Load pointing table - load(filename, extname); + load(filename); // Return return; @@ -400,24 +399,28 @@ GHorizDir GCTAPointing::dir_horiz(const GTime& time) const /************************************************************************ - * @brief Load pointing table from a pointing file + * @brief Load pointings from a FITS file * - * @param[in] filename Pointing table filename. - * @param[in] extname Pointing extension name (defaults to "POINTING") + * @param[in] filename FITS file name. + * + * Loads pointings from a pointing table FITS file. * - * Loads a pointing table from a FITS file. See the read() method for - * more information about the structure of the FITS file. + * If no extension name is provided, the pointing is are loaded from the + * "POINTING" extension. ************************************************************************/ -void GCTAPointing::load(const std::string& filename, const std::string& extname) +void GCTAPointing::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Open FITS file - file.open(filename); + file.open(fname.filename()); // Get pointing table - const GFitsTable& table = *file.table(extname); + const GFitsTable& table = *file.table(fname.extname("POINTING")); // Read pointing from table read(table); @@ -431,7 +434,7 @@ void GCTAPointing::load(const std::string& filename, const std::string& extname) /************************************************************************ - * @brief Load pointing table from a pointing file + * @brief Read pointings from a FITS table * * @param[in] filename Pointing table filename. * @param[in] extname Pointing extension name (defaults to "POINTING") diff --git a/inst/cta/src/GCTAPsf2D.cpp b/inst/cta/src/GCTAPsf2D.cpp index 4bef47c..1be3159 100644 --- a/inst/cta/src/GCTAPsf2D.cpp +++ b/inst/cta/src/GCTAPsf2D.cpp @@ -32,14 +32,14 @@ #include "GTools.hpp" #include "GException.hpp" #include "GMath.hpp" +#include "GFilename.hpp" #include "GFits.hpp" #include "GFitsBinTable.hpp" #include "GCTAPsf2D.hpp" #include "GCTAException.hpp" /* __ Method name definitions ____________________________________________ */ -#define G_READ "GCTAPsf2D::read(GFits&)" -#define G_LOAD "GCTAPsf2D::load(std::string&)" +#define G_READ "GCTAPsf2D::read(GFitsTable&)" #define G_CONTAINMENT_RADIUS "GCTAPsf2D::containment_radius(double&,"\ " double&, double&, double&, double&, double&, bool&)" @@ -75,10 +75,9 @@ GCTAPsf2D::GCTAPsf2D(void) : GCTAPsf() /***********************************************************************//** * @brief File constructor * - * @param[in] filename PSF FITS file name. + * @param[in] filename FITS file name. * - * Construct instance by loading the point spread function information from - * a PSF response table. + * Constructs point spread function from a FITS file. ***************************************************************************/ GCTAPsf2D::GCTAPsf2D(const std::string& filename) : GCTAPsf() { @@ -274,26 +273,24 @@ GCTAPsf2D* GCTAPsf2D::clone(void) const /***********************************************************************//** - * @brief Read PSF from FITS file + * @brief Read point spread function from FITS table * - * @param[in] fits FITS file pointer. + * @param[in] table FITS table. * * @exception GException::invalid_value * FITS file format differs from expectation. * - * Reads the PSF from the FITS file extension "POINT SPREAD FUNCTION". The data - * are stored in m_psf which is of type GCTAResponseTable. - * The energy axis will be set to log10. The offset angle axis and - * sigma parameter columns will be set to radians. + * Reads point spread function from the FITS @p table. + * + * The data are stored in m_psf which is of type GCTAResponseTable. The + * energy axis will be set to log10. The offset angle axis and sigma + * parameter columns will be set to radians. ***************************************************************************/ -void GCTAPsf2D::read(const GFits& fits) +void GCTAPsf2D::read(const GFitsTable& table) { // Clear response table m_psf.clear(); - // Get PSF table - const GFitsTable& table = *fits.table("POINT SPREAD FUNCTION"); - // Read PSF table m_psf.read(table); @@ -330,24 +327,26 @@ void GCTAPsf2D::read(const GFits& fits) /***********************************************************************//** - * @brief Write CTA PSF table into FITS binary table object. + * @brief Write point spread function into FITS binary table * - * @param[in] hdu FITS binary table. + * @param[in] table FITS binary table. + * + * Writes point spread function into FITS binary @p table. * * @todo Add necessary keywords. ***************************************************************************/ -void GCTAPsf2D::write(GFitsBinTable& hdu) const +void GCTAPsf2D::write(GFitsBinTable& table) const { // Create a copy of the response table - GCTAResponseTable table(m_psf); + GCTAResponseTable psf(m_psf); // Convert sigma parameters back to degrees - table.scale(1, gammalib::rad2deg); - table.scale(3, gammalib::rad2deg); - table.scale(5, gammalib::rad2deg); + psf.scale(1, gammalib::rad2deg); + psf.scale(3, gammalib::rad2deg); + psf.scale(5, gammalib::rad2deg); // Write background table - table.write(hdu); + psf.write(table); // Return return; @@ -355,26 +354,34 @@ void GCTAPsf2D::write(GFitsBinTable& hdu) const /***********************************************************************//** - * @brief Load point spread function from performance table + * @brief Load point spread function from FITS file * - * @param[in] filename Performance table file name. + * @param[in] filename FITS file name. * - * @exception GCTAExceptionHandler::file_open_error - * File could not be opened for read access. + * Loads the point spread function from a FITS file. * - * This method loads the point spread function information from a PSF - * response table. + * If no extension name is provided, the point spread function will be loaded + * from the "POINT SPREAD FUNCTION" extension. ***************************************************************************/ void GCTAPsf2D::load(const std::string& filename) { - // Open PSF FITS file - GFits fits(filename); + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; - // Read fits file - read(fits); + // Open FITS file + file.open(fname.filename()); - // Close PSF FITS file - fits.close(); + // Get PSFa table + const GFitsTable& table = *file.table(fname.extname("POINT SPREAD FUNCTION")); + + // Read PSF from table + read(table); + + // Close FITS file + file.close(); // Store filename m_filename = filename; @@ -385,18 +392,24 @@ void GCTAPsf2D::load(const std::string& filename) /***********************************************************************//** - * @brief Save PSF table into FITS file + * @brief Save point spread function table into FITS file * - * @param[in] filename PSF table FITS file name. - * @param[in] clobber Overwrite existing file? (true=yes) + * @param[in] filename FITS file name. + * @param[in] clobber Overwrite existing file? (default: false) * - * Save the PSF table into a FITS file. + * Save the point spread function into a FITS file. + * + * If no extension name is provided, the point spread function will be saved + * into the "POINT SPREAD FUNCTION" extension. ***************************************************************************/ void GCTAPsf2D::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Create binary table GFitsBinTable table; - table.extname("POINT SPREAD FUNCTION"); + table.extname(fname.extname("POINT SPREAD FUNCTION")); // Write the PSF table write(table); @@ -404,7 +417,7 @@ void GCTAPsf2D::save(const std::string& filename, const bool& clobber) const // Create FITS file, append table, and write into the file GFits fits; fits.append(table); - fits.saveto(filename, clobber); + fits.saveto(fname.filename(), clobber); // Return return; diff --git a/inst/cta/src/GCTAPsfKing.cpp b/inst/cta/src/GCTAPsfKing.cpp index 70dd660..b4d55e5 100644 --- a/inst/cta/src/GCTAPsfKing.cpp +++ b/inst/cta/src/GCTAPsfKing.cpp @@ -32,13 +32,14 @@ #include "GTools.hpp" #include "GException.hpp" #include "GMath.hpp" +#include "GFilename.hpp" #include "GFits.hpp" #include "GFitsBinTable.hpp" #include "GCTAPsfKing.hpp" #include "GCTAException.hpp" /* __ Method name definitions ____________________________________________ */ -#define G_READ "GCTAPsfKing::read(GFits&)" +#define G_READ "GCTAPsfKing::read(GFitsTable&)" #define G_CONTAINMENT_RADIUS "GCTAPsfKing::containment_radius(double&,"\ " double&, double&, double&, double&, double&, bool&)" #define G_UPDATE "GCTAPsfKing::update(double&, double&)" @@ -80,8 +81,7 @@ GCTAPsfKing::GCTAPsfKing(void) : GCTAPsf() * * @param[in] filename PSF FITS file. * - * Construct instance by loading the point spread function information from - * a FITS file that contains the PSF information in form of a column. + * Constructs point spread function from a FITS file. ***************************************************************************/ GCTAPsfKing::GCTAPsfKing(const std::string& filename) : GCTAPsf() { @@ -275,26 +275,24 @@ GCTAPsfKing* GCTAPsfKing::clone(void) const /***********************************************************************//** - * @brief Read PSF from FITS file + * @brief Read point spread function from FITS table * - * @param[in] fits FITS file pointer. + * @param[in] table FITS table. * * @exception GException::invalid_value * FITS file format differs from expectation. * - * Reads the PSF from the FITS file extension "POINT SPREAD FUNCTION". The - * data are stored in m_psf which is of type GCTAResponseTable. - * The energy axis will be set to log10. The offset angle axis and - * sigma parameter columns will be set to radians. + * Reads the point spread function from the FITS @p table. + * + * The data are stored in m_psf which is of type GCTAResponseTable. The + * energy axis will be set to log10. The offset angle axis and sigma + * parameter columns will be set to radians. ***************************************************************************/ -void GCTAPsfKing::read(const GFits& fits) +void GCTAPsfKing::read(const GFitsTable& table) { // Clear response table m_psf.clear(); - // Get PSF table - const GFitsTable& table = *fits.table("POINT SPREAD FUNCTION"); - // Read PSF table m_psf.read(table); @@ -329,16 +327,18 @@ void GCTAPsfKing::read(const GFits& fits) /***********************************************************************//** - * @brief Write CTA PSF table into FITS binary table object. + * @brief Write point spread function into FITS table * - * @param[in] hdu FITS binary table. + * @param[in] table FITS binary table. * - * @todo Add necessary keywords. + * Writes point spread function into a FITS binary @p table. + * + * @todo Add keywords. ***************************************************************************/ -void GCTAPsfKing::write(GFitsBinTable& hdu) const +void GCTAPsfKing::write(GFitsBinTable& table) const { // Write background table - m_psf.write(hdu); + m_psf.write(table); // Return return; @@ -346,25 +346,33 @@ void GCTAPsfKing::write(GFitsBinTable& hdu) const /***********************************************************************//** - * @brief Load point spread function from binary table + * @brief Load point spread function from FITS file * - * @param[in] filename Performance table file name. + * @param[in] filename FITS file name. * - * @exception GCTAExceptionHandler::file_open_error - * File could not be opened for read access. + * Loads the point spread function from a FITS file. * - * This method loads the point spread function information from a PSF - * response table. + * If no extension name is provided, the point spread function will be loaded + * from the "POINT SPREAD FUNCTION" extension. ***************************************************************************/ void GCTAPsfKing::load(const std::string& filename) { - // Open PSF FITS file - GFits file(filename); + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; - // Read fits file - read(file); + // Open FITS file + file.open(fname.filename()); - // Close PSF FITS file + // Get PSFa table + const GFitsTable& table = *file.table(fname.extname("POINT SPREAD FUNCTION")); + + // Read PSF from table + read(table); + + // Close FITS file file.close(); // Store filename @@ -375,18 +383,24 @@ void GCTAPsfKing::load(const std::string& filename) } /***********************************************************************//** - * @brief Save PSF table into FITS file + * @brief Save point spread function table into FITS file * - * @param[in] filename PSF table FITS file name. - * @param[in] clobber Overwrite existing file? (true=yes) + * @param[in] filename FITS file name. + * @param[in] clobber Overwrite existing file? (default: false) * - * Save the PSF table into a FITS file. + * Save the point spread function into a FITS file. + * + * If no extension name is provided, the point spread function will be saved + * into the "POINT SPREAD FUNCTION" extension. ***************************************************************************/ void GCTAPsfKing::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Create binary table GFitsBinTable table; - table.extname("POINT SPREAD FUNCTION"); + table.extname(fname.extname("POINT SPREAD FUNCTION")); // Write the PSF table write(table); @@ -394,7 +408,7 @@ void GCTAPsfKing::save(const std::string& filename, const bool& clobber) const // Create FITS file, append table, and write into the file GFits fits; fits.append(table); - fits.saveto(filename, clobber); + fits.saveto(fname.filename(), clobber); // Return return; diff --git a/inst/cta/src/GCTAPsfVector.cpp b/inst/cta/src/GCTAPsfVector.cpp index f241f50..7bb6b07 100644 --- a/inst/cta/src/GCTAPsfVector.cpp +++ b/inst/cta/src/GCTAPsfVector.cpp @@ -31,6 +31,7 @@ #include #include "GTools.hpp" #include "GMath.hpp" +#include "GFilename.hpp" #include "GFitsTable.hpp" #include "GFitsTableCol.hpp" #include "GCTAPsfVector.hpp" @@ -74,8 +75,7 @@ GCTAPsfVector::GCTAPsfVector(void) : GCTAPsf() * * @param[in] filename PSF FITS file. * - * Construct instance by loading the point spread function information from - * a FITS file that contains the PSF information in form of a column. + * Constructs point spread function vector from a FITS file. ***************************************************************************/ GCTAPsfVector::GCTAPsfVector(const std::string& filename) : GCTAPsf() { @@ -247,25 +247,33 @@ GCTAPsfVector* GCTAPsfVector::clone(void) const /***********************************************************************//** - * @brief Load point spread function from performance table + * @brief Load point spread function from FITS file * - * @param[in] filename Performance table file name. + * @param[in] filename FITS file name. * - * This method loads the point spread function information from a FITS file - * that contains the PSF width in a single column. + * Loads the point spread function from a FITS file. + * + * If no extension name is provided, the point spread function will be loaded + * from the "PSF" extension. ***************************************************************************/ void GCTAPsfVector::load(const std::string& filename) { - // Open PSF FITS file - GFits file(filename); + // Create file name + GFilename fname(filename); + + // Allocate FITS file + GFits file; - // Get PSF table - const GFitsTable& table = *file.table(1); + // Open FITS file + file.open(fname.filename()); - // Read PSF + // Get PSFa table + const GFitsTable& table = *file.table(fname.extname("PSF")); + + // Read PSF from table read(table); - // Close PSF FITS file + // Close FITS file file.close(); // Store filename @@ -277,12 +285,13 @@ void GCTAPsfVector::load(const std::string& filename) /***********************************************************************//** - * @brief Read CTA PSF vector + * @brief Read point spread function vector from FITS table * * @param[in] table FITS table. * - * This method reads a CTA PSF vector from the FITS HDU. Note that the - * energies are converted to TeV. Conversion is done based on the units + * Reads a point spread function vector from the FITS @p table. + * + * The energies are converted to TeV. Conversion is done based on the units * provided for the energy columns. Units that are recognized are 'keV', * 'MeV', 'GeV', and 'TeV' (case independent). * diff --git a/inst/cta/src/GCTAResponseIrf.cpp b/inst/cta/src/GCTAResponseIrf.cpp index f4055cb..3fd0821 100644 --- a/inst/cta/src/GCTAResponseIrf.cpp +++ b/inst/cta/src/GCTAResponseIrf.cpp @@ -34,6 +34,7 @@ #include "GFits.hpp" #include "GTools.hpp" #include "GMath.hpp" +#include "GFilename.hpp" #include "GIntegral.hpp" #include "GCaldb.hpp" #include "GSource.hpp" @@ -70,14 +71,17 @@ #include "GCTABackground3D.hpp" /* __ Method name definitions ____________________________________________ */ -#define G_CALDB "GCTAResponseIrf::caldb(GCaldb&)" #define G_IRF "GCTAResponseIrf::irf(GInstDir&, GEnergy&, GTime&, GSkyDir&,"\ " GEnergy&, GTime&, GObservation&)" -#define G_NPRED "GCTAResponseIrf::npred(GSkyDir&, GEnergy&, GTime&,"\ - " GObservation&)" #define G_MC "GCTAResponseIrf::mc(double&, GPhoton&, GObservation&, GRan&)" #define G_READ "GCTAResponseIrf::read(GXmlElement&)" #define G_WRITE "GCTAResponseIrf::write(GXmlElement&)" +#define G_LOAD_AEFF "GCTAResponseIrf::load_aeff(std::string&)" +#define G_LOAD_PSF "GCTAResponseIrf::load_psf(std::string&)" +#define G_LOAD_EDISP "GCTAResponseIrf::load_edisp(std::string&)" +#define G_LOAD_BACKGROUND "GCTAResponseIrf::load_background(std::string&)" +#define G_NIRF "GCTAResponseIrf::nirf(GPhoton&, GEnergy&, GTime&,"\ + " GObservation&)" #define G_IRF_RADIAL "GCTAResponseIrf::irf_radial(GEvent&, GSource&,"\ " GObservation&)" #define G_IRF_ELLIPTICAL "GCTAResponseIrf::irf_elliptical(GEvent&, GSource&,"\ @@ -96,8 +100,6 @@ " double&)" #define G_PSF_DELTA_MAX "GCTAResponseIrf::psf_delta_max(double&, double&,"\ " double&, double&, double&)" -#define G_EDISP "GCTAResponseIrf::edisp(double&, double&, double&, double&,"\ - " double&)" /* __ Macros _____________________________________________________________ */ @@ -1069,30 +1071,22 @@ void GCTAResponseIrf::load(const std::string& rspname) * * @param[in] filename Effective area filename. * - * This method allocates an effective area instance and load the effective - * area information from a response file. The following response file formats - * are supported: - * - * (1) A CTA performance table. This is an ASCII file which specifies the - * on-axis effective area as function of energy. - * - * (2) A ARF FITS file. This is a FITS file which stores the effective area - * in a vector. - * - * (3) A CTA response table. This is a FITS file which specifies the - * effective area as function of energy and offset angle. + * @exception GException::file_error + * File or extension not found. * - * This method examines the file, and depending on the detected format, - * allocates the appropriate effective area class and loads the data. + * Loads the effective area from a response file. * - * First, the method checks whether the file is a FITS file or not. If the - * file is not a FITS file, it is assumed that the file is an ASCII - * performance table. If the file is a FITS file, the number of rows found - * in the table is used to distinguish between an ARF (multiple rows) and - * a CTA response table (single row). + * If the file is a FITS file, the method will either use the extension name + * specified with the filename, or if no extension name is given, search for + * an "EFFECTIVE AREA" or "SPECRESP" extension in the file and open the + * corresponding FITS table. If a column named "SPECRESP" is found in the + * table, a GCTAAeffArf object will be allocated. Otherwise, a GCTAAeff2D + * object will be allocated. In both cases, the method will extract the + * optional "LO_THRES" and "HI_THRES" save energy thresholds from the FITS + * file header. * - * @todo Implement a method that checks if a file is a FITS file instead - * of using try-catch. + * If the file is not a FITS file, it will be interpreted as a + * GCTAAeffPerfTable performance table. ***************************************************************************/ void GCTAResponseIrf::load_aeff(const std::string& filename) { @@ -1100,68 +1094,93 @@ void GCTAResponseIrf::load_aeff(const std::string& filename) if (m_aeff != NULL) delete m_aeff; m_aeff = NULL; - // Try opening the file as a FITS file - try { + // Initialise filename + GFilename fname(filename); + + // Check for existence of file + if (!gammalib::file_exists_gzip(fname.filename())) { + std::string msg = "File \""+filename+"\" not found. Please specify " + "a valid effective area response file."; + throw GException::file_error(G_LOAD_AEFF, msg); + } + + // If file is a FITS file ... + if (gammalib::is_fits(filename)) { // Open FITS file - GFits file(filename); + GFits file(fname.filename()); + + // Get the extension name. If an extension name has been specified + // then use this name, otherwise use either the "EFFECTIVE AREA" + // or the "SPECRESP" extension. + std::string extname = ""; + if (fname.has_extname()) { + extname = fname.extname(); + } + else { + if (file.contains("EFFECTIVE AREA")) { + extname = "EFFECTIVE AREA"; + } + else if (file.contains("SPECRESP")) { + extname = "SPECRESP"; + } + } - // If file contains an "EFFECTIVE AREA" extension then load it - // as CTA response table - if (file.contains("EFFECTIVE AREA")) { + // Continue only if extension name is not empty + if (!extname.empty()) { - // Get HDU - const GFitsHDU* hdu = file.at("EFFECTIVE AREA"); + // Get FITS table + const GFitsTable& table = *file.table(extname); // Read save energy thresholds if available - if (hdu->has_card("LO_THRES")) { - m_lo_save_thres = hdu->real("LO_THRES"); + if (table.has_card("LO_THRES")) { + m_lo_save_thres = table.real("LO_THRES"); } - if (hdu->has_card("HI_THRES")) { - m_hi_save_thres = hdu->real("HI_THRES"); + if (table.has_card("HI_THRES")) { + m_hi_save_thres = table.real("HI_THRES"); } - // Close file - file.close(); + // Check for specific table column + if (table.contains("SPECRESP")) { - // Allocate Aeff from file - m_aeff = new GCTAAeff2D(filename); - - } + // Close file + file.close(); - // ... else if file contains a "SPECRESP" extension then load it - // as ARF - else if (file.contains("SPECRESP")) { + // Allocate Aeff from file + m_aeff = new GCTAAeffArf(filename); - // Get HDU - const GFitsHDU* hdu = file.at("SPECRESP"); + } // endif: load as GCTAAeffArf + + else { - // Read save energy thresholds if available - if (hdu->has_card("LO_THRES")) { - m_lo_save_thres = hdu->real("LO_THRES"); - } - if (hdu->has_card("LO_THRES")) { - m_hi_save_thres = hdu->real("HI_THRES"); - } + // Close file + file.close(); - // Close file - file.close(); + // Allocate Aeff from file + m_aeff = new GCTAAeff2D(filename); + + } // endelse: load as GCTAAeff2D - // Allocate Aeff from file - m_aeff = new GCTAAeffArf(filename); + } // endif: extension name is not empty + // Signal that no extension was found + else { + std::string msg = "FITS file \""+filename+"\" does not " + "contain a valid effective area table. " + "Please specify a valid effective area " + "response file."; + throw GException::file_error(G_LOAD_AEFF, msg); } - } + } // endif: file was FITS file + + // ... else try handling an ASCII performance table + else { - // If FITS file opening failed then assume that we have a performance - // table - catch (GException::fits_open_error &e) { + // Allocate a performance table m_aeff = new GCTAAeffPerfTable(filename); - } - // Record Aeff file name - //m_xml_aeff = filename; + } // endif: load as GCTAAeffPerfTable // Return return; @@ -1173,25 +1192,22 @@ void GCTAResponseIrf::load_aeff(const std::string& filename) * * @param[in] filename FITS file name. * - * This method loads CTA PSF information from a FITS table. Two FITS file - * formats are supported by the method: - * - * (1) A PSF vector, stored in a format similar to an ARF vector. It is - * expected that this format is only a preliminary format that will - * disappear in the future (m_psf_version=-9). + * @exception GException::file_error + * File or extension not found. * - * (2) A PSF response table, where PSF parameters are given as function of - * energy, offset angle, and eventually some other parameters. This format - * is expected to be the definitive response format for CTA - * (m_psf_version=-8). + * Loads the point spead function from a response file. * - * This method examines the FITS file, and depending on the detected format, - * calls the relevant methods. Detection is done by the number of rows that - * are found in the table. A single row means that we deal with a response - * table, while multiple rows mean that we deal with a response vector. + * If the file is a FITS file, the method will either use the extension name + * specified with the filename, or if no extension name is given, search for + * a "POINT SPREAD FUNCTION" or "PSF" extension in the file and open the + * corresponding FITS table. If columns named "GAMMA" and "SIGMA" are found + * in the table, a GCTAPsfKing object will be allocated. If columns named + * "SCALE", "SIGMA_1", "AMPL_2", "SIGMA_2", "AMPL_3" and "SIGMA_3" are found + * in the table, a GCTAPsf2D object will be allocated. Otherwise, a + * GCTAPsfVector object will be allocated. * - * @todo Implement a method that checks if a file is a FITS file instead - * of using try-catch. + * If the file is not a FITS file, it will be interpreted as a + * GCTAPsfPerfTable performance table. ***************************************************************************/ void GCTAResponseIrf::load_psf(const std::string& filename) { @@ -1199,47 +1215,100 @@ void GCTAResponseIrf::load_psf(const std::string& filename) if (m_psf != NULL) delete m_psf; m_psf = NULL; - // Try opening the file as a FITS file - try { + // Initialise filename + GFilename fname(filename); + + // Check for existence of file + if (!gammalib::file_exists_gzip(fname.filename())) { + std::string msg = "File \""+filename+"\" not found. Please specify " + "a valid point spread function response file."; + throw GException::file_error(G_LOAD_PSF, msg); + } + + // If file is a FITS file ... + if (gammalib::is_fits(filename)) { // Open FITS file - GFits file(filename); + GFits file(fname.filename()); + + // Get the extension name. If an extension name has been specified + // then use this name, otherwise use either the + // "POINT SPREAD FUNCTION" or the "PSF" extension. + std::string extname = ""; + if (fname.has_extname()) { + extname = fname.extname(); + } + else { + if (file.contains("POINT SPREAD FUNCTION")) { + extname = "POINT SPREAD FUNCTION"; + } + else if (file.contains("PSF")) { + extname = "PSF"; + } + } - // If file contains a "POINT SPREAD FUNCTION" extension then load it - // as either a King profile PSF or a 2D PSF - if (file.contains("POINT SPREAD FUNCTION")) { - const GFitsTable& table = *file.table("POINT SPREAD FUNCTION"); + // Continue only if extension name is not empty + if (!extname.empty()) { + + // Get FITS table + const GFitsTable& table = *file.table(extname); + + // Check for King profile specific table columns if (table.contains("GAMMA") && table.contains("SIGMA")) { + + // Close FITS file file.close(); + + // Allocate King profile PSF m_psf = new GCTAPsfKing(filename); + } - else if (table.contains("SCALE") && table.contains("SIGMA_1") && + + // ... otherwise check for Gaussian profile specific table + // columns + else if (table.contains("SCALE") && table.contains("SIGMA_1") && table.contains("AMPL_2") && table.contains("SIGMA_2") && table.contains("AMPL_3") && table.contains("SIGMA_3")) { + + // Close FITS file file.close(); + + // Allocate Gaussian profile PSF m_psf = new GCTAPsf2D(filename); + } + + // ... otherwise try opening as vector PSF else { + + // Close FITS file file.close(); + + // Allocate vector PSF + m_psf = new GCTAPsfVector(filename); + } - } - // ... else load it has PSF vector + } // endif: extension name is not empty + + // Signal that no extension was found else { - file.close(); - m_psf = new GCTAPsfVector(filename); + std::string msg = "FITS file \""+filename+"\" does not " + "contain a valid point spread function table. " + "Please specify a valid point spread function " + "response file."; + throw GException::file_error(G_LOAD_PSF, msg); } - } + } // endif: file was FITS file - // If FITS file opening failed then assume that we have a performance - // table - catch (GException::fits_open_error &e) { + // ... otherwise load file as a performance table + else { + + // Allocate a performance table m_psf = new GCTAPsfPerfTable(filename); + } - - // Record PSF filename - //m_xml_psf = filename; // Return return; @@ -1250,6 +1319,21 @@ void GCTAResponseIrf::load_psf(const std::string& filename) * @brief Load energy dispersion information * * @param[in] filename Energy dispersion file name. + * + * @exception GException::file_error + * File or extension not found. + * + * Loads the energy dispersion from a response file. + * + * If the file is a FITS file, the method will either use the extension name + * specified with the filename, or if no extension name is given, search for + * an "ENERGY DISPERSION" or "MATRIX" extension in the file and open the + * corresponding FITS table. If columns named "MIGRA_LO" and "MIGRA_HI" are + * found in the table, a GCTAEdisp2D object will be allocated. Otherwise, a + * GCTAEdispRmf object will be allocated. + * + * If the file is not a FITS file, it will be interpreted as a + * GCTAEdispPerfTable performance table. ***************************************************************************/ void GCTAResponseIrf::load_edisp(const std::string& filename) { @@ -1257,35 +1341,86 @@ void GCTAResponseIrf::load_edisp(const std::string& filename) if (m_edisp != NULL) delete m_edisp; m_edisp = NULL; - // Try opening the file as a FITS file - try { + // Initialise filename + GFilename fname(filename); - // Open FITS file - GFits file(filename); + // Check for existence of file + if (!gammalib::file_exists_gzip(fname.filename())) { + std::string msg = "File \""+filename+"\" not found. Please specify " + "a valid energy dispersion response file."; + throw GException::file_error(G_LOAD_EDISP, msg); + } - // If file contains an "ENERGY DISPERSION" extension then load it - // as CTA response table - if (file.contains("ENERGY DISPERSION")) { - file.close(); - m_edisp = new GCTAEdisp2D(filename); + // If file is a FITS file ... + if (gammalib::is_fits(filename)) { + + // Open FITS file + GFits file(fname.filename()); + + // Get the extension name. If an extension name has been specified + // then use this name, otherwise use either the "EFFECTIVE AREA" + // or the "SPECRESP" extension. + std::string extname = ""; + if (fname.has_extname()) { + extname = fname.extname(); + } + else { + if (file.contains("ENERGY DISPERSION")) { + extname = "ENERGY DISPERSION"; + } + else if (file.contains("MATRIX")) { + extname = "MATRIX"; + } } - // ... else load it as RMF + // Continue only if extension name is not empty + if (!extname.empty()) { + + // Get FITS table + const GFitsTable& table = *file.table(extname); + + // Check for 2D migration matrix + if (table.contains("MIGRA_LO") && table.contains("MIGRA_HI")) { + + // Close FITS file + file.close(); + + // Allocate 2D migration matrix + m_edisp = new GCTAEdisp2D(filename); + + } + + // ... otherwise allocate RMF + else { + + // Close FITS file + file.close(); + + // Allocate Gaussian profile PSF + m_edisp = new GCTAEdispRmf(filename); + + } + + } // endif: extension name is not empty + + // Signal that no extension was found else { - file.close(); - m_edisp = new GCTAEdispRmf(filename); + std::string msg = "FITS file \""+filename+"\" does not " + "contain a valid energy dispersion table. " + "Please specify a valid energy dispersion " + "response file."; + throw GException::file_error(G_LOAD_EDISP, msg); } - } + } // endif: file was FITS file - // If FITS file opening failed then assume that we have a performance - // table - catch (GException::fits_open_error &e) { + // ... otherwise load file as a performance table + else { + + // Allocate a performance table m_edisp = new GCTAEdispPerfTable(filename); - } - // Record energy dispersion filename - //m_xml_edisp = filename; + } // Return return; @@ -1296,6 +1431,17 @@ void GCTAResponseIrf::load_edisp(const std::string& filename) * @brief Load background model * * @param[in] filename Background model file name. + * + * @exception GException::file_error + * File not found. + * + * Loads the background model from a response file. + * + * If the file is a FITS file the method allocates a GCTABackground3D + * response and loads the information from the FITS file. + * + * If the file is not a FITS file it will be interpreted as a + * GCTABackgroundPerfTable performance table. ***************************************************************************/ void GCTAResponseIrf::load_background(const std::string& filename) { @@ -1303,18 +1449,25 @@ void GCTAResponseIrf::load_background(const std::string& filename) if (m_background != NULL) delete m_background; m_background = NULL; - // Try opening the file as a FITS file - try { - // Load background as 3D background + // Initialise filename + GFilename fname(filename); + + // Check for existence of file + if (!gammalib::file_exists_gzip(fname.filename())) { + std::string msg = "File \""+filename+"\" not found. Please specify " + "a valid background response file."; + throw GException::file_error(G_LOAD_BACKGROUND, msg); + } + + // If file is a FITS file than load background as 3D background + if (gammalib::is_fits(filename)) { m_background = new GCTABackground3D(filename); } - catch (GException::fits_open_error &e) { - // Load background as performance table background + + // ... otherwise load background as performance table + else { m_background = new GCTABackgroundPerfTable(filename); } - - // Record background filename - //m_xml_background = filename; // Return return; @@ -1724,8 +1877,8 @@ double GCTAResponseIrf::nirf(const GPhoton& photon, const GObservation& obs) const { // Retrieve CTA observation, ROI and pointing - const GCTAObservation& cta = retrieve_obs(G_NPRED, obs); - const GCTARoi& roi = retrieve_roi(G_NPRED, obs); + const GCTAObservation& cta = retrieve_obs(G_NIRF, obs); + const GCTARoi& roi = retrieve_roi(G_NIRF, obs); const GCTAPointing& pnt = cta.pointing(); // Get photon attributes diff --git a/inst/cta/test/test_CTA.py b/inst/cta/test/test_CTA.py index a77976b..cd0cb78 100755 --- a/inst/cta/test/test_CTA.py +++ b/inst/cta/test/test_CTA.py @@ -271,8 +271,8 @@ class Test(gammalib.GPythonTestSuite): # Load 1DC CTA observation (ARF, PSF, RMF) self.test_try("Test 1DC responses") try: - filname = self.caldb + "/../data/irf_1dc.xml" - obs = gammalib.GObservations(filname) + filename = self.caldb + "/../data/irf_1dc.xml" + obs = gammalib.GObservations(filename) self.test_try_success() except: self.test_try_failure("Unable to load 1DC responses.") diff --git a/inst/mwl/include/GMWLObservation.hpp b/inst/mwl/include/GMWLObservation.hpp index e08822c..dace35f 100644 --- a/inst/mwl/include/GMWLObservation.hpp +++ b/inst/mwl/include/GMWLObservation.hpp @@ -1,7 +1,7 @@ /*************************************************************************** * GMWLObservation.hpp - Multi-wavelength observation class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2014 by Juergen Knoedlseder * + * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -49,8 +49,6 @@ public: // Constructors and destructors GMWLObservation(void); explicit GMWLObservation(const std::string& filename); - explicit GMWLObservation(const std::string& filename, const int& extno); - explicit GMWLObservation(const std::string& filename, const std::string& extname); GMWLObservation(const GMWLObservation& obs); virtual ~GMWLObservation(void); @@ -73,8 +71,6 @@ public: // Other methods void load(const std::string& filename); - void load(const std::string& filename, const int& extno); - void load(const std::string& filename, const std::string& extname); const std::string& filename(void) const; const std::string& extno(void) const; const std::string& extname(void) const; diff --git a/inst/mwl/include/GMWLSpectrum.hpp b/inst/mwl/include/GMWLSpectrum.hpp index f54d3a4..1eb84f6 100644 --- a/inst/mwl/include/GMWLSpectrum.hpp +++ b/inst/mwl/include/GMWLSpectrum.hpp @@ -74,8 +74,6 @@ public: virtual std::string print(const GChatter& chatter = NORMAL) const; // Other methods - void load(const std::string& filename, const std::string& extname); - void load(const std::string& filename, const int& extno); void read(const GFits& file, const std::string& extname); void read(const GFits& file, const int& extno); const std::string& telescope(void) const; diff --git a/inst/mwl/pyext/GMWLObservation.i b/inst/mwl/pyext/GMWLObservation.i index da6c7da..61d7b7c 100644 --- a/inst/mwl/pyext/GMWLObservation.i +++ b/inst/mwl/pyext/GMWLObservation.i @@ -1,7 +1,7 @@ /*************************************************************************** * GMWLObservation.i - Multi-wavelength observation class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2014 by Juergen Knoedlseder * + * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -39,12 +39,11 @@ * instrument. The spectral points are given in physical units. ***************************************************************************/ class GMWLObservation : public GObservation { + public: // Constructors and destructors GMWLObservation(void); explicit GMWLObservation(const std::string& filename); - explicit GMWLObservation(const std::string& filename, const int& extno); - explicit GMWLObservation(const std::string& filename, const std::string& extname); GMWLObservation(const GMWLObservation& obs); virtual ~GMWLObservation(void); @@ -63,8 +62,6 @@ public: // Other methods void load(const std::string& filename); - void load(const std::string& filename, const int& extno); - void load(const std::string& filename, const std::string& extname); const std::string& filename(void) const; const std::string& extno(void) const; const std::string& extname(void) const; diff --git a/inst/mwl/pyext/GMWLSpectrum.i b/inst/mwl/pyext/GMWLSpectrum.i index f89ea48..d93e09e 100644 --- a/inst/mwl/pyext/GMWLSpectrum.i +++ b/inst/mwl/pyext/GMWLSpectrum.i @@ -57,8 +57,6 @@ public: virtual int number(void) const; // Other methods - void load(const std::string& filename, const std::string& extname); - void load(const std::string& filename, const int& extno); void read(const GFits& file, const std::string& extname); void read(const GFits& file, const int& extno); const std::string& telescope(void) const; diff --git a/inst/mwl/src/GMWLObservation.cpp b/inst/mwl/src/GMWLObservation.cpp index 92e1a11..1f01cad 100644 --- a/inst/mwl/src/GMWLObservation.cpp +++ b/inst/mwl/src/GMWLObservation.cpp @@ -1,7 +1,7 @@ /*************************************************************************** * GMWLObservation.cpp - Multi-wavelength observation class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2013 by Juergen Knoedlseder * + * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -28,8 +28,9 @@ #ifdef HAVE_CONFIG_H #include #endif -#include "GObservationRegistry.hpp" #include "GTools.hpp" +#include "GFilename.hpp" +#include "GObservationRegistry.hpp" #include "GException.hpp" #include "GMWLObservation.hpp" #include "GMWLSpectrum.hpp" @@ -93,50 +94,6 @@ GMWLObservation::GMWLObservation(const std::string& filename) : GObservation() /***********************************************************************//** - * @brief File constructor - * - * @param[in] filename File name. - * @param[in] extno FITS file extension number. - * - * Creates instance from file. - ***************************************************************************/ -GMWLObservation::GMWLObservation(const std::string& filename, - const int& extno) : GObservation() -{ - // Initialise members - init_members(); - - // Load observation - load(filename, extno); - - // Return - return; -} - - -/***********************************************************************//** - * @brief File constructor - * - * @param[in] filename File name. - * @param[in] extname FITS file extension name. - * - * Creates instance from file. - ***************************************************************************/ -GMWLObservation::GMWLObservation(const std::string& filename, - const std::string& extname) : GObservation() -{ - // Initialise members - init_members(); - - // Load observation - load(filename, extname); - - // Return - return; -} - - -/***********************************************************************//** * @brief Copy constructor * * @param[in] obs Observation. @@ -336,11 +293,11 @@ void GMWLObservation::read(const GXmlElement& xml) // Load file (this also stores the filename, extno and // extname) - if (gammalib::strip_whitespace(extno).length() > 0) { - load(filename, gammalib::toint(extno)); + if (!gammalib::strip_whitespace(extno).empty()) { + load(filename+"["+extno+"]"); } - else if (gammalib::strip_whitespace(extname).length() > 0) { - load(filename, extname); + else if (!gammalib::strip_whitespace(extname).empty()) { + load(filename+"["+extname+"]"); } else { load(filename); @@ -442,79 +399,32 @@ void GMWLObservation::load(const std::string& filename) // Clear observation clear(); - // Allocate spectrum - GMWLSpectrum* spec = new GMWLSpectrum; - m_events = spec; - - // Load spectrum - spec->load(filename); - - // Set attributes - name("Multi-wavelength observation"); - id(filename); - m_filename = filename; - m_instrument = spec->instrument(); - - // Return - return; -} - - -/***********************************************************************//** - * @brief Load observation - * - * @param[in] filename File name. - * @param[in] extno FITS extension number. - ***************************************************************************/ -void GMWLObservation::load(const std::string& filename, - const int& extno) -{ - // Clear observation - clear(); - - // Allocate spectrum - GMWLSpectrum* spec = new GMWLSpectrum; - m_events = spec; - - // Load spectrum - spec->load(filename, extno); - - // Set attributes - name("Multi-wavelength observation"); - id(filename+"["+gammalib::str(extno)+"]"); - m_filename = filename; - m_extno = gammalib::str(extno); - m_instrument = spec->instrument(); - - // Return - return; -} - - -/***********************************************************************//** - * @brief Load observation - * - * @param[in] filename File name. - * @param[in] extname FITS extension name. - ***************************************************************************/ -void GMWLObservation::load(const std::string& filename, - const std::string& extname) -{ - // Clear observation - clear(); + // Create file name + GFilename fname(filename); // Allocate spectrum GMWLSpectrum* spec = new GMWLSpectrum; m_events = spec; // Load spectrum - spec->load(filename, extname); + if (fname.has_extno()) { + spec->load(filename); + m_extno = gammalib::str(fname.extno()); + id(filename+"["+m_extno+"]"); + } + else if (fname.has_extname()) { + spec->load(filename); + m_extname = fname.extname(); + id(filename+"["+m_extname+"]"); + } + else { + spec->load(filename); + id(filename); + } // Set attributes name("Multi-wavelength observation"); - id(filename+"["+extname+"]"); - m_filename = filename; - m_extname = extname; + m_filename = fname.filename(); m_instrument = spec->instrument(); // Return diff --git a/inst/mwl/src/GMWLSpectrum.cpp b/inst/mwl/src/GMWLSpectrum.cpp index c5f92c6..31f3abf 100644 --- a/inst/mwl/src/GMWLSpectrum.cpp +++ b/inst/mwl/src/GMWLSpectrum.cpp @@ -1,7 +1,7 @@ /*************************************************************************** * GMWLSpectrum.cpp - Multi-wavelength spectrum class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2013 by Juergen Knoedlseder * + * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -29,6 +29,7 @@ #include #endif #include "GTools.hpp" +#include "GFilename.hpp" #include "GFits.hpp" #include "GFitsTable.hpp" #include "GEnergy.hpp" @@ -259,70 +260,25 @@ GMWLSpectrum* GMWLSpectrum::clone(void) const ***************************************************************************/ void GMWLSpectrum::load(const std::string& filename) { - // Clear object - clear(); - - // Open FITS file - GFits file(filename); - - // Read spectrum - read(file); - - // Close FITS file - file.close(); - - // Return - return; -} - - -/***********************************************************************//** - * @brief Load spectrum from FITS file - * - * @param[in] filename FITS file name. - * @param[in] extname FITS extension name. - * - * This method loads a spectrum from the specified extension from a FITS - * file. - ***************************************************************************/ -void GMWLSpectrum::load(const std::string& filename, const std::string& extname) -{ - // Clear object - clear(); - - // Open FITS file - GFits file(filename); - - // Read spectrum from FITS file - read(file, extname); - - // Close FITS file - file.close(); - - // Return - return; -} + // Create file name + GFilename fname(filename); - -/***********************************************************************//** - * @brief Load spectrum from FITS file - * - * @param[in] filename FITS file name. - * @param[in] extno FITS extension number. - * - * This method loads a spectrum from the specified extension number from a - * FITS file. - ***************************************************************************/ -void GMWLSpectrum::load(const std::string& filename, const int& extno) -{ // Clear object clear(); // Open FITS file - GFits file(filename); + GFits file(fname.filename()); - // Read spectrum from FITS file - read(file, extno); + // Read spectrum + if (fname.has_extno()) { + read(file, fname.extno()); + } + else if (fname.has_extname()) { + read(file, fname.extname()); + } + else { + read(file); + } // Close FITS file file.close(); @@ -336,7 +292,7 @@ void GMWLSpectrum::load(const std::string& filename, const int& extno) * @brief Save spectrum * * @param[in] filename File name. - * @param[in] clobber Overwrite existing file (default=false). + * @param[in] clobber Overwrite existing file (default: false). * * @todo To be implemented. ***************************************************************************/ diff --git a/inst/mwl/test/test_MWL.cpp b/inst/mwl/test/test_MWL.cpp index 8235e2f..437f1b2 100644 --- a/inst/mwl/test/test_MWL.cpp +++ b/inst/mwl/test/test_MWL.cpp @@ -191,9 +191,9 @@ void TestGMWL::test_optimizer(void) test_try("Load multi-wavelength observations"); try { obs.clear(); - GMWLObservation comptel(crab_fits, "COMPTEL"); - GMWLObservation lat(crab_fits, "LAT"); - GMWLObservation hess(crab_fits, "HESS"); + GMWLObservation comptel(crab_fits+"[COMPTEL]"); + GMWLObservation lat(crab_fits+"[LAT]"); + GMWLObservation hess(crab_fits+"[HESS]"); obs.append(comptel); obs.append(lat); obs.append(hess); diff --git a/inst/mwl/test/test_python.py b/inst/mwl/test/test_python.py index bb9a6e6..39a9bea 100755 --- a/inst/mwl/test/test_python.py +++ b/inst/mwl/test/test_python.py @@ -2,8 +2,6 @@ import gammalib import math -#from gammalib import * -#from math import * import os @@ -29,7 +27,7 @@ def extract_data(filename): # Load spectrum spectrum = gammalib.GMWLSpectrum() - spectrum.load(filename, extno) + spectrum.load(filename+"["+str(extno)+"]") # Add spectral points x = [] @@ -66,9 +64,9 @@ def fit_spectrum(filename, xmlname): """ # Load observations obs = gammalib.GObservations() - comptel = gammalib.GMWLObservation(filename, "COMPTEL") - lat = gammalib.GMWLObservation(filename, "LAT") - hess = gammalib.GMWLObservation(filename, "HESS") + comptel = gammalib.GMWLObservation(filename+"[COMPTEL]") + lat = gammalib.GMWLObservation(filename+"[LAT]") + hess = gammalib.GMWLObservation(filename+"[HESS]") obs.append(comptel) obs.append(lat) obs.append(hess) diff --git a/pyext/GCsv.i b/pyext/GCsv.i index 08f01f0..3a9645c 100644 --- a/pyext/GCsv.i +++ b/pyext/GCsv.i @@ -1,5 +1,5 @@ /*************************************************************************** - * GCsv.i - Column separated values table class * + * GCsv.i - Comma-separated values table class * * ----------------------------------------------------------------------- * * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * @@ -20,7 +20,7 @@ ***************************************************************************/ /** * @file GCsv.hpp - * @brief Column separated values table class definition + * @brief Comma-separated values table class definition * @author Juergen Knoedlseder */ %{ @@ -80,7 +80,7 @@ static int csv_tuple(PyObject *input, int *ptr) { /***********************************************************************//** * @class GCsv * - * @brief Column separated values table class definition + * @brief Comma-separated values table class definition ***************************************************************************/ class GCsv : public GBase { public: diff --git a/pyext/GEbounds.i b/pyext/GEbounds.i index f1bc2ea..0625a84 100644 --- a/pyext/GEbounds.i +++ b/pyext/GEbounds.i @@ -39,13 +39,12 @@ class GEbounds : public GContainer { public: // Constructors and destructors GEbounds(void); - GEbounds(const GEbounds& ebds); + explicit GEbounds(const std::string& filename); explicit GEbounds(const GXmlElement& xml); + GEbounds(const GEbounds& ebds); GEbounds(const GEnergy& emin, const GEnergy& emax); GEbounds(const int& num, const GEnergy& emin, const GEnergy& emax, const bool& log = true); - GEbounds(const std::string& filename, - const std::string& extname = "EBOUNDS"); virtual ~GEbounds(void); // Methods @@ -63,11 +62,9 @@ public: void extend(const GEbounds& ebds); void set_lin(const int& num, const GEnergy& emin, const GEnergy& emax); void set_log(const int& num, const GEnergy& emin, const GEnergy& emax); - void load(const std::string& filename, - const std::string& extname = "EBOUNDS"); + void load(const std::string& filename); void save(const std::string& filename, const bool& clobber = false, - const std::string& extname = "EBOUNDS", const std::string& unit = "keV") const; void read(const GFitsTable& table); void write(GFits& file, diff --git a/pyext/GEnergies.i b/pyext/GEnergies.i index c51a1d2..44378a3 100644 --- a/pyext/GEnergies.i +++ b/pyext/GEnergies.i @@ -41,8 +41,7 @@ class GEnergies : public GContainer { public: // Constructors and destructors GEnergies(void); - GEnergies(const std::string& filename, - const std::string& extname = "ENERGIES"); + explicit GEnergies(const std::string& filename); GEnergies(const GEnergies& energies); GEnergies(const int& num, const GEnergy& emin, const GEnergy& emax, const bool& log = true); @@ -64,13 +63,12 @@ public: const GEnergy& emax); void set_log(const int& num, const GEnergy& emin, const GEnergy& emax); - void load(const std::string& filename, - const std::string& extname = "ENERGIES"); + void load(const std::string& filename); void save(const std::string& filename, - const bool& clobber = false, - const std::string& extname = "ENERGIES") const; + const bool& clobber = false) const; void read(const GFitsTable& table); - void write(GFits& file, const std::string& extname = "ENERGIES") const; + void write(GFits& file, + const std::string& extname = "ENERGIES") const; }; diff --git a/pyext/GFilename.i b/pyext/GFilename.i new file mode 100644 index 0000000..312310a --- /dev/null +++ b/pyext/GFilename.i @@ -0,0 +1,71 @@ +/*************************************************************************** + * GFilename.i - Filename class * + * ----------------------------------------------------------------------- * + * copyright (C) 2015 by Juergen Knoedlseder * + * ----------------------------------------------------------------------- * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ +/** + * @file GFilename.i + * @brief Filename class interface definition + * @author Juergen Knoedlseder + */ +%{ +/* Put headers and other declarations here that are needed for compilation */ +#include "GFilename.hpp" +%} + + +/***********************************************************************//** + * @class GFilename + * + * @brief Filename class + ***************************************************************************/ +class GFilename : public GBase { + +public: + // Constructors and destructors + GFilename(void); + GFilename(const std::string& filename); + GFilename(const GFilename& filename); + GFilename(const char* filename); + virtual ~GFilename(void); + + // Methods + void clear(void); + GFilename* clone(void) const; + std::string classname(void) const; + bool empty(void) const; + int size(void) const; + int length(void) const; + const std::string& filename(void) const; + std::string extname(const std::string& defaultname = "") const; + int extno(const int& defaultno = -1) const; + int extver(const int& defaultver = 0) const; + bool has_extname(void) const; + bool has_extno(void) const; + bool has_extver(void) const; +}; + + +/***********************************************************************//** + * @brief GFilename class extension + ***************************************************************************/ +%extend GFilename { + GFilename copy() { + return (*self); + } +}; diff --git a/pyext/GFitsTableBitCol.i b/pyext/GFitsTableBitCol.i index 009db88..ce1acf6 100644 --- a/pyext/GFitsTableBitCol.i +++ b/pyext/GFitsTableBitCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableBitCol { bool __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], bool value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableBitCol copy() { return (*self); diff --git a/pyext/GFitsTableBoolCol.i b/pyext/GFitsTableBoolCol.i index de5644e..82a9459 100644 --- a/pyext/GFitsTableBoolCol.i +++ b/pyext/GFitsTableBoolCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableBoolCol { bool __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], bool value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableBoolCol copy() { return (*self); diff --git a/pyext/GFitsTableByteCol.i b/pyext/GFitsTableByteCol.i index 7b76d39..da3049b 100644 --- a/pyext/GFitsTableByteCol.i +++ b/pyext/GFitsTableByteCol.i @@ -70,16 +70,44 @@ public: ***************************************************************************/ %extend GFitsTableByteCol { unsigned char __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], unsigned char value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableByteCol copy() { return (*self); diff --git a/pyext/GFitsTableCDoubleCol.i b/pyext/GFitsTableCDoubleCol.i index 41679fd..79d258f 100644 --- a/pyext/GFitsTableCDoubleCol.i +++ b/pyext/GFitsTableCDoubleCol.i @@ -75,17 +75,45 @@ public: %extend GFitsTableCDoubleCol { /* GFits::cdouble __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } */ void __setitem__(int GFitsTableColInx[], GFits::cdouble value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableCDoubleCol copy() { return (*self); diff --git a/pyext/GFitsTableCFloatCol.i b/pyext/GFitsTableCFloatCol.i index ef53980..24d0d59 100644 --- a/pyext/GFitsTableCFloatCol.i +++ b/pyext/GFitsTableCFloatCol.i @@ -75,17 +75,45 @@ public: %extend GFitsTableCFloatCol { /* GFits::cfloat __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } */ void __setitem__(int GFitsTableColInx[], GFits::cfloat value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableCFloatCol copy() { return (*self); diff --git a/pyext/GFitsTableDoubleCol.i b/pyext/GFitsTableDoubleCol.i index d149bc0..48247a8 100644 --- a/pyext/GFitsTableDoubleCol.i +++ b/pyext/GFitsTableDoubleCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableDoubleCol { double __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], double value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableDoubleCol copy() { return (*self); diff --git a/pyext/GFitsTableFloatCol.i b/pyext/GFitsTableFloatCol.i index e9f6d79..d03cb55 100644 --- a/pyext/GFitsTableFloatCol.i +++ b/pyext/GFitsTableFloatCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableFloatCol { float __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], float value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableFloatCol copy() { return (*self); diff --git a/pyext/GFitsTableLongCol.i b/pyext/GFitsTableLongCol.i index 232140c..072475c 100644 --- a/pyext/GFitsTableLongCol.i +++ b/pyext/GFitsTableLongCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableLongCol { long __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], long value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableLongCol copy() { return (*self); diff --git a/pyext/GFitsTableLongLongCol.i b/pyext/GFitsTableLongLongCol.i index e543163..1c35914 100644 --- a/pyext/GFitsTableLongLongCol.i +++ b/pyext/GFitsTableLongLongCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableLongLongCol { long long __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], long long value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableLongLongCol copy() { return (*self); diff --git a/pyext/GFitsTableShortCol.i b/pyext/GFitsTableShortCol.i index 9bba82e..88583bf 100644 --- a/pyext/GFitsTableShortCol.i +++ b/pyext/GFitsTableShortCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableShortCol { short __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], short value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableShortCol copy() { return (*self); diff --git a/pyext/GFitsTableStringCol.i b/pyext/GFitsTableStringCol.i index 71085bd..d05b8d4 100644 --- a/pyext/GFitsTableStringCol.i +++ b/pyext/GFitsTableStringCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableStringCol { std::string __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], std::string value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableStringCol copy() { return (*self); diff --git a/pyext/GFitsTableULongCol.i b/pyext/GFitsTableULongCol.i index 075debb..03c16e0 100644 --- a/pyext/GFitsTableULongCol.i +++ b/pyext/GFitsTableULongCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableULongCol { unsigned long __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], unsigned long value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableULongCol copy() { return (*self); diff --git a/pyext/GFitsTableUShortCol.i b/pyext/GFitsTableUShortCol.i index fb477c6..23b3ea1 100644 --- a/pyext/GFitsTableUShortCol.i +++ b/pyext/GFitsTableUShortCol.i @@ -71,16 +71,44 @@ public: ***************************************************************************/ %extend GFitsTableUShortCol { unsigned short __getitem__(int GFitsTableColInx[]) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__getitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { return (*self)(GFitsTableColInx[1]); - else - return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + if (GFitsTableColInx[2] >= 0 && + GFitsTableColInx[2] < self->elements(GFitsTableColInx[1])) { + return (*self)(GFitsTableColInx[1], GFitsTableColInx[2]); + } + else { + throw GException::out_of_range("__getitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } void __setitem__(int GFitsTableColInx[], unsigned short value) { - if (GFitsTableColInx[0] == 1) + if (GFitsTableColInx[1] < 0 || GFitsTableColInx[1] >= self->length()) { + throw GException::out_of_range("__setitem__()", "Row index", + GFitsTableColInx[1], self->length()); + } + if (GFitsTableColInx[0] == 1) { (*self)(GFitsTableColInx[1]) = value; - else - (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + if (GFitsTableColInx[2] >= 0 && GFitsTableColInx[2] < + self->elements(GFitsTableColInx[1])) { + (*self)(GFitsTableColInx[1], GFitsTableColInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__()", "Column index", + GFitsTableColInx[2], + self->elements(GFitsTableColInx[1])); + } + } } GFitsTableUShortCol copy() { return (*self); diff --git a/pyext/GGti.i b/pyext/GGti.i index 4421b3d..82fec3f 100644 --- a/pyext/GGti.i +++ b/pyext/GGti.i @@ -36,9 +36,11 @@ * @brief Good Time Interval class ***************************************************************************/ class GGti : public GBase { + public: // Constructors and destructors GGti(void); + explicit GGti(const std::string& filename); GGti(const GGti& gti); GGti(const GTime& tstart, const GTime& tstop); explicit GGti(const GXmlElement& xml); @@ -59,11 +61,9 @@ public: void remove(const int& index); void reserve(const int& num); void extend(const GGti& gti); - void load(const std::string& filename, - const std::string& extname = "GTI"); + void load(const std::string& filename); void save(const std::string& filename, - const bool& clobber = false, - const std::string& extname = "GTI") const; + const bool& clobber = false) const; void read(const GFitsTable& table); void write(GFits& file, const std::string& extname = "GTI") const; diff --git a/pyext/GModel.i b/pyext/GModel.i index 7814004..e7cce46 100644 --- a/pyext/GModel.i +++ b/pyext/GModel.i @@ -72,6 +72,7 @@ public: void ts(const double& ts); const bool& tscalc(void) const; void tscalc(const bool& tscalc); + const bool& has_ts(void) const; GModelPar scale(const std::string& instrument) const; void scale(const GModelPar& par); std::string ids(void) const; diff --git a/pyext/GNodeArray.i b/pyext/GNodeArray.i index 9820a67..76285cb 100644 --- a/pyext/GNodeArray.i +++ b/pyext/GNodeArray.i @@ -39,12 +39,14 @@ namespace std { * @brief Node array class ***************************************************************************/ class GNodeArray : public GContainer { + public: // Constructors and destructors GNodeArray(void); - GNodeArray(const int& num, const double* array); + explicit GNodeArray(const std::string& filename); explicit GNodeArray(const GVector& vector); explicit GNodeArray(const std::vector& vector); + GNodeArray(const int& num, const double* array); GNodeArray(const GNodeArray& array); virtual ~GNodeArray(void); @@ -70,10 +72,9 @@ public: const int& inx_right(void) const; const double& wgt_left(void) const; const double& wgt_right(void) const; - void load(const std::string& filename, - const std::string& extname = "NODES"); - void save(const std::string& filename, const bool& clobber = false, - const std::string& extname = "NODES") const; + void load(const std::string& filename); + void save(const std::string& filename, + const bool& clobber = false) const; void read(const GFitsTable& table); void write(GFits& file, const std::string& extname = "NODES") const; diff --git a/pyext/GSkyMap.i b/pyext/GSkyMap.i index 50f3dce..1922686 100644 --- a/pyext/GSkyMap.i +++ b/pyext/GSkyMap.i @@ -183,11 +183,21 @@ public: ***************************************************************************/ %extend GSkyMap { double __getitem__(int GSkyMapInx[]) { + if (GSkyMapInx[1] < 0 || GSkyMapInx[1] >= self->npix()) { + throw GException::out_of_range("__getitem__(int)", "Sky map index", + GSkyMapInx[1], self->npix()); + } if (GSkyMapInx[0] == 1) { return (*self)(GSkyMapInx[1]); } else { - return (*self)(GSkyMapInx[1], GSkyMapInx[2]); + if (GSkyMapInx[2] >= 0 && GSkyMapInx[2] < self->nmaps()) { + return (*self)(GSkyMapInx[1], GSkyMapInx[2]); + } + else { + throw GException::out_of_range("__getitem__(int)", "Sky map number", + GSkyMapInx[2], self->nmaps()); + } } } /* @@ -196,11 +206,21 @@ public: } */ void __setitem__(int GSkyMapInx[], double value) { + if (GSkyMapInx[1] < 0 || GSkyMapInx[1] >= self->npix()) { + throw GException::out_of_range("__setitem__(int)", "Sky map index", + GSkyMapInx[1], self->npix()); + } if (GSkyMapInx[0] == 1) { (*self)(GSkyMapInx[1]) = value; } else { - (*self)(GSkyMapInx[1], GSkyMapInx[2]) = value; + if (GSkyMapInx[2] >= 0 && GSkyMapInx[2] < self->nmaps()) { + (*self)(GSkyMapInx[1], GSkyMapInx[2]) = value; + } + else { + throw GException::out_of_range("__setitem__(int)", "Sky map number", + GSkyMapInx[2], self->nmaps()); + } } } /* diff --git a/pyext/GSkyRegions.i b/pyext/GSkyRegions.i index da4fa33..5cf426a 100644 --- a/pyext/GSkyRegions.i +++ b/pyext/GSkyRegions.i @@ -50,15 +50,11 @@ public: int size(void) const; bool is_empty(void) const; GSkyRegion* set(const int& index, const GSkyRegion& region); - GSkyRegion* set(const std::string& name, const GSkyRegion& region); GSkyRegion* append(const GSkyRegion& region); GSkyRegion* insert(const int& index, const GSkyRegion& region); - GSkyRegion* insert(const std::string& name, const GSkyRegion& region); void remove(const int& index); - void remove(const std::string& name); void reserve(const int& num); void extend(const GSkyRegions& regions); - bool contains(const std::string& name) const; void load(const std::string& filename); void save(const std::string& filename) const; diff --git a/pyext/GTools.i b/pyext/GTools.i index 3974d55..4408977 100644 --- a/pyext/GTools.i +++ b/pyext/GTools.i @@ -63,6 +63,7 @@ namespace gammalib { const double& gamma); GEnergy elogmean(const GEnergy& a, const GEnergy& b); bool file_exists(const std::string& filename); + bool file_exists_gzip(const std::string& filename); bool dir_exists(const std::string& dirname); bool is_infinite(const double& x); bool is_notanumber(const double& x); @@ -84,4 +85,6 @@ namespace gammalib { void xml_check_par(const std::string& origin, const std::string& name, const int& number); + int recv(int fd, char *buffer, int len, int flags, + int timeout); } diff --git a/pyext/Makefile.am b/pyext/Makefile.am index 016c721..f086e52 100755 --- a/pyext/Makefile.am +++ b/pyext/Makefile.am @@ -51,7 +51,7 @@ INST_SWIG_TARGETS = $(MWL_SWIG_TARGETS) \ $(LAT_SWIG_TARGETS) \ $(COM_SWIG_TARGETS) -# Test scripts to be distributed in $(pyexecdir)/ctools/tests +# Test scripts to be distributed in $(pyexecdir)/gammalib/tests testscripts = gammalib/tests/__init__.py \ ../test/test_python.py \ ../test/test_GApplication.py \ @@ -139,6 +139,14 @@ all-local: build # Build the gammalib extension module build: $(BUILT_SOURCES) @PYTHON_BUILD_PREFIX@ $(PYTHON) setup.py build_ext +if IS_ELCAPITAN + -for f in build/gammalib/_*.so; do \ + echo "Post process module "$$f; \ + install_name_tool -change $(libdir)/libgamma.1.dylib @rpath/libgamma.1.dylib $$f; \ + install_name_tool -add_rpath $(libdir) $$f; \ + install_name_tool -add_rpath $(abs_top_srcdir)/src/.libs $$f; \ + done +endif # Do nothing for 'make check' #check-local: diff --git a/pyext/gammalib/support.i b/pyext/gammalib/support.i index 8ce4520..1dfdf09 100644 --- a/pyext/gammalib/support.i +++ b/pyext/gammalib/support.i @@ -71,3 +71,4 @@ %include "GUrl.i" %include "GUrlFile.i" %include "GUrlString.i" +%include "GFilename.i" diff --git a/pyext/setup.py.in b/pyext/setup.py.in index 35a9565..f60da80 100644 --- a/pyext/setup.py.in +++ b/pyext/setup.py.in @@ -1,7 +1,7 @@ ############################################################################# # Disutils setup file for gammalib Python extension module # # ------------------------------------------------------------------------- # -# Copyright (C) 2011-2014 Juergen Knoedlseder # +# Copyright (C) 2011-2015 Juergen Knoedlseder # # ------------------------------------------------------------------------- # # # # This program is free software: you can redistribute it and/or modify # @@ -139,6 +139,10 @@ else: extra_compile_args = [] extra_link_args = [] +# Optionally add link flag for El Capitan post-processing of modules +if '@IS_ELCAPITAN_TRUE@' != '#': + extra_link_args.append('-headerpad_max_install_names') + # Loop over all core modules for module in core_modules: @@ -225,19 +229,20 @@ for name in casts: names += "'"+name+"'" n_names += 1 -# Create gammalib/__init__.py file -file = open(pkg_name+'/__init__.py', 'w') -file.write('# This file is created automatically by setup.py\n') -file.write('# Please do not modify, unless you exactly know what you do.\n') -file.write('__all__ = [') -file.write(names) -file.write(']\n') -for module in all_modules: - file.write('from gammalib.'+module+' import *\n') - -# Remove useless and annoying `*_swigregister` entries from the namespace -# see https://cta-redmine.irap.omp.eu/issues/832 -file.write(""" +# Create gammalib/__init__.py file (build only) +if is_build: + file = open(pkg_name+'/__init__.py', 'w') + file.write('# This file is created automatically by setup.py\n') + file.write('# Please do not modify, unless you exactly know what you do.\n') + file.write('__all__ = [') + file.write(names) + file.write(']\n') + for module in all_modules: + file.write('from gammalib.'+module+' import *\n') + + # Remove useless and annoying `*_swigregister` entries from the namespace + # see https://cta-redmine.irap.omp.eu/issues/832 + file.write(""" bad_entries = [entry for entry in list(locals()) if entry.endswith('_swigregister')] for entry in bad_entries: @@ -245,14 +250,19 @@ for entry in bad_entries: del gammalib.gammalib """) -# Add test function -# see https://cta-redmine.irap.omp.eu/issues/1486 -file.write(""" + # Add test function + # see https://cta-redmine.irap.omp.eu/issues/1486 + file.write(""" def test(): from gammalib.tests import test_python test_python.test(installed=True) """) -file.close() + + # Add version + file.write("\n__version__ = '@PACKAGE_VERSION@'\n") + + # Close file + file.close() # Set data files to install. data_files=[('@prefix@/share/gammalib/swig', install_files)] diff --git a/src/obs/GEbounds.cpp b/src/obs/GEbounds.cpp index 913df86..4b6fa93 100644 --- a/src/obs/GEbounds.cpp +++ b/src/obs/GEbounds.cpp @@ -29,9 +29,9 @@ #include #endif #include -//#include #include "GException.hpp" #include "GTools.hpp" +#include "GFilename.hpp" #include "GEbounds.hpp" #include "GFits.hpp" #include "GFitsTable.hpp" @@ -77,17 +77,19 @@ GEbounds::GEbounds(void) /***********************************************************************//** - * @brief Copy constructor + * @brief FITS file constructor * - * @param[in] ebds Energy boundaries. + * @param[in] filename FITS file name. + * + * Constructs energy boundaries from a FITS file. ***************************************************************************/ -GEbounds::GEbounds(const GEbounds& ebds) +GEbounds::GEbounds(const std::string& filename) { - // Initialise class members for clean destruction + // Initialise members init_members(); - // Copy members - copy_members(ebds); + // Load FITS file + load(filename); // Return return; @@ -99,7 +101,7 @@ GEbounds::GEbounds(const GEbounds& ebds) * * @param[in] xml XML element. * - * Constructs energy bounds from an XML element. + * Constructs energy boundaries from an XML element. ***************************************************************************/ GEbounds::GEbounds(const GXmlElement& xml) { @@ -115,12 +117,30 @@ GEbounds::GEbounds(const GXmlElement& xml) /***********************************************************************//** + * @brief Copy constructor + * + * @param[in] ebds Energy boundaries. + ***************************************************************************/ +GEbounds::GEbounds(const GEbounds& ebds) +{ + // Initialise class members for clean destruction + init_members(); + + // Copy members + copy_members(ebds); + + // Return + return; +} + + +/***********************************************************************//** * @brief Single energy band constructor * * @param[in] emin Minimum energy of the interval. * @param[in] emax Maximum energy of the interval. * - * Constructs energy bounds for one (emin, emax) energy band. + * Constructs energy boundaries for one (emin, emax) energy band. ***************************************************************************/ GEbounds::GEbounds(const GEnergy& emin, const GEnergy& emax) { @@ -167,25 +187,6 @@ GEbounds::GEbounds(const int& num, const GEnergy& emin, const GEnergy& emax, /***********************************************************************//** - * @brief Load constructor - * - * @param[in] filename FITS filename. - * @param[in] extname FITS extension name (defaults to "EBOUNDS"). - ***************************************************************************/ -GEbounds::GEbounds(const std::string& filename, const std::string& extname) -{ - // Initialise members - init_members(); - - // Load FITS file - load(filename, extname); - - // Return - return; -} - - -/***********************************************************************//** * @brief Destructor ***************************************************************************/ GEbounds::~GEbounds(void) @@ -568,21 +569,26 @@ void GEbounds::set_log(const int& num, const GEnergy& emin, const GEnergy& emax) /***********************************************************************//** * @brief Load energy boundaries from FITS file * - * @param[in] filename FITS filename. - * @param[in] extname FITS extension name (defaults to "EBOUNDS"). + * @param[in] filename FITS file name. * - * Loads the energy boundaries from FITS file. + * Loads the energy boundaries from a FITS file. + * + * If no extension name is provided, the energy boundaries are loaded from + * the "EBOUNDS" extension. ***************************************************************************/ -void GEbounds::load(const std::string& filename, const std::string& extname) +void GEbounds::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Open FITS file - file.open(filename); + file.open(fname.filename()); // Get energy boundary table - const GFitsTable& table = *file.table(extname); + const GFitsTable& table = *file.table(fname.extname("EBOUNDS")); // Read energy boundaries from table read(table); @@ -598,26 +604,30 @@ void GEbounds::load(const std::string& filename, const std::string& extname) /***********************************************************************//** * @brief Save energy boundaries into FITS file * - * @param[in] filename FITS filename. - * @param[in] clobber Overwrite any existing file (defaults to false)? - * @param[in] extname Energy boundary extension name (defaults to "EBOUNDS"). - * @param[in] unit Energy units (defaults to "keV") + * @param[in] filename FITS file name. + * @param[in] clobber Overwrite any existing file (default: false)? + * @param[in] unit Energy units (default: "keV") * - * Saves the energy boundaries into extension @p extname of a FITS file. + * Saves energy boundaries into a FITS file. + * + * If no extension name is provided, the energy boundaries are saved into + * an "EBOUNDS" extension. ***************************************************************************/ void GEbounds::save(const std::string& filename, const bool& clobber, - const std::string& extname, const std::string& unit) const { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Write energy boundaries to FITS file - write(file, extname, unit); + write(file, fname.extname("EBOUNDS"), unit); // Save to file - file.saveto(filename, clobber); + file.saveto(fname.filename(), clobber); // Return return; diff --git a/src/obs/GEnergies.cpp b/src/obs/GEnergies.cpp index 1ce4ee9..bb29869 100644 --- a/src/obs/GEnergies.cpp +++ b/src/obs/GEnergies.cpp @@ -30,6 +30,7 @@ #endif #include "GTools.hpp" #include "GException.hpp" +#include "GFilename.hpp" #include "GEnergies.hpp" #include "GFits.hpp" #include "GFitsTable.hpp" @@ -71,20 +72,19 @@ GEnergies::GEnergies(void) /***********************************************************************//** - * @brief Load constructor + * @brief FITS file constructor * - * @param[in] filename FITS filename. - * @param[in] extname Energies extension name (defaults to "ENERGIES") + * @param[in] filename FITS file name. * - * Constructs energy container by loading energies from FITS file. + * Constructs energy container from a FITS file. ***************************************************************************/ -GEnergies::GEnergies(const std::string& filename, const std::string& extname) +GEnergies::GEnergies(const std::string& filename) { // Initialise members init_members(); // Load energies - load(filename, extname); + load(filename); // Return return; @@ -534,21 +534,26 @@ void GEnergies::set_log(const int& num, /***********************************************************************//** * @brief Load energies from FITS file * - * @param[in] filename FITS filename. - * @param[in] extname Energies extension name (defaults to "ENERGIES") + * @param[in] filename FITS file name. * * Loads the energies from FITS file. + * + * If no extension name is provided, the energies are loaded from the + * "ENERGIES" extension. ***************************************************************************/ -void GEnergies::load(const std::string& filename, const std::string& extname) +void GEnergies::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Open FITS file - file.open(filename); + file.open(fname.filename()); // Get energies table - const GFitsTable& table = *file.table(extname); + const GFitsTable& table = *file.table(fname.extname("ENERGIES")); // Read energies from table read(table); @@ -566,24 +571,25 @@ void GEnergies::load(const std::string& filename, const std::string& extname) * * @param[in] filename FITS filename. * @param[in] clobber Overwrite any existing energies extension? - * @param[in] extname Energies extension name (defaults to "ENERGIES") * - * Saves energies into extension @p extname of a FITS file. If the file does - * not exist it is created. If the file exists the energies are appended as - * extension. If another energies extension exists already it is overwritten - * if @p clobber=true. + * Saves energies into a FITS file. + * + * If no extension name is provided, the energies are saved into an + * "ENERGIES" extension. ***************************************************************************/ -void GEnergies::save(const std::string& filename, const bool& clobber, - const std::string& extname) const +void GEnergies::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Write energies to FITS file - write(file, extname); + write(file, fname.extname("ENERGIES")); // Save to file - file.saveto(filename, clobber); + file.saveto(fname.filename(), clobber); // Return return; @@ -637,7 +643,7 @@ void GEnergies::read(const GFitsTable& table) * @brief Write energies into FITS object * * @param[in] file FITS file. - * @param[in] extname Energy extension name (defaults to "ENERGIES") + * @param[in] extname Energy extension name (default: "ENERGIES") * * Writes energies into FITS object. ***************************************************************************/ diff --git a/src/obs/GGti.cpp b/src/obs/GGti.cpp index 007c810..5b2b736 100644 --- a/src/obs/GGti.cpp +++ b/src/obs/GGti.cpp @@ -30,6 +30,7 @@ #endif #include "GException.hpp" #include "GTools.hpp" +#include "GFilename.hpp" #include "GGti.hpp" #include "GFits.hpp" #include "GFitsTable.hpp" @@ -73,6 +74,26 @@ GGti::GGti(void) /***********************************************************************//** + * @brief FITS file constructor + * + * @param[in] filename FITS file name. + * + * Constructs Good Time Intervals from a FITS file. + ***************************************************************************/ +GGti::GGti(const std::string& filename) +{ + // Initialise members + init_members(); + + // Load FITS file + load(filename); + + // Return + return; +} + + +/***********************************************************************//** * @brief Copy constructor * * @param[in] gti Good Time Intervals. @@ -551,20 +572,25 @@ void GGti::extend(const GGti& gti) * @brief Load Good Time Intervals from FITS file * * @param[in] filename FITS filename. - * @param[in] extname GTI extension name (defaults to "GTI") * * Loads the Good Time Intervals from FITS file. + * + * If no extension name is provided, the energy boundaries are loaded from + * the "GTI" extension. ***************************************************************************/ -void GGti::load(const std::string& filename, const std::string& extname) +void GGti::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Open FITS file - file.open(filename); + file.open(fname.filename()); // Get GTI table - const GFitsTable& table = *file.table(extname); + const GFitsTable& table = *file.table(fname.extname("GTI")); // Read GTI from table read(table); @@ -582,24 +608,25 @@ void GGti::load(const std::string& filename, const std::string& extname) * * @param[in] filename FITS filename. * @param[in] clobber Overwrite any existing GTI extension? - * @param[in] extname GTI extension name (defaults to "GTI") * - * Saves Good Time Intervals into extension @p extname of a FITS file. If the - * file does not exist it is created. If the file exists the GTI is appended - * as extension. If another GTI exists already it is overwritten if - * @p clobber=true. + * Saves Good Time Intervals into a FITS file. + * + * If no extension name is provided, the Good Time Intervals are saved into + * an "GTI" extension. ***************************************************************************/ -void GGti::save(const std::string& filename, const bool& clobber, - const std::string& extname) const +void GGti::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Write GTI to FITS file - write(file, extname); + write(file, fname.extname("GTI")); // Save to file - file.saveto(filename, clobber); + file.saveto(fname.filename(), clobber); // Return return; diff --git a/src/sky/GSkyRegions.cpp b/src/sky/GSkyRegions.cpp index 006837a..29de588 100644 --- a/src/sky/GSkyRegions.cpp +++ b/src/sky/GSkyRegions.cpp @@ -159,58 +159,6 @@ GSkyRegions& GSkyRegions::operator=(const GSkyRegions& regions) } -/***********************************************************************//** - * @brief Return pointer to region - * - * @param[in] name region name. - * - * @exception GException::invalid_argument - * region with specified name not found in container. - * - * Returns a pointer to the region with the specified @p name. - ***************************************************************************/ -GSkyRegion* GSkyRegions::operator[](const std::string& name) -{ - // Get region index - int index = get_index(name); - - // Throw exception if region name was not found - if (index == -1) { - std::string msg ="Region with name \""+name+"\" not found in container."; - throw GException::invalid_argument(G_ACCESS, msg); - } - - // Return pointer - return m_regions[index]; -} - - -/***********************************************************************//** - * @brief Return pointer to region (const version) - * - * @param[in] name region name. - * - * @exception GException::invalid_argument - * region with specified name not found in container. - * - * Returns a const pointer to the region with the specified @p name. - ***************************************************************************/ -const GSkyRegion* GSkyRegions::operator[](const std::string& name) const -{ - // Get region index - int index = get_index(name); - - // Throw exception if region name was not found - if (index == -1) { - std::string msg ="Region with name \""+name+"\" not found in container."; - throw GException::invalid_argument(G_ACCESS, msg); - } - - // Return pointer - return m_regions[index]; -} - - /*========================================================================== = = = Public methods = @@ -315,65 +263,6 @@ GSkyRegion* GSkyRegions::set(const int& index, const GSkyRegion& region) } #endif - // Check if a region with specified name does not yet exist - int inx = get_index(region.name()); - if (inx != -1 && inx != index) { - std::string msg = - "Attempt to set region with name \""+region.name()+"\" in region" - " container at index "+gammalib::str(index)+", but a region with" - " the same name exists already at index "+gammalib::str(inx)+ - " in the container.\n" - "Every region in the region container needs a unique name."; - throw GException::invalid_value(G_SET1, msg); - } - - // Delete any existing region - if (m_regions[index] != NULL) delete m_regions[index]; - - // Assign new region by cloning - m_regions[index] = region.clone(); - - // Return pointer to region - return m_regions[index]; -} - - -/***********************************************************************//** - * @brief Set region in container - * - * @param[in] name region name. - * @param[in] region region pointer. - * @return Pointer to deep copy of region. - * - * @exception GException::invalid_argument - * region with specified name not found in container. - * @exception GException::invalid_value - * Name of region exists already in container. - * - * Set region in the container. A deep copy of the region will be made. - ***************************************************************************/ -GSkyRegion* GSkyRegions::set(const std::string& name, const GSkyRegion& region) -{ - // Get parameter index - int index = get_index(name); - - // Throw exception if parameter name was not found - if (index == -1) { - throw GException::invalid_argument(G_SET2, name); - } - - // Check if a region with specified name does not yet exist - int inx = get_index(region.name()); - if (inx != -1 && inx != index) { - std::string msg = - "Attempt to set region with name \""+region.name()+"\" in region" - " container at index "+gammalib::str(index)+", but a region with" - " the same name exists already at index "+gammalib::str(inx)+ - " in the container.\n" - "Every region in the region container needs a unique name."; - throw GException::invalid_value(G_SET2, msg); - } - // Delete any existing region if (m_regions[index] != NULL) delete m_regions[index]; @@ -399,17 +288,6 @@ GSkyRegion* GSkyRegions::set(const std::string& name, const GSkyRegion& region) ***************************************************************************/ GSkyRegion* GSkyRegions::append(const GSkyRegion& region) { - // Check if a region with specified name does not yet exist - int inx = get_index(region.name()); - if (inx != -1) { - std::string msg = - "Attempt to append region with name \""+region.name()+"\" to region" - " container, but a region with the same name exists already at" - " index "+gammalib::str(inx)+" in the container.\n" - "Every region in the region container needs a unique name."; - throw GException::invalid_value(G_APPEND, msg); - } - // Create deep copy of region GSkyRegion* ptr = region.clone(); @@ -452,66 +330,6 @@ GSkyRegion* GSkyRegions::insert(const int& index, const GSkyRegion& region) } #endif - // Check if a region with specified name does not yet exist - int inx = get_index(region.name()); - if (inx != -1) { - std::string msg = - "Attempt to insert region with name \""+region.name()+"\" in region" - " container before index "+gammalib::str(index)+", but a region" - " with the same name exists already at index "+gammalib::str(inx)+ - " in the container.\n" - "Every region in the region container needs a unique name."; - throw GException::invalid_value(G_INSERT1, msg); - } - - // Create deep copy of region - GSkyRegion* ptr = region.clone(); - - // Inserts deep copy of region - m_regions.insert(m_regions.begin()+index, ptr); - - // Return pointer to region - return ptr; -} - - -/***********************************************************************//** - * @brief Insert region into container - * - * @param[in] name region name. - * @param[in] region region. - * @return Pointer to deep copy of region. - * - * @exception GException::invalid_argument - * region with specified name not found in container. - * @exception GException::invalid_value - * Name of region exists already in container. - * - * Inserts a @p region into the container before the region with the specified - * @p name. - ***************************************************************************/ -GSkyRegion* GSkyRegions::insert(const std::string& name, const GSkyRegion& region) -{ - // Get parameter index - int index = get_index(name); - - // Throw exception if parameter name was not found - if (index == -1) { - throw GException::invalid_argument(G_INSERT2, name); - } - - // Check if a region with specified name does not yet exist - int inx = get_index(region.name()); - if (inx != -1) { - std::string msg = - "Attempt to insert region with name \""+region.name()+"\" in region" - " container before index "+gammalib::str(index)+", but a region" - " with the same name exists already at index "+gammalib::str(inx)+ - " in the container.\n" - "Every region in the region container needs a unique name."; - throw GException::invalid_value(G_INSERT2, msg); - } - // Create deep copy of region GSkyRegion* ptr = region.clone(); @@ -554,37 +372,6 @@ void GSkyRegions::remove(const int& index) /***********************************************************************//** - * @brief Remove region from container - * - * @param[in] name region name. - * - * @exception GException::invalid_argument - * region with specified name not found in container. - * - * Remove region of specified @p name from container. - ***************************************************************************/ -void GSkyRegions::remove(const std::string& name) -{ - // Get parameter index - int index = get_index(name); - - // Throw exception if region name was not found - if (index == -1) { - throw GException::invalid_argument(G_REMOVE2, name); - } - - // Delete region - delete m_regions[index]; - - // Erase region component from container - m_regions.erase(m_regions.begin() + index); - - // Return - return; -} - - -/***********************************************************************//** * @brief Append region container * * @param[in] regions region container. @@ -607,18 +394,6 @@ void GSkyRegions::extend(const GSkyRegions& regions) // Loop over all region components and append pointers to deep copies for (int i = 0; i < num; ++i) { - // Check if region name does not yet exist - int inx = get_index(regions[i]->name()); - if (inx != -1) { - std::string msg = - "Attempt to append region with name \""+regions[i]->name()+ - "\" to region container, but a region with the same name" - " exists already at index "+gammalib::str(inx)+" in the" - " container.\n" - "Every region in the region container needs a unique name."; - throw GException::invalid_value(G_EXTEND, msg); - } - // Append region to container m_regions.push_back(regions[i]->clone()); @@ -632,25 +407,6 @@ void GSkyRegions::extend(const GSkyRegions& regions) /***********************************************************************//** - * @brief Signals if region name exists - * - * @param[in] name region name. - * @return True if region with specified @p name exists. - * - * Searches all region names for a match with the specified @p name. If the - * specified name has been found, true is returned. - ***************************************************************************/ -bool GSkyRegions::contains(const std::string& name) const -{ - // Get region index - int index = get_index(name); - - // Return - return (index != -1); -} - - -/***********************************************************************//** * @brief Load regions from DS9 region file * * @param[in] filename DS9 region filename. @@ -931,29 +687,3 @@ void GSkyRegions::free_members(void) return; } - -/***********************************************************************//** - * @brief Return region index by name - * - * @param[in] name region name. - * @return region index (-1 if region name has not been found) - * - * Returns region index based on the specified @p name. If no region with the - * specified @p name is found the method returns -1. - ***************************************************************************/ -int GSkyRegions::get_index(const std::string& name) const -{ - // Initialise index - int index = -1; - - // Search region with specified name - for (int i = 0; i < size(); ++i) { - if (m_regions[i]->name() == name) { - index = i; - break; - } - } - - // Return index - return index; -} diff --git a/src/support/GCsv.cpp b/src/support/GCsv.cpp index f7e2a73..0c3c13a 100644 --- a/src/support/GCsv.cpp +++ b/src/support/GCsv.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * GCsv.cpp - Column separated values table class * + * GCsv.cpp - Comma-separated values table class * * ----------------------------------------------------------------------- * * copyright (C) 2010-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * @@ -20,7 +20,7 @@ ***************************************************************************/ /** * @file GCsv.cpp - * @brief Column separated values table class implementation + * @brief Comma-separated values table class implementation * @author Juergen Knoedlseder */ @@ -112,7 +112,7 @@ GCsv::GCsv(const std::string& filename, const std::string& sep) /***********************************************************************//** * @brief Copy constructor * - * @param[in] csv Column separated values table. + * @param[in] csv Comma-separated values table. ***************************************************************************/ GCsv::GCsv(const GCsv& csv) { @@ -149,8 +149,8 @@ GCsv::~GCsv(void) /***********************************************************************//** * @brief Assignment operator * - * @param[in] csv Column separated values table. - * @return Column separated values table. + * @param[in] csv Comma-separated values table. + * @return Comma-separated values table. ***************************************************************************/ GCsv& GCsv::operator=(const GCsv& csv) { @@ -562,7 +562,7 @@ void GCsv::init_members(void) /***********************************************************************//** * @brief Copy class members * - * @param[in] csv Column separated values table. + * @param[in] csv Comma-separated values table. ***************************************************************************/ void GCsv::copy_members(const GCsv& csv) { diff --git a/src/support/GFilename.cpp b/src/support/GFilename.cpp new file mode 100644 index 0000000..97ed953 --- /dev/null +++ b/src/support/GFilename.cpp @@ -0,0 +1,520 @@ +/*************************************************************************** + * GFilename.cpp - Filename class * + * ----------------------------------------------------------------------- * + * copyright (C) 2015 by Juergen Knoedlseder * + * ----------------------------------------------------------------------- * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ +/** + * @file GFilename.cpp + * @brief Filename class interface implementation + * @author Juergen Knoedlseder + */ + +/* __ Includes ___________________________________________________________ */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include "GFilename.hpp" +#include "GTools.hpp" +#include "GException.hpp" + +/* __ Method name definitions ____________________________________________ */ +#define G_SET_FILENAME "GFilename::set_filename(std::string&)" + +/* __ Macros _____________________________________________________________ */ + +/* __ Coding definitions _________________________________________________ */ + +/* __ Debug definitions __________________________________________________ */ + + +/*========================================================================== + = = + = Constructors/destructors = + = = + ==========================================================================*/ + +/***********************************************************************//** + * @brief Void constructor + ***************************************************************************/ +GFilename::GFilename(void) +{ + // Initialise members + init_members(); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Filename constructor + * + * @param[in] filename File name. + * + * Constructs GFilename object by assigning a @p filename. + ***************************************************************************/ +GFilename::GFilename(const std::string& filename) +{ + // Initialise members + init_members(); + + // Set filename + set_filename(filename); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Filename constructor + * + * @param[in] filename File name. + * + * Constructs GFilename object by assigning a @p filename. + ***************************************************************************/ +GFilename::GFilename(const char* filename) +{ + // Initialise members + init_members(); + + // Set filename + set_filename(std::string(filename)); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Copy constructor + * + * @param[in] filename File name. + ***************************************************************************/ +GFilename::GFilename(const GFilename& filename) +{ + // Initialise members + init_members(); + + // Copy members + copy_members(filename); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Destructor + ***************************************************************************/ +GFilename::~GFilename(void) +{ + // Free members + free_members(); + + // Return + return; +} + + +/*========================================================================== + = = + = Operators = + = = + ==========================================================================*/ + +/***********************************************************************//** + * @brief Assignment operator + * + * @param[in] filename File name. + * @return File name. + ***************************************************************************/ +GFilename& GFilename::operator=(const GFilename& filename) +{ + // Execute only if object is not identical + if (this != &filename) { + + // Free members + free_members(); + + // Initialise members + init_members(); + + // Copy members + copy_members(filename); + + } // endif: object was not identical + + // Return + return *this; +} + + +/*========================================================================== + = = + = Public methods = + = = + ==========================================================================*/ + +/***********************************************************************//** + * @brief Clear file name + ***************************************************************************/ +void GFilename::clear(void) +{ + // Free class members + free_members(); + + // Initialise members + init_members(); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Clone file name + * + * @return Pointer to deep copy of file name. + ***************************************************************************/ +GFilename* GFilename::clone(void) const +{ + // Clone object + return new GFilename(*this); +} + + +/***********************************************************************//** + * @brief Return extension name + * + * @param[in] defaultname Default extension name (default: ""). + * @return String containing extension name. + * + * Returns the extension name. If no extension name is given the name + * provided by the @p defaultname argument will be used. By default, the + * @p defaultname parameter is an empty string. + ***************************************************************************/ +std::string GFilename::extname(const std::string& defaultname) const +{ + // Set the extension name + std::string extname = m_extname; + + // If no extension name is set, the use the default extension name + if (!has_extname()) { + extname = defaultname; + } + + // Return extension name + return (extname); +} + + +/***********************************************************************//** + * @brief Return extension number + * + * @param[in] defaultno Default extension number (default: -11). + * @return Integer containing extension number. + * + * Returns the extension number. If no extension number is given the number + * provided by the @p defaultno argument will be used. By default, the + * @p defaultno parameter is set to -1. + ***************************************************************************/ +int GFilename::extno(const int& defaultno) const +{ + // Set the extension number + int extno = m_extno; + + // If no extension number is set, the use the default extension number + if (!has_extno()) { + extno = defaultno; + } + + // Return extension number + return (extno); +} + + +/***********************************************************************//** + * @brief Return extension version number + * + * @param[in] defaultver Default extension version number (default: 0). + * @return Integer containing extension version number. + * + * Returns the extension version number. If no extension version number is + * given the number provided by the @p defaultver argument will be used. By + * default, the @p defaultextver parameter is set to 0. + ***************************************************************************/ +int GFilename::extver(const int& defaultver) const +{ + // Set the extension version + int extver = m_extver; + + // If no extension version is set, the use the default extension version + if (!has_extver()) { + extver = defaultver; + } + + // Return extension version + return (extver); +} + + +/***********************************************************************//** + * @brief Print file name information + * + * @param[in] chatter Chattiness (default: NORMAL). + * @return String containing file name information. + ***************************************************************************/ +std::string GFilename::print(const GChatter& chatter) const +{ + // Initialise result string + std::string result; + + // Continue only if chatter is not silent + if (chatter != SILENT) { + + // Append header + result.append("=== GFilename ==="); + + // Append file name + result.append("\n"+gammalib::parformat("File name")); + result.append(m_filename); + + // Append extension name + result.append("\n"+gammalib::parformat("Extension name")); + if (has_extname()) { + result.append(m_extname); + } + else { + result.append("Not provided"); + } + + // Append extension number + result.append("\n"+gammalib::parformat("Extension number")); + if (has_extno()) { + result.append(gammalib::str(m_extno)); + } + else { + result.append("Not provided"); + } + + // Append extension version + result.append("\n"+gammalib::parformat("Extension version")); + if (has_extver()) { + result.append(gammalib::str(m_extver)); + } + else { + result.append("Not provided"); + } + + } // endif: chatter was not silent + + // Return result + return result; +} + + +/*========================================================================== + = = + = Private methods = + = = + ==========================================================================*/ + +/***********************************************************************//** + * @brief Initialise class members + ***************************************************************************/ +void GFilename::init_members(void) +{ + // Initialise members + m_filename.clear(); + m_extname.clear(); + m_extno = -1; + m_extver = 0; + + // Return + return; +} + + +/***********************************************************************//** + * @brief Copy class members + * + * @param[in] filename File name. + ***************************************************************************/ +void GFilename::copy_members(const GFilename& filename) +{ + // Copy members + m_filename = filename.m_filename; + m_extname = filename.m_extname; + m_extno = filename.m_extno; + m_extver = filename.m_extver; + + // Return + return; +} + + +/***********************************************************************//** + * @brief Delete class members + ***************************************************************************/ +void GFilename::free_members(void) +{ + // Return + return; +} + + +/***********************************************************************//** + * @brief Set file name + * + * @param[in] filename File name. + * + * @exception GException::invalid_argument + * Invalid file name specified. + * + * Sets all attributes of the object by parsing the file name. The file name + * can have one of the following formats: + * + * file.fits No extension + * file.fits[1] Extension number 1 (starting from 0) + * file.fits[EVENTS] EVENTS extension + * file.fits[EVENTS,2] Version 2 of the EVENTS extension + ***************************************************************************/ +void GFilename::set_filename(const std::string& filename) +{ + // Clear file name + clear(); + + // Strip any whitespace + std::string fname = gammalib::strip_whitespace(filename); + + // Continue only if filename is not empty + if (!fname.empty()) { + + // Check for [ symbol in filename + size_t start = fname.find_first_of("["); + + // If we have an extension then separate filename into filename + // part and extension part and fill the information of th object + if (start != std::string::npos) { + + // Check for ] symbol in filename + size_t stop = fname.find_first_of("]", start); + + // If there is no ] symbol then throw an exception + if (stop == std::string::npos) { + std::string msg = "Missing ] symbol in filename \""+ + fname+"\" extension. Please correct the " + "filename."; + throw GException::invalid_argument(G_SET_FILENAME, msg); + } + + // If ] is not the last character then throw an exception + if (stop < fname.length()-1) { + std::string msg = "Characters beyond ] symbol in filename \""+ + fname+"\". Please correct the filename."; + throw GException::invalid_argument(G_SET_FILENAME, msg); + } + + // Extract extension name + std::string extname = gammalib::strip_whitespace(fname.substr(start+1, stop-start-1)); + + // Check if there is a , symbol that separates extension name + // and extension version + size_t sep = extname.find_first_of(","); + + // If we have a separator, then extract the extension version + if (sep != std::string::npos) { + + // Get extension version string + std::string extver = gammalib::strip_whitespace(extname.substr(sep+1, std::string::npos)); + + // If string is empty then throw an exception + if (extver.empty()) { + std::string msg = "No extension version found after , " + "symbol in filename \""+fname+ + "\". Please correct the filename."; + throw GException::invalid_argument(G_SET_FILENAME, msg); + } + + // Extract extension version + m_extver = gammalib::toint(extver); + + // Throw an exception if the extension version is not + // positive + if (m_extver <= 0) { + std::string msg = "Non-positive extension version " + "encountered in filename \""+fname+ + "\". Please correct the filename."; + throw GException::invalid_argument(G_SET_FILENAME, msg); + } + + // Update the extension name + extname = gammalib::strip_whitespace(extname.substr(0,sep)); + + } // endif: extension version provided + + // If we have a purely numerical extension then convert the + // extension name into an extension number + if (extname.find_first_of("0123456789") != std::string::npos) { + + // Extract extension number + m_extno = gammalib::toint(extname); + + // Throw an exception if the extension version is not + // positive + if (m_extno < 0) { + std::string msg = "Negative extension number encountered " + "in filename \""+fname+"\". Please " + "correct the filename."; + throw GException::invalid_argument(G_SET_FILENAME, msg); + } + + } // endif: extension number provided + + // ... otherwise store the extension name + else { + + // Store extension name + m_extname = gammalib::toupper(extname); + + // Throw an exception if extension name is empty + if (m_extname.empty()) { + std::string msg = "Empty extension name encountered " + "in filename \""+fname+"\". Please " + "correct the filename."; + throw GException::invalid_argument(G_SET_FILENAME, msg); + } + + } // endelse: extension name provided + + // Store the file name + m_filename = gammalib::strip_whitespace(fname.substr(0,start)); + + } // endif: had extension + + // ... otherwise simply set the filename + else { + m_filename = fname; + } + + } // endif: filename was not empty + + // Return + return; +} diff --git a/src/support/GNodeArray.cpp b/src/support/GNodeArray.cpp index 0502520..9d98efd 100644 --- a/src/support/GNodeArray.cpp +++ b/src/support/GNodeArray.cpp @@ -1,7 +1,7 @@ /*************************************************************************** * GNodeArray.cpp - Array of nodes class * * ----------------------------------------------------------------------- * - * copyright (C) 2008-2014 by Juergen Knoedlseder * + * copyright (C) 2008-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -29,9 +29,10 @@ #include #endif #include +#include "GTools.hpp" #include "GException.hpp" +#include "GFilename.hpp" #include "GNodeArray.hpp" -#include "GTools.hpp" #include "GFits.hpp" #include "GFitsTable.hpp" #include "GFitsBinTable.hpp" @@ -75,6 +76,26 @@ GNodeArray::GNodeArray(void) /***********************************************************************//** + * @brief FITS file constructor + * + * @param[in] filename FITS file name. + * + * Constructs node array from a FITS file. + ***************************************************************************/ +GNodeArray::GNodeArray(const std::string& filename) +{ + // Initialise members + init_members(); + + // Load FITS file + load(filename); + + // Return + return; +} + + +/***********************************************************************//** * @brief Element constructor * * @param[in] num Number of elements. @@ -673,20 +694,25 @@ void GNodeArray::set_value(const double& value) const * @brief Load nodes from FITS file * * @param[in] filename FITS filename. - * @param[in] extname Energies extension name (defaults to "NODES") * - * Loads the nodes from FITS file. + * Loads the node array from a FITS file. + * + * If no extension name is provided, the node array is loaded from the + * "NODES" extension. ***************************************************************************/ -void GNodeArray::load(const std::string& filename, const std::string& extname) +void GNodeArray::load(const std::string& filename) { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Open FITS file - file.open(filename); + file.open(fname.filename()); // Get nodes table - const GFitsTable& table = *file.table(extname); + const GFitsTable& table = *file.table(fname.extname("NODES")); // Read nodes from table read(table); @@ -704,24 +730,25 @@ void GNodeArray::load(const std::string& filename, const std::string& extname) * * @param[in] filename FITS filename. * @param[in] clobber Overwrite any existing nodes extension? - * @param[in] extname Nodes extension name (defaults to "NODES") * - * Saves nodes into extension @p extname of a FITS file. If the file does - * not exist it is created. If the file exists the nodes are appended as - * extension. If another nodes extension exists already it is overwritten - * if @p clobber=true. + * Saves node array into a FITS file. + * + * If no extension name is provided, the node array is saved into a + * "NODES" extension. ***************************************************************************/ -void GNodeArray::save(const std::string& filename, const bool& clobber, - const std::string& extname) const +void GNodeArray::save(const std::string& filename, const bool& clobber) const { + // Create file name + GFilename fname(filename); + // Allocate FITS file GFits file; // Write nodes to FITS file - write(file, extname); + write(file, fname.extname("NODES")); // Save to file - file.saveto(filename, clobber); + file.saveto(fname.filename(), clobber); // Return return; @@ -733,7 +760,7 @@ void GNodeArray::save(const std::string& filename, const bool& clobber, * * @param[in] table FITS table. * - * Reads the nodes from a FITS table. + * Reads the nodes from a FITS @p table. ***************************************************************************/ void GNodeArray::read(const GFitsTable& table) { diff --git a/src/support/GTools.cpp b/src/support/GTools.cpp index be43add..40979c6 100644 --- a/src/support/GTools.cpp +++ b/src/support/GTools.cpp @@ -35,6 +35,7 @@ #include // select() function #include #include // recv() function +#include #include #include #include @@ -60,6 +61,7 @@ * @brief Strip leading and trailing whitespace from string * * @param[in] arg String from which whitespace should be stripped. + * @return String with stripped whitespace. ***************************************************************************/ std::string gammalib::strip_whitespace(const std::string& arg) { @@ -73,6 +75,7 @@ std::string gammalib::strip_whitespace(const std::string& arg) * * @param[in] arg String from which character should be stripped. * @param[in] chars Character(s) to be stripped. + * @return String with stripped characters. ***************************************************************************/ std::string gammalib::strip_chars(const std::string& arg, const std::string& chars) @@ -107,13 +110,20 @@ std::string gammalib::strip_chars(const std::string& arg, /***********************************************************************//** * @brief Expand environment variables in string * - * @param[in] arg String + * @param[in] arg String. + * @return String with expected environment variables. * * Expands any environment variable that is found in a string. Valid * delimiters for environment variables are $ENV{\}, $ENV(\), * ${\}, $(\) and $\ (in the last case the terminating * delimiter is either a / or a blank character or the end of the string). * Environment variables occuring within single quotes (') are ignored. + * Environment variables that do not exist will be kept as specified. + * + * The method also replaces ~ or ~user by the user's home directory, ~+ + * by the value of the PWD environment variable and ~- by the value of the + * OLDPWD variable. If the user or the PWD or OLDPWD variable are not found, + * no replacement is done. * * This function has been inspired by the function ape_util_expand_env_var * from ape_util.c in the ape software developed at HEASARC. @@ -121,9 +131,9 @@ std::string gammalib::strip_chars(const std::string& arg, std::string gammalib::expand_env(const std::string& arg) { // Set environment variable delimiters - static const char* begin_delim[] = { "$ENV{", "$ENV(", "${", "$(", "$" }; - static const char* end_delim[] = { "}", ")", "}", ")", "/" }; - static const int num_delim = 5; + static const char* begin_delim[] = { "$ENV{", "$ENV(", "${", "$(", "$", "~" }; + static const char* end_delim[] = { "}", ")", "}", ")", "/", "/" }; + static const int num_delim = 6; // Initialise result with argument std::string result = arg; @@ -171,7 +181,7 @@ std::string gammalib::expand_env(const std::string& arg) if (begin_length > 0) { // Search for the termination delimiter of the environment - // variable. There is a special case for delimiter 4: + // variable. There is a special case for delimiters 4 and 5: // It has always an end_length of zero as the / is not a real // delimiter, but just an indicator that the environment variable // ends. Another indicator is a blank. If the end of the @@ -179,7 +189,7 @@ std::string gammalib::expand_env(const std::string& arg) size_t i_start = index + begin_length; size_t i_end = i_start; size_t end_length = 0; - if (delim_idx == 4) { + if (delim_idx == 4 || delim_idx == 5) { while (i_end < result.length() && result.compare(i_end, 1, "/") != 0 && result.compare(i_end, 1, " ") != 0) { @@ -196,22 +206,53 @@ std::string gammalib::expand_env(const std::string& arg) // If termination delimiter has been found then expand the // environment variable - if (i_end < result.length() || delim_idx == 4) { + if (i_end < result.length() || delim_idx == 4 || delim_idx == 5) { // Extract environment variable name std::string name = result.substr(i_start, i_end-i_start); size_t name_length = name.length(); - // Erase delimiters and environment variable - result.erase(index, begin_length+name_length+end_length); + // Initialise pointer on environment variable + const char* env = NULL; + + // Handle ~ + if (delim_idx == 5) { + if (name_length == 0) { + if ((env = std::getenv("HOME")) == NULL) { + struct passwd *pw = getpwuid(getuid()); + if (pw != NULL) { + env = pw->pw_dir; + } + } + } + else { + if (name == "+") { + env = std::getenv("PWD"); + } + else if (name == "-") { + env = std::getenv("OLDPWD"); + } + else { + struct passwd *pw = getpwnam(name.c_str()); + if (pw != NULL) { + env = pw->pw_dir; + } + } + } + } - // Get the environment variable from the operating system - const char* env = std::getenv(name.c_str()); + // ... otherwise get the environment variable + else { + env = std::getenv(name.c_str()); + } // If the environment variable has been found then replace // it by its value if (env != NULL) { + // Erase delimiters and environment variable + result.erase(index, begin_length+name_length+end_length); + // Set replacement string and its length std::string replace(env); size_t replace_length = replace.length(); @@ -224,6 +265,12 @@ std::string gammalib::expand_env(const std::string& arg) } // endif: environment variable has been found + // If no environment variable has been found then set + // index=i_end+1 + else { + index = i_end + 1; + } + } // endif: termination delimiter found // If no environment variable has been found then set index=i_end+1 @@ -285,6 +332,7 @@ std::string gammalib::filepath(const std::string& pathname, * @brief Convert unsigned short integer value into string * * @param[in] value Unsigned short integer to be converted into string. + * @return String with unsigned short integer value. ***************************************************************************/ std::string gammalib::str(const unsigned short int& value) { @@ -298,6 +346,7 @@ std::string gammalib::str(const unsigned short int& value) * @brief Convert unsigned integer value into string * * @param[in] value Unsigned integer to be converted into string. + * @return String with unsigned integer value. ***************************************************************************/ std::string gammalib::str(const unsigned int& value) { @@ -311,6 +360,7 @@ std::string gammalib::str(const unsigned int& value) * @brief Convert unsigned long integer value into string * * @param[in] value Unsigned long integer to be converted into string. + * @return String with unsigned long integer value. ***************************************************************************/ std::string gammalib::str(const unsigned long int& value) { @@ -324,6 +374,7 @@ std::string gammalib::str(const unsigned long int& value) * @brief Convert unsigned long long integer value into string * * @param[in] value Unsigned long long integer to be converted into string. + * @return String with unsigned long long integer value. ***************************************************************************/ std::string gammalib::str(const unsigned long long int& value) { @@ -337,6 +388,7 @@ std::string gammalib::str(const unsigned long long int& value) * @brief Convert short integer value into string * * @param[in] value Short integer to be converted into string. + * @return String with short integer value. ***************************************************************************/ std::string gammalib::str(const short int& value) { @@ -350,6 +402,7 @@ std::string gammalib::str(const short int& value) * @brief Convert integer value into string * * @param[in] value Integer to be converted into string. + * @return String with integer value. ***************************************************************************/ std::string gammalib::str(const int& value) { @@ -363,6 +416,7 @@ std::string gammalib::str(const int& value) * @brief Convert long integer value into string * * @param[in] value Long integer to be converted into string. + * @return String with long integer value. ***************************************************************************/ std::string gammalib::str(const long int& value) { @@ -376,6 +430,7 @@ std::string gammalib::str(const long int& value) * @brief Convert long long integer value into string * * @param[in] value Long long integer to be converted into string. + * @return String with long long integer value. ***************************************************************************/ std::string gammalib::str(const long long int& value) { @@ -390,6 +445,7 @@ std::string gammalib::str(const long long int& value) * * @param[in] value Single precision value to be converted into string. * @param[in] precision Floating point precision (optional). + * @return String with single precision value. ***************************************************************************/ std::string gammalib::str(const float& value, const int& precision) { @@ -411,6 +467,7 @@ std::string gammalib::str(const float& value, const int& precision) * * @param[in] value Double precision value to be converted into string. * @param[in] precision Floating point precision (optional). + * @return String with double precision value. ***************************************************************************/ std::string gammalib::str(const double& value, const int& precision) { @@ -431,6 +488,7 @@ std::string gammalib::str(const double& value, const int& precision) * @brief Convert string to C string * * @param[in] arg String to be converted. + * @return C string. * * Allocates a C string with the content of a C++ string. ***************************************************************************/ @@ -456,6 +514,7 @@ char* gammalib::tochar(const std::string& arg) * @brief Convert string into short value * * @param[in] arg String to be converted. + * @return Short value. ***************************************************************************/ short gammalib::toshort(const std::string& arg) { @@ -470,6 +529,7 @@ short gammalib::toshort(const std::string& arg) * @brief Convert string into unsigned short value * * @param[in] arg String to be converted. + * @return Unsigned short value. ***************************************************************************/ unsigned short gammalib::toushort(const std::string& arg) { @@ -484,6 +544,7 @@ unsigned short gammalib::toushort(const std::string& arg) * @brief Convert string into integer value * * @param[in] arg String to be converted. + * @return Integer value. ***************************************************************************/ int gammalib::toint(const std::string& arg) { @@ -498,6 +559,7 @@ int gammalib::toint(const std::string& arg) * @brief Convert string into unsigned integer value * * @param[in] arg String to be converted. + * @return Unsigned integer value. ***************************************************************************/ unsigned int gammalib::touint(const std::string& arg) { @@ -512,6 +574,7 @@ unsigned int gammalib::touint(const std::string& arg) * @brief Convert string into long value * * @param[in] arg String to be converted. + * @return Long value. ***************************************************************************/ long gammalib::tolong(const std::string& arg) { @@ -526,6 +589,7 @@ long gammalib::tolong(const std::string& arg) * @brief Convert string into unsigned long value * * @param[in] arg String to be converted. + * @return Unsigned long value. ***************************************************************************/ unsigned long gammalib::toulong(const std::string& arg) { @@ -540,6 +604,7 @@ unsigned long gammalib::toulong(const std::string& arg) * @brief Convert string into long long value * * @param[in] arg String to be converted. + * @return Long long value. ***************************************************************************/ long long gammalib::tolonglong(const std::string& arg) { @@ -554,6 +619,7 @@ long long gammalib::tolonglong(const std::string& arg) * @brief Convert string into unsigned long long value * * @param[in] arg String to be converted. + * @return Unsigned long long value. ***************************************************************************/ unsigned long long gammalib::toulonglong(const std::string& arg) { @@ -565,9 +631,10 @@ unsigned long long gammalib::toulonglong(const std::string& arg) /***********************************************************************//** - * @brief Convert string into float value + * @brief Convert string into single precision value * * @param[in] arg String to be converted. + * @return Single precision value. ***************************************************************************/ float gammalib::tofloat(const std::string& arg) { @@ -579,9 +646,10 @@ float gammalib::tofloat(const std::string& arg) /***********************************************************************//** - * @brief Convert string into double value + * @brief Convert string into double precision value * * @param[in] arg String to be converted. + * @return Double precision value. ***************************************************************************/ double gammalib::todouble(const std::string& arg) { @@ -596,6 +664,7 @@ double gammalib::todouble(const std::string& arg) * @brief Convert string to upper case * * @param[in] arg String to be converted to upper case. + * @return String converted to upper case. ***************************************************************************/ std::string gammalib::toupper(const std::string& arg) { @@ -609,6 +678,7 @@ std::string gammalib::toupper(const std::string& arg) * @brief Convert string to lower case * * @param[in] arg String to be converted to upper case. + * @return String converted to lower case. ***************************************************************************/ std::string gammalib::tolower(const std::string& arg) { @@ -623,6 +693,7 @@ std::string gammalib::tolower(const std::string& arg) * * @param[in] s String to be splitted. * @param[in] sep Separator(s). + * @return Vector of split strings. * * Splits a string on the basis of one or multiple separator characters. The * separator characters are provided by the @p sep argument. Subsequent @@ -694,6 +765,7 @@ std::vector gammalib::split(const std::string& s, * * @param[in] s String to be filled. * @param[in] n Number of fillings. + * @return Filled strings. * * Replicates a given string n time. ***************************************************************************/ @@ -718,6 +790,7 @@ std::string gammalib::fill(const std::string& s, const int& n) * @param[in] s String to be centred. * @param[in] n Requested total width. * @param[in] c Fill character. + * @return Left justified string. * * Left justify string by adding whitespace to the right to achieve a length * of n characters. @@ -741,6 +814,7 @@ std::string gammalib::left(const std::string& s, const int& n, const char& c) * @param[in] s String to be centred. * @param[in] n Requested total width. * @param[in] c Fill character. + * @return Right justified string. * * Right justify string by adding whitespace to the left to achieve a length * of n characters. @@ -764,6 +838,7 @@ std::string gammalib::right(const std::string& s, const int& n, const char& c) * @param[in] s String to be centred. * @param[in] n Requested total width. * @param[in] c Left fill character. + * @return Centred string. * * Centre string by adding whitespace to the left and the right to achieve a * length of n characters. @@ -788,6 +863,7 @@ std::string gammalib::centre(const std::string& s, const int& n, const char& c) * * @param[in] s String to be converted. * @param[in] indent Indentation of parameter (default: 0). + * @return Parameter string. * * Converts and string into the parameter format of type "s ......: " with a * total length of G_PARFORMAT_LENGTH. @@ -813,6 +889,7 @@ std::string gammalib::parformat(const std::string& s, const int& indent) * @param[in] emax Maximum energy. * @param[in] epivot Pivot energy. * @param[in] gamma Spectral index. + * @return Photon flux under power law. * * Analytically computes * \f[\int_{E_{\rm min}}^{E_{\rm max}} @@ -859,6 +936,7 @@ double gammalib::plaw_photon_flux(const double& emin, const double& emax, * @param[in] emax Maximum energy. * @param[in] epivot Pivot energy. * @param[in] gamma Spectral index. + * @return Energy flux under power law. * * Analytically computes * \f[\int_{E_{\rm min}}^{E_{\rm max}} @@ -927,8 +1005,9 @@ GEnergy gammalib::elogmean(const GEnergy& a, const GEnergy& b) * @brief Checks if file exists * * @param[in] filename File name. + * @return True if file exists, false otherwise. * - * Checks if a file exists. If a directory with the same name if found, false + * Checks if a file exists. If a directory with the same name is found, false * is returned. The function expands any environment variable prior to * checking. ***************************************************************************/ @@ -954,9 +1033,31 @@ bool gammalib::file_exists(const std::string& filename) /***********************************************************************//** + * @brief Checks if either uncompressed or compressed file exists + * + * @param[in] filename Uncompressed file name (withput ".gz" extension) + * @return True if file exists, false otherwise. + * + * Checks if a file exists, either as an uncompressed file or with a ".gz" + * extension. If a directory with the same name is found, false is returned. + * The function expands any environment variable prior to checking. + ***************************************************************************/ +bool gammalib::file_exists_gzip(const std::string& filename) +{ + // Get result + bool result = gammalib::file_exists(filename) || + gammalib::file_exists(filename+".gz"); + + // Return result + return result; +} + + +/***********************************************************************//** * @brief Checks if directory exists * * @param[in] dirname Directory name. + * @return True if directory exists, false otherwise. * * Checks if a directory exists. The function expands any environment * variable prior to checking. @@ -986,6 +1087,7 @@ bool gammalib::dir_exists(const std::string& dirname) * @brief Checks if file is a FITS file * * @param[in] filename File name. + * @return True if file is a FITS file. * * Checks if the specified file is a FITS file. ***************************************************************************/ @@ -1000,7 +1102,7 @@ bool gammalib::is_fits(const std::string& filename) // Open file GFits fits(filename); - // If we're still alive then close file and result result to true + // If we're still alive then close file and set result to true fits.close(); result = true; @@ -1021,6 +1123,7 @@ bool gammalib::is_fits(const std::string& filename) * * @param[in] str string you want to search in. * @param[in] substring string you are looking for in str. + * @return True if a string contains a sub string. * * Checks if substring is contained in str ***************************************************************************/ @@ -1282,6 +1385,7 @@ bool gammalib::xml_has_par(const GXmlElement& xml, const std::string& name) * @param[in] origin Method requesting parameter. * @param[in] xml XML element. * @param[in] name Parameter name. + * @return Pointer to parameter XML element. * * @exception GException::invalid_value * Invalid XML format encountered. @@ -1333,6 +1437,7 @@ GXmlElement* gammalib::xml_need_par(const std::string& origin, * @param[in] origin Method requesting parameter. * @param[in] xml XML element. * @param[in] name Parameter name. + * @return Pointer to parameter XML element. * * @exception GException::invalid_value * Invalid XML format encountered. diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 3bb8fc4..eb6e105 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -14,7 +14,8 @@ sources = GException.cpp \ GRan.cpp \ GUrl.cpp \ GUrlFile.cpp \ - GUrlString.cpp + GUrlString.cpp \ + GFilename.cpp # Build libtool library noinst_LTLIBRARIES = libsupport.la diff --git a/src/vo/GVOClient.cpp b/src/vo/GVOClient.cpp index 1827f6f..ab04dd0 100644 --- a/src/vo/GVOClient.cpp +++ b/src/vo/GVOClient.cpp @@ -517,7 +517,7 @@ bool GVOClient::find_hub(void) if (!lockurl.empty()) { // If we have a file:// prefix then strip it now. This is a kluge - // and should be remplaced by a method that allows opening any kind + // and should be replaced by a method that allows opening any kind // of URL if (lockurl.compare(0, 7, "file://") == 0) { lockurl = lockurl.substr(7, std::string::npos); @@ -955,7 +955,6 @@ std::string GVOClient::receive_string(void) const int n = 0; do { n = gammalib::recv(m_socket, buffer, 1000, 0, timeout); - //n = recv(m_socket, buffer, 1000, 0); if (n > 0) { buffer[n] = '\0'; result.append(std::string(buffer)); @@ -1074,7 +1073,7 @@ std::string GVOClient::get_hub_lockfile(void) const char* hub_ptr = std::getenv("SAMP_HUB"); if (hub_ptr != NULL) { - // Check for mandatory std-lockurl: prefix (no other prefixe is + // Check for mandatory std-lockurl: prefix (no other prefix is // supported so far) std::string lockurl = std::string(hub_ptr); if (lockurl.compare(0, 12, "std-lockurl:") == 0) { @@ -1084,7 +1083,7 @@ std::string GVOClient::get_hub_lockfile(void) const } // endif: std-lockurl: prefix found - } + } // endif: SAMP_HUB environment variable found // ... otherwise the lockfile should be $HOME/.samp else { diff --git a/src/vo/GVOHub.cpp b/src/vo/GVOHub.cpp index e04be5f..bc82af0 100644 --- a/src/vo/GVOHub.cpp +++ b/src/vo/GVOHub.cpp @@ -47,6 +47,7 @@ /* __ Method name definitions ____________________________________________ */ #define G_START_HUB "GVOHub::start_hub()" +#define G_START_SOCKET "GVOHub::start_socket()" /* __ Macros _____________________________________________________________ */ @@ -179,9 +180,6 @@ GVOHub* GVOHub::clone(void) const ***************************************************************************/ void GVOHub::start(void) { - // Create SAMP file - create_samp_file(); - // Start Hub start_hub(); @@ -210,7 +208,7 @@ std::string GVOHub::print(const GChatter& chatter) const // Append Hub information result.append("\n"+gammalib::parformat("Hub identifier")+m_hub_id); result.append("\n"+gammalib::parformat("Hub key")+m_secret); - result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url); + result.append("\n"+gammalib::parformat("Hub URL")+hub_url()); result.append("\n"+gammalib::parformat("Hub host")+m_hub_host); result.append("\n"+gammalib::parformat("Hub port")+m_hub_port); result.append("\n"+gammalib::parformat("Hub path")+m_hub_path); @@ -240,7 +238,6 @@ void GVOHub::init_members(void) m_hub_host = "127.0.0.1"; m_hub_port = "2526"; m_hub_path = "xmlrpc"; - m_hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path; m_version = "1.3"; m_hub_id = "gammalib_hub"; m_socket = -1; // Signals no socket @@ -261,7 +258,6 @@ void GVOHub::copy_members(const GVOHub& hub) { // Copy members m_secret = hub.m_secret; - m_hub_url = hub.m_hub_url; m_hub_host = hub.m_hub_host; m_hub_port = hub.m_hub_port; m_hub_path = hub.m_hub_path; @@ -288,8 +284,7 @@ void GVOHub::free_members(void) } // Remove lockfile - std::string lockurl = get_hub_lockfile(); - std::remove(lockurl.c_str()); + delete_samp_file(); // Return return; @@ -306,46 +301,13 @@ void GVOHub::free_members(void) ***************************************************************************/ void GVOHub::start_hub(void) { - // Prepare TCP/IP structure - struct sockaddr_in serv_addr; - std::memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str()); - serv_addr.sin_port = htons(gammalib::toint(m_hub_port)); - - // Create Hub socket - m_socket = socket(AF_INET, SOCK_STREAM, 0); - - // Creation of hub main socket - if (m_socket < 0) { - std::string msg = "Unable to create Hub socket. Errno="+ - gammalib::str(errno); - throw GException::runtime_error(G_START_HUB, msg); - } - - // Set hub main socket to allow multiple connections - int opt = 1; - if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) { - std::string msg = "Unable to set Hub socket to multiple connections." - " Errno="+gammalib::str(errno); - throw GException::runtime_error(G_START_HUB, msg); - } - #ifdef SO_REUSEPORT - if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) { - std::string msg = "Unable to set Hub socket to multiple connections." - " Errno="+gammalib::str(errno); - throw GException::runtime_error(G_START_HUB, msg); - } - #endif - - // Server socket is opened. Now, bind it to the port, with family etc. - if (bind(m_socket, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { - std::string msg = "Unable to bind Hub socket to server socket. Errno="+ - gammalib::str(errno); - throw GException::runtime_error(G_START_HUB, msg); - } + // Get socket + m_socket = get_socket(); + + // Create SAMP file + create_samp_file(); - // Now start listening for the clients: 5 requests simultaneously pending + // Start listening for the clients: 5 requests simultaneously pending // at maximum if (listen(m_socket, 5) < 0) { std::string msg = "Unable to start listening on Hub socket. Errno="+ @@ -385,6 +347,9 @@ void GVOHub::start_hub(void) close(m_socket); m_socket = -1; + // Delete SAMP file + delete_samp_file(); + // Return return; } @@ -596,7 +561,7 @@ void GVOHub::request_register(const GXml& xml, const socklen_t& sock) response.append(" \n"); response.append(" \n"); response.append(" samp.url-translator\n"); - response.append(" "+m_hub_url+"\n"); + response.append(" "+hub_url()+"\n"); response.append(" \n"); response.append(" \n"); response.append("\n"); @@ -1628,9 +1593,10 @@ void GVOHub::send_notifications(const std::string& method, /***********************************************************************//** - * @brief Creates the lockfile, fill it + * @brief Create the lockfile * - * Implements IVOA standard REC-SAMP-1.3-20120411. + * Creates the SAMP lockfile and fill it with information. Implements IVOA + * standard REC-SAMP-1.3-20120411. ***************************************************************************/ void GVOHub::create_samp_file(void) const { @@ -1647,7 +1613,7 @@ void GVOHub::create_samp_file(void) const fprintf(fptr, "# SAMP lockfile\n"); fprintf(fptr, "# Required keys:\n"); fprintf(fptr, "samp.secret=%s\n", m_secret.c_str()); - fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", m_hub_url.c_str()); + fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", hub_url().c_str()); fprintf(fptr, "samp.profile.version=%s\n", m_version.c_str()); fprintf(fptr, "# Info stored by hub for some private reason:\n"); fprintf(fptr, "gammalib.hubid=%s\n", m_hub_id.c_str()); @@ -1663,6 +1629,87 @@ void GVOHub::create_samp_file(void) const /***********************************************************************//** + * @brief Delete the lockfile + * + * Deletes the SAMP lockfile on disk. + ***************************************************************************/ +void GVOHub::delete_samp_file(void) const +{ + // Get lockfile URL + std::string lockurl = get_hub_lockfile(); + + // Delete lockfile + std::remove(lockurl.c_str()); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Get Hub socket + * + * @return Hub socket (-1 if no socket was found). + * + * Returns Hub socket. Starting from an initial port of 2526 the method + * searches for the next free port and binds it to a socket. + ***************************************************************************/ +int GVOHub::get_socket(void) +{ + // Initialise socket, port and socket address structure + int sock = -1; + int port = 2526; + struct sockaddr_in serv_addr; + + // Loop over 100 ports at most + for (int i = 0; i < 100; ++i) { + + // Clean TCP/IP structure + std::memset(&serv_addr, 0, sizeof(serv_addr)); + + // Set TCP/IP structure + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str()); + serv_addr.sin_port = htons(port); + + // Create Hub socket + sock = socket(AF_INET, SOCK_STREAM, 0); + + // Creation of hub main socket + if (sock < 0) { + std::string msg = "Unable to create Hub socket. Errno="+ + gammalib::str(errno); + throw GException::runtime_error(G_START_SOCKET, msg); + } + + // Now bind socket to the address and port + if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { + if (errno == EADDRINUSE) { + port++; + close(sock); + } + else { + std::string msg = "Unable to bind Hub socket to address "+ + m_hub_host+":"+gammalib::str(port)+ + ". Errno="+gammalib::str(errno); + throw GException::runtime_error(G_START_HUB, msg); + } + } + else { + break; + } + + } // endfor: looped over ports + + // Store port as string + m_hub_port = gammalib::str(port); + + // Return socket + return sock; +} + + +/***********************************************************************//** * @brief Post string content to client * * @param[in] content String content to post. @@ -1948,3 +1995,20 @@ std::string GVOHub::random_string(const size_t& length) const return str; } + +/***********************************************************************//** + * @brief Return Hub URL + * + * @return Hub URL. + * + * Returns the XML-RPC endpoint for communication with the hub. + ***************************************************************************/ +std::string GVOHub::hub_url(void) const +{ + // Set Hub URL + std::string hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path; + + // Return Hub URL + return (hub_url); +} + diff --git a/test/test_GFits.py b/test/test_GFits.py index c6a3b9f..294a5df 100755 --- a/test/test_GFits.py +++ b/test/test_GFits.py @@ -48,6 +48,7 @@ class Test(gammalib.GPythonTestSuite): # Append tests self.append(self.test_fits, "Test GFits") + self.append(self.test_fits_table_columns, "Test FITS table columns") # Return return @@ -218,3 +219,49 @@ class Test(gammalib.GPythonTestSuite): # Return return + + def test_fits_table_columns(self): + """ + Test FITS table columns + """ + # Create table columns + nrows = 10 + col1 = gammalib.GFitsTableBitCol("BIT", nrows) + col2 = gammalib.GFitsTableBoolCol("BOOLEAN", nrows) + col3 = gammalib.GFitsTableByteCol("BYTE", nrows) + col4 = gammalib.GFitsTableDoubleCol("DOUBLE", nrows) + col5 = gammalib.GFitsTableFloatCol("FLOAT", nrows) + col6 = gammalib.GFitsTableLongCol("LONG", nrows) + col7 = gammalib.GFitsTableLongLongCol("LONGLONG", nrows) + col8 = gammalib.GFitsTableShortCol("SHORT", nrows) + col9 = gammalib.GFitsTableStringCol("STRING", nrows, 20) + col10 = gammalib.GFitsTableULongCol("ULONG", nrows) + col11 = gammalib.GFitsTableUShortCol("USHORT", nrows) + + # Test iterators + for row in col1: + pass + for row in col2: + pass + for row in col3: + pass + for row in col4: + pass + for row in col5: + pass + for row in col6: + pass + for row in col7: + pass + for row in col8: + pass + for row in col9: + pass + for row in col10: + pass + for row in col11: + pass + + # Return + return + \ No newline at end of file diff --git a/test/test_GSky.py b/test/test_GSky.py index 4f21ac9..b6b5cf6 100755 --- a/test/test_GSky.py +++ b/test/test_GSky.py @@ -370,6 +370,12 @@ class Test(gammalib.GPythonTestSuite): self.test_value(map[1], 3.0) self.test_value(map[2], 5.0) self.test_value(map[3], 7.0) + + # Access operator (tests also proper iteration) + sum = 0.0 + for pix in map: + sum += pix + self.test_value(sum, 16.0) # Return return diff --git a/test/test_GSupport.cpp b/test/test_GSupport.cpp index 604da15..d58fc6b 100644 --- a/test/test_GSupport.cpp +++ b/test/test_GSupport.cpp @@ -55,6 +55,7 @@ void TestGSupport::set(void){ append(static_cast(&TestGSupport::test_bilinear), "Test GBilinear"); append(static_cast(&TestGSupport::test_url_file), "Test GUrlFile"); append(static_cast(&TestGSupport::test_url_string), "Test GUrlString"); + append(static_cast(&TestGSupport::test_filename), "Test GFilename"); // Return return; @@ -170,14 +171,14 @@ void TestGSupport::test_expand_env(void) // Non existing environment variable within string s_in = "My $(HOMEIXYZ) is my castle."; - s_ref = "My is my castle."; + s_ref = "My $(HOMEIXYZ) is my castle."; s_out = gammalib::expand_env(s_in); test_assert(s_out == s_ref,"Non existing environment variable within string", "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")"); // Empty environment variable within string s_in = "My $() is my castle."; - s_ref = "My is my castle."; + s_ref = "My $() is my castle."; s_out = gammalib::expand_env(s_in); test_assert(s_out == s_ref,"Empty environment variable within string", "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")"); @@ -217,11 +218,19 @@ void TestGSupport::test_expand_env(void) test_assert(s_out == s_ref,"$ENV{HOME}${HOME}$ENV(HOME)$(HOME) only string", "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")"); - // Debugging - //std::cout << std::endl; - //std::cout << s_in << std::endl; - //std::cout << s_ref << std::endl; - //std::cout << s_out << std::endl; + // Test ~ + s_in = "My castle is ~"; + s_ref = gammalib::expand_env("My castle is $(HOME)"); + s_out = gammalib::expand_env(s_in); + test_assert(s_out == s_ref,"String with ~", + "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")"); + + // Test ~+ + s_in = "My castle is ~+"; + s_ref = gammalib::expand_env("My castle is $(PWD)"); + s_out = gammalib::expand_env(s_in); + test_assert(s_out == s_ref,"String with ~+", + "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")"); // Exit test return; @@ -508,7 +517,7 @@ void TestGSupport::test_url_file(void) std::string result = std::string(buffer, 21); test_assert(result.compare("abcdefghijklm419.9xyz") == 0, "Expected \"abcdefghijklm419.9xyz\" in file, found \""+ - result+"\n"); + result+"\""); url.close(); // Test file reading using get_char() method @@ -524,7 +533,7 @@ void TestGSupport::test_url_file(void) } while (character != EOF); test_assert(result.compare("abcdefghijklm419.9xyz") == 0, "Expected \"abcdefghijklm419.9xyz\" in file, found \""+ - result+"\n"); + result+"\""); url.close(); // Test file reading using scanf() method @@ -534,7 +543,7 @@ void TestGSupport::test_url_file(void) result = std::string(buffer, 21); test_assert(result.compare("abcdefghijklm419.9xyz") == 0, "Expected \"abcdefghijklm419.9xyz\" in file, found \""+ - result+"\n"); + result+"\""); url.close(); // Return @@ -582,7 +591,7 @@ void TestGSupport::test_url_string(void) std::string result = std::string(buffer, 21); test_assert(result.compare("abcdefghijklm419.9xyz") == 0, "Expected \"abcdefghijklm419.9xyz\" in file, found \""+ - result+"\n"); + result+"\""); // Test string reading using get_char() method result.clear(); @@ -597,7 +606,7 @@ void TestGSupport::test_url_string(void) } while (character != EOF); test_assert(result.compare("abcdefghijklm419.9xyz") == 0, "Expected \"abcdefghijklm419.9xyz\" in file, found \""+ - result+"\n"); + result+"\""); // Test string reading using scanf() method char buffer2[100]; @@ -607,7 +616,7 @@ void TestGSupport::test_url_string(void) result = std::string(buffer2, 21); test_assert(result.compare("abcdefghijklm419.9xyz") == 0, "Expected \"abcdefghijklm419.9xyz\" in file, found \""+ - result+"\n"); + result+"\""); url.close(); // Return @@ -616,6 +625,167 @@ void TestGSupport::test_url_string(void) /***********************************************************************//** + * @brief Test GFilename class + * + * Test the GFilename class. + ***************************************************************************/ +void TestGSupport::test_filename(void) +{ + // Test void constructor + test_try("Void constructor"); + try { + GFilename filename; + test_try_success(); + } + catch (std::exception &e) { + test_try_failure(e); + } + + // Set filename without extension + GFilename filename = "myfile.fits"; + test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\" filename, " + "found \""+filename.filename()+"\""); + test_assert(!filename.has_extname(), + "Expected that extension name is not set."); + + // Set filename with extension name + filename = "myfile.fits[EVENTS]"; + test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\" filename, " + "found \""+filename.filename()+"\""); + test_assert(filename.extname() == "EVENTS", + "Expected \"EVENTS\" extension name, " + "found \""+filename.extname()+"\""); + test_assert(filename.has_extname(), + "Expected that extension name is set."); + + // Set filename with extension name and version + filename = "myfile.fits[EVENTS,2]"; + test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\" filename, " + "found \""+filename.filename()+"\""); + test_assert(filename.extname() == "EVENTS", + "Expected \"EVENTS\" extension name, " + "found \""+filename.extname()+"\""); + test_assert(filename.has_extname(), + "Expected that extension name is set."); + test_value(filename.extver(), 2); + test_assert(filename.has_extver(), + "Expected that extension version is set."); + + // Set filename with lower case extension name + filename = "myfile.fits[events]"; + test_assert(filename.extname() == "EVENTS", + "Expected \"EVENTS\" extension name, " + "found \""+filename.extname()+"\""); + + // Set filename with extension number and version + filename = "myfile.fits[1,2]"; + test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\" filename, " + "found \""+filename.filename()+"\""); + test_value(filename.extno(), 1); + test_assert(filename.has_extno(), + "Expected that extension number is set."); + test_value(filename.extver(), 2); + test_assert(filename.has_extver(), + "Expected that extension version is set."); + + // Test missing closing symbol + test_try("Missing ] symbol"); + try { + GFilename filename("myfile.fits["); + test_try_failure(); + } + catch (GException::invalid_argument &e) { + test_try_success(); + } + + // Test character after closing symbol + test_try("Character after ] symbol"); + try { + GFilename filename("myfile.fits[EVENTS]a"); + test_try_failure(); + } + catch (GException::invalid_argument &e) { + test_try_success(); + } + + // Test empty extension name + test_try("Empty extension name"); + try { + GFilename filename("myfile.fits[]"); + test_try_failure(); + } + catch (GException::invalid_argument &e) { + test_try_success(); + } + + // Test invalid extension number + test_try("Invalid extension number"); + try { + GFilename filename("myfile.fits[-1]"); + test_try_failure(); + } + catch (GException::invalid_argument &e) { + test_try_success(); + } + + // Test missing extension version + test_try("Missing extension version"); + try { + GFilename filename("myfile.fits[EVENTS,]"); + test_try_failure(); + } + catch (GException::invalid_argument &e) { + test_try_success(); + } + + // Test invalid extension version + test_try("Invalid extension version"); + try { + GFilename filename("myfile.fits[EVENTS,-1]"); + test_try_failure(); + } + catch (GException::invalid_argument &e) { + test_try_success(); + } + + // Test size operators + filename = "myfile.fits"; + test_assert(!filename.empty(), "Non empty file name expected."); + test_value(filename.size(), 11); + test_value(filename.length(), 11); + + // Test default extension name + filename = "myfile.fits"; + test_assert(filename.extname("EVENTS") == "EVENTS", + "Expected \"EVENTS\" extension name, " + "found \""+filename.extname()+"\""); + filename = "myfile.fits[LUCKY]"; + test_assert(filename.extname("EVENTS") == "LUCKY", + "Expected \"LUCKY\" extension name, " + "found \""+filename.extname()+"\""); + + // Test default extension number + filename = "myfile.fits"; + test_value(filename.extno(1), 1); + filename = "myfile.fits[3]"; + test_value(filename.extno(1), 3); + + // Test default extension version + filename = "myfile.fits"; + test_value(filename.extver(1), 1); + filename = "myfile.fits[3,3]"; + test_value(filename.extver(1), 3); + + // Return + return; +} + + +/***********************************************************************//** * @brief Main test entry point ***************************************************************************/ int main(void) diff --git a/test/test_GSupport.hpp b/test/test_GSupport.hpp index e684dae..f78967c 100644 --- a/test/test_GSupport.hpp +++ b/test/test_GSupport.hpp @@ -47,12 +47,13 @@ public: virtual void set(void); virtual TestGSupport* clone(void) const; virtual std::string classname(void) const { return "TestGSupport"; } + void test_tools(void); void test_expand_env(void); void test_node_array(void); void test_bilinear(void); void test_url_file(void); void test_url_string(void); - void test_tools(void); + void test_filename(void); private: // Private methods diff --git a/test/test_GSupport.py b/test/test_GSupport.py index 2b28a9b..540da93 100755 --- a/test/test_GSupport.py +++ b/test/test_GSupport.py @@ -51,6 +51,7 @@ class Test(gammalib.GPythonTestSuite): self.append(self.test_node_array, "Test GNodeArray") self.append(self.test_url_file, "Test GUrlFile") self.append(self.test_url_string, "Test GUrlString") + self.append(self.test_filename, "Test GFilename") # Return return @@ -106,7 +107,7 @@ class Test(gammalib.GPythonTestSuite): buffer = url.read(99) self.test_assert(buffer == "abcde", "Expected \"abcde\" in file, found \""+ - buffer+"\n"); + buffer+"\"") url.close() # Return @@ -128,9 +129,41 @@ class Test(gammalib.GPythonTestSuite): buffer = url.read(99) self.test_assert(buffer == "abcde", "Expected \"abcde\" in file, found \""+ - buffer+"\n"); + buffer+"\"") url.close() # Return return + # Test GFilename class + def test_filename(self): + """ + Test GFilename class. + """ + # Test assigning file names + filename = gammalib.GFilename("myfile.fits") + self.test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\", found \""+ + filename.filename()+"\"") + filename = gammalib.GFilename("myfile.fits[EVENTS]") + self.test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\", found \""+ + filename.filename()+"\"") + self.test_assert(filename.extname() == "EVENTS", + "Expected extension \"EVENTS\", found \""+ + filename.extname()+"\"") + filename = gammalib.GFilename("myfile.fits[0]") + self.test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\", found \""+ + filename.filename()+"\"") + self.test_value(filename.extno(), 0) + filename = gammalib.GFilename("myfile.fits[0,2]") + self.test_assert(filename.filename() == "myfile.fits", + "Expected \"myfile.fits\", found \""+ + filename.filename()+"\"") + self.test_value(filename.extno(), 0) + self.test_value(filename.extver(), 2) + + # Return + return + \ No newline at end of file diff --git a/test/test_GVO.cpp b/test/test_GVO.cpp index d770b20..9163c3e 100644 --- a/test/test_GVO.cpp +++ b/test/test_GVO.cpp @@ -29,7 +29,7 @@ #include #endif #include // for system() function -#include // for sleep() function +#include // for sleep() and usleep() function #include "test_GVO.hpp" #include "GTools.hpp" @@ -68,6 +68,21 @@ TestGVO* TestGVO::clone(void) const **************************************************************************/ void TestGVO::test_GVOHub(void) { + // Kluge: wait until no Hub is online + GRan ran; + int no_hub = 0; + while (no_hub < 3) { + GVOClient client; + if (!client.ping_hub()) { + no_hub++; + usleep(ran.uniform()*1.0e6); + } + else { + no_hub = 0; + } + usleep(ran.uniform()*1.0e6); + } + // Create child process int pid = fork(); @@ -122,11 +137,25 @@ void TestGVO::test_GVOHub(void) **************************************************************************/ void TestGVO::test_GVOClient(void) { + // Kluge: wait until no Hub is online + GRan ran; + int no_hub = 0; + while (no_hub < 3) { + GVOClient client; + if (!client.ping_hub()) { + no_hub++; + usleep(ran.uniform()*1.0e6); + } + else { + no_hub = 0; + } + usleep(ran.uniform()*1.0e6); + } + // Test constructor test_try("GVOClient empty constructor"); try { GVOClient client; - //std::cout << client << std::endl; test_try_success(); } catch (std::exception &e) { @@ -175,6 +204,10 @@ int main(void) // Allocate test suit container GTestSuites testsuites("VO module"); + // Unset HOME environment variable (so that the .samp file is written + // into the test directory) + unsetenv("HOME"); + // Initially assume that we pass all tests bool success = true; diff --git a/test/test_python.py b/test/test_python.py index c0420b7..f38e9eb 100755 --- a/test/test_python.py +++ b/test/test_python.py @@ -21,6 +21,7 @@ import gammalib import sys import os +sys.path.append(os.path.dirname(os.path.abspath(__file__))) import test_GApplication import test_GLinalg import test_GModel @@ -174,7 +175,10 @@ def test(installed=False): filename = element.attribute("file") head, tail = os.path.split(filename) head, dir = os.path.split(head) - filename = "cta/"+dir+"/"+tail + if len(tail) > 0: + filename = "cta/"+dir+"/"+tail + else: + filename = "" element.attribute("file", filename) xml.save("cta/data/irf_unbinned.xml") xml = gammalib.GXml("cta/data/irf_1dc.xml") @@ -185,7 +189,10 @@ def test(installed=False): head, dir = os.path.split(head) if dir == "dc1": dir = "caldb/dc1" - filename = "cta/"+dir+"/"+tail + if len(tail) > 0: + filename = "cta/"+dir+"/"+tail + else: + filename = "" element.attribute("file", filename) xml.save("cta/data/irf_1dc.xml") @@ -202,8 +209,8 @@ def test(installed=False): else: rc = 1 - # Return - return rc + # Exit with return code + sys.exit(rc) # ======================== # @@ -214,7 +221,4 @@ if __name__ == '__main__': Perform unit testing for Python interface. """ # Run tests - rc = test() - - # Exit with return code - sys.exit(rc) + test()