Commit a28f64882575ebe84bd413a8d4613d11cebedb06
Merge branch 'devel' of https://cta-gitlab.irap.omp.eu/ctools/ctools into 2207-c…
…tskymap_RING_bkgsubtract
Showing
20 changed files
with
1071 additions
and
89 deletions
ChangeLog
| 1 | -2017-08-08 | 1 | +2017-10-11 |
| 2 | 2 | ||
| 3 | * Version 1.5.0 released | 3 | * Version 1.5.0 released |
| 4 | ======================== | 4 | ======================== |
| 5 | 5 | ||
| 6 | + Add keywords to sky maps produced by ctskymap (#2194) | ||
| 7 | + Enhance efficiency of computations in ctmodel (#2189) | ||
| 8 | + Add csmodelsois script (#2180) | ||
| 6 | Use t-type parameters for all "tmin" and "tmax" parameters (#1864) | 9 | Use t-type parameters for all "tmin" and "tmax" parameters (#1864) |
| 7 | 10 | ||
| 8 | 11 |
NEWS
| 1 | New Features and Important Changes in ctools 1.5.0 | 1 | New Features and Important Changes in ctools 1.5.0 |
| 2 | 2 | ||
| 3 | -8 August 2017 | 3 | +11 October 2017 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | Introduction | 6 | Introduction |
| @@ -53,7 +53,9 @@ None | @@ -53,7 +53,9 @@ None | ||
| 53 | 53 | ||
| 54 | ctskymap - CTA sky mapping | 54 | ctskymap - CTA sky mapping |
| 55 | -------------------------- | 55 | -------------------------- |
| 56 | -None | 56 | +Header keywords informing about the dates and times covered by the observations |
| 57 | +used to generate the skymap, as well as the event energy range, are now appended | ||
| 58 | +as header keywords to the FITS file (#2194). | ||
| 57 | 59 | ||
| 58 | 60 | ||
| 59 | ctmodel - CTA counts cube modelling | 61 | ctmodel - CTA counts cube modelling |
| @@ -61,6 +63,11 @@ ctmodel - CTA counts cube modelling | @@ -61,6 +63,11 @@ ctmodel - CTA counts cube modelling | ||
| 61 | Use t-type parameters for "tmin" and "tmax" to all specifying times in various | 63 | Use t-type parameters for "tmin" and "tmax" to all specifying times in various |
| 62 | formats (#1864). | 64 | formats (#1864). |
| 63 | 65 | ||
| 66 | +The tool now also checks which models actually overlap with the RoI of a given | ||
| 67 | +observation and then only use these models to compute the model cube. The | ||
| 68 | +parallelization of the tool has also been optimised so that diffuse models are | ||
| 69 | +not loaded over and over again (#2189). | ||
| 70 | + | ||
| 64 | 71 | ||
| 65 | ctexpcube - CTA exposure cube generation | 72 | ctexpcube - CTA exposure cube generation |
| 66 | ---------------------------------------- | 73 | ---------------------------------------- |
| @@ -119,6 +126,9 @@ None | @@ -119,6 +126,9 @@ None | ||
| 119 | 126 | ||
| 120 | cscripts | 127 | cscripts |
| 121 | -------- | 128 | -------- |
| 129 | +Add csmodelsois script that replaces selected models in a model container by | ||
| 130 | +a diffuse map cube (#2180). | ||
| 131 | + | ||
| 122 | Use t-type parameters for "tmin" and "tmax" to all specifying times in various | 132 | Use t-type parameters for "tmin" and "tmax" to all specifying times in various |
| 123 | formats (#1864). | 133 | formats (#1864). |
| 124 | 134 |
cscripts/Makefile.am
| @@ -28,6 +28,7 @@ pythonscripts = $(top_builddir)/cscripts/__init__.py \ | @@ -28,6 +28,7 @@ pythonscripts = $(top_builddir)/cscripts/__init__.py \ | ||
| 28 | $(srcdir)/csmodelinfo.py \ | 28 | $(srcdir)/csmodelinfo.py \ |
| 29 | $(srcdir)/csmodelmerge.py \ | 29 | $(srcdir)/csmodelmerge.py \ |
| 30 | $(srcdir)/csmodelselect.py \ | 30 | $(srcdir)/csmodelselect.py \ |
| 31 | + $(srcdir)/csmodelsois.py \ | ||
| 31 | $(srcdir)/csobs2caldb.py \ | 32 | $(srcdir)/csobs2caldb.py \ |
| 32 | $(srcdir)/csobsdef.py \ | 33 | $(srcdir)/csobsdef.py \ |
| 33 | $(srcdir)/csobsinfo.py \ | 34 | $(srcdir)/csobsinfo.py \ |
| @@ -60,6 +61,7 @@ parfiles = $(srcdir)/cscaldb.par \ | @@ -60,6 +61,7 @@ parfiles = $(srcdir)/cscaldb.par \ | ||
| 60 | $(srcdir)/csmodelinfo.par \ | 61 | $(srcdir)/csmodelinfo.par \ |
| 61 | $(srcdir)/csmodelmerge.par \ | 62 | $(srcdir)/csmodelmerge.par \ |
| 62 | $(srcdir)/csmodelselect.par \ | 63 | $(srcdir)/csmodelselect.par \ |
| 64 | + $(srcdir)/csmodelsois.par \ | ||
| 63 | $(srcdir)/csobs2caldb.par \ | 65 | $(srcdir)/csobs2caldb.par \ |
| 64 | $(srcdir)/csobsdef.par \ | 66 | $(srcdir)/csobsdef.par \ |
| 65 | $(srcdir)/csobsinfo.par \ | 67 | $(srcdir)/csobsinfo.par \ |
| @@ -89,6 +91,7 @@ linkscripts = cscaldb \ | @@ -89,6 +91,7 @@ linkscripts = cscaldb \ | ||
| 89 | csmodelinfo \ | 91 | csmodelinfo \ |
| 90 | csmodelmerge \ | 92 | csmodelmerge \ |
| 91 | csmodelselect \ | 93 | csmodelselect \ |
| 94 | + csmodelsois \ | ||
| 92 | csobs2caldb \ | 95 | csobs2caldb \ |
| 93 | csobsdef \ | 96 | csobsdef \ |
| 94 | csobsinfo \ | 97 | csobsinfo \ |
| @@ -123,6 +126,7 @@ testscripts = $(srcdir)/tests/__init__.py \ | @@ -123,6 +126,7 @@ testscripts = $(srcdir)/tests/__init__.py \ | ||
| 123 | $(top_srcdir)/test/test_csmodelinfo.py \ | 126 | $(top_srcdir)/test/test_csmodelinfo.py \ |
| 124 | $(top_srcdir)/test/test_csmodelmerge.py \ | 127 | $(top_srcdir)/test/test_csmodelmerge.py \ |
| 125 | $(top_srcdir)/test/test_csmodelselect.py \ | 128 | $(top_srcdir)/test/test_csmodelselect.py \ |
| 129 | + $(top_srcdir)/test/test_csmodelsois.py \ | ||
| 126 | $(top_srcdir)/test/test_csobs2caldb.py \ | 130 | $(top_srcdir)/test/test_csobs2caldb.py \ |
| 127 | $(top_srcdir)/test/test_csobsdef.py \ | 131 | $(top_srcdir)/test/test_csobsdef.py \ |
| 128 | $(top_srcdir)/test/test_csobsinfo.py \ | 132 | $(top_srcdir)/test/test_csobsinfo.py \ |
cscripts/__init__.py.in
| 1 | # ========================================================================== | 1 | # ========================================================================== |
| 2 | # cscripts Python module | 2 | # cscripts Python module |
| 3 | # | 3 | # |
| 4 | -# Copyright (C) 2015-2016 Juergen Knoedlseder | 4 | +# Copyright (C) 2015-2017 Juergen Knoedlseder |
| 5 | # | 5 | # |
| 6 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
| @@ -31,6 +31,7 @@ __all__ = [ | @@ -31,6 +31,7 @@ __all__ = [ | ||
| 31 | "csmodelinfo", | 31 | "csmodelinfo", |
| 32 | "csmodelmerge", | 32 | "csmodelmerge", |
| 33 | "csmodelselect", | 33 | "csmodelselect", |
| 34 | + "csmodelsois", | ||
| 34 | "csobs2caldb", | 35 | "csobs2caldb", |
| 35 | "csobsdef", | 36 | "csobsdef", |
| 36 | "csobsinfo", | 37 | "csobsinfo", |
| @@ -66,6 +67,7 @@ from cscripts.cslightcrv import cslightcrv | @@ -66,6 +67,7 @@ from cscripts.cslightcrv import cslightcrv | ||
| 66 | from cscripts.csmodelinfo import csmodelinfo | 67 | from cscripts.csmodelinfo import csmodelinfo |
| 67 | from cscripts.csmodelmerge import csmodelmerge | 68 | from cscripts.csmodelmerge import csmodelmerge |
| 68 | from cscripts.csmodelselect import csmodelselect | 69 | from cscripts.csmodelselect import csmodelselect |
| 70 | +from cscripts.csmodelsois import csmodelsois | ||
| 69 | from cscripts.csobs2caldb import csobs2caldb | 71 | from cscripts.csobs2caldb import csobs2caldb |
| 70 | from cscripts.csobsdef import csobsdef | 72 | from cscripts.csobsdef import csobsdef |
| 71 | from cscripts.csobsinfo import csobsinfo | 73 | from cscripts.csobsinfo import csobsinfo |
cscripts/csmodelsois.par
0 → 100644
| 1 | +############################################################################# | ||
| 2 | +# # | ||
| 3 | +# CTA Science Analysis Tools # | ||
| 4 | +# # | ||
| 5 | +# ------------------------------------------------------------------------- # | ||
| 6 | +# # | ||
| 7 | +# File: csmodelsois.par # | ||
| 8 | +# # | ||
| 9 | +# Author: Josh Cardenzana # | ||
| 10 | +# josh.cardenzana@irap.omp.eu # | ||
| 11 | +# IRAP # | ||
| 12 | +# # | ||
| 13 | +# Purpose: Parameter file for the csmodelsois application # | ||
| 14 | +# # | ||
| 15 | +############################################################################# | ||
| 16 | +# | ||
| 17 | +# General parameters | ||
| 18 | +#=================== | ||
| 19 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file" | ||
| 20 | +outcube, f, a, mapcube.fits,,, "Output map cube file" | ||
| 21 | +ptsrcsig, r, h, 1.0,0,60, "Point source Gaussian sigma in arcmin" | ||
| 22 | +soilist, s, a, ,,, "CSV list of sources to exclude from cube model" | ||
| 23 | +outmodel, f, a, model.xml,,, "Output model definition XML file" | ||
| 24 | + | ||
| 25 | +# | ||
| 26 | +# Energy binning parameters | ||
| 27 | +#========================== | ||
| 28 | +ebinalg, s, a, LOG,FILE|LIN|LOG,, "Algorithm for defining energy bins" | ||
| 29 | +emin, r, a, 0.1,,, "Start value for first energy bin in TeV" | ||
| 30 | +emax, r, a, 100.0,,, "Stop value for last energy bin in TeV" | ||
| 31 | +enumbins, i, a, 20,1,200, "Number of energy bins" | ||
| 32 | +ebinfile, f, a, NONE,,, "Name of the file containing the energy bin definition" | ||
| 33 | + | ||
| 34 | +# | ||
| 35 | +# Spatial binning parameters | ||
| 36 | +#=========================== | ||
| 37 | +nxpix, i, a, 200,,, "Size of the X axis in pixels" | ||
| 38 | +nypix, i, a, 200,,, "Size of the Y axis in pixels" | ||
| 39 | +binsz, r, a, 0.02,,, "Image scale (in degrees/pixel)" | ||
| 40 | +coordsys, s, a, CEL,CEL|GAL,,"Coordinate system (CEL - celestial, GAL - galactic)" | ||
| 41 | +proj, s, a, CAR,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method" | ||
| 42 | +ra, r, a, 83.63,0,360, "Right ascension of image center (in degrees)" | ||
| 43 | +dec, r, a, 22.01,-90,90, "Declination of image center (in degrees)" | ||
| 44 | +glon, r, a, 184.55,0,360, "Galactic longitude of image center (in degrees)" | ||
| 45 | +glat, r, a, -5.80,-90,90, "Galactic latitude of image center (in degrees)" | ||
| 46 | + | ||
| 47 | +# | ||
| 48 | +# Standard parameters | ||
| 49 | +#==================== | ||
| 50 | +publish, b, h, no,,, "Publish map cube on VO Hub?" | ||
| 51 | +chatter, i, h, 2,0,4, "Chattiness of output" | ||
| 52 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | ||
| 53 | +debug, b, h, no,,, "Debugging mode activated" | ||
| 54 | +mode, s, h, "ql",,, "Mode of automatic parameters" | ||
| 55 | +logfile, f, h, "csmodelsois.log",,, "Log filename" |
cscripts/csmodelsois.py
0 → 100755
| 1 | +#! /usr/bin/env python | ||
| 2 | +# ========================================================================== | ||
| 3 | +# Puts subset of sources in diffuse model cube | ||
| 4 | +# | ||
| 5 | +# Copyright (C) 2017 Josh Cardenzana | ||
| 6 | +# | ||
| 7 | +# This program is free software: you can redistribute it and/or modify | ||
| 8 | +# it under the terms of the GNU General Public License as published by | ||
| 9 | +# the Free Software Foundation, either version 3 of the License, or | ||
| 10 | +# (at your option) any later version. | ||
| 11 | +# | ||
| 12 | +# This program is distributed in the hope that it will be useful, | ||
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | +# GNU General Public License for more details. | ||
| 16 | +# | ||
| 17 | +# You should have received a copy of the GNU General Public License | ||
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | +# | ||
| 20 | +# ========================================================================== | ||
| 21 | +import sys | ||
| 22 | +import gammalib | ||
| 23 | +import ctools | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +# ================= # | ||
| 27 | +# csmodelsois class # | ||
| 28 | +# ================= # | ||
| 29 | +class csmodelsois(ctools.cscript): | ||
| 30 | + """ | ||
| 31 | + Puts subset of sources in diffuse model cube | ||
| 32 | + | ||
| 33 | + The csmodelsois class puts a subset of sources in a model definition | ||
| 34 | + XML file into a model cube and generates a new model definition XML file | ||
| 35 | + in which the subset of sources is replaced by a model of type | ||
| 36 | + DiffuseMapCube. | ||
| 37 | + """ | ||
| 38 | + | ||
| 39 | + # Constructor | ||
| 40 | + def __init__(self, *argv): | ||
| 41 | + """ | ||
| 42 | + Constructor | ||
| 43 | + | ||
| 44 | + Parameters | ||
| 45 | + ---------- | ||
| 46 | + argv : list of parameters | ||
| 47 | + | ||
| 48 | + Raises | ||
| 49 | + ------ | ||
| 50 | + TypeError | ||
| 51 | + An invalid number of command line arguments was provided. | ||
| 52 | + """ | ||
| 53 | + # Set name and version | ||
| 54 | + self._name = 'csmodelsois' | ||
| 55 | + self._version = ctools.__version__ | ||
| 56 | + | ||
| 57 | + # Initialize parameters | ||
| 58 | + self._init_members() | ||
| 59 | + | ||
| 60 | + # Initialise application by calling the appropriate class constructor | ||
| 61 | + self._init_cscript(argv) | ||
| 62 | + | ||
| 63 | + # Return | ||
| 64 | + return | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + # Private methods | ||
| 68 | + def _init_members(self): | ||
| 69 | + """ | ||
| 70 | + Initialize the parameters for this object | ||
| 71 | + """ | ||
| 72 | + # Initialise parameters | ||
| 73 | + self.cubegen = ctools.ctmapcube() # Implements ctmapcube for generate the cube | ||
| 74 | + self.m_models = gammalib.GModels() # Stores the full list of input models | ||
| 75 | + self.cubemodels = gammalib.GModels() # Stores the list of models to be written to file | ||
| 76 | + | ||
| 77 | + # Return | ||
| 78 | + return | ||
| 79 | + | ||
| 80 | + def _get_parameters(self): | ||
| 81 | + """ | ||
| 82 | + Get parameters from parfile | ||
| 83 | + """ | ||
| 84 | + # Query input parameters | ||
| 85 | + self['inmodel'].filename() | ||
| 86 | + self['soilist'].string() | ||
| 87 | + | ||
| 88 | + # Read input parameters | ||
| 89 | + ptsrcsig = self['ptsrcsig'].real() | ||
| 90 | + | ||
| 91 | + # Get the cube centre coordinates | ||
| 92 | + self.cubegen['coordsys'].string(self['coordsys'].string()) | ||
| 93 | + if self['coordsys'].string() == 'CEL': | ||
| 94 | + self.cubegen['xref'].real(self['ra'].real()) | ||
| 95 | + self.cubegen['yref'].real(self['dec'].real()) | ||
| 96 | + else: | ||
| 97 | + self.cubegen['xref'].real(self['glon'].real()) | ||
| 98 | + self.cubegen['yref'].real(self['glat'].real()) | ||
| 99 | + | ||
| 100 | + # Get spatial binning parameters | ||
| 101 | + self.cubegen['binsz'].real(self['binsz'].real()) | ||
| 102 | + self.cubegen['nxpix'].integer(self['nxpix'].integer()) | ||
| 103 | + self.cubegen['nypix'].integer(self['nypix'].integer()) | ||
| 104 | + self.cubegen['proj'].string(self['proj'].string()) | ||
| 105 | + | ||
| 106 | + # Get the energy binning parameters | ||
| 107 | + self.cubegen['ebinalg'].string(self['ebinalg'].string()) | ||
| 108 | + if self['ebinalg'].string() == 'FILE': | ||
| 109 | + self.cubegen['ebinfile'].filename(self['ebinfile'].filename()) | ||
| 110 | + else: | ||
| 111 | + self.cubegen['emin'].real(self['emin'].real()) | ||
| 112 | + self.cubegen['emax'].real(self['emax'].real()) | ||
| 113 | + self.cubegen['enumbins'].integer(self['enumbins'].integer()) | ||
| 114 | + | ||
| 115 | + # Get remaining hidden parameters | ||
| 116 | + self.cubegen['ptsrcsig'].real(ptsrcsig) | ||
| 117 | + | ||
| 118 | + # Read optionally output cube filenames | ||
| 119 | + if self._read_ahead(): | ||
| 120 | + self.cubegen['outcube'].filename(self['outcube'].filename()) | ||
| 121 | + self['outmodel'].filename() | ||
| 122 | + | ||
| 123 | + # Write parameters into logger | ||
| 124 | + self._log_parameters(gammalib.TERSE); | ||
| 125 | + | ||
| 126 | + return | ||
| 127 | + | ||
| 128 | + def _gen_cubemodel(self): | ||
| 129 | + """ | ||
| 130 | + Generates a binned model from the model file using ctmapcube | ||
| 131 | + """ | ||
| 132 | + # Get a list of sources we DONT want to put into the cube | ||
| 133 | + sources = self['soilist'].string().split(',') | ||
| 134 | + | ||
| 135 | + # Load the model into a model container | ||
| 136 | + if (self.m_models.size() == 0): | ||
| 137 | + self.m_models = gammalib.GModels(self['inmodel'].filename()) | ||
| 138 | + | ||
| 139 | + # Store a copy of the models | ||
| 140 | + self.cubemodels = self.m_models.copy() | ||
| 141 | + | ||
| 142 | + # Loop through models and pull out all models not in the list | ||
| 143 | + models2remove = [] | ||
| 144 | + for model in self.m_models: | ||
| 145 | + | ||
| 146 | + # If model is not a sky model then continue | ||
| 147 | + if model.classname() != 'GModelSky': | ||
| 148 | + self.cubemodels.remove(model.name()) | ||
| 149 | + | ||
| 150 | + # ... otherwise, if model is in list of sources the remove it | ||
| 151 | + # from the container | ||
| 152 | + elif model.name() in sources: | ||
| 153 | + self.cubemodels.remove(model.name()) | ||
| 154 | + | ||
| 155 | + # Log the number of models to be put into the cube | ||
| 156 | + self._log_value(self['chatter'].integer(), 'Numner of cube models', | ||
| 157 | + self.cubemodels.size()) | ||
| 158 | + | ||
| 159 | + # Return | ||
| 160 | + return | ||
| 161 | + | ||
| 162 | + | ||
| 163 | + # Public methods | ||
| 164 | + def run(self): | ||
| 165 | + """ | ||
| 166 | + Implements the actual bulk of the script's tasks | ||
| 167 | + """ | ||
| 168 | + # Switch screen logging on in debug mode | ||
| 169 | + if self._logDebug(): | ||
| 170 | + self._log.cout(True) | ||
| 171 | + | ||
| 172 | + # Get parameters | ||
| 173 | + self._get_parameters() | ||
| 174 | + | ||
| 175 | + # Set the models to put into the cube | ||
| 176 | + self._gen_cubemodel() | ||
| 177 | + | ||
| 178 | + # Only run if there still models to be filled into the cube | ||
| 179 | + if not self.cubemodels.is_empty(): | ||
| 180 | + | ||
| 181 | + # Log action | ||
| 182 | + self._log_string(gammalib.NORMAL, 'Generating model cube') | ||
| 183 | + | ||
| 184 | + # Fill the cube models into the ctmapcube object | ||
| 185 | + self.cubegen.models(self.cubemodels) | ||
| 186 | + | ||
| 187 | + # Run the map generating method | ||
| 188 | + self.cubegen.run() | ||
| 189 | + | ||
| 190 | + else: | ||
| 191 | + self._log_string(gammalib.NORMAL, | ||
| 192 | + 'List of models is empty, nothing will be done') | ||
| 193 | + | ||
| 194 | + # Return | ||
| 195 | + return | ||
| 196 | + | ||
| 197 | + def execute(self): | ||
| 198 | + """ | ||
| 199 | + Execute the script | ||
| 200 | + """ | ||
| 201 | + # Open logfile | ||
| 202 | + self.logFileOpen() | ||
| 203 | + | ||
| 204 | + # Read ahead output parameters | ||
| 205 | + self._read_ahead(True) | ||
| 206 | + | ||
| 207 | + # Run the script | ||
| 208 | + self.run() | ||
| 209 | + | ||
| 210 | + # Save model | ||
| 211 | + self.save() | ||
| 212 | + | ||
| 213 | + # Return | ||
| 214 | + return | ||
| 215 | + | ||
| 216 | + def save(self): | ||
| 217 | + """ | ||
| 218 | + Save the cube and optionally the updated XML model file | ||
| 219 | + """ | ||
| 220 | + # Save the generated cube if the cube and filename are not empty | ||
| 221 | + if ((not self.cubegen.mapcube().cube().is_empty()) and | ||
| 222 | + self._is_valid_filename(self['outcube'].filename())): | ||
| 223 | + self.cubegen.mapcube().save(self['outcube'].filename(), | ||
| 224 | + self['clobber'].boolean()) | ||
| 225 | + | ||
| 226 | + # If requested, save the updated list of models | ||
| 227 | + if self._is_valid_filename(self['outmodel'].filename()): | ||
| 228 | + | ||
| 229 | + # Generate a list of models that will be output to file | ||
| 230 | + outmodels = gammalib.GModels(self.m_models) | ||
| 231 | + | ||
| 232 | + # Remove all models used in the generated cube | ||
| 233 | + for model in self.cubemodels: | ||
| 234 | + outmodels.remove(model.name()) | ||
| 235 | + | ||
| 236 | + # Generate the actual cube model | ||
| 237 | + spat = gammalib.GModelSpatialDiffuseCube(self['outcube'].filename()) | ||
| 238 | + spec = gammalib.GModelSpectralConst() | ||
| 239 | + newmodel = gammalib.GModelSky(spat, spec) | ||
| 240 | + | ||
| 241 | + # Give the model a default name | ||
| 242 | + newmodel.name(self.cubemodelname()) | ||
| 243 | + | ||
| 244 | + # Now append the model to the list of output models | ||
| 245 | + outmodels.append(newmodel) | ||
| 246 | + | ||
| 247 | + # Save the model list | ||
| 248 | + outmodels.save(self['outmodel'].filename()) | ||
| 249 | + | ||
| 250 | + # Return | ||
| 251 | + return | ||
| 252 | + | ||
| 253 | + def mapcube(self): | ||
| 254 | + """ | ||
| 255 | + Return the mapcube generated by the underlying 'ctmapcube' object | ||
| 256 | + """ | ||
| 257 | + # Return | ||
| 258 | + return self.cubegen.mapcube() | ||
| 259 | + | ||
| 260 | + def cubemodelname(self): | ||
| 261 | + """ | ||
| 262 | + Return the name to be given to the cube model in the output XML file | ||
| 263 | + """ | ||
| 264 | + # Return | ||
| 265 | + return 'FixedSourcesCube' | ||
| 266 | + | ||
| 267 | + def models(self, models): | ||
| 268 | + """ | ||
| 269 | + Set the models | ||
| 270 | + | ||
| 271 | + Parameters | ||
| 272 | + ------- | ||
| 273 | + models : `~gammalib.GModels` | ||
| 274 | + Model container | ||
| 275 | + """ | ||
| 276 | + # Set models | ||
| 277 | + self.m_models = models | ||
| 278 | + | ||
| 279 | + # Return | ||
| 280 | + return | ||
| 281 | + | ||
| 282 | + | ||
| 283 | +# ======================== # | ||
| 284 | +# Main routine entry point # | ||
| 285 | +# ======================== # | ||
| 286 | +if __name__ == '__main__': | ||
| 287 | + | ||
| 288 | + # Create instance of application | ||
| 289 | + app = csmodelsois(sys.argv) | ||
| 290 | + | ||
| 291 | + # Execute application | ||
| 292 | + app.execute() |
doc/source/admin/release_history/1.5.rst
| @@ -22,11 +22,16 @@ Bug fixes | @@ -22,11 +22,16 @@ Bug fixes | ||
| 22 | Improvements | 22 | Improvements |
| 23 | ------------ | 23 | ------------ |
| 24 | 24 | ||
| 25 | -* TBW | 25 | +* [`2194 <https://cta-redmine.irap.omp.eu/issues/2194>`_] - |
| 26 | + Add keywords to sky maps produced by :ref:`ctskymap` | ||
| 27 | +* [`2189 <https://cta-redmine.irap.omp.eu/issues/2189>`_] - | ||
| 28 | + Enhance efficiency of computations in :ref:`ctmodel` | ||
| 26 | 29 | ||
| 27 | 30 | ||
| 28 | New features | 31 | New features |
| 29 | ------------ | 32 | ------------ |
| 30 | 33 | ||
| 34 | +* [`2180 <https://cta-redmine.irap.omp.eu/issues/2180>`_] - | ||
| 35 | + Add :ref:`csmodelsois` script | ||
| 31 | * [`1864 <https://cta-redmine.irap.omp.eu/issues/1864>`_] - | 36 | * [`1864 <https://cta-redmine.irap.omp.eu/issues/1864>`_] - |
| 32 | Use t-type parameters for all ``tmin`` and ``tmax`` parameters | 37 | Use t-type parameters for all ``tmin`` and ``tmax`` parameters |
doc/source/users/reference_manual/csmodelsois.rst
0 → 100644
| 1 | +.. _csmodelsois: | ||
| 2 | + | ||
| 3 | +csmodelsois | ||
| 4 | +=========== | ||
| 5 | + | ||
| 6 | +Generate a map cube from a subset of models in an input model. | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +Synopsis | ||
| 10 | +---------- | ||
| 11 | + | ||
| 12 | +This tool generates a map cube from a subset of sky model components contained | ||
| 13 | +in an input model. A map cube is a series of sky maps, each spanned by Right | ||
| 14 | +Ascension or Galactic longitude and Declination or Galactic latitude. Each | ||
| 15 | +map corresponds to a specific photon energy. The energy binning of the map | ||
| 16 | +cube may be either linear, logarithmic, or custom defined using an input | ||
| 17 | +file. | ||
| 18 | + | ||
| 19 | +csmodelsois generates a map cube FITS file comprising two extensions. The | ||
| 20 | +primary extension contains a 3-dimensional image containing the map cube | ||
| 21 | +values. A second extension named ``ENERGIES`` contains a binary table that | ||
| 22 | +defines the energy values of each map in the cube. | ||
| 23 | + | ||
| 24 | +Optionally, csmodelsois can also output an updated model XML file in which all | ||
| 25 | +sources from the input model XML file used to generate the map cube are | ||
| 26 | +replaced with an updated model that uses the generated map cube. This is done | ||
| 27 | +by specifying the 'outmodel' parameter. The 'soilist' parameter specifies a | ||
| 28 | +list of source names (separated by ',') to be excluded from the generated | ||
| 29 | +cube. | ||
| 30 | + | ||
| 31 | +General parameters | ||
| 32 | +------------------ | ||
| 33 | + | ||
| 34 | +``inmodel [file]`` | ||
| 35 | + Input model XML file. | ||
| 36 | + | ||
| 37 | +``outmodel [file]`` | ||
| 38 | + Output model XML file (not generated if set to ``NONE``). | ||
| 39 | + | ||
| 40 | +``outcube [file]`` | ||
| 41 | + Output map cube file. | ||
| 42 | + | ||
| 43 | +``soilist [string]`` | ||
| 44 | + CSV list of sources to be excluded from the generated map cube. | ||
| 45 | + | ||
| 46 | +``(ptsrcsig = 1.0) [real]`` | ||
| 47 | + Sigma of Gaussian to be used for point sources (in arcmin). | ||
| 48 | + | ||
| 49 | +``ebinalg <FILE|LIN|LOG> [string]`` | ||
| 50 | + Algorithm for defining energy bins. | ||
| 51 | + | ||
| 52 | +``emin [real]`` | ||
| 53 | + Lower energy value for first energy bin (in TeV). | ||
| 54 | + | ||
| 55 | +``emax [real]`` | ||
| 56 | + Upper energy value for last energy bin (in TeV). | ||
| 57 | + | ||
| 58 | +``enumbins [integer]`` | ||
| 59 | + Number of energy bins. | ||
| 60 | + | ||
| 61 | +``ebinfile [file]`` | ||
| 62 | + Name of the file containing the energy bin definition. | ||
| 63 | + | ||
| 64 | +``nxpix [integer]`` | ||
| 65 | + Number of cube bins in Right Ascension or Galactic longitude. | ||
| 66 | + | ||
| 67 | +``nypix [integer]`` | ||
| 68 | + Number of cube bins in Declination or Galactic latitude. | ||
| 69 | + | ||
| 70 | +``binsz [real]`` | ||
| 71 | + Image scale (in degrees/pixel). | ||
| 72 | + | ||
| 73 | +``coordsys <CEL|GAL> [string]`` | ||
| 74 | + Coordinate system (CEL - celestial, GAL - galactic). | ||
| 75 | + | ||
| 76 | +``proj <AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN> [string]`` | ||
| 77 | + Projection method. | ||
| 78 | + | ||
| 79 | +``ra [real]`` | ||
| 80 | + Right Ascension of cube centre (J2000, in degrees). | ||
| 81 | + | ||
| 82 | +``dec [real]`` | ||
| 83 | + Declination of cube centre (J2000, in degrees). | ||
| 84 | + | ||
| 85 | +``glon [real]`` | ||
| 86 | + Galactic longitude of cube centre (in degrees). | ||
| 87 | + | ||
| 88 | +``glat [real]`` | ||
| 89 | + Galactic latitude of cube centre (in degrees). | ||
| 90 | + | ||
| 91 | + | ||
| 92 | +Standard parameters | ||
| 93 | +------------------- | ||
| 94 | + | ||
| 95 | +``(publish = no) [boolean]`` | ||
| 96 | + Specifies whether the map cube should be published on VO Hub. | ||
| 97 | + | ||
| 98 | +``(chatter = 2) [integer]`` | ||
| 99 | + Verbosity of the executable: | ||
| 100 | + ``chatter = 0``: no information will be logged | ||
| 101 | + | ||
| 102 | + ``chatter = 1``: only errors will be logged | ||
| 103 | + | ||
| 104 | + ``chatter = 2``: errors and actions will be logged | ||
| 105 | + | ||
| 106 | + ``chatter = 3``: report about the task execution | ||
| 107 | + | ||
| 108 | + ``chatter = 4``: detailed report about the task execution | ||
| 109 | + | ||
| 110 | +``(clobber = yes) [boolean]`` | ||
| 111 | + Specifies whether an existing output counts cube file should be overwritten. | ||
| 112 | + | ||
| 113 | +``(debug = no) [boolean]`` | ||
| 114 | + Enables debug mode. In debug mode the executable will dump any log file output to the console. | ||
| 115 | + | ||
| 116 | +``(mode = ql) [string]`` | ||
| 117 | + Mode of automatic parameters (default is "ql", i.e. "query and learn"). | ||
| 118 | + | ||
| 119 | +``(logfile = csmodelsois.log) [string]`` | ||
| 120 | + Name of log file. | ||
| 121 | + | ||
| 122 | + | ||
| 123 | +Related tools or scripts | ||
| 124 | +------------------------ | ||
| 125 | + | ||
| 126 | +:ref:`ctmapcube` |
doc/source/users/reference_manual/ctmapcube.rst
| @@ -36,40 +36,40 @@ General parameters | @@ -36,40 +36,40 @@ General parameters | ||
| 36 | 36 | ||
| 37 | ``ebinalg <FILE|LIN|LOG> [string]`` | 37 | ``ebinalg <FILE|LIN|LOG> [string]`` |
| 38 | Algorithm for defining energy bins. | 38 | Algorithm for defining energy bins. |
| 39 | - | 39 | + |
| 40 | ``emin [real]`` | 40 | ``emin [real]`` |
| 41 | Lower energy value for first energy bin (in TeV). | 41 | Lower energy value for first energy bin (in TeV). |
| 42 | - | 42 | + |
| 43 | ``emax [real]`` | 43 | ``emax [real]`` |
| 44 | Upper energy value for last energy bin (in TeV). | 44 | Upper energy value for last energy bin (in TeV). |
| 45 | - | 45 | + |
| 46 | ``enumbins [integer]`` | 46 | ``enumbins [integer]`` |
| 47 | Number of energy bins. | 47 | Number of energy bins. |
| 48 | - | 48 | + |
| 49 | ``ebinfile [file]`` | 49 | ``ebinfile [file]`` |
| 50 | Name of the file containing the energy bin definition. | 50 | Name of the file containing the energy bin definition. |
| 51 | - | 51 | + |
| 52 | ``nxpix [integer]`` | 52 | ``nxpix [integer]`` |
| 53 | Number of cube bins in Right Ascension or Galactic longitude. | 53 | Number of cube bins in Right Ascension or Galactic longitude. |
| 54 | - | 54 | + |
| 55 | ``nypix [integer]`` | 55 | ``nypix [integer]`` |
| 56 | Number of cube bins in Declination or Galactic latitude. | 56 | Number of cube bins in Declination or Galactic latitude. |
| 57 | - | 57 | + |
| 58 | ``binsz [real]`` | 58 | ``binsz [real]`` |
| 59 | Image scale (in degrees/pixel). | 59 | Image scale (in degrees/pixel). |
| 60 | - | 60 | + |
| 61 | ``coordsys <CEL|GAL> [string]`` | 61 | ``coordsys <CEL|GAL> [string]`` |
| 62 | Coordinate system (CEL - celestial, GAL - galactic). | 62 | Coordinate system (CEL - celestial, GAL - galactic). |
| 63 | - | 63 | + |
| 64 | ``proj <AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN> [string]`` | 64 | ``proj <AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN> [string]`` |
| 65 | Projection method. | 65 | Projection method. |
| 66 | - | 66 | + |
| 67 | ``xref [real]`` | 67 | ``xref [real]`` |
| 68 | Right Ascension / Galactic longitude of cube centre (J2000, in degrees). | 68 | Right Ascension / Galactic longitude of cube centre (J2000, in degrees). |
| 69 | - | 69 | + |
| 70 | ``yref [real]`` | 70 | ``yref [real]`` |
| 71 | Declination / Galactic latitude of cube centre (J2000, in degrees). | 71 | Declination / Galactic latitude of cube centre (J2000, in degrees). |
| 72 | - | 72 | + |
| 73 | 73 | ||
| 74 | Standard parameters | 74 | Standard parameters |
| 75 | ------------------- | 75 | ------------------- |
| @@ -80,21 +80,21 @@ Standard parameters | @@ -80,21 +80,21 @@ Standard parameters | ||
| 80 | ``(chatter = 2) [integer]`` | 80 | ``(chatter = 2) [integer]`` |
| 81 | Verbosity of the executable: | 81 | Verbosity of the executable: |
| 82 | ``chatter = 0``: no information will be logged | 82 | ``chatter = 0``: no information will be logged |
| 83 | - | 83 | + |
| 84 | ``chatter = 1``: only errors will be logged | 84 | ``chatter = 1``: only errors will be logged |
| 85 | - | 85 | + |
| 86 | ``chatter = 2``: errors and actions will be logged | 86 | ``chatter = 2``: errors and actions will be logged |
| 87 | - | 87 | + |
| 88 | ``chatter = 3``: report about the task execution | 88 | ``chatter = 3``: report about the task execution |
| 89 | - | 89 | + |
| 90 | ``chatter = 4``: detailed report about the task execution | 90 | ``chatter = 4``: detailed report about the task execution |
| 91 | - | 91 | + |
| 92 | ``(clobber = yes) [boolean]`` | 92 | ``(clobber = yes) [boolean]`` |
| 93 | Specifies whether an existing output counts cube file should be overwritten. | 93 | Specifies whether an existing output counts cube file should be overwritten. |
| 94 | - | 94 | + |
| 95 | ``(debug = no) [boolean]`` | 95 | ``(debug = no) [boolean]`` |
| 96 | Enables debug mode. In debug mode the executable will dump any log file output to the console. | 96 | Enables debug mode. In debug mode the executable will dump any log file output to the console. |
| 97 | - | 97 | + |
| 98 | ``(mode = ql) [string]`` | 98 | ``(mode = ql) [string]`` |
| 99 | Mode of automatic parameters (default is "ql", i.e. "query and learn"). | 99 | Mode of automatic parameters (default is "ql", i.e. "query and learn"). |
| 100 | 100 | ||
| @@ -105,4 +105,4 @@ Standard parameters | @@ -105,4 +105,4 @@ Standard parameters | ||
| 105 | Related tools or scripts | 105 | Related tools or scripts |
| 106 | ------------------------ | 106 | ------------------------ |
| 107 | 107 | ||
| 108 | -None | 108 | +:ref:`csmodelsois` |
examples/show_spectrum.py
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | # ========================================================================== | 2 | # ========================================================================== |
| 3 | # Display spectrum generated by csspec | 3 | # Display spectrum generated by csspec |
| 4 | # | 4 | # |
| 5 | -# Copyright (C) 2015-2016 Juergen Knoedlseder | 5 | +# Copyright (C) 2015-2017 Juergen Knoedlseder |
| 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 |
| @@ -91,6 +91,9 @@ def plot_spectrum(filename, plotfile): | @@ -91,6 +91,9 @@ def plot_spectrum(filename, plotfile): | ||
| 91 | ul_ed_engs.append(c_ed.real(row)) | 91 | ul_ed_engs.append(c_ed.real(row)) |
| 92 | ul_eu_engs.append(c_eu.real(row)) | 92 | ul_eu_engs.append(c_eu.real(row)) |
| 93 | 93 | ||
| 94 | + # Set upper limit errors | ||
| 95 | + yerr = [0.6 * x for x in ul_flux] | ||
| 96 | + | ||
| 94 | # Plot the spectrum | 97 | # Plot the spectrum |
| 95 | plt.figure() | 98 | plt.figure() |
| 96 | plt.loglog() | 99 | plt.loglog() |
| @@ -98,7 +101,7 @@ def plot_spectrum(filename, plotfile): | @@ -98,7 +101,7 @@ def plot_spectrum(filename, plotfile): | ||
| 98 | plt.errorbar(energies, flux, yerr=e_flux, xerr=[ed_engs, eu_engs], | 101 | plt.errorbar(energies, flux, yerr=e_flux, xerr=[ed_engs, eu_engs], |
| 99 | fmt='ro') | 102 | fmt='ro') |
| 100 | plt.errorbar(ul_energies, ul_flux, xerr=[ul_ed_engs, ul_eu_engs], | 103 | plt.errorbar(ul_energies, ul_flux, xerr=[ul_ed_engs, ul_eu_engs], |
| 101 | - yerr=1.0e-11, uplims=True, fmt='ro') | 104 | + yerr=yerr, uplims=True, fmt='ro') |
| 102 | plt.xlabel('Energy (TeV)') | 105 | plt.xlabel('Energy (TeV)') |
| 103 | plt.ylabel(r'E $\times$ dN/dE (erg cm$^{-2}$ s$^{-1}$)') | 106 | plt.ylabel(r'E $\times$ dN/dE (erg cm$^{-2}$ s$^{-1}$)') |
| 104 | 107 |
pyext/ctobservation.i
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * ctobservation - Base class for observation tools * | 2 | * ctobservation - Base class for observation tools * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2016 by Juergen Knoedlseder * | 4 | + * copyright (C) 2016-2017 by Juergen Knoedlseder * |
| 5 | * ----------------------------------------------------------------------- * | 5 | * ----------------------------------------------------------------------- * |
| 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 * |
| @@ -89,6 +89,7 @@ public: | @@ -89,6 +89,7 @@ public: | ||
| 89 | 89 | ||
| 90 | // Public methods | 90 | // Public methods |
| 91 | const GObservations& obs(void) const; | 91 | const GObservations& obs(void) const; |
| 92 | + void write_ogip_keywords(GFitsHDU* hdu) const; | ||
| 92 | 93 | ||
| 93 | // Make methods private in Python by prepending an underscore | 94 | // Make methods private in Python by prepending an underscore |
| 94 | %rename(_first_unbinned_observation) first_unbinned_observation; | 95 | %rename(_first_unbinned_observation) first_unbinned_observation; |
src/ctmodel/ctmodel.cpp
| @@ -235,48 +235,55 @@ void ctmodel::run(void) | @@ -235,48 +235,55 @@ void ctmodel::run(void) | ||
| 235 | log_header1(TERSE, "Generate model cube"); | 235 | log_header1(TERSE, "Generate model cube"); |
| 236 | 236 | ||
| 237 | // Loop over all observations in the container | 237 | // Loop over all observations in the container |
| 238 | - #pragma omp parallel for | ||
| 239 | - for (int i = 0; i < m_obs.size(); ++i) { | 238 | + #pragma omp parallel |
| 239 | + { | ||
| 240 | + // Create a models object for this core | ||
| 241 | + GModels models(m_obs.models()); | ||
| 240 | 242 | ||
| 241 | - // Get CTA observation | ||
| 242 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 243 | - | ||
| 244 | - // Skip observation if it's not CTA | ||
| 245 | - if (obs == NULL) { | ||
| 246 | - log_header3(TERSE, get_obs_header(m_obs[i])); | ||
| 247 | - std::string msg = " Skipping "+m_obs[i]->instrument()+ | ||
| 248 | - " observation"; | ||
| 249 | - log_string(NORMAL, msg); | ||
| 250 | - } | ||
| 251 | - | ||
| 252 | - // Fill cube and leave loop if we are binned mode (meaning we | ||
| 253 | - // only have one binned observation) | ||
| 254 | - else if (m_binned) { | ||
| 255 | - fill_cube(obs); | ||
| 256 | - i = m_obs.size(); | ||
| 257 | - } | ||
| 258 | - | ||
| 259 | - // Skip observation if we have a binned observation | ||
| 260 | - else if (obs->eventtype() == "CountsCube") { | ||
| 261 | - log_header3(TERSE, get_obs_header(m_obs[i])); | ||
| 262 | - std::string msg = " Skipping binned "+m_obs[i]->instrument()+ | ||
| 263 | - " observation"; | ||
| 264 | - log_string(NORMAL, msg); | ||
| 265 | - } | ||
| 266 | - | ||
| 267 | - // Otherwise, everything seems to be fine, so fill the cube from obs | ||
| 268 | - else { | ||
| 269 | - // Fill the cube | ||
| 270 | - fill_cube(obs); | 243 | + #pragma omp for schedule(static,1) |
| 244 | + for (int i = 0; i < m_obs.size(); ++i) { | ||
| 271 | 245 | ||
| 272 | - // Dispose events to free memory if event file exists on disk | ||
| 273 | - if (obs->eventfile().length() > 0 && obs->eventfile().exists()) { | ||
| 274 | - obs->dispose_events(); | 246 | + // Get CTA observation |
| 247 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 248 | + | ||
| 249 | + // Skip observation if it's not CTA | ||
| 250 | + if (obs == NULL) { | ||
| 251 | + log_header3(TERSE, get_obs_header(m_obs[i])); | ||
| 252 | + std::string msg = " Skipping "+m_obs[i]->instrument()+ | ||
| 253 | + " observation"; | ||
| 254 | + log_string(NORMAL, msg); | ||
| 275 | } | 255 | } |
| 276 | - } | ||
| 277 | - | ||
| 278 | - } // endfor: looped over observations | 256 | + |
| 257 | + // Fill cube and leave loop if we are binned mode (meaning we | ||
| 258 | + // only have one binned observation) | ||
| 259 | + else if (m_binned) { | ||
| 260 | + fill_cube(obs, models); | ||
| 261 | + i = m_obs.size(); | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + // Skip observation if we have a binned observation | ||
| 265 | + else if (obs->eventtype() == "CountsCube") { | ||
| 266 | + log_header3(TERSE, get_obs_header(m_obs[i])); | ||
| 267 | + std::string msg = " Skipping binned "+m_obs[i]->instrument()+ | ||
| 268 | + " observation"; | ||
| 269 | + log_string(NORMAL, msg); | ||
| 270 | + } | ||
| 271 | + | ||
| 272 | + // Otherwise, everything seems to be fine, so fill the cube from obs | ||
| 273 | + else { | ||
| 274 | + // Fill the cube | ||
| 275 | + fill_cube(obs, models); | ||
| 276 | + | ||
| 277 | + // Dispose events to free memory if event file exists on disk | ||
| 278 | + if (obs->eventfile().length() > 0 && obs->eventfile().exists()) { | ||
| 279 | + obs->dispose_events(); | ||
| 280 | + } | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + } // endfor: looped over observations | ||
| 279 | 284 | ||
| 285 | + } // end openmp parallel section | ||
| 286 | + | ||
| 280 | // Write model cube into header | 287 | // Write model cube into header |
| 281 | log_header1(NORMAL, "Model cube"); | 288 | log_header1(NORMAL, "Model cube"); |
| 282 | log_string(NORMAL, m_cube.print()); | 289 | log_string(NORMAL, m_cube.print()); |
| @@ -789,7 +796,7 @@ void ctmodel::extract_cube_properties(void) | @@ -789,7 +796,7 @@ void ctmodel::extract_cube_properties(void) | ||
| 789 | * GTI of the model cube so that cube GTI is a list of the GTIs of all | 796 | * GTI of the model cube so that cube GTI is a list of the GTIs of all |
| 790 | * observations that were used to generate the model cube. | 797 | * observations that were used to generate the model cube. |
| 791 | ***************************************************************************/ | 798 | ***************************************************************************/ |
| 792 | -void ctmodel::fill_cube(const GCTAObservation* obs) | 799 | +void ctmodel::fill_cube(const GCTAObservation* obs, GModels& models) |
| 793 | { | 800 | { |
| 794 | // Get number of spatial and spectral bins in counts cube | 801 | // Get number of spatial and spectral bins in counts cube |
| 795 | int npix = m_cube.npix(); | 802 | int npix = m_cube.npix(); |
| @@ -819,8 +826,8 @@ void ctmodel::fill_cube(const GCTAObservation* obs) | @@ -819,8 +826,8 @@ void ctmodel::fill_cube(const GCTAObservation* obs) | ||
| 819 | int num_outside_roi = 0; | 826 | int num_outside_roi = 0; |
| 820 | 827 | ||
| 821 | // Extract copy of models from observation container | 828 | // Extract copy of models from observation container |
| 822 | - GModels models(m_obs.models()); | ||
| 823 | - | 829 | + GModels ex_models = trim_models(models, roi); |
| 830 | + | ||
| 824 | // Get pointer to event cube pixels | 831 | // Get pointer to event cube pixels |
| 825 | double* pixels = const_cast<double*>(m_cube.counts().pixels()); | 832 | double* pixels = const_cast<double*>(m_cube.counts().pixels()); |
| 826 | 833 | ||
| @@ -877,6 +884,9 @@ void ctmodel::fill_cube(const GCTAObservation* obs) | @@ -877,6 +884,9 @@ void ctmodel::fill_cube(const GCTAObservation* obs) | ||
| 877 | 884 | ||
| 878 | } // endfor: looped over all cube bins | 885 | } // endfor: looped over all cube bins |
| 879 | 886 | ||
| 887 | + // Re-append the models to the main model | ||
| 888 | + models.extend(ex_models); | ||
| 889 | + | ||
| 880 | // Update GTIs | 890 | // Update GTIs |
| 881 | #pragma omp critical(ctmodel_fill_cube) | 891 | #pragma omp critical(ctmodel_fill_cube) |
| 882 | { | 892 | { |
| @@ -905,3 +915,66 @@ void ctmodel::fill_cube(const GCTAObservation* obs) | @@ -905,3 +915,66 @@ void ctmodel::fill_cube(const GCTAObservation* obs) | ||
| 905 | // Return | 915 | // Return |
| 906 | return; | 916 | return; |
| 907 | } | 917 | } |
| 918 | + | ||
| 919 | + | ||
| 920 | +/***********************************************************************//** | ||
| 921 | + * @brief Find the models falling inside a defined region of interest. | ||
| 922 | + * | ||
| 923 | + * @param[in,out] all_models Model container to be trimmed. | ||
| 924 | + * @param[in] roi Observation region of interest. | ||
| 925 | + * @return New model container containing only models inside RoI. | ||
| 926 | + * | ||
| 927 | + * Note that a buffer is added to the observation region to ensure that | ||
| 928 | + * point sources (which have radius=0) are appropriately included if they | ||
| 929 | + * fall near the edge of the observation. | ||
| 930 | + ***************************************************************************/ | ||
| 931 | +GModels ctmodel::trim_models(GModels& all_models, const GCTARoi& roi) | ||
| 932 | +{ | ||
| 933 | + // Create the model container containing only models in RoI | ||
| 934 | + GModels excluded_models; | ||
| 935 | + | ||
| 936 | + // Do nothing if roi is not valid. This will be the case for binned data | ||
| 937 | + // sets as they have the default roi radius of 0. In this case we would | ||
| 938 | + // remove ALL models, which is obviously incorrect. So we keep all models | ||
| 939 | + // when filling based on a counts cube. | ||
| 940 | + if (!roi.is_valid()) { | ||
| 941 | + return excluded_models; | ||
| 942 | + } | ||
| 943 | + | ||
| 944 | + // Remove all models that dont overlap with the region of interest. Note | ||
| 945 | + // that an extra factor is used since point sources have regions of | ||
| 946 | + // radius 0, which is a problem when they fall just barely outside the | ||
| 947 | + // RoI. This ensures point sources are appropriately included. | ||
| 948 | + GSkyRegionCircle obsreg(roi.centre().dir(), roi.radius()+0.5); | ||
| 949 | + | ||
| 950 | + // Loop over the models in the passed container | ||
| 951 | + for (int i = 0; i < all_models.size(); ++i) { | ||
| 952 | + | ||
| 953 | + // Cast the model to a GModelSky object | ||
| 954 | + GModelSky* model = dynamic_cast<GModelSky*>(all_models[i]); | ||
| 955 | + | ||
| 956 | + // If model is not a GModelSky model than skip | ||
| 957 | + if (model == NULL) { | ||
| 958 | + continue; | ||
| 959 | + } | ||
| 960 | + | ||
| 961 | + // Otherwise, exclude the model if it isn't a diffuse cube and it | ||
| 962 | + // doesn't overlap with the observation. | ||
| 963 | + if (!(model->spatial()->code() == GMODEL_SPATIAL_DIFFUSE) && | ||
| 964 | + (!model->spatial()->region()->overlaps(obsreg))) { | ||
| 965 | + | ||
| 966 | + // Append model to the excluded models | ||
| 967 | + excluded_models.append(*model); | ||
| 968 | + | ||
| 969 | + // Remove model | ||
| 970 | + all_models.remove(i); | ||
| 971 | + | ||
| 972 | + // Decrement to prevent skipping models | ||
| 973 | + i--; | ||
| 974 | + } | ||
| 975 | + | ||
| 976 | + } // endfor: looped over all models | ||
| 977 | + | ||
| 978 | + // Return excluded models | ||
| 979 | + return excluded_models; | ||
| 980 | +} |
src/ctmodel/ctmodel.hpp
| @@ -74,14 +74,15 @@ public: | @@ -74,14 +74,15 @@ public: | ||
| 74 | 74 | ||
| 75 | protected: | 75 | protected: |
| 76 | // Protected methods | 76 | // Protected methods |
| 77 | - void init_members(void); | ||
| 78 | - void copy_members(const ctmodel& app); | ||
| 79 | - void free_members(void); | ||
| 80 | - void get_parameters(void); | ||
| 81 | - void get_obs(void); | ||
| 82 | - void extract_cube_properties(void); | ||
| 83 | - void fill_cube(const GCTAObservation* obs); | ||
| 84 | - bool has_cube(void) const; | 77 | + void init_members(void); |
| 78 | + void copy_members(const ctmodel& app); | ||
| 79 | + void free_members(void); | ||
| 80 | + void get_parameters(void); | ||
| 81 | + void get_obs(void); | ||
| 82 | + void extract_cube_properties(void); | ||
| 83 | + void fill_cube(const GCTAObservation* obs, GModels& models); | ||
| 84 | + bool has_cube(void) const; | ||
| 85 | + GModels trim_models(GModels& all_models, const GCTARoi& roi); | ||
| 85 | 86 | ||
| 86 | // User parameters | 87 | // User parameters |
| 87 | GFilename m_outcube; //!< Output model cube | 88 | GFilename m_outcube; //!< Output model cube |
src/ctskymap/ctskymap.cpp
| @@ -281,23 +281,39 @@ void ctskymap::save(void) | @@ -281,23 +281,39 @@ void ctskymap::save(void) | ||
| 281 | GFits fits; | 281 | GFits fits; |
| 282 | 282 | ||
| 283 | // Write sky map into FITS file | 283 | // Write sky map into FITS file |
| 284 | - m_skymap.write(fits); | 284 | + GFitsHDU* hdu = m_skymap.write(fits); |
| 285 | + | ||
| 286 | + // Write keywords into sky map extension | ||
| 287 | + write_ogip_keywords(hdu); | ||
| 288 | + write_hdu_keywords(hdu); | ||
| 285 | 289 | ||
| 286 | // If background subtraction is requested then write background map | 290 | // If background subtraction is requested then write background map |
| 287 | // and significance map to FITS file | 291 | // and significance map to FITS file |
| 288 | if (m_bkgsubtract != "NONE") { | 292 | if (m_bkgsubtract != "NONE") { |
| 289 | 293 | ||
| 290 | // Write background map into FITS file | 294 | // Write background map into FITS file |
| 291 | - m_bkgmap.write(fits); | 295 | + hdu = m_bkgmap.write(fits); |
| 292 | 296 | ||
| 293 | // Set background map extension name | 297 | // Set background map extension name |
| 294 | - fits[fits.size()-1]->extname("BACKGROUND"); | 298 | + if (hdu != NULL) { |
| 299 | + hdu->extname("BACKGROUND"); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + // Write keywords into background extension | ||
| 303 | + write_ogip_keywords(hdu); | ||
| 304 | + write_hdu_keywords(hdu); | ||
| 295 | 305 | ||
| 296 | // Write significance map into FITS file | 306 | // Write significance map into FITS file |
| 297 | - m_sigmap.write(fits); | 307 | + hdu = m_sigmap.write(fits); |
| 298 | 308 | ||
| 299 | // Set significance map extension name | 309 | // Set significance map extension name |
| 300 | - fits[fits.size()-1]->extname("SIGNIFICANCE"); | 310 | + if (hdu != NULL) { |
| 311 | + hdu->extname("SIGNIFICANCE"); | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + // Write keywords into significance extension | ||
| 315 | + write_ogip_keywords(hdu); | ||
| 316 | + write_hdu_keywords(hdu); | ||
| 301 | 317 | ||
| 302 | } // endif: background subtraction was requested | 318 | } // endif: background subtraction was requested |
| 303 | 319 | ||
| @@ -525,7 +541,7 @@ void ctskymap::map_events(GCTAObservation* obs) | @@ -525,7 +541,7 @@ void ctskymap::map_events(GCTAObservation* obs) | ||
| 525 | // Make sure that the observation holds a CTA event list. If this | 541 | // Make sure that the observation holds a CTA event list. If this |
| 526 | // is not the case then throw an exception. | 542 | // is not the case then throw an exception. |
| 527 | if (events == NULL) { | 543 | if (events == NULL) { |
| 528 | - throw GException::no_list(G_BIN_EVENTS); | 544 | + throw GException::no_list(G_MAP_EVENTS); |
| 529 | } | 545 | } |
| 530 | 546 | ||
| 531 | // Setup energy range covered by data | 547 | // Setup energy range covered by data |
| @@ -647,7 +663,7 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -647,7 +663,7 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 647 | get_obs_header(obs)+" to compute IRF background. " | 663 | get_obs_header(obs)+" to compute IRF background. " |
| 648 | "Please specify response information or use " | 664 | "Please specify response information or use " |
| 649 | "another background subtraction method."; | 665 | "another background subtraction method."; |
| 650 | - throw GException::invalid_value(G_BKG_SUBTRACT_IRF, msg); | 666 | + throw GException::invalid_value(G_MAP_BACKGROUND_IRF, msg); |
| 651 | } | 667 | } |
| 652 | 668 | ||
| 653 | // Get IRF background template | 669 | // Get IRF background template |
| @@ -659,7 +675,7 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -659,7 +675,7 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 659 | "response function for "+ | 675 | "response function for "+ |
| 660 | get_obs_header(obs)+". Please specify an instrument " | 676 | get_obs_header(obs)+". Please specify an instrument " |
| 661 | "response function containing a background template."; | 677 | "response function containing a background template."; |
| 662 | - throw GException::invalid_value(G_BKG_SUBTRACT_IRF, msg); | 678 | + throw GException::invalid_value(G_MAP_BACKGROUND_IRF, msg); |
| 663 | } | 679 | } |
| 664 | 680 | ||
| 665 | // Compute natural logarithm of energy range in MeV | 681 | // Compute natural logarithm of energy range in MeV |
| @@ -860,6 +876,30 @@ void ctskymap::map_background_ring(GCTAObservation* obs) | @@ -860,6 +876,30 @@ void ctskymap::map_background_ring(GCTAObservation* obs) | ||
| 860 | return; | 876 | return; |
| 861 | } | 877 | } |
| 862 | 878 | ||
| 879 | +/***********************************************************************//** | ||
| 880 | + * @brief Write keywords in FITS HDU | ||
| 881 | + * | ||
| 882 | + * @param[in,out] hdu Pointer to FITS HDU. | ||
| 883 | + * | ||
| 884 | + * Writes keywords in FITS HDU. | ||
| 885 | + ***************************************************************************/ | ||
| 886 | +void ctskymap::write_hdu_keywords(GFitsHDU* hdu) const | ||
| 887 | +{ | ||
| 888 | + // Continue only if pointer is valid | ||
| 889 | + if (hdu != NULL) { | ||
| 890 | + | ||
| 891 | + // Set keywords | ||
| 892 | + hdu->card("BKGSUB", m_bkgsubtract, "Background substraction method"); | ||
| 893 | + hdu->card("E_MIN", m_emin, "[TeV] Lower energy boundary"); | ||
| 894 | + hdu->card("E_MAX", m_emax, "[TeV] Upper energy boundary"); | ||
| 895 | + hdu->card("EUNIT", "TeV", "Units for E_MIN and E_MAX"); | ||
| 896 | + | ||
| 897 | + } // endif: pointer was valid | ||
| 898 | + | ||
| 899 | + // Return | ||
| 900 | + return; | ||
| 901 | +} | ||
| 902 | + | ||
| 863 | 903 | ||
| 864 | /***********************************************************************//** | 904 | /***********************************************************************//** |
| 865 | * @brief Computes the bin-by-bin significance if background subtraction requested | 905 | * @brief Computes the bin-by-bin significance if background subtraction requested |
src/ctskymap/ctskymap.hpp
| @@ -80,6 +80,7 @@ protected: | @@ -80,6 +80,7 @@ protected: | ||
| 80 | const GSkyMap& sensitivity, | 80 | const GSkyMap& sensitivity, |
| 81 | const GSkyDir& position, | 81 | const GSkyDir& position, |
| 82 | double& non, double& noff, double& alpha); | 82 | double& non, double& noff, double& alpha); |
| 83 | + void write_hdu_keywords(GFitsHDU* hdu) const; | ||
| 83 | 84 | ||
| 84 | // Background integration kernel | 85 | // Background integration kernel |
| 85 | class irf_kern : public GFunction { | 86 | class irf_kern : public GFunction { |
src/support/ctobservation.cpp
| @@ -192,6 +192,53 @@ ctobservation& ctobservation::operator=(const ctobservation& app) | @@ -192,6 +192,53 @@ ctobservation& ctobservation::operator=(const ctobservation& app) | ||
| 192 | = = | 192 | = = |
| 193 | ==========================================================================*/ | 193 | ==========================================================================*/ |
| 194 | 194 | ||
| 195 | +/***********************************************************************//** | ||
| 196 | + * @brief Write OGIP keywords in FITS HDU | ||
| 197 | + * | ||
| 198 | + * @param[in,out] hdu Pointer to FITS HDU. | ||
| 199 | + * | ||
| 200 | + * Writes OGIP keywords in FITS HDU. | ||
| 201 | + ***************************************************************************/ | ||
| 202 | +void ctobservation::write_ogip_keywords(GFitsHDU* hdu) const | ||
| 203 | +{ | ||
| 204 | + // Continue only if pointer is valid | ||
| 205 | + if (hdu != NULL) { | ||
| 206 | + | ||
| 207 | + // Set creator | ||
| 208 | + std::string creator = this->name() + " v" + this->version(); | ||
| 209 | + | ||
| 210 | + // Compute times | ||
| 211 | + std::string utc_obs = m_ogip_tstart.utc(); | ||
| 212 | + std::string utc_end = m_ogip_tstop.utc(); | ||
| 213 | + std::string date_obs = utc_obs.substr(0, 10); | ||
| 214 | + std::string time_obs = utc_obs.substr(11, 8); | ||
| 215 | + std::string date_end = utc_end.substr(0, 10); | ||
| 216 | + std::string time_end = utc_end.substr(11, 8); | ||
| 217 | + | ||
| 218 | + // Compute deadtime correction | ||
| 219 | + double deadc = (m_ogip_ontime > 0.0) ? m_ogip_livetime / m_ogip_ontime : 1.0; | ||
| 220 | + | ||
| 221 | + // Set observation information | ||
| 222 | + hdu->card("CREATOR", creator, "Program which created the file"); | ||
| 223 | + hdu->card("TELESCOP", m_ogip_telescope, "Telescope"); | ||
| 224 | + | ||
| 225 | + // Set observation time information | ||
| 226 | + hdu->card("DATE_OBS", date_obs, "Observation start date"); | ||
| 227 | + hdu->card("TIME_OBS", time_obs, "Observation start time"); | ||
| 228 | + hdu->card("DATE_END", date_end, "Observation end date"); | ||
| 229 | + hdu->card("TIME_END", time_end, "Observation end time"); | ||
| 230 | + hdu->card("TELAPSE", m_ogip_telapse, "[s] Elapsed time"); | ||
| 231 | + hdu->card("ONTIME", m_ogip_ontime, "[s] Total good time including deadtime"); | ||
| 232 | + hdu->card("LIVETIME", m_ogip_livetime, "[s] Total livetime"); | ||
| 233 | + hdu->card("EXPOSURE", m_ogip_exposure, "[s] Exposure time"); | ||
| 234 | + hdu->card("DEADC", deadc, "Deadtime correction factor"); | ||
| 235 | + | ||
| 236 | + } // endif: pointer was valid | ||
| 237 | + | ||
| 238 | + // Return | ||
| 239 | + return; | ||
| 240 | +} | ||
| 241 | + | ||
| 195 | 242 | ||
| 196 | /*========================================================================== | 243 | /*========================================================================== |
| 197 | = = | 244 | = = |
| @@ -208,6 +255,13 @@ void ctobservation::init_members(void) | @@ -208,6 +255,13 @@ void ctobservation::init_members(void) | ||
| 208 | m_obs.clear(); | 255 | m_obs.clear(); |
| 209 | 256 | ||
| 210 | // Initialise private members | 257 | // Initialise private members |
| 258 | + m_ogip_telescope.clear(); | ||
| 259 | + m_ogip_tstart.clear(); | ||
| 260 | + m_ogip_tstop.clear(); | ||
| 261 | + m_ogip_telapse = 0.0; | ||
| 262 | + m_ogip_exposure = 0.0; | ||
| 263 | + m_ogip_ontime = 0.0; | ||
| 264 | + m_ogip_livetime = 0.0; | ||
| 211 | m_index_unbinned = 0; | 265 | m_index_unbinned = 0; |
| 212 | 266 | ||
| 213 | // Return | 267 | // Return |
| @@ -226,6 +280,13 @@ void ctobservation::copy_members(const ctobservation& app) | @@ -226,6 +280,13 @@ void ctobservation::copy_members(const ctobservation& app) | ||
| 226 | m_obs = app.m_obs; | 280 | m_obs = app.m_obs; |
| 227 | 281 | ||
| 228 | // Copy private members | 282 | // Copy private members |
| 283 | + m_ogip_telescope = app.m_ogip_telescope; | ||
| 284 | + m_ogip_tstart = app.m_ogip_tstart; | ||
| 285 | + m_ogip_tstop = app.m_ogip_tstop; | ||
| 286 | + m_ogip_telapse = app.m_ogip_telapse; | ||
| 287 | + m_ogip_exposure = app.m_ogip_exposure; | ||
| 288 | + m_ogip_ontime = app.m_ogip_ontime; | ||
| 289 | + m_ogip_livetime = app.m_ogip_livetime; | ||
| 229 | m_index_unbinned = app.m_index_unbinned; | 290 | m_index_unbinned = app.m_index_unbinned; |
| 230 | 291 | ||
| 231 | // Return | 292 | // Return |
| @@ -258,6 +319,15 @@ const GCTAObservation* ctobservation::first_unbinned_observation(void) const | @@ -258,6 +319,15 @@ const GCTAObservation* ctobservation::first_unbinned_observation(void) const | ||
| 258 | // Initialise index | 319 | // Initialise index |
| 259 | m_index_unbinned = 0; | 320 | m_index_unbinned = 0; |
| 260 | 321 | ||
| 322 | + // Initialise OGIP members | ||
| 323 | + m_ogip_telescope.clear(); | ||
| 324 | + m_ogip_tstart.clear(); | ||
| 325 | + m_ogip_tstop.clear(); | ||
| 326 | + m_ogip_telapse = 0.0; | ||
| 327 | + m_ogip_exposure = 0.0; | ||
| 328 | + m_ogip_ontime = 0.0; | ||
| 329 | + m_ogip_livetime = 0.0; | ||
| 330 | + | ||
| 261 | // Get next unbinned CTA observation | 331 | // Get next unbinned CTA observation |
| 262 | const GCTAObservation* obs = next_unbinned_observation(); | 332 | const GCTAObservation* obs = next_unbinned_observation(); |
| 263 | 333 | ||
| @@ -323,6 +393,31 @@ const GCTAObservation* ctobservation::next_unbinned_observation(void) const | @@ -323,6 +393,31 @@ const GCTAObservation* ctobservation::next_unbinned_observation(void) const | ||
| 323 | 393 | ||
| 324 | } // endfor: looped over all observation | 394 | } // endfor: looped over all observation |
| 325 | 395 | ||
| 396 | + // Update OGIP members | ||
| 397 | + if (obs != NULL) { | ||
| 398 | + if (m_ogip_telapse == 0.0) { | ||
| 399 | + m_ogip_telescope = obs->instrument(); | ||
| 400 | + m_ogip_tstart = obs->gti().tstart(); | ||
| 401 | + m_ogip_tstop = obs->gti().tstop(); | ||
| 402 | + m_ogip_telapse = obs->gti().telapse(); | ||
| 403 | + m_ogip_exposure = obs->ontime(); | ||
| 404 | + m_ogip_ontime = obs->ontime(); | ||
| 405 | + m_ogip_livetime = obs->livetime(); | ||
| 406 | + } | ||
| 407 | + else { | ||
| 408 | + if (obs->gti().tstart() < m_ogip_tstart) { | ||
| 409 | + m_ogip_tstart = obs->gti().tstart(); | ||
| 410 | + } | ||
| 411 | + if (obs->gti().tstop() > m_ogip_tstop) { | ||
| 412 | + m_ogip_tstop = obs->gti().tstop(); | ||
| 413 | + } | ||
| 414 | + m_ogip_telapse += obs->gti().telapse(); | ||
| 415 | + m_ogip_exposure += obs->ontime(); | ||
| 416 | + m_ogip_ontime += obs->ontime(); | ||
| 417 | + m_ogip_livetime += obs->livetime(); | ||
| 418 | + } | ||
| 419 | + } | ||
| 420 | + | ||
| 326 | // Return next CTA observation | 421 | // Return next CTA observation |
| 327 | return obs; | 422 | return obs; |
| 328 | } | 423 | } |
src/support/ctobservation.hpp
| @@ -63,6 +63,7 @@ public: | @@ -63,6 +63,7 @@ public: | ||
| 63 | 63 | ||
| 64 | // Methods | 64 | // Methods |
| 65 | const GObservations& obs(void) const; | 65 | const GObservations& obs(void) const; |
| 66 | + void write_ogip_keywords(GFitsHDU* hdu) const; | ||
| 66 | 67 | ||
| 67 | #ifndef SWIG | 68 | #ifndef SWIG |
| 68 | protected: | 69 | protected: |
| @@ -82,11 +83,18 @@ protected: | @@ -82,11 +83,18 @@ protected: | ||
| 82 | void save_events_xml(void); | 83 | void save_events_xml(void); |
| 83 | 84 | ||
| 84 | // Protected members | 85 | // Protected members |
| 85 | - GObservations m_obs; //!< Observation container | 86 | + GObservations m_obs; //!< Observation container |
| 86 | 87 | ||
| 87 | private: | 88 | private: |
| 88 | // Private members | 89 | // Private members |
| 89 | - mutable int m_index_unbinned; //!< Current index of unbinned observation | 90 | + mutable std::string m_ogip_telescope; //!< Name of telescope |
| 91 | + mutable GTime m_ogip_tstart; //!< Start time for OGIP keywords | ||
| 92 | + mutable GTime m_ogip_tstop; //!< Stop time for OGIP keywords | ||
| 93 | + mutable double m_ogip_telapse; //!< Elapsed time | ||
| 94 | + mutable double m_ogip_exposure; //!< Exposure time | ||
| 95 | + mutable double m_ogip_ontime; //!< Ontime for OGIP keywords | ||
| 96 | + mutable double m_ogip_livetime; //!< Livetime for OGIP keywords | ||
| 97 | + mutable int m_index_unbinned; //!< Current index of unbinned observation | ||
| 90 | }; | 98 | }; |
| 91 | 99 | ||
| 92 | 100 |
test/test_csmodelsois.py
0 → 100755
| 1 | +#! /usr/bin/env python | ||
| 2 | +# ========================================================================== | ||
| 3 | +# This scripts performs unit tests for the csmodelsois tool. | ||
| 4 | +# | ||
| 5 | +# Copyright (C) 2017 Josh Cardenzana | ||
| 6 | +# | ||
| 7 | +# This program is free software: you can redistribute it and/or modify | ||
| 8 | +# it under the terms of the GNU General Public License as published by | ||
| 9 | +# the Free Software Foundation, either version 3 of the License, or | ||
| 10 | +# (at your option) any later version. | ||
| 11 | +# | ||
| 12 | +# This program is distributed in the hope that it will be useful, | ||
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | +# GNU General Public License for more details. | ||
| 16 | +# | ||
| 17 | +# You should have received a copy of the GNU General Public License | ||
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | +# | ||
| 20 | +# ========================================================================== | ||
| 21 | +import os | ||
| 22 | +import gammalib | ||
| 23 | +import cscripts | ||
| 24 | +from testing import test | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +# =============================== # | ||
| 28 | +# Test class for csmodelsois tool # | ||
| 29 | +# =============================== # | ||
| 30 | +class Test(test): | ||
| 31 | + """ | ||
| 32 | + Test class for csmodelsois tool | ||
| 33 | + | ||
| 34 | + This test class makes unit tests for the csmodelsois tool by using it from | ||
| 35 | + the command line and from Python. | ||
| 36 | + """ | ||
| 37 | + | ||
| 38 | + # Constructor | ||
| 39 | + def __init__(self): | ||
| 40 | + """ | ||
| 41 | + Constructor | ||
| 42 | + """ | ||
| 43 | + # Call base class constructor | ||
| 44 | + test.__init__(self) | ||
| 45 | + | ||
| 46 | + # Return | ||
| 47 | + return | ||
| 48 | + | ||
| 49 | + # Set test functions | ||
| 50 | + def set(self): | ||
| 51 | + """ | ||
| 52 | + Set all test functions | ||
| 53 | + """ | ||
| 54 | + # Set test name | ||
| 55 | + self.name('csmodelsois') | ||
| 56 | + | ||
| 57 | + # Append tests | ||
| 58 | + self.append(self._test_cmd, 'Test csmodelsois on command line') | ||
| 59 | + self.append(self._test_python, 'Test csmodelsois from Python') | ||
| 60 | + | ||
| 61 | + # Return | ||
| 62 | + return | ||
| 63 | + | ||
| 64 | + # Test csmodelsois on command line | ||
| 65 | + def _test_cmd(self): | ||
| 66 | + """ | ||
| 67 | + Test csmodelsois on the command line | ||
| 68 | + """ | ||
| 69 | + # Set tool name | ||
| 70 | + csmodelsois = self._script('csmodelsois') | ||
| 71 | + | ||
| 72 | + # Setup csmodelsois command | ||
| 73 | + cmd = csmodelsois+' inmodel="'+self._model+'"'+ \ | ||
| 74 | + ' outcube="csmodelsois_cmd1.fits"'+\ | ||
| 75 | + ' emin=0.1 emax=100.0 enumbins=10 ebinalg=LOG'+ \ | ||
| 76 | + ' nxpix=100 nypix=100 binsz=0.04 coordsys=CEL'+ \ | ||
| 77 | + ' soilist="" outmodel=NONE'+ \ | ||
| 78 | + ' ra=83.63 dec=22.01 proj=CAR'+ \ | ||
| 79 | + ' logfile="csmodelsois_cmd1.log" chatter=1' | ||
| 80 | + | ||
| 81 | + # Check if execution of wrong command fails | ||
| 82 | + self.test_assert(self._execute('command_that_does_not_exist') != 0, | ||
| 83 | + 'Self test of test script') | ||
| 84 | + | ||
| 85 | + # Check if execution was successful | ||
| 86 | + self.test_assert(self._execute(cmd) == 0, | ||
| 87 | + 'Check successful execution from command line') | ||
| 88 | + | ||
| 89 | + # Check map cube | ||
| 90 | + self._check_result_file('csmodelsois_cmd1.fits') | ||
| 91 | + | ||
| 92 | + # Setup csmodelsois command | ||
| 93 | + cmd = csmodelsois+' inmodel="events_that_do_not_exist.fits"'+ \ | ||
| 94 | + ' outcube="ccsmodelsois_cmd2.fits"'+\ | ||
| 95 | + ' emin=0.1 emax=100.0 enumbins=10 ebinalg=LOG'+ \ | ||
| 96 | + ' nxpix=100 nypix=100 binsz=0.04 coordsys=CEL'+ \ | ||
| 97 | + ' soilist="" outmodel=NONE'+ \ | ||
| 98 | + ' ra=83.63 dec=22.01 proj=CAR'+ \ | ||
| 99 | + ' logfile="csmodelsois_cmd2.log"' | ||
| 100 | + | ||
| 101 | + # Check if execution failed | ||
| 102 | + self.test_assert(self._execute(cmd) != 0, | ||
| 103 | + 'Check invalid input file when executed from command line') | ||
| 104 | + | ||
| 105 | + # Check csmodelsois --help | ||
| 106 | + self._check_help(csmodelsois) | ||
| 107 | + | ||
| 108 | + # Return | ||
| 109 | + return | ||
| 110 | + | ||
| 111 | + # Test csmodelsois from Python | ||
| 112 | + def _test_python(self): | ||
| 113 | + """ | ||
| 114 | + Test csmodelsois from Python | ||
| 115 | + """ | ||
| 116 | + # Allocate csmodelsois | ||
| 117 | + modelsois = cscripts.csmodelsois() | ||
| 118 | + | ||
| 119 | + # Check that empty csmodelsois tool holds an map cube that has no | ||
| 120 | + # energy bins | ||
| 121 | + self._check_cube(modelsois.mapcube(), nmaps=0, npixels=0) | ||
| 122 | + | ||
| 123 | + # Check that saving does nothing | ||
| 124 | + modelsois['outcube'] = 'csmodelsois_py0.fits' | ||
| 125 | + modelsois['outmodel'] = 'NONE' | ||
| 126 | + modelsois['logfile'] = 'csmodelsois_py0.log' | ||
| 127 | + modelsois.logFileOpen() | ||
| 128 | + modelsois.save() | ||
| 129 | + self.test_assert(not os.path.isfile('csmodelsois_py0.fits'), | ||
| 130 | + 'Check that no map cube has been created') | ||
| 131 | + | ||
| 132 | + # Check that clearing does not lead to an exception or segfault | ||
| 133 | + modelsois.clear() | ||
| 134 | + | ||
| 135 | + # Now set csmodelsois parameters | ||
| 136 | + modelsois['inmodel'] = self._model | ||
| 137 | + modelsois['ebinalg'] = 'LOG' | ||
| 138 | + modelsois['emin'] = 0.1 | ||
| 139 | + modelsois['emax'] = 100.0 | ||
| 140 | + modelsois['enumbins'] = 10 | ||
| 141 | + modelsois['nxpix'] = 100 | ||
| 142 | + modelsois['nypix'] = 100 | ||
| 143 | + modelsois['binsz'] = 0.04 | ||
| 144 | + modelsois['coordsys'] = 'CEL' | ||
| 145 | + modelsois['proj'] = 'CAR' | ||
| 146 | + modelsois['ra'] = 83.63 | ||
| 147 | + modelsois['dec'] = 22.01 | ||
| 148 | + modelsois['ptsrcsig'] = 1.0 | ||
| 149 | + modelsois['outcube'] = 'csmodelsois_py1.fits' | ||
| 150 | + modelsois['logfile'] = 'csmodelsois_py1.log' | ||
| 151 | + modelsois['chatter'] = 2 | ||
| 152 | + modelsois['soilist'] = '' | ||
| 153 | + modelsois['outmodel'] = 'NONE' | ||
| 154 | + | ||
| 155 | + # Run csmodelsois tool | ||
| 156 | + modelsois.logFileOpen() # Make sure we get a log file | ||
| 157 | + modelsois.run() | ||
| 158 | + | ||
| 159 | + # Save map cube | ||
| 160 | + modelsois.save() | ||
| 161 | + | ||
| 162 | + # Check map cube | ||
| 163 | + self._check_result_file('csmodelsois_py1.fits') | ||
| 164 | + | ||
| 165 | + # Allocate csmodelsois scripts, set models and do now a linear | ||
| 166 | + # binning; also do not use Gaussian point sources | ||
| 167 | + modelsois = cscripts.csmodelsois() | ||
| 168 | + modelsois['inmodel'] = self._model | ||
| 169 | + modelsois['ebinalg'] = 'LIN' | ||
| 170 | + modelsois['emin'] = 0.1 | ||
| 171 | + modelsois['emax'] = 100.0 | ||
| 172 | + modelsois['enumbins'] = 10 | ||
| 173 | + modelsois['nxpix'] = 100 | ||
| 174 | + modelsois['nypix'] = 100 | ||
| 175 | + modelsois['binsz'] = 0.04 | ||
| 176 | + modelsois['coordsys'] = 'CEL' | ||
| 177 | + modelsois['proj'] = 'CAR' | ||
| 178 | + modelsois['ra'] = 83.63 | ||
| 179 | + modelsois['dec'] = 22.01 | ||
| 180 | + modelsois['ptsrcsig'] = 0.0 | ||
| 181 | + modelsois['outcube'] = 'csmodelsois_py2.fits' | ||
| 182 | + modelsois['logfile'] = 'csmodelsois_py2.log' | ||
| 183 | + modelsois['chatter'] = 4 | ||
| 184 | + modelsois['soilist'] = '' | ||
| 185 | + modelsois['outmodel'] = 'NONE' | ||
| 186 | + | ||
| 187 | + # Execute mapcube | ||
| 188 | + modelsois.logFileOpen() # Needed to get a new log file | ||
| 189 | + modelsois.execute() | ||
| 190 | + | ||
| 191 | + # Check result file | ||
| 192 | + self._check_result_file('csmodelsois_py2.fits') | ||
| 193 | + | ||
| 194 | + # Update output filenames and output a new model file | ||
| 195 | + modelsois['outcube'] = 'csmodelsois_py3.fits' | ||
| 196 | + modelsois['logfile'] = 'csmodelsois_py3.log' | ||
| 197 | + modelsois['outmodel'] = 'csmodelsois_py3.xml' | ||
| 198 | + | ||
| 199 | + # Execute the file | ||
| 200 | + modelsois.logFileOpen() | ||
| 201 | + modelsois.execute() | ||
| 202 | + | ||
| 203 | + # Now check that the output model file doesnt contain a Crab Sources | ||
| 204 | + models3 = gammalib.GModels('csmodelsois_py3.xml') | ||
| 205 | + self.test_assert(not models3.contains('Crab'), | ||
| 206 | + 'Check Crab model is not present') | ||
| 207 | + self.test_assert(models3.contains(modelsois.cubemodelname()), | ||
| 208 | + 'Check cube model is present') | ||
| 209 | + self._check_result_file('csmodelsois_py3.fits') | ||
| 210 | + | ||
| 211 | + # Return | ||
| 212 | + return | ||
| 213 | + | ||
| 214 | + # Check result file | ||
| 215 | + def _check_result_file(self, filename): | ||
| 216 | + """ | ||
| 217 | + Check content of map cube | ||
| 218 | + | ||
| 219 | + Parameters | ||
| 220 | + ---------- | ||
| 221 | + filename : str | ||
| 222 | + Map cube file name | ||
| 223 | + """ | ||
| 224 | + # Load map cube | ||
| 225 | + cube = gammalib.GModelSpatialDiffuseCube(filename) | ||
| 226 | + | ||
| 227 | + # Check map cube | ||
| 228 | + self._check_cube(cube) | ||
| 229 | + | ||
| 230 | + # Return | ||
| 231 | + return | ||
| 232 | + | ||
| 233 | + # Check map cube | ||
| 234 | + def _check_cube(self, cube, nmaps=11, npixels=10000): | ||
| 235 | + """ | ||
| 236 | + Check map cube | ||
| 237 | + | ||
| 238 | + Parameters | ||
| 239 | + ---------- | ||
| 240 | + cube : `~gammalib.GModelSpatialDiffuseCube` | ||
| 241 | + Map cube | ||
| 242 | + nmaps : int, optional | ||
| 243 | + Number of maps | ||
| 244 | + npixels : int, optional | ||
| 245 | + Number of pixels | ||
| 246 | + """ | ||
| 247 | + # Get energies (this forces loading in case the map cube is not | ||
| 248 | + # loaded) | ||
| 249 | + energies = cube.energies() | ||
| 250 | + self.test_value(len(cube.energies()), nmaps, 'Check number of energies') | ||
| 251 | + | ||
| 252 | + # Check dimensions | ||
| 253 | + self.test_value(cube.maps(), nmaps, 'Check number of maps') | ||
| 254 | + self.test_value(cube.pixels(), npixels, 'Check number of pixels') | ||
| 255 | + | ||
| 256 | + # Return | ||
| 257 | + return |
test/test_ctskymap.py
| @@ -221,7 +221,7 @@ class Test(test): | @@ -221,7 +221,7 @@ class Test(test): | ||
| 221 | skymap['proj'] = 'CAR' | 221 | skymap['proj'] = 'CAR' |
| 222 | skymap['xref'] = 184.5575 | 222 | skymap['xref'] = 184.5575 |
| 223 | skymap['yref'] = -5.7844 | 223 | skymap['yref'] = -5.7844 |
| 224 | - skymap['bkgsubtract'] = 'IRF' | 224 | + skymap['bkgsubtract'] = 'IRF' |
| 225 | skymap['caldb'] = self._caldb | 225 | skymap['caldb'] = self._caldb |
| 226 | skymap['irf'] = self._irf | 226 | skymap['irf'] = self._irf |
| 227 | skymap['outmap'] = 'ctskymap_py4.fits' | 227 | skymap['outmap'] = 'ctskymap_py4.fits' |
| @@ -234,6 +234,8 @@ class Test(test): | @@ -234,6 +234,8 @@ class Test(test): | ||
| 234 | 234 | ||
| 235 | # Check result file | 235 | # Check result file |
| 236 | self._check_result_file('ctskymap_py4.fits') | 236 | self._check_result_file('ctskymap_py4.fits') |
| 237 | + self._check_result_file('ctskymap_py4.fits[BACKGROUND]') | ||
| 238 | + self._check_result_file('ctskymap_py4.fits[SIGNIFICANCE]') | ||
| 237 | 239 | ||
| 238 | # ================================ | 240 | # ================================ |
| 239 | # TEST RING BACKGROUND SUBTRACTION | 241 | # TEST RING BACKGROUND SUBTRACTION |
| @@ -268,6 +270,8 @@ class Test(test): | @@ -268,6 +270,8 @@ class Test(test): | ||
| 268 | 270 | ||
| 269 | # Check result file | 271 | # Check result file |
| 270 | self._check_result_file('ctskymap_py5.fits', 100, 100) | 272 | self._check_result_file('ctskymap_py5.fits', 100, 100) |
| 273 | + self._check_result_file('ctskymap_py5.fits[BACKGROUND]', 100, 100) | ||
| 274 | + self._check_result_file('ctskymap_py5.fits[SIGNIFICANCE]', 100, 100) | ||
| 271 | 275 | ||
| 272 | # Return | 276 | # Return |
| 273 | return | 277 | return |
test/test_python_cscripts.py
| @@ -32,6 +32,7 @@ import test_cslightcrv | @@ -32,6 +32,7 @@ import test_cslightcrv | ||
| 32 | import test_csmodelinfo | 32 | import test_csmodelinfo |
| 33 | import test_csmodelmerge | 33 | import test_csmodelmerge |
| 34 | import test_csmodelselect | 34 | import test_csmodelselect |
| 35 | +import test_csmodelsois | ||
| 35 | import test_csobs2caldb | 36 | import test_csobs2caldb |
| 36 | import test_csobsdef | 37 | import test_csobsdef |
| 37 | import test_csobsinfo | 38 | import test_csobsinfo |
| @@ -121,6 +122,7 @@ def test(installed=False, debug=False): | @@ -121,6 +122,7 @@ def test(installed=False, debug=False): | ||
| 121 | test_csmodelinfo.Test(), | 122 | test_csmodelinfo.Test(), |
| 122 | test_csmodelmerge.Test(), | 123 | test_csmodelmerge.Test(), |
| 123 | test_csmodelselect.Test(), | 124 | test_csmodelselect.Test(), |
| 125 | + test_csmodelsois.Test(), | ||
| 124 | test_csobs2caldb.Test(), | 126 | test_csobs2caldb.Test(), |
| 125 | test_csobsdef.Test(), | 127 | test_csobsdef.Test(), |
| 126 | test_csobsinfo.Test(), | 128 | test_csobsinfo.Test(), |
| @@ -145,7 +147,7 @@ def test(installed=False, debug=False): | @@ -145,7 +147,7 @@ def test(installed=False, debug=False): | ||
| 145 | 147 | ||
| 146 | # Check for VHEFITS environment variable | 148 | # Check for VHEFITS environment variable |
| 147 | if 'VHEFITS' in os.environ: | 149 | if 'VHEFITS' in os.environ: |
| 148 | - | 150 | + |
| 149 | # If the environment variable exists then unset it for the test | 151 | # If the environment variable exists then unset it for the test |
| 150 | # cases. Since Python is executed in a subprocess this will not | 152 | # cases. Since Python is executed in a subprocess this will not |
| 151 | # impact the environment variable in the parent shell. | 153 | # impact the environment variable in the parent shell. |