Commit bb9a556d85a74a6a24f53ab3dbeb4dde46508ef8

Authored by Jürgen Knödlseder
1 parent 6887a0c9

Implement csfootprint script (#3592)

cscripts/Makefile.am
1 ############################################################################# 1 #############################################################################
2 # Makefile for cscripts scripts # 2 # Makefile for cscripts scripts #
3 # ------------------------------------------------------------------------- # 3 # ------------------------------------------------------------------------- #
4 -# Copyright (C) 2016-2021 Juergen Knoedlseder # 4 +# Copyright (C) 2016-2022 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 #
@@ -25,6 +25,7 @@ pythonscripts = $(top_builddir)/cscripts/__init__.py \ @@ -25,6 +25,7 @@ pythonscripts = $(top_builddir)/cscripts/__init__.py \
25 $(srcdir)/csbkgmodel.py \ 25 $(srcdir)/csbkgmodel.py \
26 $(srcdir)/cscaldb.py \ 26 $(srcdir)/cscaldb.py \
27 $(srcdir)/csebins.py \ 27 $(srcdir)/csebins.py \
  28 + $(srcdir)/csfootprint.py \
28 $(srcdir)/csinfo.py \ 29 $(srcdir)/csinfo.py \
29 $(srcdir)/cslightcrv.py \ 30 $(srcdir)/cslightcrv.py \
30 $(srcdir)/csmodelinfo.py \ 31 $(srcdir)/csmodelinfo.py \
@@ -88,6 +89,7 @@ parfiles = $(srcdir)/csadd2caldb.par \ @@ -88,6 +89,7 @@ parfiles = $(srcdir)/csadd2caldb.par \
88 $(srcdir)/cstsmapsplit.par \ 89 $(srcdir)/cstsmapsplit.par \
89 $(srcdir)/csviscube.par \ 90 $(srcdir)/csviscube.par \
90 $(srcdir)/csscs.par \ 91 $(srcdir)/csscs.par \
  92 + $(srcdir)/csfootprint.par \
91 $(srcdir)/csworkflow.par \ 93 $(srcdir)/csworkflow.par \
92 $(srcdir)/csfindobs.par \ 94 $(srcdir)/csfindobs.par \
93 $(srcdir)/csiactcopy.par \ 95 $(srcdir)/csiactcopy.par \
@@ -123,6 +125,7 @@ linkscripts = csadd2caldb \ @@ -123,6 +125,7 @@ linkscripts = csadd2caldb \
123 cstsmapsplit \ 125 cstsmapsplit \
124 csviscube \ 126 csviscube \
125 csscs \ 127 csscs \
  128 + csfootprint \
126 csworkflow \ 129 csworkflow \
127 csfindobs \ 130 csfindobs \
128 csiactcopy \ 131 csiactcopy \
@@ -163,6 +166,7 @@ testscripts = $(srcdir)/tests/__init__.py \ @@ -163,6 +166,7 @@ testscripts = $(srcdir)/tests/__init__.py \
163 $(top_srcdir)/test/test_cstsmapsplit.py \ 166 $(top_srcdir)/test/test_cstsmapsplit.py \
164 $(top_srcdir)/test/test_csviscube.py \ 167 $(top_srcdir)/test/test_csviscube.py \
165 $(top_srcdir)/test/test_csscs.py \ 168 $(top_srcdir)/test/test_csscs.py \
  169 + $(top_srcdir)/test/test_csfootprint.py \
166 $(top_srcdir)/test/test_csworkflow.py \ 170 $(top_srcdir)/test/test_csworkflow.py \
167 $(top_srcdir)/test/test_obsutils.py \ 171 $(top_srcdir)/test/test_obsutils.py \
168 $(top_srcdir)/test/test_mputils.py \ 172 $(top_srcdir)/test/test_mputils.py \
cscripts/__init__.py.in
1 # ========================================================================== 1 # ==========================================================================
2 # cscripts Python module 2 # cscripts Python module
3 # 3 #
4 -# Copyright (C) 2015-2021 Juergen Knoedlseder 4 +# Copyright (C) 2015-2022 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
@@ -28,6 +28,7 @@ __all__ = [ @@ -28,6 +28,7 @@ __all__ = [
28 "csbkgmodel", 28 "csbkgmodel",
29 "cscaldb", 29 "cscaldb",
30 "csebins", 30 "csebins",
  31 + "csfootprint",
31 "csinfo", 32 "csinfo",
32 "cslightcrv", 33 "cslightcrv",
33 "csmodelinfo", 34 "csmodelinfo",
@@ -94,6 +95,7 @@ from cscripts.cstsmapmerge import cstsmapmerge @@ -94,6 +95,7 @@ from cscripts.cstsmapmerge import cstsmapmerge
94 from cscripts.cstsmapsplit import cstsmapsplit 95 from cscripts.cstsmapsplit import cstsmapsplit
95 from cscripts.csviscube import csviscube 96 from cscripts.csviscube import csviscube
96 from cscripts.csscs import csscs 97 from cscripts.csscs import csscs
  98 +from cscripts.csfootprint import csfootprint
97 from cscripts.csworkflow import csworkflow 99 from cscripts.csworkflow import csworkflow
98 from cscripts import obsutils 100 from cscripts import obsutils
99 from cscripts import modutils 101 from cscripts import modutils
cscripts/csfootprint.par 0 → 100644
  1 +#############################################################################
  2 +# #
  3 +# Science Analysis Tools #
  4 +# #
  5 +# ------------------------------------------------------------------------- #
  6 +# #
  7 +# File: csfootprint.par #
  8 +# #
  9 +# Author: Juergen Knoedlseder #
  10 +# Jurgen.Knodlseder@irap.omp.eu #
  11 +# IRAP #
  12 +# #
  13 +# Purpose: Parameter file for the csfootprint script #
  14 +# #
  15 +#############################################################################
  16 +#
  17 +# Input and output parameters
  18 +#============================
  19 +infile, f, h, $HOME/.gamma/statistics.xml,,, "Input high-level statistics XML file"
  20 +outfile, f, a, NONE,,, "Output graphics file (NONE if no graphics should be generated)"
  21 +
  22 +#
  23 +# Script parameters
  24 +#==================
  25 +tmin, t, a, NONE,,, "Start time for report (UTC string, JD, MJD or MET in seconds)"
  26 +tmax, t, a, NONE,,, "Stop time for report (UTC string, JD, MJD or MET in seconds)"
  27 +
  28 +#
  29 +# Standard parameters
  30 +#====================
  31 +chatter, i, h, 2,0,4, "Chattiness of output"
  32 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  33 +debug, b, h, no,,, "Activate debugging mode?"
  34 +mode, s, h, ql,,, "Mode of automatic parameters"
  35 +logfile, f, h, csfootprint.log,,, "Log filename"
cscripts/csfootprint.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# Carbon footprint report script
  4 +#
  5 +# Copyright (C) 2022 Juergen Knoedlseder
  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 +# csfootprint class #
  28 +# ================= #
  29 +class csfootprint(ctools.cscript):
  30 + """
  31 + Carbon footprint report script
  32 + """
  33 +
  34 + # Constructor
  35 + def __init__(self, *argv):
  36 + """
  37 + Constructor
  38 +
  39 + Parameters
  40 + ----------
  41 + argv : list of str
  42 + List of IRAF command line parameter strings of the form
  43 + ``parameter=3``.
  44 + """
  45 + # Initialise application by calling the base class constructor
  46 + self._init_cscript(self.__class__.__name__, ctools.__version__, argv)
  47 +
  48 + # Return
  49 + return
  50 +
  51 + # State methods for pickling
  52 + def __getstate__(self):
  53 + """
  54 + Extend ctools.cscript __getstate__ method
  55 +
  56 + Returns
  57 + -------
  58 + state : dict
  59 + Pickled instance
  60 + """
  61 + # Set pickled dictionary
  62 + state = {'base' : ctools.cscript.__getstate__(self)}
  63 +
  64 + # Return pickled dictionary
  65 + return state
  66 +
  67 + def __setstate__(self, state):
  68 + """
  69 + Extend ctools.cscript __setstate__ method
  70 +
  71 + Parameters
  72 + ----------
  73 + state : dict
  74 + Pickled instance
  75 + """
  76 + # Set state
  77 + ctools.cscript.__setstate__(self, state['base'])
  78 +
  79 + # Return
  80 + return
  81 +
  82 +
  83 + # Private methods
  84 + def _get_parameters(self):
  85 + """
  86 + Get parameters from parfile
  87 + """
  88 + # Query input parameters
  89 + self['infile'].filename()
  90 + if self['tmin'].is_valid():
  91 + self['tmin'].time()
  92 + if self['tmax'].is_valid():
  93 + self['tmax'].time()
  94 +
  95 + # Query ahead output model filename
  96 + if self._read_ahead():
  97 + if self['outfile'].is_valid():
  98 + self['outfile'].filename()
  99 +
  100 + # Write input parameters into logger
  101 + self._log_parameters(gammalib.TERSE)
  102 +
  103 + # Return
  104 + return
  105 +
  106 + # Load statistics
  107 + def _load_statistics(self):
  108 + """
  109 + Load statistics
  110 + """
  111 + # Initialise statistics
  112 + statistics = {}
  113 +
  114 + # Get filename
  115 + infile = self['infile'].filename()
  116 +
  117 + # Load XML file
  118 + xml = gammalib.GXml()
  119 + xml.load(infile)
  120 +
  121 + # Get useful nodes
  122 + header = xml.element('statistics > header')
  123 + data = xml.element('statistics > data')
  124 + dates = header.element('dates')
  125 + countries = data.element('countries')
  126 + versions = data.element('versions')
  127 + daily = data.element('daily')
  128 +
  129 + # Extract header dates information
  130 + statistics['creation'] = dates.element('creation').string()
  131 + statistics['modified'] = dates.element('modified').string()
  132 + statistics['start'] = dates.element('start').string()
  133 + statistics['stop'] = dates.element('stop').string()
  134 +
  135 + # Set used time interval [start,stop]
  136 + if self['tmin'].is_valid():
  137 + start = self['tmin'].time().utc()
  138 + if start < statistics['start']:
  139 + start = statistics['start']
  140 + else:
  141 + start = statistics['start']
  142 + if self['tmax'].is_valid():
  143 + stop = self['tmax'].time().utc()
  144 + if stop > statistics['stop']:
  145 + stop = statistics['stop']
  146 + else:
  147 + stop = statistics['stop']
  148 +
  149 + # Set used time interval
  150 + statistics['use_start'] = start
  151 + statistics['use_stop'] = stop
  152 +
  153 + # Extract list of countries
  154 + statistics['countries'] = []
  155 + num = countries.elements()
  156 + for i in range(num):
  157 + element = countries.element(i)
  158 + country = element.name()
  159 + calls = element.attribute('calls')
  160 + wall = element.attribute('wall')
  161 + cpu = element.attribute('cpu')
  162 + gCO2e = element.attribute('gCO2e')
  163 + entry = {'country': country, 'calls': calls, 'wall': wall,
  164 + 'cpu': cpu, 'gCO2e': gCO2e}
  165 + statistics['countries'].append(entry)
  166 +
  167 + # Extract list of versions
  168 + statistics['versions'] = []
  169 + num = versions.elements()
  170 + for i in range(num):
  171 + element = versions.element(i)
  172 + version = element.name()
  173 + calls = element.attribute('calls')
  174 + wall = element.attribute('wall')
  175 + cpu = element.attribute('cpu')
  176 + gCO2e = element.attribute('gCO2e')
  177 + entry = {'version': version, 'calls': calls, 'wall': wall,
  178 + 'cpu': cpu, 'gCO2e': gCO2e}
  179 + statistics['versions'].append(entry)
  180 +
  181 + # Extract daily and tools statistics
  182 + statistics['daily'] = []
  183 + statistics['tools'] = []
  184 + num = daily.elements()
  185 + total_calls = 0
  186 + total_wall = 0.0
  187 + total_cpu = 0.0
  188 + total_gCO2e = 0.0
  189 + for i in range(num):
  190 +
  191 + # Get date
  192 + element = daily.element(i)
  193 + date = element.element('value',0).string()
  194 +
  195 + # Continue if date is out of range
  196 + if date < start[0:10] or date > stop[0:10]:
  197 + continue
  198 +
  199 + # Collect information
  200 + tools = element.element('tools',0)
  201 + ntools = tools.elements()
  202 + sum_calls = 0
  203 + sum_wall = 0.0
  204 + sum_cpu = 0.0
  205 + sum_gCO2e = 0.0
  206 + for k in range(ntools):
  207 +
  208 + # Extract information
  209 + tool = tools.element(k)
  210 + name = tool.name()
  211 + calls = int(tool.attribute('calls'))
  212 + wall = float(tool.attribute('wall'))
  213 + cpu = float(tool.attribute('cpu'))
  214 + gCO2e = float(tool.attribute('gCO2e'))
  215 +
  216 + # Update sums
  217 + sum_calls += calls
  218 + sum_wall += wall
  219 + sum_cpu += cpu
  220 + sum_gCO2e += gCO2e
  221 +
  222 + # Update tools data
  223 + if name in statistics['tools']:
  224 + statistics['tools'][name]['calls'] += calls
  225 + statistics['tools'][name]['wall'] += wall
  226 + statistics['tools'][name]['cpu'] += cpu
  227 + statistics['tools'][name]['gCO2e'] += gCO2e
  228 + else:
  229 + entry = {'name': name, 'calls': calls, 'wall': wall,
  230 + 'cpu': cpu, 'gCO2e': gCO2e}
  231 + statistics['tools'].append(entry)
  232 +
  233 + # Update totals
  234 + total_calls += sum_calls
  235 + total_wall += sum_wall
  236 + total_cpu += sum_cpu
  237 + total_gCO2e += sum_gCO2e
  238 +
  239 + # Set entry
  240 + entry = {'date': date, 'calls': sum_calls, 'wall': sum_wall,
  241 + 'cpu': sum_cpu, 'gCO2e': sum_gCO2e}
  242 + statistics['daily'].append(entry)
  243 +
  244 + # Update total statistics
  245 + statistics['calls'] = total_calls
  246 + statistics['wall'] = total_wall
  247 + statistics['cpu'] = total_cpu
  248 + statistics['gCO2e'] = total_gCO2e
  249 +
  250 + # Return statistics
  251 + return statistics
  252 +
  253 + # Format time
  254 + def _format_time(self, seconds):
  255 + """
  256 + Format time
  257 +
  258 + Parameters
  259 + ----------
  260 + seconds : float
  261 + Time in seconds
  262 + """
  263 + # Format according to precision
  264 + if seconds < 60.0:
  265 + format = '%.3f seconds' % (seconds)
  266 + elif seconds < 3600.0:
  267 + format = '%.3f minutes' % (seconds/60.0)
  268 + else:
  269 + format = '%.3f hours' % (seconds/3600.0)
  270 +
  271 + # Return format
  272 + return format
  273 +
  274 + # Format carbon footprint
  275 + def _format_footprint(self, gCO2e):
  276 + """
  277 + Format carbon footprint
  278 +
  279 + Parameters
  280 + ----------
  281 + gCO2e : float
  282 + Carbon footprint in gCO2e
  283 + """
  284 + # Format according to precision
  285 + if gCO2e < 1000.0:
  286 + format = '%.3f g CO2e' % (gCO2e)
  287 + elif seconds < 1.0e6:
  288 + format = '%.3f kg CO2e' % (gCO2e/1000.0)
  289 + else:
  290 + format = '%.3f t CO2e' % (gCO2e/1.0e6)
  291 +
  292 + # Return format
  293 + return format
  294 +
  295 + # Log global statistics
  296 + def _global_statistics(self, statistics):
  297 + """
  298 + Log global statistics
  299 +
  300 + Parameters
  301 + ----------
  302 + statistics : dict
  303 + Statistics dictionary
  304 + """
  305 + # Log header
  306 + self._log_header1(gammalib.TERSE, 'Global statistics')
  307 +
  308 + # Derive information
  309 + tstart = gammalib.GTime(statistics['use_start'])
  310 + tstop = gammalib.GTime(statistics['use_stop'])
  311 + duration = tstop - tstart
  312 + if statistics['cpu'] != 0.0:
  313 + ci_cpu = statistics['gCO2e']/(statistics['cpu']/3600.0)
  314 + else:
  315 + ci_cpu = 0.0
  316 + if duration != 0.0:
  317 + fp_dur = statistics['gCO2e']/(duration * gammalib.sec2day)
  318 + else:
  319 + fp_dur = 0.0
  320 + fp_yr = fp_dur * 365.25
  321 + dur_str = self._format_time(duration)
  322 + if statistics['wall'] != 0.0:
  323 + load_str = '%.1f %%' % (statistics['cpu']/statistics['wall']*100.0)
  324 + else:
  325 + load_str = 'undefined'
  326 + ci_cpu_str = self._format_footprint(ci_cpu) + ' / CPU hour'
  327 + fp_dur_str = self._format_footprint(fp_dur) + ' / day'
  328 + fp_yr_str = self._format_footprint(fp_yr) + ' / year'
  329 + wall_str = self._format_time(statistics['wall'])
  330 + cpu_str = self._format_time(statistics['cpu'])
  331 + gCO2e_str = self._format_footprint(statistics['gCO2e'])
  332 + date_str = '%s - %s' % (statistics['start'], statistics['stop'])
  333 + use_str = '%s - %s' % (statistics['use_start'], statistics['use_stop'])
  334 +
  335 + # Log report information
  336 + self._log_value(gammalib.NORMAL, 'Creation date', statistics['creation'])
  337 + self._log_value(gammalib.NORMAL, 'Last statistics update', statistics['modified'])
  338 + self._log_value(gammalib.NORMAL, 'Statistics date interval', date_str)
  339 + self._log_value(gammalib.NORMAL, 'Used date interval', use_str)
  340 + self._log_value(gammalib.NORMAL, 'Duration of used interval', dur_str)
  341 + self._log_value(gammalib.NORMAL, 'Total number of ctool runs', statistics['calls'])
  342 + self._log_value(gammalib.NORMAL, 'Total wall clock time', wall_str)
  343 + self._log_value(gammalib.NORMAL, 'Total CPU time', cpu_str)
  344 + self._log_value(gammalib.NORMAL, 'Average CPU load', load_str)
  345 + self._log_value(gammalib.NORMAL, 'Total carbon footprint', gCO2e_str)
  346 + self._log_value(gammalib.NORMAL, 'Average carbon intensity', ci_cpu_str)
  347 + self._log_value(gammalib.NORMAL, 'Average daily footprint', fp_dur_str)
  348 + self._log_value(gammalib.NORMAL, 'Expected annual footprint', fp_yr_str)
  349 +
  350 + # Return
  351 + return
  352 +
  353 + # Log daily statistics
  354 + def _daily_statistics(self, statistics):
  355 + """
  356 + Log daily statistics
  357 +
  358 + Parameters
  359 + ----------
  360 + statistics : dict
  361 + Statistics dictionary
  362 + """
  363 + # Log header
  364 + self._log_header1(gammalib.TERSE, 'Daily statistics')
  365 +
  366 + # Log daily carbon footprint statistics
  367 + self._log_header3(gammalib.NORMAL, 'Carbon footprint')
  368 +
  369 + # Loop over daily entries
  370 + for entry in statistics['daily']:
  371 + self._log_value(gammalib.NORMAL, entry['date'], self._format_footprint(entry['gCO2e']))
  372 +
  373 + # Log daily run statistics
  374 + self._log_header3(gammalib.NORMAL, 'ctools or cscript calls')
  375 +
  376 + # Loop over daily entries
  377 + for entry in statistics['daily']:
  378 + self._log_value(gammalib.NORMAL, entry['date'], entry['calls'])
  379 +
  380 + # Log daily carbon footprint statistics
  381 + self._log_header3(gammalib.NORMAL, 'Used wall clock time')
  382 +
  383 + # Loop over daily entries
  384 + for entry in statistics['daily']:
  385 + self._log_value(gammalib.NORMAL, entry['date'], self._format_time(entry['wall']))
  386 +
  387 + # Log daily carbon footprint statistics
  388 + self._log_header3(gammalib.NORMAL, 'Used CPU time')
  389 +
  390 + # Loop over daily entries
  391 + for entry in statistics['daily']:
  392 + self._log_value(gammalib.NORMAL, entry['date'], self._format_time(entry['cpu']))
  393 +
  394 + # Return
  395 + return
  396 +
  397 + # Log tools statistics
  398 + def _tools_statistics(self, statistics):
  399 + """
  400 + Log tools statistics
  401 +
  402 + Parameters
  403 + ----------
  404 + statistics : dict
  405 + Statistics dictionary
  406 + """
  407 + # Get Python version information
  408 + req_version = (2,4)
  409 + cur_version = sys.version_info
  410 +
  411 + # Log header
  412 + self._log_header1(gammalib.TERSE, 'ctools and cscripts statistics')
  413 +
  414 + # Log daily carbon footprint statistics
  415 + self._log_header3(gammalib.NORMAL, 'Carbon footprint')
  416 +
  417 + # Optionally sort list
  418 + if cur_version > req_version:
  419 + sorted_entries = sorted(statistics['tools'], key=lambda d: d['gCO2e'], reverse=True)
  420 + else:
  421 + sorted_entries = statistics['tools']
  422 +
  423 + # Loop over entries
  424 + for i, entry in enumerate(sorted_entries):
  425 + if i < 10:
  426 + level = gammalib.NORMAL
  427 + else:
  428 + level = gammalib.EXPLICIT
  429 + self._log_value(level, entry['name'], self._format_footprint(entry['gCO2e']))
  430 + if len(sorted_entries) > 9 and self['chatter'].integer() < 3:
  431 + self._log_string(gammalib.NORMAL, ' ... (list truncated after 10 entries) ...')
  432 +
  433 + # Log daily run statistics
  434 + self._log_header3(gammalib.NORMAL, 'ctools or cscript calls')
  435 +
  436 + # Optionally sort list
  437 + if cur_version > req_version:
  438 + sorted_entries = sorted(statistics['tools'], key=lambda d: d['calls'], reverse=True)
  439 + else:
  440 + sorted_entries = statistics['tools']
  441 +
  442 + # Loop over entries
  443 + for i, entry in enumerate(sorted_entries):
  444 + if i < 10:
  445 + level = gammalib.NORMAL
  446 + else:
  447 + level = gammalib.EXPLICIT
  448 + self._log_value(level, entry['name'], entry['calls'])
  449 + if len(sorted_entries) > 9 and self['chatter'].integer() < 3:
  450 + self._log_string(gammalib.NORMAL, ' ... (list truncated after 10 entries) ...')
  451 +
  452 + # Log daily carbon footprint statistics
  453 + self._log_header3(gammalib.NORMAL, 'Used wall clock time')
  454 +
  455 + # Optionally sort list
  456 + if cur_version > req_version:
  457 + sorted_entries = sorted(statistics['tools'], key=lambda d: d['wall'], reverse=True)
  458 + else:
  459 + sorted_entries = statistics['tools']
  460 +
  461 + # Loop over entries
  462 + for i, entry in enumerate(sorted_entries):
  463 + if i < 10:
  464 + level = gammalib.NORMAL
  465 + else:
  466 + level = gammalib.EXPLICIT
  467 + self._log_value(level, entry['name'], self._format_time(entry['wall']))
  468 + if len(sorted_entries) > 9 and self['chatter'].integer() < 3:
  469 + self._log_string(gammalib.NORMAL, ' ... (list truncated after 10 entries) ...')
  470 +
  471 + # Log daily carbon footprint statistics
  472 + self._log_header3(gammalib.NORMAL, 'Used CPU time')
  473 +
  474 + # Optionally sort list
  475 + if cur_version > req_version:
  476 + sorted_entries = sorted(statistics['tools'], key=lambda d: d['cpu'], reverse=True)
  477 + else:
  478 + sorted_entries = statistics['tools']
  479 +
  480 + # Loop over entries
  481 + for i, entry in enumerate(sorted_entries):
  482 + if i < 10:
  483 + level = gammalib.NORMAL
  484 + else:
  485 + level = gammalib.EXPLICIT
  486 + self._log_value(level, entry['name'], self._format_time(entry['cpu']))
  487 + if len(sorted_entries) > 9 and self['chatter'].integer() < 3:
  488 + self._log_string(gammalib.NORMAL, ' ... (list truncated after 10 entries) ...')
  489 +
  490 +
  491 + # Return
  492 + return
  493 +
  494 +
  495 + # Public methods
  496 + def run(self):
  497 + """
  498 + Run the script
  499 + """
  500 + # Switch screen logging on in debug mode
  501 + if self._logDebug():
  502 + self._log.cout(True)
  503 +
  504 + # Get parameters
  505 + self._get_parameters()
  506 +
  507 + # Log header
  508 + self._log_header1(gammalib.TERSE, 'Load statistics data')
  509 +
  510 + # Load statistics
  511 + statistics = self._load_statistics()
  512 +
  513 + # Log statistics
  514 + self._global_statistics(statistics)
  515 + self._daily_statistics(statistics)
  516 + self._tools_statistics(statistics)
  517 +
  518 + # Return
  519 + return
  520 +
  521 + def save(self):
  522 + """
  523 + Save something
  524 + """
  525 + # Write header
  526 + self._log_header1(gammalib.TERSE, 'Save graphics')
  527 +
  528 + # Continue only if filename is valid
  529 + if self['outfile'].is_valid():
  530 +
  531 + # Implement saving of graphics file
  532 + pass
  533 +
  534 + # ... signal that no graphics file was specified
  535 + else:
  536 + self._log_value(gammalib.NORMAL, 'Graphics file', 'not specified')
  537 +
  538 + # Return
  539 + return
  540 +
  541 +
  542 +# ======================== #
  543 +# Main routine entry point #
  544 +# ======================== #
  545 +if __name__ == '__main__':
  546 +
  547 + # Create instance of application
  548 + app = csfootprint(sys.argv)
  549 +
  550 + # Execute application
  551 + app.execute()
doc/source/users/environment.rst
@@ -60,4 +60,104 @@ computation took, and :math:`{\rm Carbon\,\,footprint}` is the carbon footprint @@ -60,4 +60,104 @@ computation took, and :math:`{\rm Carbon\,\,footprint}` is the carbon footprint
60 60
61 The carbon footprint of all ctools and cscript runs are stored in an ASCII file 61 The carbon footprint of all ctools and cscript runs are stored in an ASCII file
62 that you will find in a folder under your home directory, named ``.gamma/statistics.csv``. 62 that you will find in a folder under your home directory, named ``.gamma/statistics.csv``.
  63 +This file is regularly scanned and purged by the GammaLib daemon that creates the
  64 +high-level statistics file ``.gamma/statistics.xml`` that is in the same folder. You may
  65 +display the content of this file using the ``csfootprint`` script:
  66 +
  67 +.. code-block:: bash
  68 +
  69 + $ csfootprint debug=yes
  70 + Start time for report (UTC string, JD, MJD or MET in seconds) [NONE]
  71 + Stop time for report (UTC string, JD, MJD or MET in seconds) [NONE]
  72 + Output graphics file (NONE if no graphics should be generated) [NONE]
  73 + ...
  74 + 2022-02-20T14:38:29: +===================+
  75 + 2022-02-20T14:38:29: | Global statistics |
  76 + 2022-02-20T14:38:29: +===================+
  77 + 2022-02-20T14:38:29: Creation date .............: 2022-02-19T22:09:05
  78 + 2022-02-20T14:38:29: Last statistics update ....: 2022-02-20T14:35:20
  79 + 2022-02-20T14:38:29: Statistics date interval ..: 2022-02-18T22:21:56 - 2022-02-20T14:35:17
  80 + 2022-02-20T14:38:29: Used date interval ........: 2022-02-18T22:21:56 - 2022-02-20T14:35:17
  81 + 2022-02-20T14:38:29: Duration of used interval .: 40.222 hours
  82 + 2022-02-20T14:38:29: Total number of ctool runs : 3104
  83 + 2022-02-20T14:38:29: Total wall clock time .....: 34.200 minutes
  84 + 2022-02-20T14:38:29: Total CPU time ............: 27.543 minutes
  85 + 2022-02-20T14:38:29: Average CPU load ..........: 80.5 %
  86 + 2022-02-20T14:38:29: Total carbon footprint ....: 1.623 g CO2e
  87 + 2022-02-20T14:38:29: Average carbon intensity ..: 3.535 g CO2e / CPU hour
  88 + 2022-02-20T14:38:29: Average daily footprint ...: 0.968 g CO2e / day
  89 + 2022-02-20T14:38:29: Expected annual footprint .: 353.632 g CO2e / year
  90 + 2022-02-20T14:38:29:
  91 + 2022-02-20T14:38:29: +==================+
  92 + 2022-02-20T14:38:29: | Daily statistics |
  93 + 2022-02-20T14:38:29: +==================+
  94 + 2022-02-20T14:38:29: === Carbon footprint ===
  95 + 2022-02-20T14:38:29: 2022-02-18 ................: 1.336 g CO2e
  96 + 2022-02-20T14:38:29: 2022-02-19 ................: 0.010 g CO2e
  97 + 2022-02-20T14:38:29: 2022-02-20 ................: 0.277 g CO2e
  98 + 2022-02-20T14:38:29: === ctools or cscript calls ===
  99 + 2022-02-20T14:38:29: 2022-02-18 ................: 2895
  100 + 2022-02-20T14:38:29: 2022-02-19 ................: 80
  101 + 2022-02-20T14:38:29: 2022-02-20 ................: 129
  102 + 2022-02-20T14:38:29: === Used wall clock time ===
  103 + 2022-02-20T14:38:29: 2022-02-18 ................: 25.483 minutes
  104 + 2022-02-20T14:38:29: 2022-02-19 ................: 1.033 minutes
  105 + 2022-02-20T14:38:29: 2022-02-20 ................: 7.683 minutes
  106 + 2022-02-20T14:38:29: === Used CPU time ===
  107 + 2022-02-20T14:38:29: 2022-02-18 ................: 22.682 minutes
  108 + 2022-02-20T14:38:29: 2022-02-19 ................: 9.895 seconds
  109 + 2022-02-20T14:38:29: 2022-02-20 ................: 4.695 minutes
  110 + 2022-02-20T14:38:29:
  111 + 2022-02-20T14:38:29: +================================+
  112 + 2022-02-20T14:38:29: | ctools and cscripts statistics |
  113 + 2022-02-20T14:38:29: +================================+
  114 + 2022-02-20T14:38:29: === Carbon footprint ===
  115 + 2022-02-20T14:38:29: ctlike ....................: 0.318 g CO2e
  116 + 2022-02-20T14:38:29: cspull ....................: 0.186 g CO2e
  117 + 2022-02-20T14:38:29: csbkgmodel ................: 0.178 g CO2e
  118 + 2022-02-20T14:38:29: ctobssim ..................: 0.172 g CO2e
  119 + 2022-02-20T14:38:29: ctobssim ..................: 0.087 g CO2e
  120 + 2022-02-20T14:38:29: comobsbin .................: 0.081 g CO2e
  121 + 2022-02-20T14:38:29: comlixmap .................: 0.069 g CO2e
  122 + 2022-02-20T14:38:29: ctulimit ..................: 0.064 g CO2e
  123 + 2022-02-20T14:38:29: cstsdist ..................: 0.058 g CO2e
  124 + 2022-02-20T14:38:29: ctselect ..................: 0.044 g CO2e
  125 + 2022-02-20T14:38:29: ... (list truncated after 10 entries) ...
  126 + 2022-02-20T14:38:29: === ctools or cscript calls ===
  127 + 2022-02-20T14:38:29: ctobssim ..................: 1795
  128 + 2022-02-20T14:38:29: ctlike ....................: 220
  129 + 2022-02-20T14:38:29: ctselect ..................: 87
  130 + 2022-02-20T14:38:29: csfootprint ...............: 80
  131 + 2022-02-20T14:38:29: cscaldb ...................: 79
  132 + 2022-02-20T14:38:29: csscs .....................: 55
  133 + 2022-02-20T14:38:29: ctulimit ..................: 54
  134 + 2022-02-20T14:38:29: ctcubemask ................: 51
  135 + 2022-02-20T14:38:29: csphagen ..................: 46
  136 + 2022-02-20T14:38:29: ctbin .....................: 31
  137 + 2022-02-20T14:38:29: ... (list truncated after 10 entries) ...
  138 + 2022-02-20T14:38:29: === Used wall clock time ===
  139 + 2022-02-20T14:38:29: ctlike ....................: 5.367 minutes
  140 + 2022-02-20T14:38:29: cspull ....................: 3.817 minutes
  141 + 2022-02-20T14:38:29: csbkgmodel ................: 3.067 minutes
  142 + 2022-02-20T14:38:29: ctobssim ..................: 2.967 minutes
  143 + 2022-02-20T14:38:29: csfootprint ...............: 2.300 minutes
  144 + 2022-02-20T14:38:29: ctobssim ..................: 1.483 minutes
  145 + 2022-02-20T14:38:29: comobsbin .................: 1.367 minutes
  146 + 2022-02-20T14:38:29: cstsdist ..................: 1.300 minutes
  147 + 2022-02-20T14:38:29: comlixmap .................: 1.183 minutes
  148 + 2022-02-20T14:38:29: ctselect ..................: 1.083 minutes
  149 + 2022-02-20T14:38:29: ... (list truncated after 10 entries) ...
  150 + 2022-02-20T14:38:29: === Used CPU time ===
  151 + 2022-02-20T14:38:29: ctlike ....................: 5.392 minutes
  152 + 2022-02-20T14:38:29: cspull ....................: 3.157 minutes
  153 + 2022-02-20T14:38:29: csbkgmodel ................: 3.029 minutes
  154 + 2022-02-20T14:38:29: ctobssim ..................: 2.921 minutes
  155 + 2022-02-20T14:38:29: ctobssim ..................: 1.469 minutes
  156 + 2022-02-20T14:38:29: comobsbin .................: 1.367 minutes
  157 + 2022-02-20T14:38:29: comlixmap .................: 1.169 minutes
  158 + 2022-02-20T14:38:29: ctulimit ..................: 1.086 minutes
  159 + 2022-02-20T14:38:29: cstsdist ..................: 58.978 seconds
  160 + 2022-02-20T14:38:29: ctselect ..................: 45.005 seconds
  161 + 2022-02-20T14:38:29: ... (list truncated after 10 entries) ...
  162 +
63 163
doc/source/users/reference_manual/csfootprint.rst 0 → 100644
  1 +.. _csfootprint:
  2 +
  3 +csfootprint
  4 +===========
  5 +
  6 +Generates a carbon footprint report for the usage of ctools on your computed.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +This script generates a carbon footprint report based on the usage of ctools
  13 +on your computed. ctools usage statistics are collected in the file
  14 +``~/.gamma/statistics.xml`` that is located in the user's home directory. The
  15 +information file is updated using a dedicated daemon that works in the background
  16 +and collects information about ctools usage.
  17 +
  18 +
  19 +General parameters
  20 +------------------
  21 +
  22 +``(infile = $HOME/.gamma/statistics.xml) [file]``
  23 + Input high-level statistics XML file.
  24 +
  25 +``outfile [file]``
  26 + Output graphics file (``NONE`` if no graphics should be generated).
  27 +
  28 +``tmin [time]``
  29 + Start time for footprint reporting (UTC string, JD, MJD or MET in seconds).
  30 + Start times given in MET seconds are counted with respect to the time
  31 + reference of the input observation(s).
  32 + If ``INDEF``, ``NONE``, ``UNDEF`` or ``UNDEFINED`` is passed as value, the
  33 + report will be generated for the full data provided in the statistics
  34 + file.
  35 +
  36 +``tmax [time]``
  37 + Stop time for footprint reporting (UTC string, JD, MJD or MET in seconds).
  38 + Stop times given in MET seconds are counted with respect to the time
  39 + reference of the input observation(s).
  40 + If ``INDEF``, ``NONE``, ``UNDEF`` or ``UNDEFINED`` is passed as value, the
  41 + report will be generated for the full data provided in the statistics
  42 + file.
  43 +
  44 +
  45 +Standard parameters
  46 +-------------------
  47 +
  48 +``(chatter = 2) [integer]``
  49 + Verbosity of the executable:
  50 + ``chatter = 0``: no information will be logged
  51 +
  52 + ``chatter = 1``: only errors will be logged
  53 +
  54 + ``chatter = 2``: errors and actions will be logged
  55 +
  56 + ``chatter = 3``: report about the task execution
  57 +
  58 + ``chatter = 4``: detailed report about the task execution
  59 +
  60 +``(clobber = yes) [boolean]``
  61 + Specifies whether an existing output file should be overwritten.
  62 +
  63 +``(debug = no) [boolean]``
  64 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  65 +
  66 +``(mode = ql) [string]``
  67 + Mode of automatic parameters (default is ``ql``, i.e. "query and learn").
  68 +
  69 +``(logfile = csfootprint.log) [string]``
  70 + Name of log file.
  71 +
  72 +
  73 +Related tools or scripts
  74 +------------------------
  75 +
  76 +None
doc/source/users/reference_manual/index.rst
@@ -57,6 +57,7 @@ CTA and IACT analysis tools and scripts @@ -57,6 +57,7 @@ CTA and IACT analysis tools and scripts
57 ctskymap --- Generates sky map <ctskymap> 57 ctskymap --- Generates sky map <ctskymap>
58 csbkgmodel --- Generates background model for 3D analysis <csbkgmodel> 58 csbkgmodel --- Generates background model for 3D analysis <csbkgmodel>
59 csebins --- Generates energy boundaries for stacked analysis <csebins> 59 csebins --- Generates energy boundaries for stacked analysis <csebins>
  60 + csfootprint --- Generates carbon footprint report <csfootprint>
60 csobsdef --- Generates observation definition file <csobsdef> 61 csobsdef --- Generates observation definition file <csobsdef>
61 csobsselect --- Select observations from observation definition file <csobsselect> 62 csobsselect --- Select observations from observation definition file <csobsselect>
62 csphagen --- Generates PHA, ARF, RMF files based on source/background regions <csphagen> 63 csphagen --- Generates PHA, ARF, RMF files based on source/background regions <csphagen>
test/data/statistics.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<statistics title="High-level statistic">
  3 + <header>
  4 + <dates>
  5 + <creation>2022-02-19T22:09:05</creation>
  6 + <modified>2022-02-20T14:35:20</modified>
  7 + <start>2022-02-18T22:21:56</start>
  8 + <stop>2022-02-20T14:35:17</stop>
  9 + </dates>
  10 + <countries>
  11 + <country>FR</country>
  12 + </countries>
  13 + </header>
  14 + <data>
  15 + <daily>
  16 + <date>
  17 + <value>2022-02-18</value>
  18 + <tools>
  19 + <test_GApplication version="1.0.0" calls="10" wall="0" cpu="0.034568" gCO2e="3.6524768e-05" />
  20 + <ctobssim version="2.0.0.dev" calls="1795" wall="178" cpu="175.230736" gCO2e="0.172060195882" />
  21 + <ctselect version="2.0.0.dev" calls="87" wall="65" cpu="45.005446" gCO2e="0.0441931424436" />
  22 + <ctphase version="2.0.0.dev" calls="13" wall="0" cpu="0.162489" gCO2e="0.0001595595941" />
  23 + <ctfindvar version="2.0.0.dev" calls="9" wall="3" cpu="2.356012" gCO2e="0.002313321049" />
  24 + <ctbin version="2.0.0.dev" calls="31" wall="6" cpu="4.978268" gCO2e="0.004889514038" />
  25 + <ctlike version="2.0.0.dev" calls="220" wall="322" cpu="323.513057" gCO2e="0.31765157135" />
  26 + <cttsmap version="2.0.0.dev" calls="10" wall="12" cpu="10.679273" gCO2e="0.01048572233" />
  27 + <ctmodel version="2.0.0.dev" calls="28" wall="6" cpu="4.591355" gCO2e="0.004508190556" />
  28 + <ctskymap version="2.0.0.dev" calls="19" wall="1" cpu="0.433249" gCO2e="0.0004254149905" />
  29 + <ctexpcube version="2.0.0.dev" calls="24" wall="6" cpu="4.030692" gCO2e="0.00395767278" />
  30 + <ctpsfcube version="2.0.0.dev" calls="23" wall="5" cpu="3.274088" gCO2e="0.003214774076" />
  31 + <ctedispcube version="2.0.0.dev" calls="14" wall="3" cpu="3.050093" gCO2e="0.002994823833" />
  32 + <ctbkgcube version="2.0.0.dev" calls="23" wall="6" cpu="2.757245" gCO2e="0.002707299323" />
  33 + <ctmapcube version="2.0.0.dev" calls="14" wall="14" cpu="4.75437" gCO2e="0.0046682128217" />
  34 + <ctcubemask version="2.0.0.dev" calls="51" wall="8" cpu="1.13723" gCO2e="0.0011201495309" />
  35 + <ctbutterfly version="2.0.0.dev" calls="5" wall="1" cpu="0.759734" gCO2e="0.0007459676696" />
  36 + <ctulimit version="2.0.0.dev" calls="54" wall="64" cpu="65.159264" gCO2e="0.06397913951" />
  37 + <cterror version="2.0.0.dev" calls="10" wall="25" cpu="25.103675" gCO2e="0.02464868358" />
  38 + <ctprob version="2.0.0.dev" calls="11" wall="4" cpu="1.608447" gCO2e="0.0015793075709" />
  39 + <cscript_test version="2.0.0.dev" calls="27" wall="3" cpu="0.913572" gCO2e="0.000897810804" />
  40 + <ctobservation_test version="2.0.0.dev" calls="2" wall="0" cpu="0.002656" gCO2e="2.608842e-06" />
  41 + <ctlikelihood_test version="2.0.0.dev" calls="1" wall="0" cpu="0.000474" gCO2e="4.673725e-07" />
  42 + <csadd2caldb version="2.0.0.dev" calls="7" wall="0" cpu="0.082939" gCO2e="8.1443581e-05" />
  43 + <csbkgmodel version="2.0.0.dev" calls="16" wall="184" cpu="181.730569" gCO2e="0.178436729885" />
  44 + <cscaldb version="2.0.0.dev" calls="6" wall="0" cpu="0.020241" gCO2e="1.9882967e-05" />
  45 + <csebins version="2.0.0.dev" calls="3" wall="1" cpu="0.586342" gCO2e="0.000575717516" />
  46 + <csobsselect version="2.0.0.dev" calls="18" wall="1" cpu="0.091911" gCO2e="9.1630531e-05" />
  47 + <cslightcrv version="2.0.0.dev" calls="27" wall="45" cpu="29.142719" gCO2e="0.028614540668" />
  48 + <csphagen version="2.0.0.dev" calls="46" wall="38" cpu="33.605548" gCO2e="0.032996623152" />
  49 + <csmodelinfo version="2.0.0.dev" calls="4" wall="2" cpu="0.510316" gCO2e="0.000501071409" />
  50 + <csmodelmerge version="2.0.0.dev" calls="6" wall="0" cpu="0.035814" gCO2e="3.5175674e-05" />
  51 + <csmodelselect version="2.0.0.dev" calls="3" wall="0" cpu="0.032228" gCO2e="3.164878e-05" />
  52 + <csmodelsois version="2.0.0.dev" calls="4" wall="5" cpu="4.443827" gCO2e="0.004363287526" />
  53 + <csobs2caldb version="2.0.0.dev" calls="4" wall="0" cpu="0.536876" gCO2e="0.00052715198" />
  54 + <csobsdef version="2.0.0.dev" calls="5" wall="2" cpu="2.083649" gCO2e="0.002045889685" />
  55 + <csobsinfo version="2.0.0.dev" calls="5" wall="3" cpu="2.06328" gCO2e="0.00202735977" />
  56 + <csphasecrv version="2.0.0.dev" calls="26" wall="29" cpu="16.067829" gCO2e="0.015776636533" />
  57 + <cspull version="2.0.0.dev" calls="24" wall="6" cpu="2.647948" gCO2e="0.002599984392" />
  58 + <csresmap version="2.0.0.dev" calls="6" wall="0" cpu="0.614617" gCO2e="0.0006034869" />
  59 + <csresspec version="2.0.0.dev" calls="8" wall="3" cpu="3.078816" gCO2e="0.003023022045" />
  60 + <csroot2caldb version="2.0.0.dev" calls="2" wall="1" cpu="0.036487" gCO2e="3.58296e-05" />
  61 + <cssens version="2.0.0.dev" calls="12" wall="25" cpu="12.589562" gCO2e="0.012361392076" />
  62 + <csspec version="2.0.0.dev" calls="18" wall="64" cpu="43.689946" gCO2e="0.042898087855" />
  63 + <cssrcdetect version="2.0.0.dev" calls="3" wall="1" cpu="0.155595" gCO2e="0.00015277975" />
  64 + <cstsdist version="2.0.0.dev" calls="17" wall="78" cpu="58.977613" gCO2e="0.057908662799" />
  65 + <cstsmapmerge version="2.0.0.dev" calls="7" wall="0" cpu="0.054628" gCO2e="5.3648664e-05" />
  66 + <cstsmapsplit version="2.0.0.dev" calls="7" wall="3" cpu="0.686096" gCO2e="0.000673666381" />
  67 + <csviscube version="2.0.0.dev" calls="2" wall="1" cpu="1.127427" gCO2e="0.0011069963" />
  68 + <csscs version="2.0.0.dev" calls="55" wall="32" cpu="23.301421" gCO2e="0.022879160613" />
  69 + <csworkflow version="2.0.0.dev" calls="3" wall="22" cpu="21.524805" gCO2e="0.021134671" />
  70 + <mputils_test version="2.0.0.dev" calls="9" wall="0" cpu="0.019627" gCO2e="1.92879525e-05" />
  71 + <csfindobs version="2.0.0.dev" calls="5" wall="0" cpu="0.03152" gCO2e="3.0956552e-05" />
  72 + <csiactcopy version="2.0.0.dev" calls="8" wall="2" cpu="0.12279" gCO2e="0.000120576215" />
  73 + <csiactdata version="2.0.0.dev" calls="4" wall="0" cpu="0.023479" gCO2e="2.3057371e-05" />
  74 + <csiactobs version="2.0.0.dev" calls="9" wall="7" cpu="4.970589" gCO2e="0.004880509978" />
  75 + <comobsselect version="2.0.0.dev" calls="2" wall="1" cpu="0.118271" gCO2e="0.0001161293" />
  76 + <comobsbin version="2.0.0.dev" calls="3" wall="82" cpu="82.020818" gCO2e="0.080534191756" />
  77 + <comobsback version="2.0.0.dev" calls="5" wall="21" cpu="21.588201" gCO2e="0.02119691057" />
  78 + <comobsmodel version="2.0.0.dev" calls="3" wall="1" cpu="0.475343" gCO2e="0.000466731257" />
  79 + <comobsadd version="2.0.0.dev" calls="3" wall="2" cpu="1.467164" gCO2e="0.00144057658" />
  80 + <comobsres version="2.0.0.dev" calls="3" wall="19" cpu="17.898668" gCO2e="0.017574257417" />
  81 + <comobssim version="2.0.0.dev" calls="3" wall="1" cpu="0.355431" gCO2e="0.000348993711" />
  82 + <comlixfit version="2.0.0.dev" calls="5" wall="44" cpu="42.639466" gCO2e="0.041866632735" />
  83 + <comlixmap version="2.0.0.dev" calls="5" wall="71" cpu="70.110307" gCO2e="0.06883955744" />
  84 + <comsrcdetect version="2.0.0.dev" calls="3" wall="0" cpu="0.035303" gCO2e="3.4668041e-05" />
  85 + </tools>
  86 + </date>
  87 + <date>
  88 + <value>2022-02-19</value>
  89 + <tools>
  90 + <cscaldb version="2.0.0.dev" calls="79" wall="27" cpu="2.098166" gCO2e="0.00206024862" />
  91 + <ctobssim version="2.0.0.dev" calls="1" wall="35" cpu="7.797325" gCO2e="0.007656001" />
  92 + </tools>
  93 + </date>
  94 + <date>
  95 + <value>2022-02-20</value>
  96 + <tools>
  97 + <ctobssim version="2.0.0.dev" calls="14" wall="89" cpu="88.139225" gCO2e="0.086544736" />
  98 + <ctlike version="2.0.0.dev" calls="14" wall="1" cpu="2.907895" gCO2e="0.0028552129" />
  99 + <cspull version="2.0.0.dev" calls="10" wall="229" cpu="189.407517" gCO2e="0.1859745197" />
  100 + <test_GApplication version="1.0.0" calls="4" wall="1" cpu="0.020321" gCO2e="2.2644983e-05" country="FR" />
  101 + <cscaldb version="2.0.0.dev" country="FR" calls="7" wall="3" cpu="0.194611" gCO2e="0.00019109055" />
  102 + <csfootprint version="2.0.0.dev" country="FR" calls="80" wall="138" cpu="1.05496" gCO2e="0.00103598216" />
  103 + </tools>
  104 + </date>
  105 + </daily>
  106 + <countries>
  107 + <FR version="2.0.0.dev" calls="83" wall="140" cpu="1.136547" gCO2e="0.00111609432" />
  108 + </countries>
  109 + <versions>
  110 + <2.0.0.dev calls="82" wall="138" cpu="1.109517" gCO2e="0.00108955228" />
  111 + </versions>
  112 + </data>
  113 +</statistics>
test/test_csfootprint.py 0 → 100644
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This scripts performs unit tests for the csfootprint script.
  4 +#
  5 +# Copyright (C) 2022 Juergen Knoedlseder
  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 csfootprint script #
  29 +# ================================= #
  30 +class Test(test):
  31 + """
  32 + Test class for csfootprint script
  33 +
  34 + This test class makes unit tests for the csfootprint script 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 + # Set members
  47 + self._infile = self._datadir + '/statistics.xml'
  48 +
  49 + # Return
  50 + return
  51 +
  52 + # Set test functions
  53 + def set(self):
  54 + """
  55 + Set all test functions
  56 + """
  57 + # Set test name
  58 + self.name('csfootprint')
  59 +
  60 + # Append tests
  61 + self.append(self._test_cmd, 'Test csfootprint on command line')
  62 + self.append(self._test_python, 'Test csfootprint from Python')
  63 + self.append(self._test_pickeling, 'Test csfootprint pickeling')
  64 +
  65 + # Return
  66 + return
  67 +
  68 + # Test csfootprint on command line
  69 + def _test_cmd(self):
  70 + """
  71 + Test csfootprint on the command line
  72 + """
  73 + # Set script name
  74 + csfootprint = self._script('csfootprint')
  75 +
  76 + # Setup csfootprint command
  77 + cmd = csfootprint+' infile="'+self._infile+'" outfile=NONE tmin=NONE'+ \
  78 + ' tmax=NONE logfile="csfootprint_cmd1.log" chatter=1'
  79 +
  80 + # Check if execution was successful
  81 + self.test_value(self._execute(cmd), 0,
  82 + 'Check successful execution from command line')
  83 +
  84 + # Setup csfootprint command
  85 + cmd = csfootprint+' infile="file_that_does_not_exist.xml" outfile=NONE tmin=NONE'+ \
  86 + ' tmax=NONE logfile="csfootprint_cmd1.log" chatter=1'
  87 +
  88 + # Check if execution was successful
  89 + self.test_assert(self._execute(cmd, success=False) != 0,
  90 + 'Check invalid input file when executed from command line')
  91 +
  92 + # Check csfootprint --help
  93 + self._check_help(csfootprint)
  94 +
  95 + # Return
  96 + return
  97 +
  98 + # Test csfootprint from Python
  99 + def _test_python(self):
  100 + """
  101 + Test csfootprint from Python
  102 + """
  103 + # Allocate csfootprint
  104 + script = cscripts.csfootprint()
  105 +
  106 + # Check that saving does not nothing
  107 + script['infile'] = self._infile
  108 + script['outfile'] = 'NONE'
  109 + script['tmin'] = 'NONE'
  110 + script['tmax'] = 'NONE'
  111 + script['logfile'] = 'csfootprint_py0.log'
  112 + script['chatter'] = 2
  113 +
  114 + # Run csfootprint script
  115 + script.logFileOpen()
  116 + script.run()
  117 +
  118 + # Check result
  119 + self._check_result(script)
  120 +
  121 + # Return
  122 + return
  123 +
  124 + # Test csfootprint pickeling
  125 + def _test_pickeling(self):
  126 + """
  127 + Test csfootprint pickeling
  128 + """
  129 + # Perform pickeling test of empty class
  130 + self._pickeling(cscripts.csfootprint())
  131 +
  132 + # Setup script for pickling text
  133 + script = cscripts.csfootprint()
  134 + script['infile'] = self._infile
  135 + script['outfile'] = 'NONE'
  136 + script['tmin'] = 'NONE'
  137 + script['tmax'] = 'NONE'
  138 + script['logfile'] = 'csfootprint_py1_pickle.log'
  139 + script['chatter'] = 2
  140 +
  141 + # Perform pickeling tests of filled class
  142 + obj = self._pickeling(script)
  143 +
  144 + # Run csfootprint script and save result
  145 + obj.logFileOpen() # Make sure we get a log file
  146 + obj.run()
  147 + obj.save()
  148 +
  149 + # Check result
  150 + self._check_result(script)
  151 +
  152 + # Return
  153 + return
  154 +
  155 + # Check csfootprint result
  156 + def _check_result(self, script):
  157 + """
  158 + Check content of script
  159 +
  160 + Parameters
  161 + ----------
  162 + script : `~cscripts.csfootprint`
  163 + csfootprint instance
  164 + """
  165 + # TODO: Implement test on script result
  166 +
  167 + # Return
  168 + return
test/test_python_cscripts.py
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 # ========================================================================== 2 # ==========================================================================
3 # This scripts performs unit tests for cscripts 3 # This scripts performs unit tests for cscripts
4 # 4 #
5 -# Copyright (C) 2016-2021 Juergen Knoedlseder 5 +# Copyright (C) 2016-2022 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
@@ -28,6 +28,7 @@ import test_cscaldb @@ -28,6 +28,7 @@ import test_cscaldb
28 import test_csadd2caldb 28 import test_csadd2caldb
29 import test_csbkgmodel 29 import test_csbkgmodel
30 import test_csebins 30 import test_csebins
  31 +import test_csfootprint
31 import test_csfindobs 32 import test_csfindobs
32 import test_csinfo 33 import test_csinfo
33 import test_cslightcrv 34 import test_cslightcrv
@@ -146,6 +147,7 @@ def test(installed=False, debug=False): @@ -146,6 +147,7 @@ def test(installed=False, debug=False):
146 test_cstsmapsplit.Test(), 147 test_cstsmapsplit.Test(),
147 test_csviscube.Test(), 148 test_csviscube.Test(),
148 test_csscs.Test(), 149 test_csscs.Test(),
  150 + test_csfootprint.Test(),
149 test_csworkflow.Test(), 151 test_csworkflow.Test(),
150 test_obsutils.Test(), 152 test_obsutils.Test(),
151 test_mputils.Test()] 153 test_mputils.Test()]