ctools 2.1.0
Loading...
Searching...
No Matches
csiactobs.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# ==========================================================================
3# Generates an IACT observation definition XML file
4#
5# Copyright (C) 2015-2022 Michael Mayer
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# ==========================================================================
21import sys
22import os
23import json
24import gammalib
25import ctools
26
27
28# =============== #
29# csiactobs class #
30# =============== #
31class csiactobs(ctools.cscript):
32 """
33 Generates an IACT observation definition XML file
34
35 This class implements the creation of a observation xml file for IACT
36 data analysis. This class is dedicated for use inside a IACT
37 Collaboration, i.e. it can only be used if you have access to IACT data
38 in FITS format. The FITS data has to be structured and in the format
39 described here:
40 http://gamma-astro-data-formats.readthedocs.org/en/latest/
41 """
42
43 # Constructor
44 def __init__(self, *argv):
45 """
46 Constructor
47 """
48 # Initialise application by calling the base class constructor
49 self._init_cscript(self.__class__.__name__, ctools.__version__, argv)
50
51 # Initialise some members
52 self._obs = gammalib.GObservations()
53 self._ebounds = gammalib.GEbounds()
54 self._datapath = os.getenv('VHEFITS','')
55 self._prodname = ''
56 self._xml = gammalib.GXml()
57 self._models = gammalib.GModels()
58 self._runlist = []
59 self._runlistfile = gammalib.GFilename()
60 self._bkgpars = 0
61 self._master_indx = ''
62 self._use_bkg_scale = False
63 self._ev_hiera = ['']
64 self._aeff_hiera = ['']
65 self._psf_hiera = ['']
66 self._bkg_hiera = ['']
67 self._edisp_hiera = ['']
68 self._bkg_mod_hiera = ['']
69 self._bkg_gauss_norm = 1.0
72 self._bkg_aeff_index = 0.0
73 self._bkg_aeff_norm = 1.0
75 self._hdu_index = ''
76 self._obs_index = ''
77 self._subdir = ''
78 self._debug = False
79
80 # Initialise empty observation definition XML file
81 self._xml.append(gammalib.GXmlElement('observation_list '
82 'title="observation list"'))
83
84 # Append an observation list to XML instance
85 self._xml.append(gammalib.GXmlElement('observation_list title="observation list"'))
86 self._xml_obslist = self._xml.element('observation_list', 0)
87
88 # Return
89 return
90
91
92 # Private methods
93 def _get_parameters(self):
94 """
95 Get parameters from parfile and setup the observation
96 """
97 # Query datapath. If the parameter is not NONE then use it, otherwise
98 # use the datapath from the VHEFITS environment variable
99 datapath = self['datapath'].string()
100 if gammalib.toupper(datapath) != 'NONE':
101 self._datapath = datapath
102 else:
103 self._datapath = os.getenv('VHEFITS','')
104
105 # Expand environment
106 self._datapath = gammalib.expand_env(self._datapath)
107
108 # Query input parameters
109 self['inmodel'].query()
110
111 # Read FITS production
112 self._prodname = self['prodname'].string()
113
114 # Read runlist file if list not already filled
115 if len(self._runlist) == 0:
116
117 # Get file name
118 self._runlistfile = self['infile'].filename()
119
120 # Read runlist from file
121 runfile = open(self._runlistfile.url())
122 for line in runfile.readlines():
123 if len(line) == 0:
124 continue
125 if line[0] == '#':
126 continue
127 if len(line.split()) > 0:
128 self._runlist.append(line.split()[0])
129 runfile.close()
130
131 # Read number of background parameters
132 self._bkgpars = self['bkgpars'].integer()
133
134 # Query ahead output parameters
135 if self._read_ahead():
136 self['outmodel'].filename()
137 self['outobs'].filename()
138
139 # Master index file name
140 self._master_indx = self['master_indx'].string()
141
142 # Read flag for background scaling factor
143 self._use_bkg_scale = self['bkg_scale'].boolean()
144
145 # Read hierarchy of file loading
146 self._ev_hiera = self['ev_hiera'].string().split('|')
147 self._aeff_hiera = self['aeff_hiera'].string().split('|')
148 self._psf_hiera = self['psf_hiera'].string().split('|')
149 self._bkg_hiera = self['bkg_hiera'].string().split('|')
150 self._edisp_hiera = self['edisp_hiera'].string().split('|')
151 self._bkg_mod_hiera = self['bkg_mod_hiera'].string().split('|')
152
153 # Read hidden background parameters
154 self._bkg_gauss_norm = self['bkg_gauss_norm'].real()
155 self._bkg_gauss_index = self['bkg_gauss_index'].real()
156 self._bkg_gauss_sigma = self['bkg_gauss_sigma'].real()
157 self._bkg_aeff_index = self['bkg_aeff_index'].real()
158 self._bkg_aeff_norm = self['bkg_aeff_norm'].real()
159 self._bkg_range_factor = self['bkg_range_factor'].real()
160
161 # Open master index file and look for prodname
162 master_file = os.path.join(self._datapath, self._master_indx)
163 if not os.path.isfile(master_file):
164 raise RuntimeError('FITS data store not available. No master '
165 'index file found. Make sure the file is '
166 'copied from the server and your datapath '
167 'is set correctly.')
168
169 # Open and load JSON file
170 json_data = open(master_file).read()
171 data = json.loads(json_data)
172 if not 'datasets' in data:
173 raise RuntimeError('Key "datasets" not available in master '
174 'index file.')
175
176 # Get configurations
177 configs = data['datasets']
178
179 # Initialise HDUs
180 self._hdu_index = self._obs_index = ''
181
182 # Get HDUs
183 for config in configs:
184
185 # Check if prodname is present
186 if self._prodname == config['name']:
187 self._hdu_index = str(os.path.join(self._datapath,
188 config['hduindx']))
189 self._obs_index = str(os.path.join(self._datapath,
190 config['obsindx']))
191
192 # Leave loop if index file names were found
193 break
194
195 # Check index files
196 if self._hdu_index == '' or self._obs_index == '':
197 raise RuntimeError('*** ERROR: FITS data store "'+self._prodname+
198 '" not available. Run csiactdata to get a list '
199 'of available storage names')
200
201 # Check HDU names
202 filename = gammalib.GFilename(self._hdu_index+'[HDU_INDEX]')
203 if not filename.is_fits():
204 raise RuntimeError('*** ERROR: HDU index file "'+self._hdu_index+
205 '[HDU_INDEX]" for FITS data store "'+
206 self._prodname+'" not available. Check your '
207 'master index file or run csiactdata to get '
208 'a list of available storage names.')
209
210 # Check for existence of 'BKG_SCALE' in the observation index file if
211 # required
212 if self._use_bkg_scale:
213
214 # Create filename
215 filename = gammalib.GFilename(self._obs_index+'[OBS_INDEX]')
216
217 # Check if it is a FITS file
218 if filename.is_fits():
219
220 # Open FITS file
221 fits = gammalib.GFits(self._obs_index)
222
223 # Check if column "BKG_SCALE" is found and signal its possible
224 # usage
225 if not fits['OBS_INDEX'].contains('BKG_SCALE'):
226 self._use_bkg_scale = False
227
228 # Close FITS file
229 fits.close()
230
231 else:
232 # Signal that there is no background scale
233 self._use_bkg_scale = False
234
235 # Create base data directory from hdu index file location
236 self._subdir = os.path.dirname(self._hdu_index)
237 self._debug = False # Debugging in client tools
238
239 # Write input parameters into logger
240 self._log_parameters(gammalib.TERSE)
241
242 # Return
243 return
244
245 def _background_spectrum(self, prefactor, index, emin=0.01, emax=100.0):
246 """
247 Create a background spectrum model dependent on user parameters
248
249 Parameters
250 ----------
251 prefactor : float
252 Power law prefactor of spectral model
253 index : float
254 Power law index of spectral model
255 emin : float
256 Minimum energy (in case a spectral node function is required)
257 emax : float
258 Maximum energy (in case a spectral node function is required)
259
260 Returns
261 -------
262 spec : `~gammalib.GModelSpectral()`
263 Spectral model for the background shape
264 """
265 # Handle constant spectral model
266 if index == 0.0 and self._bkgpars <= 1:
267 spec = gammalib.GModelSpectralConst()
268
269 # Set parameter range
270 spec['Normalization'].min(prefactor / self._bkg_range_factor)
271 spec['Normalization'].max(prefactor * self._bkg_range_factor)
272 spec['Normalization'].value(prefactor)
273
274 # Freeze or release normalisation parameter
275 if self._bkgpars == 0:
276 spec['Normalization'].fix()
277 else:
278 spec['Normalization'].free()
279
280 else:
281
282 # Create power law model
283 if self._bkgpars <= 2:
284
285 # Set Power Law model with arbitrary pivot energy
286 pivot = gammalib.GEnergy(1.0,'TeV')
287 spec = gammalib.GModelSpectralPlaw(prefactor, index, pivot)
288
289 # Set parameter ranges
290 spec[0].min(prefactor / self._bkg_range_factor)
291 spec[0].max(prefactor * self._bkg_range_factor)
292 spec[1].scale(1)
293 spec[1].min(-5.0)
294 spec[1].max(5.0)
295
296 # Set number of free parameters
297 if self._bkgpars == 0:
298 spec[0].fix()
299 spec[1].fix()
300 elif self._bkgpars == 1:
301 spec[0].free()
302 spec[1].fix()
303 else:
304 spec[0].free()
305 spec[1].free()
306
307 else:
308
309 # Create reference powerlaw
310 pivot = gammalib.GEnergy(1.0,'TeV')
311 plaw = gammalib.GModelSpectralPlaw(prefactor, index, pivot)
312
313 # Create spectral model and energy values
314 spec = gammalib.GModelSpectralNodes()
315
316 # Create logarithmic energy nodes
317 bounds = gammalib.GEbounds(self._bkgpars,
318 gammalib.GEnergy(emin,'TeV'),
319 gammalib.GEnergy(emax,'TeV'))
320
321 # Loop over bounds and set intensity value
322 for i in range(bounds.size()):
323 energy = bounds.elogmean(i)
324 value = plaw.eval(energy)
325
326 # Append energy, value - tuple to node function
327 spec.append(energy, value)
328
329 # Loop over parameters
330 for par in spec:
331
332 # Fix energy nodes
333 if 'Energy' in par.name():
334 par.fix()
335
336 # Release intensity nodes
337 elif 'Intensity' in par.name():
338 value = par.value()
339 par.scale(value)
340 par.min(value / self._bkg_range_factor)
341 par.max(value * self._bkg_range_factor)
342
343 # Return spectrum
344 return spec
345
346 def _iact_background(self, telescope, obs_id, bkg_scale, bkgtype,
347 emin=0.01, emax=100):
348 """
349 Create an IACT background model
350
351 Parameters
352 ----------
353 telescope : str
354 Name of telescope
355 obs_id : str
356 Observation ID
357 bkg_scale : float
358 Background scaling factor
359 bkgtype : str
360 Type of background (irf,aeff, or gauss)
361
362 Returns
363 -------
364 model : `~gammalib.GModelData()`
365 Background model for IACT observation
366 """
367 # Handle IrfBackground
368 if bkgtype == 'irf':
369
370 # Set parameters to have a constant spectral model
371 prefactor = 1.0
372 index = 0.0
373 prefactor *= bkg_scale
374
375 # Create background spectrum
376 spec = self._background_spectrum(prefactor, index, emin, emax)
377
378 # Create background model
379 bck = gammalib.GCTAModelIrfBackground(spec)
380
381 # Set AeffBackground
382 elif bkgtype == 'aeff':
383
384 # Set background components
385 prefactor = bkg_scale * self._bkg_aeff_norm
386 spec = self._background_spectrum(prefactor,
387 self._bkg_aeff_index,
388 emin, emax)
389
390 # Create background model
391 bck = gammalib.GCTAModelAeffBackground(spec)
392
393 # Set Gaussian Background
394 elif bkgtype == 'gauss':
395
396 # Set background components
397 prefactor = bkg_scale * self._bkg_gauss_norm
398 spec = self._background_spectrum(prefactor,
399 self._bkg_gauss_index,
400 emin, emax)
401 radial = gammalib.GCTAModelRadialGauss(self._bkg_gauss_sigma)
402
403 # Create background model
404 bck = gammalib.GCTAModelRadialAcceptance(radial, spec)
405
406 else:
407 msg = 'Background type "'+bkgtype+'" unsupported'
408 raise RuntimeError(msg)
409
410 # Copy model
411 model = bck.clone()
412
413 # Assign specific run id
414 model.ids(str(obs_id))
415
416 # Assign instrument
417 model.instruments(telescope)
418
419 # Set name (arbitrary)
420 model.name('bkg_'+str(obs_id))
421
422 # Turn off TS calculation for background model
423 model.tscalc(False)
424
425 # Return model
426 return model
427
429 """
430 Append input models
431 """
432 # If there are models provided by "inmodels" then append them now to
433 # the model container
434 if self['inmodel'].is_valid():
435
436 # Get filename
437 filename = self['inmodel'].filename().url()
438
439 # Log header and input model file
440 self._log_header1(gammalib.TERSE, 'Append input models')
441 self._log_value(gammalib.NORMAL, 'Input model file', filename)
442
443 # Load input models
444 models = gammalib.GModels(filename)
445
446 # Loop over input models and append them to the model container
447 for model in models:
448 self._models.append(model)
449 self._log_value(gammalib.NORMAL, 'Append model',
450 '"'+model.name()+'"')
451
452 # Return
453 return
454
455 def _write_summary(self):
456 """
457 Write observation summary
458 """
459 # Log header
460 self._log_header1(gammalib.NORMAL, 'Observation summary')
461
462 # Set energy range dependent on whether boundaries exist or
463 # not
464 if self._ebounds.size() > 0:
465 erange = '%s - %s' % (str(self._ebounds.emin()),
466 str(self._ebounds.emax()))
467 else:
468 erange = 'not available'
469
470 # Log energy range
471 self._log_value(gammalib.NORMAL, 'Energy range', erange)
472
473 # Return
474 return
475
476 def _get_filename(self, hdu, hierarchy, formats):
477 """
478 Retrieves a filename from a hdu index
479
480 Parameters
481 ----------
482 hdu : `~gammalib.GFitsTable`
483 HDU FITS table
484 hierarchy : list of str
485 List of strings containing the hierarchy how to look for files
486 formats : list of str
487 File formats available for this observation
488
489 Returns
490 -------
491 filename : str
492 Filename of requested file
493 """
494
495 # Initialise filename
496 filename = ''
497
498 # Handle hierarchies
499 index = -1
500
501 # Loop over possible formats
502 for version in hierarchy:
503
504 # Count number of same available versions
505 n = formats.count(version)
506
507 # Leave loop and store index of first occurence
508 if n > 0:
509 index = formats.index(version)
510 break
511
512 # Build filename from information stored in hduindx_hdu
513 if index >= 0:
514 filename = os.path.join(self._subdir,
515 hdu['FILE_DIR'][index],
516 hdu['FILE_NAME'][index])
517 filehdu = hdu['HDU_NAME'][index]
518 filename += '['+filehdu+']'
519
520 # Return filename
521 return filename
522
523 def _is_present(self, filename, obs_id, filetype):
524 """
525 Checks if a filename is present
526
527 Parameters
528 ----------
529 filename : str
530 Filename
531 obs_id : int
532 Observation ID
533 filetype : str
534 Type of file
535
536 Returns
537 -------
538 present : bool
539 True if filename is present, False otherwise
540 """
541
542 # Initialise return value
543 present = True
544
545 # Create filename instance
546 fname = gammalib.GFilename(filename)
547
548 # Check if file is empty
549 if fname.is_empty():
550 msg = 'Skipping observation "%s": No %s found' % (obs_id, filetype)
551 self._log_string(gammalib.NORMAL, msg)
552 present = False
553
554 # Check if file exists
555 elif not fname.exists():
556 msg = ('Skipping observation "%s": %s "%s" does not exist' %
557 (obs_id, filetype, filename))
558 self._log_string(gammalib.NORMAL, msg)
559 present = False
560
561 # Return present flag
562 return present
563
564
565 # Public methods
566 def process(self):
567 """
568 Process the script
569 """
570 # Get parameters
571 self._get_parameters()
572
573 # Clear models
574 self._models.clear()
575
576 # Log output
577 msg = 'Looping over %d runs' % len(self._runlist)
578 self._log_header1(gammalib.TERSE, msg)
579
580 # Initialise energy range values for logging
581 self._ebounds.clear()
582
583 # Loop over runs
584 for obs_id in self._runlist:
585
586 # Create selection string
587 obs_selection = '[OBS_ID=='+str(obs_id)+']'
588
589 # Open HDU index file
590 hduindx = gammalib.GFits(self._hdu_index+'[HDU_INDEX]'+
591 obs_selection)
592 hduindx_hdu = hduindx['HDU_INDEX']
593
594 # Initialise types and formats
595 formats = []
596 for i in range(hduindx_hdu.nrows()):
597 formats.append(hduindx_hdu['HDU_CLASS'][i])
598
599 # Retrieve filenames
600 eventfile = self._get_filename(hduindx_hdu, self._ev_hiera, formats)
601 aefffile = self._get_filename(hduindx_hdu, self._aeff_hiera, formats)
602 psffile = self._get_filename(hduindx_hdu, self._psf_hiera, formats)
603 edispfile = self._get_filename(hduindx_hdu, self._edisp_hiera, formats)
604 bkgfile = self._get_filename(hduindx_hdu, self._bkg_hiera, formats)
605
606 # Check for presence of required event file
607 if not self._is_present(eventfile, obs_id, "event file"):
608 continue
609
610 # Check for presence of required effective area file
611 if not self._is_present(aefffile, obs_id, "effective area file"):
612 continue
613
614 # Check for presence of required psf file
615 if not self._is_present(psffile, obs_id, "PSF file"):
616 continue
617
618 # Check for optional energy dispersion file
619 if not gammalib.GFilename(edispfile).exists():
620
621 # Print warning that edisp cannot be used for this observation
622 msg = ('Warning: observation "%s" has no energy dispersion '
623 'information' % obs_id)
624 self._log_string(gammalib.NORMAL, msg)
625
626 # Set energy dispersion file as empty
627 edispfile = ''
628
629 # Create a copy of background model hierarchy for this run
630 run_bkg_mod_hierarchy = list(self._bkg_mod_hiera)
631
632 # Check if background file is available
633 # Remove IRF background from hierarchy if file doesnt exist
634 if not gammalib.GFilename(bkgfile).exists():
635
636 # Set background file as empty
637 bkgfile = ''
638
639 # Check for IRF background in background model hierarchy
640 if 'irf' in run_bkg_mod_hierarchy:
641
642 # Remove IRF background if file doesnt exist
643 run_bkg_mod_hierarchy.remove('irf')
644
645 # Print warning that edisp cannot be used for this
646 # observation
647 msg = ('Warning: observation "%s" has no background '
648 'information (IRF background cannot be used)' %
649 obs_id)
650 self._log_string(gammalib.NORMAL, msg)
651
652 # Check if background model hierarchy is empty
653 if len(run_bkg_mod_hierarchy) == 0:
654
655 # Skip observation if no background can be used
656 msg = ('Skipping observation "%s": No background can be '
657 'used' % obs_id)
658 self._log_string(gammalib.NORMAL, msg)
659 continue
660
661 else:
662 # Log if we fall back to next background approach
663 msg = ('Observation "%s": Falling back to background "%s"' %
664 (obs_id, run_bkg_mod_hierarchy[0]))
665 self._log_string(gammalib.NORMAL, msg)
666
667 # Close hdu index file
668 hduindx.close()
669
670 # Initialise background scale
671 bkg_scale = 1.0
672
673 # Check if background scale should be used
674 if self._use_bkg_scale:
675
676 # Read background scale from fits file
677 obsindx = gammalib.GFits(self._obs_index+'[OBS_INDEX]'+
678 obs_selection)
679 bkg_scale = obsindx['OBS_INDEX']['BKG_SCALE'][0]
680 obsindx.close()
681
682 # Open event FITS file
683 fits = gammalib.GFits(eventfile)
684
685 # Get object and telescope strings from event hdu
686 events = fits[gammalib.GFilename(eventfile).extname()]
687 object_name = events.string('OBJECT')
688 telescope = events.string('TELESCOP')
689
690 # Close FITS file
691 fits.close()
692
693 # Open effective area file to look for threshold
694 aeff_fits = gammalib.GFits(aefffile)
695 aeff_table = aeff_fits[gammalib.GFilename(aefffile).extname()]
696
697 # Set energy range from header keyword if present
698 if aeff_table.has_card('LO_THRES') and aeff_table.has_card('HI_THRES'):
699
700 # Get safe energy range
701 run_emin = gammalib.GEnergy(aeff_table.real('LO_THRES'), 'TeV')
702 run_emax = gammalib.GEnergy(aeff_table.real('HI_THRES'), 'TeV')
703
704 # Append to ebounds
705 self._ebounds.append(run_emin, run_emax)
706
707 else:
708 # Set default values for energy range
709 run_emin = gammalib.GEnergy(10,'GeV')
710 run_emax = gammalib.GEnergy(100,'TeV')
711
712 # Close Aeff fits file
713 aeff_fits.close()
714
715 # Append instrumental background model
716 self._models.append(self._iact_background(telescope,
717 obs_id,
718 bkg_scale,
719 run_bkg_mod_hierarchy[0],
720 run_emin.TeV(),
721 run_emax.TeV()))
722
723 # Append observation to XML and set attributes
724 obs = self._xml_obslist.append('observation')
725 obs.attribute('name', object_name)
726 obs.attribute('id', str(obs_id))
727 obs.attribute('instrument', telescope)
728
729 # Append event file
730 ev = gammalib.GXmlElement('parameter name="EventList"')
731 ev.attribute('file', eventfile)
732
733 # Append effective area
734 aeff = gammalib.GXmlElement('parameter name="EffectiveArea"')
735 aeff.attribute('file', aefffile)
736
737 # Append PSF
738 psf = gammalib.GXmlElement('parameter name="PointSpreadFunction"')
739 psf.attribute('file', psffile)
740
741 # Append energy dispersion
742 edisp = gammalib.GXmlElement('parameter name="EnergyDispersion"')
743 edisp.attribute('file', edispfile)
744
745 # Append background
746 bck = gammalib.GXmlElement('parameter name="Background"')
747 bck.attribute('file', bkgfile)
748
749 # Assign events and IRFs to observation
750 obs.append(ev)
751 obs.append(aeff)
752 obs.append(psf)
753 obs.append(edisp)
754 obs.append(bck)
755
756 # Log the observation ID and object name that has been appended
757 self._log_value(gammalib.NORMAL, 'Append observation', '%s ("%s")' %
758 (obs_id, object_name))
759
760 # Log the file names of the event and response files
761 self._log_value(gammalib.EXPLICIT, ' Event file', eventfile)
762 self._log_value(gammalib.EXPLICIT, ' Effective area file', aefffile)
763 self._log_value(gammalib.EXPLICIT, ' Point spread function file',
764 psffile)
765 self._log_value(gammalib.EXPLICIT, ' Energy dispersion file',
766 edispfile)
767 self._log_value(gammalib.EXPLICIT, ' Background file', bkgfile)
768 if self._use_bkg_scale:
769 self._log_value(gammalib.EXPLICIT, ' Background scale',
770 bkg_scale)
771
772 # Append models provided by "inmodel" to the model container
773 self._append_inmodels()
774
775 # Write observation summary
776 self._write_summary()
777
778 # Write warning in no observation could be used from runlist
779 if self._xml_obslist.size() == 0:
780 self._log_string(gammalib.NORMAL, 'WARNING: No observation was '
781 'appended from specified runlist')
782
783 # Return
784 return
785
786 def save(self):
787 """
788 Save observation definition and model definition XML file
789 """
790 # Write header
791 self._log_header1(gammalib.TERSE, 'Save XML files')
792
793 # Get filenames
794 outobs = self['outobs'].filename()
795 outmodel = self['outmodel'].filename()
796
797 # Log observation definition file name
798 self._log_value(gammalib.NORMAL, 'Obs. definition XML file',
799 outobs.url())
800
801 # Save observation definition XML file
802 self._xml.save(outobs.url())
803
804 # Log model definition file name
805 self._log_value(gammalib.NORMAL, 'Model definiton XML file',
806 outmodel.url())
807
808 # Save model XML file
809 self._models.save(outmodel.url())
810
811 # Return
812 return
813
814 def runlist(self, runlist):
815 """
816 Set runlist
817
818 Parameters
819 ----------
820 runlist : list
821 List of observation IDs
822
823 Raises
824 ------
825 RuntimeError
826 Input runlist is not a Python list
827 """
828 # If the runlist is convertable to a Python list then store the
829 # runlist in the class
830 try:
831 self._runlist = list(runlist)
832
833 # ... otherwise raise an exception
834 except:
835 raise RuntimeError('Argument is not a Python list')
836
837 # Return
838 return
839
840 def ebounds(self):
841 """
842 Return runlist energy boundaries
843 """
844 # Return energy boundaries
845 return self._ebounds
846
847 def obs(self):
848 """
849 Return observations container
850 """
851 # Clear observations
852 self._obs.clear()
853
854 # Read observations if XML is filled
855 if self._xml.size():
856 self._obs.read(self._xml)
857
858 # Assign models
859 self._obs.models(self._models)
860
861 # Return observations
862 return self._obs
863
864
865# ======================== #
866# Main routine entry point #
867# ======================== #
868if __name__ == '__main__':
869
870 # Create instance of application
871 app = csiactobs(sys.argv)
872
873 # Execute application
874 app.execute()
_iact_background(self, telescope, obs_id, bkg_scale, bkgtype, emin=0.01, emax=100)
Definition csiactobs.py:347
_is_present(self, filename, obs_id, filetype)
Definition csiactobs.py:523
_background_spectrum(self, prefactor, index, emin=0.01, emax=100.0)
Definition csiactobs.py:245
_get_filename(self, hdu, hierarchy, formats)
Definition csiactobs.py:476