Commit 0be0a1a4450dd64c86fc9b87dd08a291684a8716
1 parent
90c2e5d8
Integrate code
Showing
10 changed files
with
940 additions
and
650 deletions
ChangeLog
| 1 | -2018-11-23 | 1 | +2018-12-11 |
| 2 | 2 | ||
| 3 | * Version 1.6.0 released | 3 | * Version 1.6.0 released |
| 4 | ======================== | 4 | ======================== |
| @@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
| 7 | CTA background rates are now per ontime (#2758) | 7 | CTA background rates are now per ontime (#2758) |
| 8 | Apply event bin weighting in ctmodel for stacked computation (#2721) | 8 | Apply event bin weighting in ctmodel for stacked computation (#2721) |
| 9 | Enable ctbin to produce counts cubes for a joint binned analysis (#2714) | 9 | Enable ctbin to produce counts cubes for a joint binned analysis (#2714) |
| 10 | + Add ctfindvar tool (#2713) | ||
| 10 | Add Jupyter notebooks for H.E.S.S. DR1 (#2712) | 11 | Add Jupyter notebooks for H.E.S.S. DR1 (#2712) |
| 11 | csphagen now creates appropriate model for likelihood fitting (#2711) | 12 | csphagen now creates appropriate model for likelihood fitting (#2711) |
| 12 | csphagen now supports any kind of background model (#2710) | 13 | csphagen now supports any kind of background model (#2710) |
NEWS
| 1 | New Features and Important Changes in ctools 1.6.0 | 1 | New Features and Important Changes in ctools 1.6.0 |
| 2 | 2 | ||
| 3 | -23 November 2018 | 3 | +11 December 2018 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | Introduction | 6 | Introduction |
| @@ -126,6 +126,12 @@ ctexpcube - CTA exposure cube generation | @@ -126,6 +126,12 @@ ctexpcube - CTA exposure cube generation | ||
| 126 | None | 126 | None |
| 127 | 127 | ||
| 128 | 128 | ||
| 129 | +ctfindvar - Variability search | ||
| 130 | +------------------------------ | ||
| 131 | +New: the ctfindvar tool searches for source variability using an On/Off method | ||
| 132 | +in the time domain (#2713). | ||
| 133 | + | ||
| 134 | + | ||
| 129 | ctlike - Maximum likelihood fitting | 135 | ctlike - Maximum likelihood fitting |
| 130 | ----------------------------------- | 136 | ----------------------------------- |
| 131 | Add hidden "like_accuracy" parameter to allow control of the accuracy of | 137 | Add hidden "like_accuracy" parameter to allow control of the accuracy of |
doc/source/admin/release_history/1.6.rst
| @@ -14,6 +14,7 @@ In particular, this release provides: | @@ -14,6 +14,7 @@ In particular, this release provides: | ||
| 14 | * Support for Xspec spectral analysis | 14 | * Support for Xspec spectral analysis |
| 15 | * Improved computation speed for :ref:`ctskymap` and :ref:`csphagen` | 15 | * Improved computation speed for :ref:`ctskymap` and :ref:`csphagen` |
| 16 | * Parallelisation of various cscripts | 16 | * Parallelisation of various cscripts |
| 17 | +* Support for source variability searches | ||
| 17 | * Support for Python pickeling | 18 | * Support for Python pickeling |
| 18 | * A Code Generator to facilitate adding ctools and cscripts | 19 | * A Code Generator to facilitate adding ctools and cscripts |
| 19 | 20 | ||
| @@ -102,6 +103,8 @@ Improvements | @@ -102,6 +103,8 @@ Improvements | ||
| 102 | New features | 103 | New features |
| 103 | ------------ | 104 | ------------ |
| 104 | 105 | ||
| 106 | +* [`2713 <https://cta-redmine.irap.omp.eu/issues/2713>`_] - | ||
| 107 | + Add :ref:`ctfindvar` tool | ||
| 105 | * [`2709 <https://cta-redmine.irap.omp.eu/issues/2709>`_] - | 108 | * [`2709 <https://cta-redmine.irap.omp.eu/issues/2709>`_] - |
| 106 | Add code generator | 109 | Add code generator |
| 107 | * [`2694 <https://cta-redmine.irap.omp.eu/issues/2694>`_] - | 110 | * [`2694 <https://cta-redmine.irap.omp.eu/issues/2694>`_] - |
doc/source/users/reference_manual/ctfindvar.rst
| 1 | .. _ctfindvar: | 1 | .. _ctfindvar: |
| 2 | 2 | ||
| 3 | ctfindvar | 3 | ctfindvar |
| 4 | -============================== | 4 | +========= |
| 5 | 5 | ||
| 6 | -ToDo: Describe in a one liner what the tool is doing. | 6 | +Search for source variability. |
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | Synopsis | 9 | Synopsis |
| 10 | -------- | 10 | -------- |
| 11 | -This tool is used to search for source variability. | ||
| 12 | -The variability is computed by binning the arrival time of the photons | ||
| 13 | -and applying the on-off method to each bin, integrating the background | ||
| 14 | -over all the other bins. | ||
| 15 | -A Limit is set to include a bin in the background sample, i.e., its | ||
| 16 | -significance with respect to all the others bins has to be lower than 4.5 | ||
| 17 | -The significance of each bin is computed using Li&Ma eq. 17. | ||
| 18 | -A limit on the background sample can also be included, taking only into | ||
| 19 | -account bins that have a number of counts which is higher than a threshold | ||
| 20 | -defined by the user via the "minoff" parameter. | ||
| 21 | - | ||
| 22 | -Variability is calculated for each pixel of the sky given in the input files. | ||
| 23 | -The results of the variability is further stored in the srcsig.fits file, | ||
| 24 | -where the GTIs and the significance of each bin are stored. | ||
| 25 | -Only the sources with a significance > 4.5 sigmas are stored. | ||
| 26 | - | ||
| 27 | -:ref:`ctfindvar` takes in input some observation files. | ||
| 28 | -It calculates a cube with several maps, each one with a count number integrated | ||
| 29 | -over a time period defined by the tinterval parameter, for each pixel. | ||
| 30 | -The tinterval parameter is the time scale over which the variability | ||
| 31 | -will be searched. | ||
| 32 | - | ||
| 33 | -Inputs files: | ||
| 34 | -- observation file xml, or event list .fits | ||
| 35 | - | ||
| 36 | -Output files: | ||
| 37 | -- countscube.fits | ||
| 38 | - provides all the count-skymaps contained in the cube. | ||
| 39 | -- peaksigmap.fits | ||
| 40 | - a skymap of the highest significance for each pixel | ||
| 41 | -- srcsig.fits | ||
| 42 | - a table containing the GTIs together with the significance | ||
| 43 | - for all the sources with a significant variability detected. | ||
| 44 | - | ||
| 45 | - | ||
| 46 | -The significance of a source can be displayed using the | ||
| 47 | -``show_variability_evolution.py`` script in the example forlder | 11 | + |
| 12 | +This tool searches for source variability by applying the On/Off method in the | ||
| 13 | +time domain. The variability of sky map pixels is computed by binning the events | ||
| 14 | +as function of the photon arrival time and applying the On/Off method to each | ||
| 15 | +time bin, integrating the background over all the other time bins. Only bins | ||
| 16 | +with a variabilty significance below a given threshold, defined by the hidden | ||
| 17 | +``threshold`` parameter, are included in the background estimate. Furthermore, | ||
| 18 | +only time bins that exceed a minimum number of events, specified by the hidden | ||
| 19 | +``minoff`` parameter, are considered for the background estimate. The significance | ||
| 20 | +of each time bin is computed using Li & Ma formula. | ||
| 21 | + | ||
| 22 | +:ref:`ctfindvar` will search a grid of sky map pixels for source variability. Using | ||
| 23 | +the hidden ``smooth_kernel`` and ``smooth_rad`` parameters, the sky map may be | ||
| 24 | +smoothed before the variability search. The tool will compute sky maps for a | ||
| 25 | +number of time bins. The duration of each time bin is specified by the ``tinterval`` | ||
| 26 | +parameter, the start and stop time are defined by the ``tmin`` and ``tmax`` | ||
| 27 | +parameters. If the start and stop time are ``NONE``, the start and stop times will | ||
| 28 | +be extracted from the input event list(s). Note that ``tinterval`` specifies the | ||
| 29 | +time scale over which the variability will be searched. | ||
| 30 | + | ||
| 31 | +The tool will determine the sky map pixel with the maximum variability and store | ||
| 32 | +the variability histogram and pixel position as ``MAXSIGPIXEL`` in the output file, | ||
| 33 | +specified using the ``outmap`` parameter. In addition, the tool will determine the | ||
| 34 | +variability for a number of source positions. If an input model is specified | ||
| 35 | +using the ``inmodel`` parameter, the source positions will be defined by the centre | ||
| 36 | +positions of all gamma-ray source components in the input model. If no input | ||
| 37 | +model is specified, the tool will use the ``xsrc`` and ``ysrc`` parameters to allow | ||
| 38 | +the specification of a source position. The results will be stored in the output | ||
| 39 | +file using either the source names found in the model definition file, or the | ||
| 40 | +name ``SOURCE`` if the source position was specified by the ``xsrc`` and ``ysrc`` | ||
| 41 | +parameters. | ||
| 42 | + | ||
| 43 | +All sky map pixels with a variability above the value specified by the ``threshold`` | ||
| 44 | +will also added be as a point source model to the ``outmodel`` file. Each source will | ||
| 45 | +have a power law as the spectral component with a total flux that corresponds to | ||
| 46 | +1% of the Crab nebula flux. | ||
| 47 | + | ||
| 48 | 48 | ||
| 49 | General parameters | 49 | General parameters |
| 50 | ------------------ | 50 | ------------------ |
| @@ -56,7 +56,17 @@ General parameters | @@ -56,7 +56,17 @@ General parameters | ||
| 56 | Input model definition file for extracting source positions. | 56 | Input model definition file for extracting source positions. |
| 57 | 57 | ||
| 58 | ``(outcube = NONE) [file]`` | 58 | ``(outcube = NONE) [file]`` |
| 59 | - Filename for saving counts cube, NONE will result in no cube being saved. | 59 | + Filename for saving counts cube, ``NONE`` will result in no cube being saved. |
| 60 | + | ||
| 61 | +``outmap [file]`` | ||
| 62 | + Filename for output sky map containing the maximum significance for each | ||
| 63 | + spatial pixel. The file also contains the variability significance as function | ||
| 64 | + of time for each source of interest, and the pixel with the maximum | ||
| 65 | + significance. Furthermore, it contains the Right Ascension and Declination | ||
| 66 | + of each source of interest and the pixel with the maximum significance. | ||
| 67 | + | ||
| 68 | +``outmodel [file]`` | ||
| 69 | + Output model definition file containing sources for significant pixels. | ||
| 60 | 70 | ||
| 61 | ``caldb [string]`` | 71 | ``caldb [string]`` |
| 62 | Calibration database (only required for IRF background subtraction if no | 72 | Calibration database (only required for IRF background subtraction if no |
| @@ -66,40 +76,45 @@ General parameters | @@ -66,40 +76,45 @@ General parameters | ||
| 66 | Instrument response function (only required for IRF background subtraction | 76 | Instrument response function (only required for IRF background subtraction |
| 67 | if no response information is provided by ``inobs``). | 77 | if no response information is provided by ``inobs``). |
| 68 | 78 | ||
| 69 | -``prefix [string]`` | ||
| 70 | - Output file prefix. The method will save two files: | ||
| 71 | - - Skymap containing the maximum significance for each spatial pixel | ||
| 72 | - - File containing the significance as a function of time interval for each | ||
| 73 | - source | ||
| 74 | 79 | ||
| 75 | -``(minoff = 0) [real]`` | ||
| 76 | - Minimum number of off counts to compute the significance | 80 | +Variability search parameters |
| 81 | +----------------------------- | ||
| 82 | + | ||
| 83 | +``coordsys <CEL|GAL> [string]`` | ||
| 84 | + Coordinate system (CEL - celestial, GAL - galactic). | ||
| 85 | + | ||
| 86 | +``xsrc [real]`` | ||
| 87 | + Right Ascension / Galactic longitude of source of interest (J2000, in degrees) | ||
| 88 | + | ||
| 89 | +``ysrc [real]`` | ||
| 90 | + Declination / Galactic latitude of source of interest (J2000, in degrees) | ||
| 77 | 91 | ||
| 78 | ``emin [real]`` | 92 | ``emin [real]`` |
| 79 | - Minimum energy (TeV) for extracting events. A value of 0 results in no cut | ||
| 80 | - being applied. | 93 | + Minimum energy (TeV) for extracting events. |
| 81 | 94 | ||
| 82 | ``emax [real]`` | 95 | ``emax [real]`` |
| 83 | - Maximum energy (TeV) for extracting events. A value of 0 results in no cut | ||
| 84 | - being applied. | 96 | + Maximum energy (TeV) for extracting events. |
| 85 | 97 | ||
| 86 | -``(sig_thr = 4.5) [real]`` | 98 | +``(threshold = 4.5) [real]`` |
| 87 | Significance threshold for variability detection. | 99 | Significance threshold for variability detection. |
| 88 | 100 | ||
| 89 | -``(smoothkrnl = NONE) <GAUSSIAN|DISK|NONE> [string]`` | 101 | +``(minoff = 0) [real]`` |
| 102 | + Minimum number of off counts to compute the significance. | ||
| 103 | + | ||
| 104 | +``(smooth_kernel = NONE) <GAUSSIAN|DISK|NONE> [string]`` | ||
| 90 | Kernel to be used in smoothing the counts maps before computing | 105 | Kernel to be used in smoothing the counts maps before computing |
| 91 | significances. | 106 | significances. |
| 92 | 107 | ||
| 93 | -``(smoothpar = 0.05) [real]`` | ||
| 94 | - Parameter for the smoothing kernel. This is either the sigma of the GAUSSIAN | ||
| 95 | - or the radius of the DISK. | 108 | +``(smooth_rad = 0.05) [real]`` |
| 109 | + Radius of smoothing kernel in degrees. This is either the sigma of the | ||
| 110 | + ``GAUSSIAN`` or the radius of the ``DISK``. | ||
| 96 | 111 | ||
| 97 | 112 | ||
| 98 | Time binning parameters | 113 | Time binning parameters |
| 99 | ----------------------- | 114 | ----------------------- |
| 100 | 115 | ||
| 101 | ``tinterval [real]`` | 116 | ``tinterval [real]`` |
| 102 | - interval in seconds for each time step. | 117 | + Interval in seconds for each time step. |
| 103 | 118 | ||
| 104 | ``tmin [time]`` | 119 | ``tmin [time]`` |
| 105 | Start time for interval determination (UTC string, JD, MJD or MET in seconds). | 120 | Start time for interval determination (UTC string, JD, MJD or MET in seconds). |
| @@ -120,7 +135,7 @@ Spatial binning parameters | @@ -120,7 +135,7 @@ Spatial binning parameters | ||
| 120 | -------------------------- | 135 | -------------------------- |
| 121 | 136 | ||
| 122 | ``(usepnt = no) [boolean]`` | 137 | ``(usepnt = no) [boolean]`` |
| 123 | - Use CTA pointing direction for cube centre instead of xref/yref parameters? | 138 | + Use CTA pointing direction for sky map centre instead of xref/yref parameters? |
| 124 | 139 | ||
| 125 | ``nxpix [integer]`` | 140 | ``nxpix [integer]`` |
| 126 | Number of cube bins in Right Ascension or Galactic longitude. | 141 | Number of cube bins in Right Ascension or Galactic longitude. |
| @@ -129,25 +144,16 @@ Spatial binning parameters | @@ -129,25 +144,16 @@ Spatial binning parameters | ||
| 129 | Number of cube bins in Declination or Galactic latitude. | 144 | Number of cube bins in Declination or Galactic latitude. |
| 130 | 145 | ||
| 131 | ``binsz [real]`` | 146 | ``binsz [real]`` |
| 132 | - Cube bin size (in degrees/pixel). | ||
| 133 | - | ||
| 134 | -``coordsys <CEL|GAL> [string]`` | ||
| 135 | - Coordinate system (CEL - celestial, GAL - galactic). | 147 | + Sky map pixel size (in degrees/pixel). |
| 136 | 148 | ||
| 137 | ``proj <AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN> [string]`` | 149 | ``proj <AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN> [string]`` |
| 138 | Projection method. | 150 | Projection method. |
| 139 | 151 | ||
| 140 | ``xref [real]`` | 152 | ``xref [real]`` |
| 141 | - Right Ascension / Galactic longitude of cube centre (J2000, in degrees). | 153 | + Right Ascension / Galactic longitude of sky map centre (J2000, in degrees). |
| 142 | 154 | ||
| 143 | ``yref [real]`` | 155 | ``yref [real]`` |
| 144 | - Declination / Galactic latitude of cube centre (J2000, in degrees). | ||
| 145 | - | ||
| 146 | -``xsrc [real]`` | ||
| 147 | - Right Ascension / Galactic longitude of source of interest (J2000, in degrees) | ||
| 148 | - | ||
| 149 | -``ysrc [real]`` | ||
| 150 | - Declination / Galactic latitude of source of interest (J2000, in degrees) | 156 | + Declination / Galactic latitude of sky map centre (J2000, in degrees). |
| 151 | 157 | ||
| 152 | 158 | ||
| 153 | Standard parameters | 159 | Standard parameters |
doc/source/users/reference_manual/index.rst
| @@ -17,7 +17,6 @@ ctools | @@ -17,7 +17,6 @@ ctools | ||
| 17 | .. toctree:: | 17 | .. toctree:: |
| 18 | :maxdepth: 1 | 18 | :maxdepth: 1 |
| 19 | 19 | ||
| 20 | - ctfindvar --- ToDo: Describe what tool is doing <ctfindvar> | ||
| 21 | ctbin --- Generates counts cube <ctbin> | 20 | ctbin --- Generates counts cube <ctbin> |
| 22 | ctbkgcube --- Generates background cube <ctbkgcube> | 21 | ctbkgcube --- Generates background cube <ctbkgcube> |
| 23 | ctbutterfly --- Compute butterfly <ctbutterfly> | 22 | ctbutterfly --- Compute butterfly <ctbutterfly> |
| @@ -25,6 +24,7 @@ ctools | @@ -25,6 +24,7 @@ ctools | ||
| 25 | ctedispcube --- Generates energy dispersion cube <ctedispcube> | 24 | ctedispcube --- Generates energy dispersion cube <ctedispcube> |
| 26 | cterror --- Calculates likelihood profile errors <cterror> | 25 | cterror --- Calculates likelihood profile errors <cterror> |
| 27 | ctexpcube --- Generates exposure cube <ctexpcube> | 26 | ctexpcube --- Generates exposure cube <ctexpcube> |
| 27 | + ctfindvar --- Search for source variability <ctfindvar> | ||
| 28 | ctlike --- Performs maximum likelihood fitting <ctlike> | 28 | ctlike --- Performs maximum likelihood fitting <ctlike> |
| 29 | ctmapcube --- Generates a map cube <ctmapcube> | 29 | ctmapcube --- Generates a map cube <ctmapcube> |
| 30 | ctmodel --- Computes model counts cube <ctmodel> | 30 | ctmodel --- Computes model counts cube <ctmodel> |
examples/show_variability_evolution.py
| 1 | #! /usr/bin/env python | 1 | #! /usr/bin/env python |
| 2 | # ========================================================================== | 2 | # ========================================================================== |
| 3 | -# Shows butterfly diagram created with ctbutterfly | 3 | +# Shows source variability evolution created with ctfindvar |
| 4 | # | 4 | # |
| 5 | -# Copyright (C) 2014-2017 Simon Bonnefoy | 5 | +# Copyright (C) 2018 Simon Bonnefoy |
| 6 | # | 6 | # |
| 7 | # This program is free software: you can redistribute it and/or modify | 7 | # This program is free software: you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by | 8 | # it under the terms of the GNU General Public License as published by |
| @@ -43,6 +43,8 @@ def plot_variability_evolution(filename, plotfile, srcname): | @@ -43,6 +43,8 @@ def plot_variability_evolution(filename, plotfile, srcname): | ||
| 43 | Name of spectrum FITS file | 43 | Name of spectrum FITS file |
| 44 | plotfile : str | 44 | plotfile : str |
| 45 | Plot file name | 45 | Plot file name |
| 46 | + srcname : str | ||
| 47 | + Source name | ||
| 46 | """ | 48 | """ |
| 47 | # Read variability file | 49 | # Read variability file |
| 48 | fits = gammalib.GFits(filename) | 50 | fits = gammalib.GFits(filename) |
| @@ -51,41 +53,45 @@ def plot_variability_evolution(filename, plotfile, srcname): | @@ -51,41 +53,45 @@ def plot_variability_evolution(filename, plotfile, srcname): | ||
| 51 | c_gti_stop = table['TSTOP'] | 53 | c_gti_stop = table['TSTOP'] |
| 52 | c_sig = table[srcname] | 54 | c_sig = table[srcname] |
| 53 | 55 | ||
| 54 | - #convert the c_sig object to list | ||
| 55 | - table_c_sig=[] | ||
| 56 | - table_c_gti=[] | ||
| 57 | - | 56 | + # Convert the c_sig object to list |
| 57 | + table_c_sig = [] | ||
| 58 | + table_c_gti = [] | ||
| 58 | for k in c_sig: | 59 | for k in c_sig: |
| 59 | table_c_sig.append(k) | 60 | table_c_sig.append(k) |
| 60 | - for j,k in zip(c_gti_start, c_gti_stop): | 61 | + for j, k in zip(c_gti_start, c_gti_stop): |
| 61 | table_c_gti.append(0.5*(j+k)) | 62 | table_c_gti.append(0.5*(j+k)) |
| 62 | 63 | ||
| 63 | - #Initializing the plots | ||
| 64 | - axarr=[] | ||
| 65 | - f = plt.figure(figsize=(12,7)) | ||
| 66 | - ax1 = f.add_subplot(121) | ||
| 67 | - ax2 = f.add_subplot(122) | 64 | + # Initializing the plots |
| 65 | + axarr = [] | ||
| 66 | + f = plt.figure(figsize=(12,7)) | ||
| 67 | + ax1 = f.add_subplot(121) | ||
| 68 | + ax2 = f.add_subplot(122) | ||
| 68 | axarr.append(ax1) | 69 | axarr.append(ax1) |
| 69 | axarr.append(ax2) | 70 | axarr.append(ax2) |
| 70 | 71 | ||
| 72 | + # Create first plot | ||
| 71 | axarr[0].plot(table_c_gti, table_c_sig) | 73 | axarr[0].plot(table_c_gti, table_c_sig) |
| 72 | axarr[0].set_title('Significance evolution') | 74 | axarr[0].set_title('Significance evolution') |
| 73 | axarr[0].set_xlabel('MJD') | 75 | axarr[0].set_xlabel('MJD') |
| 74 | axarr[0].set_ylabel('Significance') | 76 | axarr[0].set_ylabel('Significance') |
| 75 | 77 | ||
| 76 | - axarr[1].hist(table_c_sig, 20, range=[min(table_c_sig), max(table_c_sig)], histtype='stepfilled', facecolor='g', alpha=0.75) | 78 | + # Create second plot |
| 79 | + axarr[1].hist(table_c_sig, 20, range=[min(table_c_sig), max(table_c_sig)], | ||
| 80 | + histtype='stepfilled', facecolor='g', alpha=0.75) | ||
| 77 | axarr[1].set_title('Significance distribution') | 81 | axarr[1].set_title('Significance distribution') |
| 78 | axarr[1].set_xlabel('Significance') | 82 | axarr[1].set_xlabel('Significance') |
| 79 | axarr[1].set_ylabel('Counts') | 83 | axarr[1].set_ylabel('Counts') |
| 80 | 84 | ||
| 81 | - #IT SEEMS THAT THE LOG SCALE IS NOT WORKING WELL !!!!!! | ||
| 82 | - #axarr[1].gca().set_yscale('log') | ||
| 83 | - | 85 | + # Optionally save result in file |
| 84 | if plotfile != "": | 86 | if plotfile != "": |
| 85 | f.savefig(plotfile+".png") | 87 | f.savefig(plotfile+".png") |
| 86 | 88 | ||
| 87 | plt.show() | 89 | plt.show() |
| 88 | 90 | ||
| 91 | + # Return | ||
| 92 | + return | ||
| 93 | + | ||
| 94 | + | ||
| 89 | # ========================== # | 95 | # ========================== # |
| 90 | # Show variability evolution # | 96 | # Show variability evolution # |
| 91 | # ========================== # | 97 | # ========================== # |
src/ctfindvar/ctfindvar.cpp
| @@ -39,6 +39,7 @@ | @@ -39,6 +39,7 @@ | ||
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | /* __ Method name definitions ____________________________________________ */ | 41 | /* __ Method name definitions ____________________________________________ */ |
| 42 | +#define G_INX2GTI "ctfindvar::inx2gti(int&)" | ||
| 42 | #define G_FILL_CUBE "ctfindvar::fill_cube(GCTAObservation*)" | 43 | #define G_FILL_CUBE "ctfindvar::fill_cube(GCTAObservation*)" |
| 43 | #define G_FILL_ALPHA_VECTOR "ctfindvar::fill_alpha_vector(const int&, "\ | 44 | #define G_FILL_ALPHA_VECTOR "ctfindvar::fill_alpha_vector(const int&, "\ |
| 44 | "vector<double>&)" | 45 | "vector<double>&)" |
| @@ -235,146 +236,16 @@ void ctfindvar::run(void) | @@ -235,146 +236,16 @@ void ctfindvar::run(void) | ||
| 235 | // Write input observation container into logger | 236 | // Write input observation container into logger |
| 236 | log_observations(NORMAL, m_obs, "Input observation"); | 237 | log_observations(NORMAL, m_obs, "Input observation"); |
| 237 | 238 | ||
| 238 | - // Loop over all unbinned CTA observations in the container | ||
| 239 | - #pragma omp parallel for | ||
| 240 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 241 | - | ||
| 242 | - // Get pointer to observation | ||
| 243 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 244 | - | ||
| 245 | - // Fill the cube | ||
| 246 | - fill_cube(obs); | ||
| 247 | - | ||
| 248 | - // Dispose events to free memory | ||
| 249 | - obs->dispose_events(); | ||
| 250 | - | ||
| 251 | - } // endfor: looped over observations | ||
| 252 | - | ||
| 253 | - // Smooth the maps if requested | ||
| 254 | - if ((*this)["smoothkrnl"].is_valid() && | ||
| 255 | - (*this)["smoothkrnl"].string() != "NONE") { | ||
| 256 | - m_counts.smooth((*this)["smoothkrnl"].string(), | ||
| 257 | - (*this)["smoothpar"].real()); | ||
| 258 | - } | ||
| 259 | - | ||
| 260 | - // Get number of maps | ||
| 261 | - const int nbins = m_counts.nmaps(); | ||
| 262 | - | ||
| 263 | - // creating GSkyDir to get the position of the source and each pixels | ||
| 264 | - | ||
| 265 | - // Extract which pixel in the map each source is located in | ||
| 266 | - std::vector<int> srcInxPix; | ||
| 267 | - if (m_inmodel.size() > 0) { | ||
| 268 | - for (int mod = 0; mod < m_inmodel.size(); ++mod) { | ||
| 269 | - | ||
| 270 | - // Extract the model | ||
| 271 | - GModelSky* model = dynamic_cast<GModelSky*>(m_inmodel[mod]); | ||
| 272 | - if (model != NULL) { | ||
| 273 | - // Get the source position | ||
| 274 | - GModelSpatial* model_spatial = model->spatial(); | ||
| 275 | - GSkyRegion* model_region = model_spatial->region(); | ||
| 276 | - GSkyDir srcSkyDir = | ||
| 277 | - dynamic_cast<GSkyRegionCircle*>(model_region)->centre(); | ||
| 278 | - | ||
| 279 | - // Store the map index of this source | ||
| 280 | - int src_map_index = m_counts.dir2inx(srcSkyDir); | ||
| 281 | - srcInxPix.push_back(src_map_index); | ||
| 282 | - } else { | ||
| 283 | - m_inmodel.remove(mod); | ||
| 284 | - mod--; | ||
| 285 | - } | ||
| 286 | - } | ||
| 287 | - } | ||
| 288 | - // ... otherwise only one source position is queried | ||
| 289 | - else { | ||
| 290 | - GSkyDir srcSkyDir; | ||
| 291 | - if ((*this)["coordsys"].string() == "CEL") { | ||
| 292 | - srcSkyDir.radec_deg((*this)["xsrc"].real(),(*this)["ysrc"].real()); | ||
| 293 | - } else { | ||
| 294 | - srcSkyDir.lb_deg((*this)["xsrc"].real(),(*this)["ysrc"].real()); | ||
| 295 | - } | ||
| 296 | - | ||
| 297 | - // Store the index of this source | ||
| 298 | - int src_map_index = m_counts.dir2inx(srcSkyDir); | ||
| 299 | - srcInxPix.push_back(src_map_index); | ||
| 300 | - } | ||
| 301 | - | ||
| 302 | - //preparing the histogram with significance evolution | ||
| 303 | - //for the source center and the highest sig-pix | ||
| 304 | - m_pixsigsrc = GNdarray(srcInxPix.size(), nbins); | ||
| 305 | - m_pixsigmax = GNdarray(nbins); | ||
| 306 | - | ||
| 307 | - //Prepare the final skymap with the max significance of each pixel | ||
| 308 | - double max_sig = 0; | ||
| 309 | - | ||
| 310 | - log_header1(NORMAL, "Looping Over Pixels"); | ||
| 311 | - | ||
| 312 | - //looping over all the pixels in the cube | ||
| 313 | - #pragma omp parallel for | ||
| 314 | - for (int pix_number = 0; pix_number < m_counts.npix(); pix_number++) { | ||
| 315 | - | ||
| 316 | - //Preparing array to store significance evolution of | ||
| 317 | - //each pixel | ||
| 318 | - GNdarray pixSig(nbins); | ||
| 319 | - double total_counts=0; | ||
| 320 | - | ||
| 321 | - //Checking the integrated count of each pixel | ||
| 322 | - for (int k = 0; k < m_counts.nmaps(); k++) { | ||
| 323 | - total_counts += m_counts(pix_number, k); | ||
| 324 | - } | ||
| 325 | - | ||
| 326 | - //Getting the variability significance for the pixel | ||
| 327 | - get_variability_sig(pix_number,nbins, pixSig); | ||
| 328 | - | ||
| 329 | - //Getting the significance evolution for the source | ||
| 330 | - for (int src = 0; src < srcInxPix.size(); src++) { | 239 | + // Create GTIs |
| 240 | + init_gtis(); | ||
| 331 | 241 | ||
| 332 | - // Store the distribution if the source is located at this position | ||
| 333 | - if (srcInxPix[src] == pix_number) { | 242 | + // Create counts cube |
| 243 | + create_cube(); | ||
| 334 | 244 | ||
| 335 | - #pragma omp critical(ctfind_run) | ||
| 336 | - for (int i = 0; i < nbins; i++) { | ||
| 337 | - m_pixsigsrc(src,i) = pixSig(i); | ||
| 338 | - } | ||
| 339 | - } | ||
| 340 | - #ifdef G_DEBUG | ||
| 341 | - std::cout << "checking pixel number of the source of interest" << pix_number << std::endl; | ||
| 342 | - std::cout << "number of counts in pixel of the source of interest" << total_counts << std::endl; | ||
| 343 | - pixSigSrc=pixSig; | ||
| 344 | - std::cout << "checking pixel number " << pix_number << " with total number of counts of: " << total_counts << std::endl; | ||
| 345 | - std::cin.ignore(); | ||
| 346 | - std::cout << "checking pixel number of the source of interest: " << pix_number << " - with total number of counts of: " << total_counts << std::endl; | ||
| 347 | - #endif | ||
| 348 | - } | ||
| 349 | - } | ||
| 350 | - | ||
| 351 | - // Getting the evolution for the pix with highest significance | ||
| 352 | - #pragma omp critical(ctfind_run) | ||
| 353 | - { | ||
| 354 | - if (max(pixSig) > max_sig) { | ||
| 355 | - // Update the pixel position with the maximum sigma | ||
| 356 | - max_sig = max(pixSig); | ||
| 357 | - m_max_sig_dir = m_counts.inx2dir(pix_number); | ||
| 358 | - m_pixsigmax = pixSig; | ||
| 359 | - } | ||
| 360 | - } | ||
| 361 | - //storing sig in skymap | ||
| 362 | - m_peaksigmap(pix_number) = max(pixSig); | ||
| 363 | - | ||
| 364 | - //If the significance is greater than sig threshold, the position | ||
| 365 | - //is stored in a model | ||
| 366 | - if (max(pixSig) > m_sig_threshold) { | ||
| 367 | - GSkyDir dir_pix = m_counts.inx2dir(pix_number); | ||
| 368 | - fill_model_sig_pos(dir_pix); | ||
| 369 | - } | ||
| 370 | - | ||
| 371 | - } | ||
| 372 | - | ||
| 373 | - log_header1(NORMAL, "Analysis finished"); | ||
| 374 | - log_value(NORMAL, "Maximum sigma", max_sig); | ||
| 375 | - log_value(NORMAL, "Max pixel RA", m_max_sig_dir.ra_deg()); | ||
| 376 | - log_value(NORMAL, "Max pixel DEC", m_max_sig_dir.dec_deg()); | 245 | + // Analyse cube |
| 246 | + analyse_cube(); | ||
| 377 | 247 | ||
| 248 | + // Return | ||
| 378 | return; | 249 | return; |
| 379 | } | 250 | } |
| 380 | 251 | ||
| @@ -388,37 +259,52 @@ void ctfindvar::run(void) | @@ -388,37 +259,52 @@ void ctfindvar::run(void) | ||
| 388 | ***************************************************************************/ | 259 | ***************************************************************************/ |
| 389 | void ctfindvar::save(void) | 260 | void ctfindvar::save(void) |
| 390 | { | 261 | { |
| 262 | + // Write header | ||
| 391 | log_header1(TERSE, "Saving results"); | 263 | log_header1(TERSE, "Saving results"); |
| 392 | 264 | ||
| 393 | - // Filenames | ||
| 394 | - std::string prefix((*this)["prefix"].string()); | ||
| 395 | - | ||
| 396 | // Write counts cube | 265 | // Write counts cube |
| 397 | if ((*this)["outcube"].is_valid()) { | 266 | if ((*this)["outcube"].is_valid()) { |
| 267 | + | ||
| 268 | + // Get counts cube output filename | ||
| 398 | GFilename outcube = (*this)["outcube"].filename(); | 269 | GFilename outcube = (*this)["outcube"].filename(); |
| 399 | - log_value(TERSE, "Saving counts cube", outcube); | 270 | + |
| 271 | + // Save counts cube | ||
| 400 | m_counts.save(outcube, (*this)["clobber"].boolean()); | 272 | m_counts.save(outcube, (*this)["clobber"].boolean()); |
| 273 | + | ||
| 274 | + // Log saving | ||
| 275 | + log_value(TERSE, "Saving counts cube", outcube); | ||
| 401 | } | 276 | } |
| 402 | 277 | ||
| 403 | // Create a FITS file for storing the output | 278 | // Create a FITS file for storing the output |
| 404 | - m_outfile.clear(); | 279 | + GFits fits; |
| 405 | 280 | ||
| 406 | // Write the most significant values for each pixel | 281 | // Write the most significant values for each pixel |
| 407 | - log_string(TERSE, "Appending maximum significances map to output file"); | ||
| 408 | - m_peaksigmap.write(m_outfile, "PEAKSIGMAP"); | 282 | + m_peaksigmap.write(fits, "PEAKSIGMAP"); |
| 283 | + | ||
| 284 | + // Write source histograms | ||
| 285 | + write_source_histograms(fits); | ||
| 409 | 286 | ||
| 410 | - // Write individual source distributions | ||
| 411 | - write_srchist(); | 287 | + // Get output map filename |
| 288 | + GFilename outmap = (*this)["outmap"].filename(); | ||
| 412 | 289 | ||
| 413 | - // Write the output file | ||
| 414 | - GFilename outfilename = prefix + "signifmap.fits"; | ||
| 415 | - log_value(TERSE, "Saving results to ", outfilename); | ||
| 416 | - m_outfile.saveto(outfilename, (*this)["clobber"].boolean()); | 290 | + // Save output map |
| 291 | + fits.saveto(outmap, (*this)["clobber"].boolean()); | ||
| 417 | 292 | ||
| 418 | - //Save the model file with position with significance | 293 | + // Log saving |
| 294 | + log_value(TERSE, "Saving output map", outmap); | ||
| 295 | + | ||
| 296 | + // Save the model definition file | ||
| 419 | if (m_model_above_thr.size() > 2) { | 297 | if (m_model_above_thr.size() > 2) { |
| 420 | - GFilename model_filename = prefix + "model_significant_directions.xml"; | ||
| 421 | - m_model_above_thr.save(model_filename); | 298 | + |
| 299 | + // Get model output filename | ||
| 300 | + GFilename outmodel = (*this)["outmodel"].filename(); | ||
| 301 | + | ||
| 302 | + // Save model | ||
| 303 | + m_model_above_thr.save(outmodel); | ||
| 304 | + | ||
| 305 | + // Log saving | ||
| 306 | + log_value(TERSE, "Saving output model", outmodel); | ||
| 307 | + | ||
| 422 | } | 308 | } |
| 423 | 309 | ||
| 424 | // Return | 310 | // Return |
| @@ -429,7 +315,7 @@ void ctfindvar::save(void) | @@ -429,7 +315,7 @@ void ctfindvar::save(void) | ||
| 429 | /***********************************************************************//** | 315 | /***********************************************************************//** |
| 430 | * @brief Get the map index associated with a given time | 316 | * @brief Get the map index associated with a given time |
| 431 | * | 317 | * |
| 432 | - * @param[in] time Time | 318 | + * @param[in] time Time |
| 433 | * @return Index of map in counts cube | 319 | * @return Index of map in counts cube |
| 434 | ***************************************************************************/ | 320 | ***************************************************************************/ |
| 435 | int ctfindvar::time2inx(const GTime& time) | 321 | int ctfindvar::time2inx(const GTime& time) |
| @@ -438,29 +324,35 @@ int ctfindvar::time2inx(const GTime& time) | @@ -438,29 +324,35 @@ int ctfindvar::time2inx(const GTime& time) | ||
| 438 | int map_index = -1; | 324 | int map_index = -1; |
| 439 | 325 | ||
| 440 | // Loop over all GTIs | 326 | // Loop over all GTIs |
| 441 | - for (int i = 0; i < m_gti.size(); i++) { | ||
| 442 | - // Check if interval contains the time | 327 | + for (int i = 0; i < m_gti.size(); ++i) { |
| 328 | + | ||
| 329 | + // If interval contains the time then break | ||
| 443 | if (m_gti[i].contains(time)) { | 330 | if (m_gti[i].contains(time)) { |
| 444 | map_index = i; | 331 | map_index = i; |
| 445 | break; | 332 | break; |
| 446 | } | 333 | } |
| 334 | + | ||
| 447 | } | 335 | } |
| 448 | 336 | ||
| 337 | + // Return map index | ||
| 449 | return map_index; | 338 | return map_index; |
| 450 | } | 339 | } |
| 451 | 340 | ||
| 452 | 341 | ||
| 453 | /***********************************************************************//** | 342 | /***********************************************************************//** |
| 454 | - * @brief Return reference to significance cube object | 343 | + * @brief Return Good Time Interval for index |
| 344 | + * | ||
| 345 | + * @param[in] index Index | ||
| 346 | + * @return Good Time Interval | ||
| 455 | ***************************************************************************/ | 347 | ***************************************************************************/ |
| 456 | GGti ctfindvar::inx2gti(const int& index) | 348 | GGti ctfindvar::inx2gti(const int& index) |
| 457 | { | 349 | { |
| 350 | + // Throw an exception if index is invalid | ||
| 458 | if ((index < 0) || (index >= m_gti.size())) { | 351 | if ((index < 0) || (index >= m_gti.size())) { |
| 459 | - // Index is invalid, so throw an error | ||
| 460 | - throw GException::invalid_value("ctfindvar::inx2gti(const int&)", | ||
| 461 | - "'index' parameter out of range"); | 352 | + throw GException::out_of_range(G_INX2GTI, "Time index", index, m_gti.size()); |
| 462 | } | 353 | } |
| 463 | 354 | ||
| 355 | + // Return Good Time Interval | ||
| 464 | return m_gti[index]; | 356 | return m_gti[index]; |
| 465 | } | 357 | } |
| 466 | 358 | ||
| @@ -483,7 +375,6 @@ void ctfindvar::init_members(void) | @@ -483,7 +375,6 @@ void ctfindvar::init_members(void) | ||
| 483 | m_max_sig_dir.clear(); | 375 | m_max_sig_dir.clear(); |
| 484 | m_minoff = 0.0; | 376 | m_minoff = 0.0; |
| 485 | m_sig_threshold = 0.0; | 377 | m_sig_threshold = 0.0; |
| 486 | - m_outfile.clear(); | ||
| 487 | m_peaksigmap.clear(); | 378 | m_peaksigmap.clear(); |
| 488 | m_pixsigsrc.clear(); | 379 | m_pixsigsrc.clear(); |
| 489 | m_tstart.clear(); | 380 | m_tstart.clear(); |
| @@ -511,7 +402,6 @@ void ctfindvar::copy_members(const ctfindvar& app) | @@ -511,7 +402,6 @@ void ctfindvar::copy_members(const ctfindvar& app) | ||
| 511 | m_max_sig_dir = app.m_max_sig_dir; | 402 | m_max_sig_dir = app.m_max_sig_dir; |
| 512 | m_minoff = app.m_minoff; | 403 | m_minoff = app.m_minoff; |
| 513 | m_sig_threshold = app.m_sig_threshold; | 404 | m_sig_threshold = app.m_sig_threshold; |
| 514 | - m_outfile = app.m_outfile; | ||
| 515 | m_peaksigmap = app.m_peaksigmap; | 405 | m_peaksigmap = app.m_peaksigmap; |
| 516 | m_pixsigsrc = app.m_pixsigsrc; | 406 | m_pixsigsrc = app.m_pixsigsrc; |
| 517 | m_tstart = app.m_tstart; | 407 | m_tstart = app.m_tstart; |
| @@ -537,39 +427,35 @@ void ctfindvar::free_members(void) | @@ -537,39 +427,35 @@ void ctfindvar::free_members(void) | ||
| 537 | 427 | ||
| 538 | /***********************************************************************//** | 428 | /***********************************************************************//** |
| 539 | * @brief Get application parameters | 429 | * @brief Get application parameters |
| 540 | - * | ||
| 541 | - * @todo Implement method | ||
| 542 | ***************************************************************************/ | 430 | ***************************************************************************/ |
| 543 | void ctfindvar::get_parameters(void) | 431 | void ctfindvar::get_parameters(void) |
| 544 | { | 432 | { |
| 545 | - #ifdef _OPENMP | ||
| 546 | - int nthreads = (*this)["nthreads"].integer(); | ||
| 547 | - if (nthreads > 0) { | ||
| 548 | - omp_set_num_threads(nthreads); | ||
| 549 | - } | ||
| 550 | - #endif | ||
| 551 | - | ||
| 552 | // Load the observations | 433 | // Load the observations |
| 553 | setup_observations(m_obs, true, true, false); | 434 | setup_observations(m_obs, true, true, false); |
| 554 | 435 | ||
| 555 | - // Get the rest of the parameters | ||
| 556 | - if (read_ahead()) { | ||
| 557 | - (*this)["prefix"].string(); | ||
| 558 | - | ||
| 559 | - if ((*this)["inmodel"].is_valid()) { | ||
| 560 | - m_inmodel = GModels((*this)["inmodel"].filename()); | ||
| 561 | - } else { | ||
| 562 | - // Get the desired source position from user | ||
| 563 | - (*this)["xsrc"].real(); | ||
| 564 | - (*this)["ysrc"].real(); | ||
| 565 | - } | 436 | + // Either load model or query source position parameters |
| 437 | + if ((*this)["inmodel"].is_valid()) { | ||
| 438 | + m_inmodel = GModels((*this)["inmodel"].filename()); | ||
| 439 | + } | ||
| 440 | + else { | ||
| 441 | + (*this)["coordsys"].string(); | ||
| 442 | + (*this)["xsrc"].real(); | ||
| 443 | + (*this)["ysrc"].real(); | ||
| 566 | } | 444 | } |
| 567 | 445 | ||
| 568 | - // Create GTIs and counts cube | ||
| 569 | - init_gtis(); | ||
| 570 | - init_cube(); | 446 | + // Query time limit parameters |
| 447 | + (*this)["tinterval"].real(); | ||
| 448 | + if ((*this)["tmin"].is_valid()) { | ||
| 449 | + (*this)["tmin"].time(); | ||
| 450 | + } | ||
| 451 | + if ((*this)["tmax"].is_valid()) { | ||
| 452 | + (*this)["tmax"].time(); | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + // Create map to query spatial parameters | ||
| 456 | + create_map(m_obs); | ||
| 571 | 457 | ||
| 572 | - // Get the energy limits | 458 | + // Read energy limits |
| 573 | m_emin = GEnergy((*this)["emin"].real(), "TeV"); | 459 | m_emin = GEnergy((*this)["emin"].real(), "TeV"); |
| 574 | m_emax = GEnergy((*this)["emax"].real(), "TeV"); | 460 | m_emax = GEnergy((*this)["emax"].real(), "TeV"); |
| 575 | 461 | ||
| @@ -577,7 +463,28 @@ void ctfindvar::get_parameters(void) | @@ -577,7 +463,28 @@ void ctfindvar::get_parameters(void) | ||
| 577 | m_minoff = (*this)["minoff"].real(); | 463 | m_minoff = (*this)["minoff"].real(); |
| 578 | 464 | ||
| 579 | // Get minimum significance to set a source as variable | 465 | // Get minimum significance to set a source as variable |
| 580 | - m_sig_threshold = (*this)["sig_thr"].real(); | 466 | + m_sig_threshold = (*this)["threshold"].real(); |
| 467 | + | ||
| 468 | + // Query smoothing parameters | ||
| 469 | + if ((*this)["smooth_kernel"].is_valid()) { | ||
| 470 | + (*this)["smooth_kernel"].string(); | ||
| 471 | + (*this)["smooth_rad"].real(); | ||
| 472 | + } | ||
| 473 | + | ||
| 474 | + // If needed later, query output filenames now | ||
| 475 | + if (read_ahead()) { | ||
| 476 | + (*this)["outcube"].query(); | ||
| 477 | + (*this)["outmap"].query(); | ||
| 478 | + (*this)["outmodel"].query(); | ||
| 479 | + } | ||
| 480 | + | ||
| 481 | + // Set number of OpenMP threads | ||
| 482 | + #ifdef _OPENMP | ||
| 483 | + int nthreads = (*this)["nthreads"].integer(); | ||
| 484 | + if (nthreads > 0) { | ||
| 485 | + omp_set_num_threads(nthreads); | ||
| 486 | + } | ||
| 487 | + #endif | ||
| 581 | 488 | ||
| 582 | // Write parameters into logger | 489 | // Write parameters into logger |
| 583 | log_parameters(TERSE); | 490 | log_parameters(TERSE); |
| @@ -588,117 +495,139 @@ void ctfindvar::get_parameters(void) | @@ -588,117 +495,139 @@ void ctfindvar::get_parameters(void) | ||
| 588 | 495 | ||
| 589 | 496 | ||
| 590 | /***********************************************************************//** | 497 | /***********************************************************************//** |
| 591 | - * @brief Initialize counts cube | 498 | + * @brief Initialize Good Time Intervals |
| 592 | * | 499 | * |
| 593 | - * Sets up the required event cube and time interval storage objects | ||
| 594 | - * associated with this object | ||
| 595 | - ***************************************************************************/ | ||
| 596 | -void ctfindvar::init_cube(void) | ||
| 597 | -{ | ||
| 598 | - // Create the basic skymap | ||
| 599 | - m_counts = create_map(m_obs); | ||
| 600 | - | ||
| 601 | - // Resize to the appropriate number of time intervals | ||
| 602 | - m_counts.nmaps(m_gti.size()); | ||
| 603 | - | ||
| 604 | - // Create the peaksigmap | ||
| 605 | - m_peaksigmap = m_counts.extract(1); | ||
| 606 | -} | ||
| 607 | - | ||
| 608 | - | ||
| 609 | -/***********************************************************************//** | ||
| 610 | - * @brief Initialize counts cube | 500 | + * @exception GException::invalid_value |
| 501 | + * Invalid start or stop time or insufficient time bins | ||
| 611 | * | 502 | * |
| 612 | - * Sets up the required event cube and time interval storage objects | ||
| 613 | - * associated with this object | 503 | + * Initialise Good Time Intervals for the variability search. |
| 614 | ***************************************************************************/ | 504 | ***************************************************************************/ |
| 615 | void ctfindvar::init_gtis(void) | 505 | void ctfindvar::init_gtis(void) |
| 616 | { | 506 | { |
| 617 | - double tinterval = (*this)["tinterval"].real(); | ||
| 618 | - m_tstart = GTime("JD 999999999"); // large unreasonable Julian date | ||
| 619 | - m_tstop = GTime("JD 0"); // small unreasonable Julian date | 507 | + // Log header |
| 508 | + log_header1(NORMAL, "Initialise Good Time Intervals"); | ||
| 620 | 509 | ||
| 621 | - // Set the start time | ||
| 622 | - if ((*this)["tmin"].is_valid()) { | ||
| 623 | - log_string(NORMAL, "Setting start time from command line"); | ||
| 624 | - m_tstart = (*this)["tmin"].time(); | ||
| 625 | - } else { | ||
| 626 | - log_string(NORMAL, "Setting start time from observations"); | ||
| 627 | - for (int o=0; o<m_obs.size(); o++) { | ||
| 628 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]); | ||
| 629 | - | ||
| 630 | - // Check that the start time of the run is less than tstart | ||
| 631 | - if (obs->gti().tstart() < m_tstart) { | ||
| 632 | - m_tstart = obs->gti().tstart(); | ||
| 633 | - } | ||
| 634 | - } | ||
| 635 | - } | 510 | + // Clear time intervals |
| 511 | + m_gti.clear(); | ||
| 636 | 512 | ||
| 637 | - // Set the stop time | ||
| 638 | - if ((*this)["tmax"].is_valid()) { | ||
| 639 | - log_string(NORMAL, "Setting stop time from command line"); | ||
| 640 | - m_tstop = (*this)["tmax"].time(); | ||
| 641 | - } else { | 513 | + // Set start and stop times |
| 514 | + m_tstart = get_tstart(); | ||
| 515 | + m_tstop = get_tstop(); | ||
| 642 | 516 | ||
| 643 | - log_string(NORMAL, "Setting stop time from observations"); | ||
| 644 | - for (int o=0; o<m_obs.size(); o++) { | ||
| 645 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]); | ||
| 646 | - | ||
| 647 | - // Check that the stop time of the run is larger than tstop | ||
| 648 | - if (obs->gti().tstop() > m_tstop) { | ||
| 649 | - m_tstop = obs->gti().tstop(); | ||
| 650 | - } | ||
| 651 | - } | ||
| 652 | - } | 517 | + // Query time interval |
| 518 | + double tinterval = (*this)["tinterval"].real(); | ||
| 653 | 519 | ||
| 654 | - // Fill the number of good time intervals | 520 | + // Compute time bins |
| 655 | double tstart_sec = m_tstart.secs(); | 521 | double tstart_sec = m_tstart.secs(); |
| 656 | double tstop_sec = m_tstop.secs(); | 522 | double tstop_sec = m_tstop.secs(); |
| 657 | int bins = (tstop_sec - tstart_sec) / tinterval + 0.5; | 523 | int bins = (tstop_sec - tstart_sec) / tinterval + 0.5; |
| 658 | 524 | ||
| 659 | // Log information | 525 | // Log information |
| 660 | - log_value(NORMAL, "treference (mjd)", m_tstart.reference().mjdref()); | ||
| 661 | - log_value(NORMAL, "tstart (sec)", tstart_sec); | ||
| 662 | - log_value(NORMAL, "tstop (sec)", tstop_sec); | ||
| 663 | - log_value(NORMAL, "Total time", tstop_sec-tstart_sec); | ||
| 664 | - log_value(NORMAL, "Time interval", tinterval); | ||
| 665 | - log_value(NORMAL, "nbins", bins); | ||
| 666 | - | ||
| 667 | - // Throw if tstart == tstop | 526 | + log_value(NORMAL, "Reference time (mjd)", m_tstart.reference().mjdref()); |
| 527 | + log_value(NORMAL, "Start time (sec)", tstart_sec); | ||
| 528 | + log_value(NORMAL, "Stop time (sec)", tstop_sec); | ||
| 529 | + log_value(NORMAL, "Total time (sec)", tstop_sec-tstart_sec); | ||
| 530 | + log_value(NORMAL, "Time interval (sec)", tinterval); | ||
| 531 | + log_value(NORMAL, "Number of time bins", bins); | ||
| 532 | + | ||
| 533 | + // Throw exception if tstart == tstop | ||
| 668 | if (m_tstart == m_tstop) { | 534 | if (m_tstart == m_tstop) { |
| 669 | throw GException::invalid_value(G_INIT_GTIS, | 535 | throw GException::invalid_value(G_INIT_GTIS, |
| 670 | "Start time is equal to stop time"); | 536 | "Start time is equal to stop time"); |
| 671 | - } else if (bins < 2) { | 537 | + } |
| 538 | + else if (bins < 2) { | ||
| 672 | std::string msg = "Method requires at least two time bins (" + | 539 | std::string msg = "Method requires at least two time bins (" + |
| 673 | gammalib::str(bins) + " bins found)."; | 540 | gammalib::str(bins) + " bins found)."; |
| 674 | throw GException::invalid_value(G_INIT_GTIS, msg); | 541 | throw GException::invalid_value(G_INIT_GTIS, msg); |
| 675 | } | 542 | } |
| 676 | 543 | ||
| 677 | - for (int i=0; i<bins; i++) { | 544 | + // Set up Good Time Intervals by appending all intervals that overlap |
| 545 | + // with at least one of the observations | ||
| 546 | + for (int i = 0; i < bins; ++i) { | ||
| 678 | 547 | ||
| 679 | - // Get the next time interval | ||
| 680 | - GTime next_tstart(m_tstart + i*tinterval); | ||
| 681 | - GTime next_tstop(m_tstart + (i+1.0)*tinterval); | ||
| 682 | - GGti next_gti(next_tstart, next_tstop); | 548 | + // Get time interval |
| 549 | + GTime tstart(m_tstart + i*tinterval); | ||
| 550 | + GTime tstop(m_tstart + (i+1.0)*tinterval); | ||
| 551 | + GGti gti(tstart, tstop); | ||
| 683 | 552 | ||
| 684 | // Make sure there's an observation that overlaps with this GTI | 553 | // Make sure there's an observation that overlaps with this GTI |
| 685 | - for (int o=0; o<m_obs.size(); o++) { | ||
| 686 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]); | ||
| 687 | - | ||
| 688 | - if (gti_overlap(obs->gti(), next_gti) > 0.0) { | ||
| 689 | - m_gti.push_back(next_gti); | ||
| 690 | - break; | ||
| 691 | - } | ||
| 692 | - } | 554 | + for (int k = 0; k < m_obs.size(); ++k) { |
| 555 | + | ||
| 556 | + // Get CTA observation | ||
| 557 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[k]); | ||
| 558 | + | ||
| 559 | + // Continue only if observation is valid | ||
| 560 | + if (obs != NULL) { | ||
| 561 | + | ||
| 562 | + // Add GTI is the time intervals overlap | ||
| 563 | + if (gti_overlap(obs->gti(), gti) > 0.0) { | ||
| 564 | + m_gti.push_back(gti); | ||
| 565 | + break; | ||
| 566 | + } | ||
| 567 | + | ||
| 568 | + } // endif: observation was valid | ||
| 569 | + | ||
| 570 | + } // endfor: looped over observations | ||
| 571 | + | ||
| 572 | + } // endfor: looped over Good Time Intervals | ||
| 573 | + | ||
| 574 | + // Return | ||
| 575 | + return; | ||
| 576 | +} | ||
| 577 | + | ||
| 578 | + | ||
| 579 | +/***********************************************************************//** | ||
| 580 | + * @brief Create counts cube | ||
| 581 | + * | ||
| 582 | + * Creates a counts cube comprising a sky map for each Good Time Interval. | ||
| 583 | + ***************************************************************************/ | ||
| 584 | +void ctfindvar::create_cube(void) | ||
| 585 | +{ | ||
| 586 | + // Log header | ||
| 587 | + log_header1(NORMAL, "Create counts cube"); | ||
| 588 | + | ||
| 589 | + // Create the basic skymap | ||
| 590 | + m_counts = create_map(m_obs); | ||
| 591 | + | ||
| 592 | + // Resize to the appropriate number of time intervals | ||
| 593 | + m_counts.nmaps(m_gti.size()); | ||
| 594 | + | ||
| 595 | + // Create the peaksigmap | ||
| 596 | + m_peaksigmap = m_counts.extract(1); | ||
| 597 | + | ||
| 598 | + // Loop over all unbinned CTA observations in the container | ||
| 599 | + #pragma omp parallel for | ||
| 600 | + for (int i = 0; i < m_obs.size(); ++i) { | ||
| 601 | + | ||
| 602 | + // Get pointer to observation | ||
| 603 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 604 | + | ||
| 605 | + // Fill the cube | ||
| 606 | + fill_cube(obs); | ||
| 607 | + | ||
| 608 | + // Dispose events to free memory | ||
| 609 | + obs->dispose_events(); | ||
| 610 | + | ||
| 611 | + } // endfor: looped over observations | ||
| 612 | + | ||
| 613 | + // Smooth the maps if requested | ||
| 614 | + if ((*this)["smooth_kernel"].is_valid() && | ||
| 615 | + (*this)["smooth_kernel"].string() != "NONE") { | ||
| 616 | + m_counts.smooth((*this)["smooth_kernel"].string(), | ||
| 617 | + (*this)["smooth_rad"].real()); | ||
| 693 | } | 618 | } |
| 619 | + | ||
| 620 | + // Return | ||
| 621 | + return; | ||
| 694 | } | 622 | } |
| 695 | 623 | ||
| 696 | 624 | ||
| 697 | /***********************************************************************//** | 625 | /***********************************************************************//** |
| 698 | - * @brief Fill the cube from the events in the map | 626 | + * @brief Fill the cube from the events in an observation |
| 699 | * | 627 | * |
| 700 | - * Sets up the required event cube and time interval storage objects | ||
| 701 | - * associated with this object | 628 | + * @param[in] obs Pointer to CTA observation. |
| 629 | + * | ||
| 630 | + * Fills the cube from the events in an observation. | ||
| 702 | ***************************************************************************/ | 631 | ***************************************************************************/ |
| 703 | void ctfindvar::fill_cube(GCTAObservation* obs) | 632 | void ctfindvar::fill_cube(GCTAObservation* obs) |
| 704 | { | 633 | { |
| @@ -733,10 +662,6 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | @@ -733,10 +662,6 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | ||
| 733 | int num_outside_time = 0; | 662 | int num_outside_time = 0; |
| 734 | int num_in_map = 0; | 663 | int num_in_map = 0; |
| 735 | 664 | ||
| 736 | - // Specify whether we are cutting on energy or not | ||
| 737 | - bool cut_emin = (m_emin.TeV() > 0.0) ? true : false; | ||
| 738 | - bool cut_emax = (m_emax.TeV() > 0.0) ? true : false; | ||
| 739 | - | ||
| 740 | // Fill counts sky map | 665 | // Fill counts sky map |
| 741 | for (int i = 0; i < events->size(); ++i) { | 666 | for (int i = 0; i < events->size(); ++i) { |
| 742 | 667 | ||
| @@ -744,16 +669,14 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | @@ -744,16 +669,14 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | ||
| 744 | const GCTAEventAtom* event = (*events)[i]; | 669 | const GCTAEventAtom* event = (*events)[i]; |
| 745 | 670 | ||
| 746 | // Check that the energy is valid | 671 | // Check that the energy is valid |
| 747 | - if ((cut_emin && event->energy() < m_emin) || | ||
| 748 | - (cut_emax && event->energy() > m_emax)) { | 672 | + if ((event->energy() < m_emin) || (event->energy() > m_emax)) { |
| 749 | num_outside_ecut++; | 673 | num_outside_ecut++; |
| 750 | continue; | 674 | continue; |
| 751 | } | 675 | } |
| 752 | 676 | ||
| 753 | - // Determine event time | ||
| 754 | - GTime evnt_time = event->time(); | ||
| 755 | - int time_indx = time2inx(evnt_time); | ||
| 756 | - | 677 | + // Determine event time index |
| 678 | + int time_indx = time2inx(event->time()); | ||
| 679 | + | ||
| 757 | // Check if event is in the GTIs | 680 | // Check if event is in the GTIs |
| 758 | if ((time_indx > -1) && (time_indx < m_counts.nmaps())) { | 681 | if ((time_indx > -1) && (time_indx < m_counts.nmaps())) { |
| 759 | 682 | ||
| @@ -791,10 +714,11 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | @@ -791,10 +714,11 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | ||
| 791 | // Increment number of maps | 714 | // Increment number of maps |
| 792 | num_in_map++; | 715 | num_in_map++; |
| 793 | 716 | ||
| 794 | - } else { | ||
| 795 | - // Event falls outside the specified time range | 717 | + } |
| 718 | + | ||
| 719 | + // ... otherwise, event falls outside the specified time range | ||
| 720 | + else { | ||
| 796 | num_outside_time++; | 721 | num_outside_time++; |
| 797 | - continue; | ||
| 798 | } | 722 | } |
| 799 | 723 | ||
| 800 | } // endfor: looped over all events | 724 | } // endfor: looped over all events |
| @@ -818,242 +742,557 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | @@ -818,242 +742,557 @@ void ctfindvar::fill_cube(GCTAObservation* obs) | ||
| 818 | 742 | ||
| 819 | 743 | ||
| 820 | /***********************************************************************//** | 744 | /***********************************************************************//** |
| 821 | - * @brief Save the current sky direction to model if significance > thr | ||
| 822 | - * | ||
| 823 | - * @param[in] dir_pix pixel sky direction | ||
| 824 | - * @param[out] m_model_sig_above_thr model position with sig>thr | 745 | + * @brief Analyse all pixels of counts cube |
| 825 | ***************************************************************************/ | 746 | ***************************************************************************/ |
| 826 | -void ctfindvar::fill_model_sig_pos(const GSkyDir& dir_pix) | 747 | +void ctfindvar::analyse_cube(void) |
| 827 | { | 748 | { |
| 828 | - //Set spatial components | ||
| 829 | - GModelSpatialPointSource spatial(dir_pix); | 749 | + // Log header |
| 750 | + log_header1(NORMAL, "Analyse sky map pixels"); | ||
| 830 | 751 | ||
| 831 | - //Set fake spectral component (powerlaw with 1% of Crab) | ||
| 832 | - GModelSpectralPlaw spectral(5.7e-18, -2.48, GEnergy(0.3, "TeV")); | 752 | + // Get number of GTIs |
| 753 | + const int nbins = m_gti.size(); | ||
| 833 | 754 | ||
| 834 | - //Creat a sky model | ||
| 835 | - GModelSky model(spatial, spectral); | ||
| 836 | - | ||
| 837 | - //Extracting the coordinate to name the model | ||
| 838 | - double ra = dir_pix.ra_deg(); | ||
| 839 | - double dec = dir_pix.dec_deg(); | ||
| 840 | - std::string name = "Sky_direction_" + gammalib::str(ra, 4) + | ||
| 841 | - "_" + gammalib::str(dec, 4); | ||
| 842 | - model.name(name); | ||
| 843 | - | ||
| 844 | - //Add the model for this pixel to the output mode | ||
| 845 | - m_model_above_thr.append(model); | 755 | + // Get relevant sky map pixels |
| 756 | + std::vector<int> srcInxPix = get_pixels(); | ||
| 757 | + | ||
| 758 | + // Preparing the histogram with significance evolution for the source | ||
| 759 | + // center and the highest sig-pix | ||
| 760 | + m_pixsigsrc = GNdarray(srcInxPix.size(), nbins); | ||
| 761 | + m_pixsigmax = GNdarray(nbins); | ||
| 762 | + | ||
| 763 | + // Initialise maximum significance | ||
| 764 | + double max_sig = 0; | ||
| 765 | + | ||
| 766 | + // looping over all the pixels in the cube | ||
| 767 | + #pragma omp parallel for | ||
| 768 | + for (int ipix = 0; ipix < m_counts.npix(); ++ipix) { | ||
| 769 | + | ||
| 770 | + // Compute total counts for pixel | ||
| 771 | + double total_counts = 0.0; | ||
| 772 | + for (int k = 0; k < nbins; ++k) { | ||
| 773 | + total_counts += m_counts(ipix, k); | ||
| 774 | + } | ||
| 775 | + | ||
| 776 | + // Getting the variability significance for the current pixel | ||
| 777 | + GNdarray pixSig = get_variability_sig(ipix); | ||
| 778 | + | ||
| 779 | + // Getting the significance evolution for the source | ||
| 780 | + for (int src = 0; src < srcInxPix.size(); ++src) { | ||
| 781 | + | ||
| 782 | + // Store the distribution if the source is located at this position | ||
| 783 | + if (srcInxPix[src] == ipix) { | ||
| 784 | + | ||
| 785 | + #pragma omp critical(ctfindvar_analyse_cube) | ||
| 786 | + for (int i = 0; i < nbins; i++) { | ||
| 787 | + m_pixsigsrc(src,i) = pixSig(i); | ||
| 788 | + } | ||
| 789 | + } | ||
| 790 | + | ||
| 791 | + } // endfor: looped over sources | ||
| 792 | + | ||
| 793 | + // Make sure that this code is not executed in parallel | ||
| 794 | + #pragma omp critical(ctfindvar_analyse_cube) | ||
| 795 | + { | ||
| 796 | + // Determine the pixel with the highest significance | ||
| 797 | + if (max(pixSig) > max_sig) { | ||
| 798 | + max_sig = max(pixSig); | ||
| 799 | + m_max_sig_dir = m_counts.inx2dir(ipix); | ||
| 800 | + m_pixsigmax = pixSig; | ||
| 801 | + } | ||
| 802 | + | ||
| 803 | + // Storing sig in skymap | ||
| 804 | + m_peaksigmap(ipix) = max(pixSig); | ||
| 805 | + | ||
| 806 | + // If the significance is greater than the significance threshold, | ||
| 807 | + // the position is stored in a model | ||
| 808 | + if (max(pixSig) > m_sig_threshold) { | ||
| 809 | + GSkyDir dir_pix = m_counts.inx2dir(ipix); | ||
| 810 | + m_model_above_thr.append(sky_model(dir_pix)); | ||
| 811 | + } | ||
| 812 | + } | ||
| 846 | 813 | ||
| 814 | + } // endfor: looped over pixels | ||
| 815 | + | ||
| 816 | + // Log results | ||
| 817 | + log_value(NORMAL, "Maximum significance", max_sig); | ||
| 818 | + log_value(NORMAL, "Right Ascension of maximum", m_max_sig_dir.ra_deg()); | ||
| 819 | + log_value(NORMAL, "Declination of maximum", m_max_sig_dir.dec_deg()); | ||
| 820 | + | ||
| 821 | + // Return | ||
| 822 | + return; | ||
| 847 | } | 823 | } |
| 824 | + | ||
| 825 | + | ||
| 848 | /***********************************************************************//** | 826 | /***********************************************************************//** |
| 849 | - * @brief Get the map index associated with a given time | 827 | + * @brief Return pixel vector |
| 828 | + * | ||
| 829 | + * @return Vector of sky map pixels | ||
| 850 | * | 830 | * |
| 851 | - * @param[in] pix_number Spatial pixel | ||
| 852 | - * @param[out] alpha_vector Vector containing effective exposure | 831 | + * Returns a vector of sky map pixels that corresponds to the source model |
| 832 | + * positions. | ||
| 853 | ***************************************************************************/ | 833 | ***************************************************************************/ |
| 854 | -void ctfindvar::fill_alpha_vector(const int& pix_number, | ||
| 855 | - std::vector<double>& alpha_vector) | 834 | +std::vector<int> ctfindvar::get_pixels(void) |
| 856 | { | 835 | { |
| 857 | - // Pixel position | ||
| 858 | - GSkyDir pix_dir = m_counts.inx2dir(pix_number); | 836 | + // Initialise pixel array |
| 837 | + std::vector<int> srcInxPix; | ||
| 859 | 838 | ||
| 860 | - // Loop over all observations | ||
| 861 | - for (int i = 0; i < m_obs.size(); i++) { | ||
| 862 | - // Skip if observation does not overlap with this pixel position | ||
| 863 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 864 | - GCTARoi roi = obs->roi(); | ||
| 865 | - GSkyDir roi_centre = roi.centre().dir(); | 839 | + // If there are input models then extract |
| 840 | + if (m_inmodel.size() > 0) { | ||
| 866 | 841 | ||
| 867 | - if (roi_centre.dist_deg(pix_dir) > roi.radius()) { | ||
| 868 | - continue; | ||
| 869 | - } | ||
| 870 | - | ||
| 871 | - // Convert sky direction to instrument direction | ||
| 872 | - GCTAInstDir instdir = obs->pointing().instdir(pix_dir); | 842 | + // Loop over models |
| 843 | + for (int i = 0; i < m_inmodel.size(); ++i) { | ||
| 873 | 844 | ||
| 874 | - // Extract the good time intervals of the observation | ||
| 875 | - const GGti& obs_gti(obs->gti()); | 845 | + // Extract the model |
| 846 | + GModelSky* model = dynamic_cast<GModelSky*>(m_inmodel[i]); | ||
| 876 | 847 | ||
| 877 | - // Loop over all time bins | ||
| 878 | - for (int j = 0; j < m_gti.size(); j++) { | 848 | + // If model is a sky model then extract the model centre. Note |
| 849 | + // that this only works for a model that results a GSkyRegionCircle | ||
| 850 | + // object as region. | ||
| 851 | + if (model != NULL) { | ||
| 879 | 852 | ||
| 880 | - // Make sure observation overlaps with this time interval | ||
| 881 | - double exposure = gti_overlap(m_gti[j], obs_gti); | ||
| 882 | - if (exposure > 0.0) { | 853 | + // Get the source position |
| 854 | + GModelSpatial* spatial = model->spatial(); | ||
| 855 | + GSkyRegion* region = spatial->region(); | ||
| 856 | + GSkyRegionCircle* circle = dynamic_cast<GSkyRegionCircle*>(region); | ||
| 857 | + | ||
| 858 | + // If region circle is valid then | ||
| 859 | + if (circle != NULL) { | ||
| 860 | + int ipix = m_counts.dir2inx(circle->centre()); | ||
| 861 | + srcInxPix.push_back(ipix); | ||
| 862 | + continue; | ||
| 863 | + } | ||
| 883 | 864 | ||
| 884 | - // Get IRF response | ||
| 885 | - const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*> | ||
| 886 | - (obs->response()); | 865 | + } // endif: model was a sky model |
| 887 | 866 | ||
| 888 | - // Throw an exception if observation has no instrument response function | ||
| 889 | - if (rsp == NULL) { | ||
| 890 | - std::string msg = | ||
| 891 | - "No response information available for "+ | ||
| 892 | - get_obs_header(obs)+" to compute IRF background. " | ||
| 893 | - "Please specify response information or use " | ||
| 894 | - "another background subtraction method."; | ||
| 895 | - throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg); | ||
| 896 | - } | 867 | + // If we are still alive then remove the model since it is neither |
| 868 | + // a sky model, nor does it have a region circle | ||
| 869 | + m_inmodel.remove(i); | ||
| 870 | + i--; | ||
| 897 | 871 | ||
| 898 | - // Get IRF background template | ||
| 899 | - const GCTABackground* bkg = rsp->background(); | 872 | + } // endfor: looped over all models |
| 900 | 873 | ||
| 901 | - // Throw an exception if observation has no IRF background template | ||
| 902 | - if (bkg == NULL) { | ||
| 903 | - std::string msg = | ||
| 904 | - "No IRF background template found in instrument " | ||
| 905 | - "response function for "+ | ||
| 906 | - get_obs_header(obs)+". Please specify an instrument " | ||
| 907 | - "response function containing a background template."; | ||
| 908 | - throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg); | ||
| 909 | - } | 874 | + } // endif: there were input models |
| 875 | + | ||
| 876 | + // ... otherwise query the source position | ||
| 877 | + else { | ||
| 910 | 878 | ||
| 911 | - // Multiply background rate with livetime and solid angle | ||
| 912 | - #pragma omp critical(ctfindvar_alpha_vector) | ||
| 913 | - alpha_vector[j] += exposure * bkg->rate_ebin(instdir, m_emin, m_emax); | ||
| 914 | - } | 879 | + // Query source direction |
| 880 | + GSkyDir dir; | ||
| 881 | + if ((*this)["coordsys"].string() == "CEL") { | ||
| 882 | + dir.radec_deg((*this)["xsrc"].real(),(*this)["ysrc"].real()); | ||
| 883 | + } | ||
| 884 | + else { | ||
| 885 | + dir.lb_deg((*this)["xsrc"].real(),(*this)["ysrc"].real()); | ||
| 915 | } | 886 | } |
| 916 | - } | ||
| 917 | 887 | ||
| 918 | - return; | ||
| 919 | -} | 888 | + // Store the index of this source |
| 889 | + int ipix = m_counts.dir2inx(dir); | ||
| 890 | + srcInxPix.push_back(ipix); | ||
| 891 | + | ||
| 892 | + } // endelse: queried source position | ||
| 893 | + | ||
| 894 | + // Return pixel array | ||
| 895 | + return srcInxPix; | ||
| 896 | +} | ||
| 897 | + | ||
| 898 | + | ||
| 899 | +/***********************************************************************//** | ||
| 900 | + * @brief Return sky model for a given sky direction | ||
| 901 | + * | ||
| 902 | + * @param[in] dir Sky direction | ||
| 903 | + * @return Sky model for a given sky direction | ||
| 904 | + * | ||
| 905 | + * Returns a point source sky model at the position of the current pixel | ||
| 906 | + * with a power law spectral model corresponding to 1% of the Crab flux. | ||
| 907 | + * | ||
| 908 | + * The model name is built from the celestial coordinates of the source. | ||
| 909 | + ***************************************************************************/ | ||
| 910 | +GModelSky ctfindvar::sky_model(const GSkyDir& dir) const | ||
| 911 | +{ | ||
| 912 | + // Set point source spatial component from sky direction | ||
| 913 | + GModelSpatialPointSource spatial(dir); | ||
| 920 | 914 | ||
| 915 | + // Set fake spectral component (powerlaw with 1% of Crab) | ||
| 916 | + GModelSpectralPlaw spectral(5.7e-18, -2.48, GEnergy(0.3, "TeV")); | ||
| 921 | 917 | ||
| 918 | + // Create a sky model | ||
| 919 | + GModelSky model(spatial, spectral); | ||
| 920 | + | ||
| 921 | + // Build model name from celestial coordinates | ||
| 922 | + double ra = dir.ra_deg(); | ||
| 923 | + double dec = dir.dec_deg(); | ||
| 924 | + std::string name = gammalib::str(ra, 4); | ||
| 925 | + if (dec < 0.0) { | ||
| 926 | + name += "-"; | ||
| 927 | + } | ||
| 928 | + else { | ||
| 929 | + name += "+"; | ||
| 930 | + } | ||
| 931 | + name += gammalib::str(std::abs(dec), 4); | ||
| 932 | + | ||
| 933 | + // Set model name | ||
| 934 | + model.name(name); | ||
| 935 | + | ||
| 936 | + // Return model | ||
| 937 | + return model; | ||
| 938 | +} | ||
| 922 | 939 | ||
| 923 | 940 | ||
| 924 | /***********************************************************************//** | 941 | /***********************************************************************//** |
| 925 | - * @brief Obtain the significance of variability in a given bin | 942 | + * @brief Get the significance of variability for a given skymap pixel |
| 926 | * | 943 | * |
| 927 | - * @param[in] pix_number Pixel in the skymap | ||
| 928 | - * @param[in] nbins Number of bins in the skymap | ||
| 929 | - * @param[out] sig_histogram Histogram for storing returned significances | 944 | + * @param[in] ipix Sky map pixel index. |
| 945 | + * @return Histogram of significances. | ||
| 930 | * | 946 | * |
| 931 | * Significance is computed according to Li & Ma equation 17: | 947 | * Significance is computed according to Li & Ma equation 17: |
| 932 | * see: https://doi.org/10.1086/161295 | 948 | * see: https://doi.org/10.1086/161295 |
| 933 | * Some modification is made in order to handle the case where Non = 0, | 949 | * Some modification is made in order to handle the case where Non = 0, |
| 934 | * but Noff != 0. | 950 | * but Noff != 0. |
| 935 | ***************************************************************************/ | 951 | ***************************************************************************/ |
| 936 | -void ctfindvar::get_variability_sig(const int& pix_number, | ||
| 937 | - const int& nbins, | ||
| 938 | - GNdarray& sig_histogram) | 952 | +GNdarray ctfindvar::get_variability_sig(const int& ipix) |
| 939 | { | 953 | { |
| 940 | - std::vector<bool> accepted_bin_bckg_vector(nbins, true); | ||
| 941 | - bool background_validated = false; | ||
| 942 | - double non, noff; | ||
| 943 | - double alpha, sig; | 954 | + // Initialise result |
| 955 | + GNdarray sig_histogram(m_gti.size()); | ||
| 956 | + | ||
| 957 | + // Initialise vectors | ||
| 958 | + std::vector<bool> accepted_bin_bckg_vector(m_gti.size(), true); | ||
| 944 | 959 | ||
| 945 | - // Fill the alpha values for each vector | ||
| 946 | - std::vector<double> alpha_vector(nbins, 0.0); | ||
| 947 | - fill_alpha_vector(pix_number, alpha_vector); | 960 | + // Get alpha values for specified pixel |
| 961 | + std::vector<double> alphas = get_alphas(ipix); | ||
| 948 | 962 | ||
| 949 | - // Loop over pixels until all background pixls are removed | 963 | + // Loop over pixels until all background pixels are removed |
| 964 | + bool background_validated = false; | ||
| 950 | while (background_validated == false) { | 965 | while (background_validated == false) { |
| 966 | + | ||
| 967 | + // Signal that background was validated | ||
| 951 | background_validated = true; | 968 | background_validated = true; |
| 952 | 969 | ||
| 953 | // Loop over all the GTIs of the pixel | 970 | // Loop over all the GTIs of the pixel |
| 954 | - for (int i = 0; i < nbins; i++) { | 971 | + for (int i = 0; i < m_gti.size(); ++i) { |
| 955 | 972 | ||
| 956 | - // The GTI is discared from bckg calculation and not checked again. | 973 | + // The GTI is discared from background calculation and not |
| 974 | + // checked again | ||
| 957 | if (!accepted_bin_bckg_vector[i]) { | 975 | if (!accepted_bin_bckg_vector[i]) { |
| 958 | continue; | 976 | continue; |
| 959 | - } | ||
| 960 | - // Check if bin fails minoff check or no observations overlap it | ||
| 961 | - else if (m_counts(pix_number, i) < m_minoff || alpha_vector[i] == 0) { | 977 | + } |
| 978 | + | ||
| 979 | + // ... otherwise check if bin fails minoff check or no observations | ||
| 980 | + // overlap it | ||
| 981 | + else if (m_counts(ipix, i) < m_minoff || alphas[i] == 0) { | ||
| 962 | accepted_bin_bckg_vector[i] = false; | 982 | accepted_bin_bckg_vector[i] = false; |
| 963 | continue; | 983 | continue; |
| 964 | } | 984 | } |
| 965 | 985 | ||
| 966 | - noff = 0.0; | ||
| 967 | - alpha = 0.0; | ||
| 968 | - // Gor one GTI selected (i), looping over all the others (j). | ||
| 969 | - for (int j = 0; j < nbins; j++) { | 986 | + // ... otherwise |
| 987 | + double noff = 0.0; | ||
| 988 | + double alpha = 0.0; | ||
| 989 | + | ||
| 990 | + // Got one GTI selected (i), looping over all the others (j). | ||
| 991 | + for (int j = 0; j < m_gti.size(); ++j) { | ||
| 970 | if (j != i && accepted_bin_bckg_vector[j] == 1) { | 992 | if (j != i && accepted_bin_bckg_vector[j] == 1) { |
| 971 | - noff += m_counts(pix_number, j); | ||
| 972 | - alpha += alpha_vector[j]; | 993 | + noff += m_counts(ipix, j); |
| 994 | + alpha += alphas[j]; | ||
| 973 | } | 995 | } |
| 974 | } | 996 | } |
| 975 | 997 | ||
| 976 | // The background is averaged on the number of bins -1 | 998 | // The background is averaged on the number of bins -1 |
| 977 | - non = m_counts(pix_number, i); | ||
| 978 | - alpha = alpha_vector[i]/alpha; | 999 | + double non = m_counts(ipix, i); |
| 1000 | + alpha = alphas[i]/alpha; | ||
| 979 | 1001 | ||
| 980 | // Compute sensitivity in Gaussian sigma using Li & Ma | 1002 | // Compute sensitivity in Gaussian sigma using Li & Ma |
| 981 | double alpha1 = alpha + 1.0; | 1003 | double alpha1 = alpha + 1.0; |
| 982 | double ntotal = non+noff; | 1004 | double ntotal = non+noff; |
| 983 | double arg1 = non/ntotal; | 1005 | double arg1 = non/ntotal; |
| 984 | double arg2 = noff/ntotal; | 1006 | double arg2 = noff/ntotal; |
| 985 | - if (noff == 0.0) { | ||
| 986 | - sig = 0.0; | ||
| 987 | - } else if (non > 0.0) { | ||
| 988 | - double term1 = non * std::log((alpha1/alpha)*arg1); | ||
| 989 | - double term2 = noff * std::log(alpha1*arg2); | ||
| 990 | - sig = std::sqrt(2.0 * (term1 + term2)); | ||
| 991 | - } else { | ||
| 992 | - sig = std::sqrt(2.0 * noff * std::log(alpha1)); | ||
| 993 | - } | ||
| 994 | - | ||
| 995 | - // Specify the sign of the significance | ||
| 996 | - sig *= (non < alpha*noff) ? -1.0 : 1.0; | ||
| 997 | - | ||
| 998 | - if (alpha == 0.0) { | ||
| 999 | - sig = 0.0; | 1007 | + double sig = 0.0; |
| 1008 | + if (alpha != 0.0) { | ||
| 1009 | + if (noff == 0.0) { | ||
| 1010 | + sig = 0.0; | ||
| 1011 | + } | ||
| 1012 | + else if (non > 0.0) { | ||
| 1013 | + double term1 = non * std::log((alpha1/alpha)*arg1); | ||
| 1014 | + double term2 = noff * std::log(alpha1*arg2); | ||
| 1015 | + sig = std::sqrt(2.0 * (term1 + term2)); | ||
| 1016 | + } | ||
| 1017 | + else { | ||
| 1018 | + sig = std::sqrt(2.0 * noff * std::log(alpha1)); | ||
| 1019 | + } | ||
| 1020 | + sig *= (non < alpha*noff) ? -1.0 : 1.0; | ||
| 1000 | } | 1021 | } |
| 1001 | 1022 | ||
| 1002 | // Update the significance | 1023 | // Update the significance |
| 1003 | sig_histogram(i) = sig; | 1024 | sig_histogram(i) = sig; |
| 1004 | 1025 | ||
| 1005 | - // If bin is significant, it's removed from bckg and we loop again. | 1026 | + // If bin is significant, it's removed from the background and |
| 1027 | + // we loop again | ||
| 1006 | if (sig > m_sig_threshold) { | 1028 | if (sig > m_sig_threshold) { |
| 1007 | accepted_bin_bckg_vector[i] = false; | 1029 | accepted_bin_bckg_vector[i] = false; |
| 1008 | background_validated = false; | 1030 | background_validated = false; |
| 1009 | } | 1031 | } |
| 1010 | - } | ||
| 1011 | 1032 | ||
| 1012 | - } | 1033 | + } // endfor: looped over all GTIs |
| 1034 | + | ||
| 1035 | + } // endwhile: iterate until converged | ||
| 1036 | + | ||
| 1037 | + // Return significance histogram | ||
| 1038 | + return sig_histogram; | ||
| 1013 | } | 1039 | } |
| 1014 | 1040 | ||
| 1015 | 1041 | ||
| 1016 | /***********************************************************************//** | 1042 | /***********************************************************************//** |
| 1043 | + * @brief Get alpha vector | ||
| 1044 | + * | ||
| 1045 | + * @param[in] ipix Sky map pixel index | ||
| 1046 | + * @return Vector containing effective exposure | ||
| 1047 | + ***************************************************************************/ | ||
| 1048 | +std::vector<double> ctfindvar::get_alphas(const int& ipix) const | ||
| 1049 | +{ | ||
| 1050 | + // Initialise alpha vector | ||
| 1051 | + std::vector<double> alphas(m_gti.size(), 0.0); | ||
| 1052 | + | ||
| 1053 | + // Convert pixel index into sky direction | ||
| 1054 | + GSkyDir pix_dir = m_counts.inx2dir(ipix); | ||
| 1055 | + | ||
| 1056 | + // Loop over all observations | ||
| 1057 | + for (int i = 0; i < m_obs.size(); ++i) { | ||
| 1058 | + | ||
| 1059 | + // Get CTA observation | ||
| 1060 | + const GCTAObservation* obs = dynamic_cast<const GCTAObservation*>(m_obs[i]); | ||
| 1061 | + | ||
| 1062 | + // Fall through if observation is not valid | ||
| 1063 | + if (obs == NULL) { | ||
| 1064 | + continue; | ||
| 1065 | + } | ||
| 1066 | + | ||
| 1067 | + // Get RoI. Fall through if observation does not overlap with this | ||
| 1068 | + // pixel position | ||
| 1069 | + GCTARoi roi = obs->roi(); | ||
| 1070 | + GSkyDir roi_centre = roi.centre().dir(); | ||
| 1071 | + if (roi_centre.dist_deg(pix_dir) > roi.radius()) { | ||
| 1072 | + continue; | ||
| 1073 | + } | ||
| 1074 | + | ||
| 1075 | + // Convert sky direction to instrument direction | ||
| 1076 | + GCTAInstDir instdir = obs->pointing().instdir(pix_dir); | ||
| 1077 | + | ||
| 1078 | + // Extract the good time intervals of the observation | ||
| 1079 | + const GGti& obs_gti(obs->gti()); | ||
| 1080 | + | ||
| 1081 | + // Loop over all time bins | ||
| 1082 | + for (int j = 0; j < m_gti.size(); ++j) { | ||
| 1083 | + | ||
| 1084 | + // Make sure observation overlaps with this time interval | ||
| 1085 | + double exposure = gti_overlap(m_gti[j], obs_gti); | ||
| 1086 | + if (exposure > 0.0) { | ||
| 1087 | + | ||
| 1088 | + // Get IRF response | ||
| 1089 | + const GCTAResponseIrf* rsp = | ||
| 1090 | + dynamic_cast<const GCTAResponseIrf*>(obs->response()); | ||
| 1091 | + | ||
| 1092 | + // Throw an exception if observation has no instrument response function | ||
| 1093 | + if (rsp == NULL) { | ||
| 1094 | + std::string msg = | ||
| 1095 | + "No response information available for "+ | ||
| 1096 | + get_obs_header(obs)+" to compute IRF background. " | ||
| 1097 | + "Please specify response information or use " | ||
| 1098 | + "another background subtraction method."; | ||
| 1099 | + throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg); | ||
| 1100 | + } | ||
| 1101 | + | ||
| 1102 | + // Get IRF background template | ||
| 1103 | + const GCTABackground* bkg = rsp->background(); | ||
| 1104 | + | ||
| 1105 | + // Throw an exception if observation has no IRF background template | ||
| 1106 | + if (bkg == NULL) { | ||
| 1107 | + std::string msg = | ||
| 1108 | + "No IRF background template found in instrument " | ||
| 1109 | + "response function for "+ | ||
| 1110 | + get_obs_header(obs)+". Please specify an instrument " | ||
| 1111 | + "response function containing a background template."; | ||
| 1112 | + throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg); | ||
| 1113 | + } | ||
| 1114 | + | ||
| 1115 | + // Add up background rate | ||
| 1116 | + alphas[j] += exposure * bkg->rate_ebin(instdir, m_emin, m_emax); | ||
| 1117 | + | ||
| 1118 | + } // endif: exposure was positive | ||
| 1119 | + | ||
| 1120 | + } // endfor: looped over all time bins | ||
| 1121 | + | ||
| 1122 | + } // endfor: looped over all observations | ||
| 1123 | + | ||
| 1124 | + // Return alphas | ||
| 1125 | + return alphas; | ||
| 1126 | +} | ||
| 1127 | + | ||
| 1128 | + | ||
| 1129 | +/***********************************************************************//** | ||
| 1017 | * @brief Returns number of seconds that two GTIs overlap | 1130 | * @brief Returns number of seconds that two GTIs overlap |
| 1018 | * | 1131 | * |
| 1019 | * @param[in] gti1 First GTI | 1132 | * @param[in] gti1 First GTI |
| 1020 | * @param[in] gti2 Second GTI | 1133 | * @param[in] gti2 Second GTI |
| 1021 | * @return Number of seconds that @p gti1 and @p gti2 overlap | 1134 | * @return Number of seconds that @p gti1 and @p gti2 overlap |
| 1022 | ***************************************************************************/ | 1135 | ***************************************************************************/ |
| 1023 | -double ctfindvar::gti_overlap(const GGti& gti1, const GGti& gti2) | 1136 | +double ctfindvar::gti_overlap(const GGti& gti1, const GGti& gti2) const |
| 1024 | { | 1137 | { |
| 1138 | + // Initialise no overlap | ||
| 1025 | double overlap = 0.0; | 1139 | double overlap = 0.0; |
| 1140 | + | ||
| 1141 | + // Set first and second GTI so that gti_1st starts before gti_2nd | ||
| 1026 | const GGti& gti_1st = (gti1.tstart() <= gti2.tstart()) ? gti1 : gti2; | 1142 | const GGti& gti_1st = (gti1.tstart() <= gti2.tstart()) ? gti1 : gti2; |
| 1027 | - const GGti& gti_2nd = (gti1.tstart() > gti2.tstart()) ? gti1 : gti2; | 1143 | + const GGti& gti_2nd = (gti1.tstart() > gti2.tstart()) ? gti1 : gti2; |
| 1028 | 1144 | ||
| 1029 | - // gti1 starts earlier | 1145 | + // Compute overlap |
| 1030 | if (gti_1st.tstop() > gti_2nd.tstart()) { | 1146 | if (gti_1st.tstop() > gti_2nd.tstart()) { |
| 1031 | if (gti_1st.tstop() <= gti_2nd.tstop()) { | 1147 | if (gti_1st.tstop() <= gti_2nd.tstop()) { |
| 1032 | overlap = gti_1st.tstop() - gti_2nd.tstart(); | 1148 | overlap = gti_1st.tstop() - gti_2nd.tstart(); |
| 1033 | - } else if (gti_1st.tstop() > gti_2nd.tstop()) { | 1149 | + } |
| 1150 | + else if (gti_1st.tstop() > gti_2nd.tstop()) { | ||
| 1034 | overlap = gti_2nd.tstop() - gti_2nd.tstart(); | 1151 | overlap = gti_2nd.tstop() - gti_2nd.tstart(); |
| 1035 | } | 1152 | } |
| 1036 | } | 1153 | } |
| 1037 | 1154 | ||
| 1155 | + // Return overlap | ||
| 1038 | return overlap; | 1156 | return overlap; |
| 1039 | } | 1157 | } |
| 1040 | 1158 | ||
| 1041 | 1159 | ||
| 1042 | /***********************************************************************//** | 1160 | /***********************************************************************//** |
| 1043 | - * @brief Write individual histograms in CSV format | 1161 | + * @brief Get start time |
| 1162 | + * | ||
| 1163 | + * @return Start time | ||
| 1164 | + ***************************************************************************/ | ||
| 1165 | +GTime ctfindvar::get_tstart(void) | ||
| 1166 | +{ | ||
| 1167 | + // Initialise start time with large unreasonable Julian date | ||
| 1168 | + GTime tstart("JD 999999999"); | ||
| 1169 | + | ||
| 1170 | + // If tmin parameter is valid then set the start time | ||
| 1171 | + if ((*this)["tmin"].is_valid()) { | ||
| 1172 | + | ||
| 1173 | + // Query tmin parameter | ||
| 1174 | + tstart = (*this)["tmin"].time(); | ||
| 1175 | + | ||
| 1176 | + // Log action | ||
| 1177 | + log_string(NORMAL, "Setting start time \"tmin\" parameter"); | ||
| 1178 | + | ||
| 1179 | + } // endif: tmin parameter was valid | ||
| 1180 | + | ||
| 1181 | + // ... otherwise set start time from observations | ||
| 1182 | + else { | ||
| 1183 | + | ||
| 1184 | + // Loop over all observations | ||
| 1185 | + for (int k = 0; k < m_obs.size(); ++k) { | ||
| 1186 | + | ||
| 1187 | + // Get CTA observation | ||
| 1188 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[k]); | ||
| 1189 | + | ||
| 1190 | + // Continue only if observation is valid | ||
| 1191 | + if (obs != NULL) { | ||
| 1192 | + | ||
| 1193 | + // Update start time if the start time of the observation is | ||
| 1194 | + // smaller than the current start time | ||
| 1195 | + if (obs->gti().tstart() < tstart) { | ||
| 1196 | + tstart = obs->gti().tstart(); | ||
| 1197 | + } | ||
| 1198 | + | ||
| 1199 | + } // endif: observation was valid | ||
| 1200 | + | ||
| 1201 | + } // endfor: looped over observations | ||
| 1202 | + | ||
| 1203 | + // Log action | ||
| 1204 | + log_string(NORMAL, "Setting start time from observations"); | ||
| 1205 | + | ||
| 1206 | + } // endelse: no valid time specified | ||
| 1207 | + | ||
| 1208 | + // Return start time | ||
| 1209 | + return tstart; | ||
| 1210 | +} | ||
| 1211 | + | ||
| 1212 | + | ||
| 1213 | +/***********************************************************************//** | ||
| 1214 | + * @brief Get stop time | ||
| 1215 | + * | ||
| 1216 | + * @return Stop time | ||
| 1044 | ***************************************************************************/ | 1217 | ***************************************************************************/ |
| 1045 | -void ctfindvar::write_srchist(void) | 1218 | +GTime ctfindvar::get_tstop(void) |
| 1219 | +{ | ||
| 1220 | + // Initialise stop time with small unreasonable Julian date | ||
| 1221 | + GTime tstop("JD 0"); | ||
| 1222 | + | ||
| 1223 | + // If tmax parameter is valid then set the stop time | ||
| 1224 | + if ((*this)["tmax"].is_valid()) { | ||
| 1225 | + | ||
| 1226 | + // Query tmax parameter | ||
| 1227 | + tstop = (*this)["tmax"].time(); | ||
| 1228 | + | ||
| 1229 | + // Log action | ||
| 1230 | + log_string(NORMAL, "Setting stop time \"tmax\" parameter"); | ||
| 1231 | + | ||
| 1232 | + } // endif: tmax parameter was valid | ||
| 1233 | + | ||
| 1234 | + // ... otherwise set stop time from observations | ||
| 1235 | + else { | ||
| 1236 | + | ||
| 1237 | + // Loop over all observations | ||
| 1238 | + for (int k = 0; k < m_obs.size(); ++k) { | ||
| 1239 | + | ||
| 1240 | + // Get CTA observation | ||
| 1241 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[k]); | ||
| 1242 | + | ||
| 1243 | + // Continue only if observation is valid | ||
| 1244 | + if (obs != NULL) { | ||
| 1245 | + | ||
| 1246 | + // Update stop time if the stop time of the observation is | ||
| 1247 | + // larger than the current stop time | ||
| 1248 | + if (obs->gti().tstop() > tstop) { | ||
| 1249 | + tstop = obs->gti().tstop(); | ||
| 1250 | + } | ||
| 1251 | + | ||
| 1252 | + } // endif: observation was valid | ||
| 1253 | + | ||
| 1254 | + } // endfor: looped over observations | ||
| 1255 | + | ||
| 1256 | + // Log action | ||
| 1257 | + log_string(NORMAL, "Setting stop time from observations"); | ||
| 1258 | + | ||
| 1259 | + } // endelse: no valid time specified | ||
| 1260 | + | ||
| 1261 | + // Return stop time | ||
| 1262 | + return tstop; | ||
| 1263 | +} | ||
| 1264 | + | ||
| 1265 | + | ||
| 1266 | +/***********************************************************************//** | ||
| 1267 | + * @brief Write source histograms in FITS format | ||
| 1268 | + * | ||
| 1269 | + * @param[in,out] fits FITS file | ||
| 1270 | + * | ||
| 1271 | + * This method creates two FITS binary table extensions and appends them to | ||
| 1272 | + * the FITS file. | ||
| 1273 | + * | ||
| 1274 | + * The first extension is named "SOURCE SIGNIFICANCE" and contains the | ||
| 1275 | + * significance of the variability as function of time bin for the pixel | ||
| 1276 | + * with the maximum significance and for each source. | ||
| 1277 | + * | ||
| 1278 | + * The second extension is named "SOURCE POSITION" and contains the Right | ||
| 1279 | + * Ascension and Declination for the maximum significance pixel and for each | ||
| 1280 | + * source. | ||
| 1281 | + ***************************************************************************/ | ||
| 1282 | +void ctfindvar::write_source_histograms(GFits& fits) | ||
| 1046 | { | 1283 | { |
| 1047 | // Setup data storage for time and source significances | 1284 | // Setup data storage for time and source significances |
| 1048 | double tinterval = (*this)["tinterval"].real(); | 1285 | double tinterval = (*this)["tinterval"].real(); |
| 1049 | - int nentries = (m_tstop-m_tstart) / tinterval + 0.5; | ||
| 1050 | - int nsources = m_pixsigsrc.shape()[0]; | ||
| 1051 | - GNdarray time_info(2, nentries); | ||
| 1052 | - GNdarray max_pixel_info(nentries); | ||
| 1053 | - GNdarray src_info(nsources, nentries); | ||
| 1054 | - | ||
| 1055 | - // Store the full set of information | ||
| 1056 | - for (int i=0; i<nentries; i++) { | 1286 | + int nbins = (m_tstop-m_tstart) / tinterval + 0.5; |
| 1287 | + int nsrc = m_pixsigsrc.shape()[0]; | ||
| 1288 | + GNdarray time_info(2, nbins); | ||
| 1289 | + GNdarray max_pixel_info(nbins); | ||
| 1290 | + GNdarray src_info(nsrc, nbins); | ||
| 1291 | + | ||
| 1292 | + // Loop over time bins | ||
| 1293 | + for (int i = 0; i < nbins; ++i) { | ||
| 1294 | + | ||
| 1295 | + // Set time bin mid point | ||
| 1057 | GTime tstart_bin(m_tstart + i * tinterval); | 1296 | GTime tstart_bin(m_tstart + i * tinterval); |
| 1058 | GTime tstop_bin(m_tstart + (i+1) * tinterval); | 1297 | GTime tstop_bin(m_tstart + (i+1) * tinterval); |
| 1059 | GTime midpoint((tstop_bin.secs()+tstart_bin.secs())*0.5); | 1298 | GTime midpoint((tstop_bin.secs()+tstart_bin.secs())*0.5); |
| @@ -1066,111 +1305,125 @@ void ctfindvar::write_srchist(void) | @@ -1066,111 +1305,125 @@ void ctfindvar::write_srchist(void) | ||
| 1066 | int index = time2inx(midpoint); | 1305 | int index = time2inx(midpoint); |
| 1067 | 1306 | ||
| 1068 | // Loop over every source | 1307 | // Loop over every source |
| 1069 | - for (int src=0; src<nsources; src++) { | ||
| 1070 | - if (index >= 0) { | ||
| 1071 | - src_info(src,i) = m_pixsigsrc(src,index); | ||
| 1072 | - } else { | ||
| 1073 | - src_info(src,i) = 0.0; | ||
| 1074 | - } | 1308 | + for (int k = 0; k < nsrc; ++k) { |
| 1309 | + src_info(k,i) = (index >= 0) ? m_pixsigsrc(k,index) : 0.0; | ||
| 1075 | } | 1310 | } |
| 1076 | 1311 | ||
| 1077 | - // Fill max pixel information | ||
| 1078 | - if (index >= 0) { | ||
| 1079 | - max_pixel_info(i) = m_pixsigmax(index); | ||
| 1080 | - } | 1312 | + // Fill maximum pixel information |
| 1313 | + max_pixel_info(i) = (index >= 0) ? m_pixsigmax(index) : 0.0; | ||
| 1314 | + | ||
| 1315 | + } // endfor: looped over time bins | ||
| 1316 | + | ||
| 1317 | + // Create binary tables | ||
| 1318 | + GFitsBinTable table_signif(nbins); | ||
| 1319 | + GFitsBinTable table_pos(nsrc+1); | ||
| 1320 | + table_signif.extname("SOURCE SIGNIFICANCE"); | ||
| 1321 | + table_pos.extname("SOURCE POSITION"); | ||
| 1322 | + | ||
| 1323 | + // Create columns for time bins | ||
| 1324 | + GFitsTableDoubleCol time_start("TSTART", nbins); | ||
| 1325 | + GFitsTableDoubleCol time_stop("TSTOP", nbins); | ||
| 1326 | + GFitsTableDoubleCol time_sigma("MAXSIGPIXEL", nbins); | ||
| 1327 | + time_start.unit("MJD"); | ||
| 1328 | + time_stop.unit("MJD"); | ||
| 1329 | + time_sigma.unit("sigma"); | ||
| 1330 | + | ||
| 1331 | + // Create columns for source position | ||
| 1332 | + GFitsTableStringCol pos_name("SOURCE", nsrc+1, 20); | ||
| 1333 | + GFitsTableDoubleCol pos_ra("RA", nsrc+1); | ||
| 1334 | + GFitsTableDoubleCol pos_dec("DEC", nsrc+1); | ||
| 1335 | + pos_ra.unit("deg"); | ||
| 1336 | + pos_dec.unit("deg"); | ||
| 1337 | + | ||
| 1338 | + // Fill time bin columns | ||
| 1339 | + for (int i = 0; i < nbins; ++i) { | ||
| 1340 | + time_start(i) = time_info(0,i); | ||
| 1341 | + time_stop(i) = time_info(1,i); | ||
| 1342 | + time_sigma(i) = max_pixel_info(i); | ||
| 1081 | } | 1343 | } |
| 1082 | 1344 | ||
| 1083 | - // Call the appropriate method for writing the data | ||
| 1084 | - write_srchist_fits(time_info, max_pixel_info, src_info); | ||
| 1085 | -} | 1345 | + // Fill source columns |
| 1346 | + pos_name(0) = "MAXSIGPIXEL"; | ||
| 1347 | + pos_ra(0) = m_max_sig_dir.ra_deg(); | ||
| 1348 | + pos_dec(0) = m_max_sig_dir.dec_deg(); | ||
| 1086 | 1349 | ||
| 1087 | - | ||
| 1088 | -/***********************************************************************//** | ||
| 1089 | - * @brief Write individual histograms in FITS format | ||
| 1090 | - * | ||
| 1091 | - * @param[in] time_info Start and stop time in MJD for each bin | ||
| 1092 | - * @param[in] src_info Significance distribution for each source | ||
| 1093 | - | ||
| 1094 | - * This method stores the extracted significance for each source at each time | ||
| 1095 | - * interval between tstart and tstop. Each time bin contains information on | ||
| 1096 | - * the start and stop time of that bin (in MJD) and the extracted variability | ||
| 1097 | - * significance of the source in that time bin. | ||
| 1098 | - ***************************************************************************/ | ||
| 1099 | -void ctfindvar::write_srchist_fits(const GNdarray& time_info, | ||
| 1100 | - const GNdarray& max_pixel_info, | ||
| 1101 | - const GNdarray& src_info) | ||
| 1102 | -{ | ||
| 1103 | - log_string(NORMAL, "Storing histograms in FITS format"); | ||
| 1104 | - | ||
| 1105 | - // Create the table | ||
| 1106 | - int nrows = time_info.shape()[1]; | ||
| 1107 | - GFitsBinTable table_signif(nrows); | ||
| 1108 | - GFitsBinTable table_dir(2); | ||
| 1109 | - table_signif.extname("SRCSIGNIF"); | ||
| 1110 | - table_dir.extname("SRCPOSITION"); | ||
| 1111 | - | ||
| 1112 | - // Append the start/stop time and max pixel columns | ||
| 1113 | - GFitsTableDoubleCol start_mjd("TSTART", nrows); | ||
| 1114 | - GFitsTableDoubleCol stop_mjd("TSTOP", nrows); | ||
| 1115 | - GFitsTableDoubleCol max_pix("MAXSIGPIXEL", nrows); | ||
| 1116 | - for (int i=0; i<nrows; i++) { | ||
| 1117 | - start_mjd(i) = time_info(0,i); | ||
| 1118 | - stop_mjd(i) = time_info(1,i); | ||
| 1119 | - max_pix(i) = max_pixel_info(i); | ||
| 1120 | - } | ||
| 1121 | - table_signif.append(start_mjd); | ||
| 1122 | - table_signif.append(stop_mjd); | ||
| 1123 | - table_signif.append(max_pix); | ||
| 1124 | - | ||
| 1125 | - // Store the position of the peak pixel | ||
| 1126 | - GFitsTableDoubleCol max_pix_dir("MAXSIGPIXEL",2); | ||
| 1127 | - max_pix_dir(0) = m_max_sig_dir.ra_deg(); | ||
| 1128 | - max_pix_dir(1) = m_max_sig_dir.dec_deg(); | ||
| 1129 | - table_dir.append(max_pix_dir); | 1350 | + // Append columns to tables |
| 1351 | + table_signif.append(time_start); | ||
| 1352 | + table_signif.append(time_stop); | ||
| 1353 | + table_signif.append(time_sigma); | ||
| 1130 | 1354 | ||
| 1131 | // Append the distribution for each source | 1355 | // Append the distribution for each source |
| 1132 | - int src_count = src_info.shape()[0]; | ||
| 1133 | - for (int src=0; src<src_count; src++) { | ||
| 1134 | - | 1356 | + for (int k = 0; k < nsrc; ++k) { |
| 1357 | + | ||
| 1358 | + // Initialise source name and direction | ||
| 1135 | std::string src_name("SOURCE"); | 1359 | std::string src_name("SOURCE"); |
| 1136 | GSkyDir src_dir; | 1360 | GSkyDir src_dir; |
| 1137 | 1361 | ||
| 1138 | // Get the name from the input model file | 1362 | // Get the name from the input model file |
| 1139 | - if (m_inmodel.size() > 0) { | ||
| 1140 | - src_name = m_inmodel[src]->name(); | ||
| 1141 | - | ||
| 1142 | - // Get source position | ||
| 1143 | - GModelSky* model = dynamic_cast<GModelSky*>(m_inmodel[src]); | ||
| 1144 | - GModelSpatial* model_spatial = model->spatial(); | ||
| 1145 | - GSkyRegion* model_region = model_spatial->region(); | ||
| 1146 | - src_dir = dynamic_cast<GSkyRegionCircle*>(model_region)->centre(); | ||
| 1147 | - } | ||
| 1148 | - // ... otherwise set the position from xsrc,ysrc | 1363 | + if (m_inmodel.size() > k) { |
| 1364 | + | ||
| 1365 | + // Extract the model | ||
| 1366 | + GModelSky* model = dynamic_cast<GModelSky*>(m_inmodel[k]); | ||
| 1367 | + | ||
| 1368 | + // If model is a sky model then extract the model centre. Note | ||
| 1369 | + // that this only works for a model that results a GSkyRegionCircle | ||
| 1370 | + // object as region. | ||
| 1371 | + if (model != NULL) { | ||
| 1372 | + | ||
| 1373 | + // Get the source position | ||
| 1374 | + GModelSpatial* spatial = model->spatial(); | ||
| 1375 | + GSkyRegion* region = spatial->region(); | ||
| 1376 | + GSkyRegionCircle* circle = dynamic_cast<GSkyRegionCircle*>(region); | ||
| 1377 | + | ||
| 1378 | + // If region circle is valid then extract source name and | ||
| 1379 | + // sky direction | ||
| 1380 | + if (circle != NULL) { | ||
| 1381 | + src_name = m_inmodel[k]->name(); | ||
| 1382 | + src_dir = circle->centre(); | ||
| 1383 | + } | ||
| 1384 | + | ||
| 1385 | + } // endif: model was a sky model | ||
| 1386 | + | ||
| 1387 | + } // endif: there were enough models in the input model | ||
| 1388 | + | ||
| 1389 | + // ... otherwise set the position from the xsrc and ysrc parameters | ||
| 1149 | else { | 1390 | else { |
| 1150 | if ((*this)["coordsys"].string() == "CEL") { | 1391 | if ((*this)["coordsys"].string() == "CEL") { |
| 1151 | - src_dir.radec_deg((*this)["xsrc"].real(), (*this)["yref"].real()); | ||
| 1152 | - } else { | ||
| 1153 | - src_dir.lb_deg((*this)["xsrc"].real(), (*this)["yref"].real()); | 1392 | + src_dir.radec_deg((*this)["xsrc"].real(), (*this)["ysrc"].real()); |
| 1393 | + } | ||
| 1394 | + else { | ||
| 1395 | + src_dir.lb_deg((*this)["xsrc"].real(), (*this)["ysrc"].real()); | ||
| 1154 | } | 1396 | } |
| 1155 | } | 1397 | } |
| 1156 | - | ||
| 1157 | - // Create and fill a new column | ||
| 1158 | - GFitsTableDoubleCol src_sig_col(src_name, nrows); | ||
| 1159 | - for (int i=0; i<nrows; i++) { | ||
| 1160 | - src_sig_col(i) = src_info(src, i); | 1398 | + |
| 1399 | + // Create new time column for source | ||
| 1400 | + GFitsTableDoubleCol column(src_name, nbins); | ||
| 1401 | + column.unit("sigma"); | ||
| 1402 | + | ||
| 1403 | + // Fill column | ||
| 1404 | + for (int i = 0; i < nbins; ++i) { | ||
| 1405 | + column(i) = src_info(k, i); | ||
| 1161 | } | 1406 | } |
| 1162 | - table_signif.append(src_sig_col); | ||
| 1163 | 1407 | ||
| 1164 | - // Store the positions of the source | ||
| 1165 | - GFitsTableDoubleCol src_dir_col(src_name,2); | ||
| 1166 | - src_dir_col(0) = src_dir.ra_deg(); | ||
| 1167 | - src_dir_col(1) = src_dir.dec_deg(); | ||
| 1168 | - table_dir.append(src_dir_col); | ||
| 1169 | - } | 1408 | + // Append column to time table |
| 1409 | + table_signif.append(column); | ||
| 1410 | + | ||
| 1411 | + // Store source infirmation | ||
| 1412 | + pos_name(k+1) = src_name; | ||
| 1413 | + pos_ra(k+1) = src_dir.ra_deg(); | ||
| 1414 | + pos_dec(k+1) = src_dir.dec_deg(); | ||
| 1415 | + | ||
| 1416 | + } // endfor: looped over sources | ||
| 1170 | 1417 | ||
| 1171 | - // Store information regarding the source positions | 1418 | + // Append columns to tables |
| 1419 | + table_pos.append(pos_name); | ||
| 1420 | + table_pos.append(pos_ra); | ||
| 1421 | + table_pos.append(pos_dec); | ||
| 1172 | 1422 | ||
| 1173 | - // Write the tables to a file | ||
| 1174 | - m_outfile.append(table_signif); | ||
| 1175 | - m_outfile.append(table_dir); | 1423 | + // Append tables to FITS file |
| 1424 | + fits.append(table_signif); | ||
| 1425 | + fits.append(table_pos); | ||
| 1426 | + | ||
| 1427 | + // Return | ||
| 1428 | + return; | ||
| 1176 | } | 1429 | } |
src/ctfindvar/ctfindvar.hpp
| @@ -68,27 +68,22 @@ public: | @@ -68,27 +68,22 @@ public: | ||
| 68 | 68 | ||
| 69 | protected: | 69 | protected: |
| 70 | // Protected methods | 70 | // Protected methods |
| 71 | - void init_members(void); | ||
| 72 | - void copy_members(const ctfindvar& app); | ||
| 73 | - void free_members(void); | ||
| 74 | - void get_parameters(void); | ||
| 75 | - void init_cube(void); | ||
| 76 | - void init_gtis(void); | ||
| 77 | - void fill_cube(GCTAObservation* obs); | ||
| 78 | - void fill_model_sig_pos(const GSkyDir& dir_pix); | ||
| 79 | - void fill_alpha_vector(const int& pix_number, | ||
| 80 | - std::vector<double>& alpha_vector); | ||
| 81 | - void get_variability_sig(const int& pix_number, | ||
| 82 | - const int& nbins, | ||
| 83 | - GNdarray& sig_histogram); | ||
| 84 | - double gti_overlap(const GGti& gti1, | ||
| 85 | - const GGti& gti2); | ||
| 86 | - | ||
| 87 | - // Writing methods for individual source histograms | ||
| 88 | - void write_srchist(void); | ||
| 89 | - void write_srchist_fits(const GNdarray& time_info, | ||
| 90 | - const GNdarray& max_pixel_info, | ||
| 91 | - const GNdarray& src_info); | 71 | + void init_members(void); |
| 72 | + void copy_members(const ctfindvar& app); | ||
| 73 | + void free_members(void); | ||
| 74 | + void get_parameters(void); | ||
| 75 | + void init_gtis(void); | ||
| 76 | + void create_cube(void); | ||
| 77 | + void fill_cube(GCTAObservation* obs); | ||
| 78 | + void analyse_cube(void); | ||
| 79 | + std::vector<int> get_pixels(void); | ||
| 80 | + GNdarray get_variability_sig(const int& ipix); | ||
| 81 | + std::vector<double> get_alphas(const int& ipix) const; | ||
| 82 | + double gti_overlap(const GGti& gti1, const GGti& gti2) const; | ||
| 83 | + GTime get_tstart(void); | ||
| 84 | + GTime get_tstop(void); | ||
| 85 | + GModelSky sky_model(const GSkyDir& dir) const; | ||
| 86 | + void write_source_histograms(GFits& fits); | ||
| 92 | 87 | ||
| 93 | // Protected members | 88 | // Protected members |
| 94 | GSkyMap m_counts; //!< Counts for each time interval | 89 | GSkyMap m_counts; //!< Counts for each time interval |
| @@ -97,7 +92,6 @@ protected: | @@ -97,7 +92,6 @@ protected: | ||
| 97 | GSkyDir m_max_sig_dir; //!< Sky direction associated with maximum significance | 92 | GSkyDir m_max_sig_dir; //!< Sky direction associated with maximum significance |
| 98 | double m_minoff; //!< Minimum counts for use in significance calculation | 93 | double m_minoff; //!< Minimum counts for use in significance calculation |
| 99 | double m_sig_threshold; //!< Minimum significance required to set source as variable | 94 | double m_sig_threshold; //!< Minimum significance required to set source as variable |
| 100 | - GFits m_outfile; //!< FITS object to store output | ||
| 101 | GSkyMap m_peaksigmap; //!< Skymap holding the maximum significance | 95 | GSkyMap m_peaksigmap; //!< Skymap holding the maximum significance |
| 102 | GNdarray m_pixsigsrc; //!< Store distributions of the source significances | 96 | GNdarray m_pixsigsrc; //!< Store distributions of the source significances |
| 103 | GNdarray m_pixsigmax; //!< Store distribution for pixel with max significance | 97 | GNdarray m_pixsigmax; //!< Store distribution for pixel with max significance |
src/ctfindvar/ctfindvar.par
| @@ -16,22 +16,26 @@ | @@ -16,22 +16,26 @@ | ||
| 16 | # | 16 | # |
| 17 | # General parameters | 17 | # General parameters |
| 18 | #=================== | 18 | #=================== |
| 19 | -inobs, f, a, events.fits,,, "Input event list, counts cube or observation definition XML file" | 19 | +inobs, f, a, events.fits,,, "Input event list or observation definition XML file" |
| 20 | inmodel, f, h, NONE,,, "Input model definition file for extracting source positions" | 20 | inmodel, f, h, NONE,,, "Input model definition file for extracting source positions" |
| 21 | -outcube, f, h, NONE,,, "Filename for counts cube" | 21 | +outcube, f, h, NONE,,, "Output counts cube file" |
| 22 | +outmap, f, a, map.fits,,, "Output map file" | ||
| 23 | +outmodel, f, a, model.xml,,, "Output model definition file" | ||
| 22 | caldb, s, a, prod2,,, "Calibration database" | 24 | caldb, s, a, prod2,,, "Calibration database" |
| 23 | irf, s, a, South_0.5h,,, "Instrument response function" | 25 | irf, s, a, South_0.5h,,, "Instrument response function" |
| 24 | -prefix, s, a, findvar_,,, "Prefix for output files" | ||
| 25 | 26 | ||
| 26 | # | 27 | # |
| 27 | # Variability search parameters | 28 | # Variability search parameters |
| 28 | #============================== | 29 | #============================== |
| 29 | -minoff, r, h, 0,,, "Minimum required events in off bin for computing Noff and alpha" | ||
| 30 | -emin, r, a, 0,,, "Lower energy limit (units of TeV; 0 => no cut)" | ||
| 31 | -emax, r, a, 0,,, "Upper energy limit (units of TeV; 0 => no cut)" | ||
| 32 | -sig_thr, r, h, 4.5,,, "Significance threshold for variability detection" | ||
| 33 | -smoothkrnl, s, h, NONE, GAUSSIAN|DISK|NONE,, "Smoothing kernel for counts maps" | ||
| 34 | -smoothpar, r, h, 0.05,,, "Parameter for the smoothing kernel" | 30 | +coordsys, s, a, CEL,CEL|GAL,,"Coordinate system (CEL - celestial, GAL - galactic)" |
| 31 | +xsrc, r, a, 83.63,0,360, "First coordinate of the source of interest (RA or galactic l)" | ||
| 32 | +ysrc, r, a, 22.01,-90,90, "Second coordinate of the source of interest (DEC or galactic b)" | ||
| 33 | +emin, r, a, 0.1,,, "Lower energy limit (TeV)" | ||
| 34 | +emax, r, a, 100.0,,, "Upper energy limit (TeV)" | ||
| 35 | +threshold, r, h, 4.5,,, "Significance threshold for variability detection" | ||
| 36 | +minoff, r, h, 0,,, "Minimum required events in off bin for computing Noff and alpha" | ||
| 37 | +smooth_kernel, s, h, NONE, GAUSSIAN|DISK|NONE,, "Smoothing kernel for counts maps" | ||
| 38 | +smooth_rad, r, h, 0.05,,, "Smoothing kernel radius (deg)" | ||
| 35 | 39 | ||
| 36 | # | 40 | # |
| 37 | # Time binning parameters | 41 | # Time binning parameters |
| @@ -47,12 +51,9 @@ usepnt, b, h, no,,, "Use pointing instead of xref/yref parameters?" | @@ -47,12 +51,9 @@ usepnt, b, h, no,,, "Use pointing instead of xref/yref parameters?" | ||
| 47 | nxpix, i, a, 200,,, "Size of the X axis in pixels" | 51 | nxpix, i, a, 200,,, "Size of the X axis in pixels" |
| 48 | nypix, i, a, 200,,, "Size of the Y axis in pixels" | 52 | nypix, i, a, 200,,, "Size of the Y axis in pixels" |
| 49 | binsz, r, a, 0.02,,, "Image scale (in degrees/pixel)" | 53 | binsz, r, a, 0.02,,, "Image scale (in degrees/pixel)" |
| 50 | -coordsys, s, a, CEL,CEL|GAL,,"Coordinate system (CEL - celestial, GAL - galactic)" | ||
| 51 | proj, s, a, CAR,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method" | 54 | proj, s, a, CAR,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method" |
| 52 | xref, r, a, 83.63,0,360, "First coordinate of image center in degrees (RA or galactic l)" | 55 | xref, r, a, 83.63,0,360, "First coordinate of image center in degrees (RA or galactic l)" |
| 53 | yref, r, a, 22.51,-90,90, "Second coordinate of image center in degrees (DEC or galactic b)" | 56 | yref, r, a, 22.51,-90,90, "Second coordinate of image center in degrees (DEC or galactic b)" |
| 54 | -xsrc, r, a, 83.63,0,360, "First coordinate of the source of interest (RA or galactic l)" | ||
| 55 | -ysrc, r, a, 22.51,-90,90, "Second coordinate of the source of interest (DEC or galactic b)" | ||
| 56 | 57 | ||
| 57 | # | 58 | # |
| 58 | # Standard parameters | 59 | # Standard parameters |
test/test_ctfindvar.py
| @@ -71,8 +71,9 @@ class Test(test): | @@ -71,8 +71,9 @@ class Test(test): | ||
| 71 | 71 | ||
| 72 | # Setup ctfindvar command | 72 | # Setup ctfindvar command |
| 73 | cmd = ctfindvar+' inobs="'+self._events+'"'+\ | 73 | cmd = ctfindvar+' inobs="'+self._events+'"'+\ |
| 74 | + ' outmap="ctfindvar_cmd1.fits"'+\ | ||
| 75 | + ' outmodel="ctfindvar_cmd1.xml"'+\ | ||
| 74 | ' logfile="ctfindvar_cmd1.log" chatter=1'+\ | 76 | ' logfile="ctfindvar_cmd1.log" chatter=1'+\ |
| 75 | - ' prefix=ctfindvar_test_ '+\ | ||
| 76 | ' tmin=NONE tmax=NONE tinterval=20'+\ | 77 | ' tmin=NONE tmax=NONE tinterval=20'+\ |
| 77 | ' emin=0.2 emax=1.1'+\ | 78 | ' emin=0.2 emax=1.1'+\ |
| 78 | ' nxpix=200 nypix=200 binsz=0.05'+\ | 79 | ' nxpix=200 nypix=200 binsz=0.05'+\ |
| @@ -80,12 +81,28 @@ class Test(test): | @@ -80,12 +81,28 @@ class Test(test): | ||
| 80 | ' xref=83.63 yref=22.51'+\ | 81 | ' xref=83.63 yref=22.51'+\ |
| 81 | ' xsrc=83.63 ysrc=22.51'+\ | 82 | ' xsrc=83.63 ysrc=22.51'+\ |
| 82 | ' caldb=prod2 irf=South_0.5h' | 83 | ' caldb=prod2 irf=South_0.5h' |
| 83 | - | ||
| 84 | - | 84 | + |
| 85 | # Check if execution was successful | 85 | # Check if execution was successful |
| 86 | self.test_value(self._execute(cmd), 0, | 86 | self.test_value(self._execute(cmd), 0, |
| 87 | 'Check successful execution from command line') | 87 | 'Check successful execution from command line') |
| 88 | 88 | ||
| 89 | + # Setup ctfindvar command | ||
| 90 | + cmd = ctfindvar+' inobs="event_file_that_does_not_exist.fits"'+ \ | ||
| 91 | + ' outmap="ctfindvar_cmd2.fits"'+ \ | ||
| 92 | + ' outmodel="ctfindvar_cmd2.xml"'+ \ | ||
| 93 | + ' logfile="ctfindvar_cmd2.log" chatter=1'+ \ | ||
| 94 | + ' tmin=NONE tmax=NONE tinterval=20'+ \ | ||
| 95 | + ' emin=0.2 emax=1.1'+ \ | ||
| 96 | + ' nxpix=200 nypix=200 binsz=0.05'+ \ | ||
| 97 | + ' proj=CAR coordsys=CEL'+ \ | ||
| 98 | + ' xref=83.63 yref=22.51'+ \ | ||
| 99 | + ' xsrc=83.63 ysrc=22.51'+ \ | ||
| 100 | + ' caldb=prod2 irf=South_0.5h' | ||
| 101 | + | ||
| 102 | + # Check if execution was successful | ||
| 103 | + self.test_assert(self._execute(cmd, success=False) != 0, | ||
| 104 | + 'Check invalid input file when executed from command line') | ||
| 105 | + | ||
| 89 | # Check ctfindvar --help | 106 | # Check ctfindvar --help |
| 90 | self._check_help(ctfindvar) | 107 | self._check_help(ctfindvar) |
| 91 | 108 | ||
| @@ -101,11 +118,8 @@ class Test(test): | @@ -101,11 +118,8 @@ class Test(test): | ||
| 101 | # Allocate ctfindvar | 118 | # Allocate ctfindvar |
| 102 | ctfindvar = ctools.ctfindvar() | 119 | ctfindvar = ctools.ctfindvar() |
| 103 | 120 | ||
| 104 | - #setup ctfindvar | 121 | + # Setup ctfindvar |
| 105 | ctfindvar['inobs'] = self._events | 122 | ctfindvar['inobs'] = self._events |
| 106 | - ctfindvar['logfile'] = 'ctfindvar_py0.log' | ||
| 107 | - ctfindvar['chatter'] = 1 | ||
| 108 | - ctfindvar['prefix'] = 'ctfindvar_test_python_' | ||
| 109 | ctfindvar['tmin'] = 'NONE' | 123 | ctfindvar['tmin'] = 'NONE' |
| 110 | ctfindvar['tmax'] = 'NONE' | 124 | ctfindvar['tmax'] = 'NONE' |
| 111 | ctfindvar['tinterval'] = 20 | 125 | ctfindvar['tinterval'] = 20 |
| @@ -122,32 +136,39 @@ class Test(test): | @@ -122,32 +136,39 @@ class Test(test): | ||
| 122 | ctfindvar['ysrc'] = 22.51 | 136 | ctfindvar['ysrc'] = 22.51 |
| 123 | ctfindvar['caldb'] = 'prod2' | 137 | ctfindvar['caldb'] = 'prod2' |
| 124 | ctfindvar['irf'] = 'South_0.5h' | 138 | ctfindvar['irf'] = 'South_0.5h' |
| 139 | + ctfindvar['outmap'] = 'ctfindvar_py0.fits' | ||
| 140 | + ctfindvar['outmodel'] = 'ctfindvar_py0.xml' | ||
| 141 | + ctfindvar['logfile'] = 'ctfindvar_py0.log' | ||
| 142 | + ctfindvar['chatter'] = 1 | ||
| 125 | 143 | ||
| 126 | - ## Run ctfindvar tool | 144 | + # Run ctfindvar tool |
| 127 | ctfindvar.logFileOpen() | 145 | ctfindvar.logFileOpen() |
| 128 | ctfindvar.run() | 146 | ctfindvar.run() |
| 129 | 147 | ||
| 130 | # Check that saving does not nothing | 148 | # Check that saving does not nothing |
| 131 | - ctfindvar['logfile'] = 'ctfindvar_py1.log' | 149 | + ctfindvar['outmap'] = 'ctfindvar_py1.fits' |
| 150 | + ctfindvar['outmodel'] = 'ctfindvar_py1.xml' | ||
| 151 | + ctfindvar['logfile'] = 'ctfindvar_py1.log' | ||
| 132 | ctfindvar.logFileOpen() | 152 | ctfindvar.logFileOpen() |
| 133 | ctfindvar.save() | 153 | ctfindvar.save() |
| 134 | 154 | ||
| 135 | # Check result | 155 | # Check result |
| 136 | - self._check_result_file('ctfindvar_test_python_signifmap.fits') | 156 | + self._check_result_file('ctfindvar_py1.fits') |
| 137 | 157 | ||
| 138 | # Copy ctfindvar tool | 158 | # Copy ctfindvar tool |
| 139 | cpy_tool = ctfindvar | 159 | cpy_tool = ctfindvar |
| 140 | 160 | ||
| 141 | # Run copy of ctfindvar tool again | 161 | # Run copy of ctfindvar tool again |
| 142 | - cpy_tool['logfile'] = 'ctfindvar_py2.log' | ||
| 143 | - cpy_tool['chatter'] = 3 | ||
| 144 | - cpy_tool['prefix'] = 'ctfindvar_test_copytool_' | 162 | + cpy_tool['outmap'] = 'ctfindvar_py2.fits' |
| 163 | + cpy_tool['outmodel'] = 'ctfindvar_py2.xml' | ||
| 164 | + cpy_tool['logfile'] = 'ctfindvar_py2.log' | ||
| 165 | + cpy_tool['chatter'] = 3 | ||
| 145 | cpy_tool.logFileOpen() | 166 | cpy_tool.logFileOpen() |
| 146 | cpy_tool.run() | 167 | cpy_tool.run() |
| 147 | cpy_tool.save() | 168 | cpy_tool.save() |
| 148 | 169 | ||
| 149 | # Check result | 170 | # Check result |
| 150 | - self._check_result_file('ctfindvar_test_copytool_signifmap.fits') | 171 | + self._check_result_file('ctfindvar_py2.fits') |
| 151 | 172 | ||
| 152 | # Check that clearing does not lead to an exception or segfault | 173 | # Check that clearing does not lead to an exception or segfault |
| 153 | ctfindvar.clear() | 174 | ctfindvar.clear() |
| @@ -158,17 +179,16 @@ class Test(test): | @@ -158,17 +179,16 @@ class Test(test): | ||
| 158 | # Check ctfindvar result | 179 | # Check ctfindvar result |
| 159 | def _check_result_file(self, filename): | 180 | def _check_result_file(self, filename): |
| 160 | """ | 181 | """ |
| 161 | - Check content of tool | 182 | + Check ctfindvar result |
| 162 | 183 | ||
| 163 | Parameters | 184 | Parameters |
| 164 | ---------- | 185 | ---------- |
| 165 | - tool : `~ctools.ctfindvar` | ||
| 166 | - ctfindvar instance | 186 | + filename : str |
| 187 | + Output file | ||
| 167 | """ | 188 | """ |
| 168 | - print "checking if you amazing file is valid" | ||
| 169 | - # Read variability file | ||
| 170 | - fits = gammalib.GFits(filename) | ||
| 171 | - self.test_value(fits.size(), 3, | ||
| 172 | - 'Check for 3 rows in srcsig file') | 189 | + # Read variability file |
| 190 | + fits = gammalib.GFits(filename) | ||
| 191 | + self.test_value(fits.size(), 3, 'Check for 3 extensions in output file') | ||
| 192 | + | ||
| 173 | # Return | 193 | # Return |
| 174 | return | 194 | return |