ATLAS Offline Software
perfmonmt-refit.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 # Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
4 
5 import argparse
6 import json
7 import numpy
8 import sys
9 
10 # Helper for range parsing
11 def parse_range(string):
12  result = string.split(',')
13  if len(result) != 2 or not result[0].isnumeric() or not result[1].isnumeric() or int(result[0]) >= int(result[1]):
14  print(f"Invalid input range {string} (must be N,M w/ N/M as numbers and M>N)...")
15  sys.exit(1)
16  else:
17  return result
18 
19 # Main function
20 if '__main__' in __name__:
21 
22  # Parse the user input
23  parser = argparse.ArgumentParser(description = 'Script to re-fit PerfMonMTSvc measurements')
24 
25  parser.add_argument('-i', '--input', type = str, required = True,
26  help = 'PerfMonMTSvc JSON file')
27  parser.add_argument('-r', '--range', type = parse_range, dest = 'range',
28  help = 'A comma comma-separated list that determines the '
29  'minimum and maximum event numbers over which one wants '
30  'to perform the fit (e.g. 10,100)')
31  parser.add_argument('-f', '--slice', type = float, dest = 'slice',
32  help = 'A (python) slice defining the event-range over '
33  'to which one wants to perform the fit from the end '
34  '(default: 0.8, i.e. last 80 percent of the events)')
35  parser.add_argument('-o', '--observable', dest = 'obs', nargs = '?', default = 'pss',
36  choices = ['vmem', 'rss', 'pss', 'swap', 'cpuTime', 'wallTime'],
37  help = 'Variable to fit')
38  parser.add_argument('-m', '--minimal', dest = 'minimal', action = 'store_true',
39  help = 'Prints only the result')
40  parser.add_argument('-d', '--debug', dest = 'debug', action = 'store_true',
41  help = 'Enables debug printouts')
42 
43  args = parser.parse_args()
44 
45  # Check the argument settings
46  # User needs to pick either a range or a slice
47  if args.range and args.slice:
48  print('Please specify either range or slice fitting - not both, quitting...')
49  sys.exit(1)
50  # If neither a slice nor a range provided, set a slice
51  if not args.range and not args.slice:
52  args.slice = 0.8
53  # The slice range should be >0. and <1.
54  if args.slice and (float(args.slice) > 1. or float(args.slice) < 0.):
55  print('Slice cannot be outside [0, 1], resetting to 1...')
56  args.slice = 1.
57 
58  # Load the data, perform the fit, and print the requested information
59  with(open(args.input)) as json_file:
60 
61  data = json.load(json_file)
62 
63  # Check if data exist
64  if 'eventLevel' not in data or args.obs not in data['eventLevel']['1']:
65  print('Data do not contain the necessary information, please check'
66  ' the input file or the provided observable...')
67  sys.exit(1)
68 
69  # Fill the arrays
70  x, y = [], []
71 
72  for entry in sorted(data['eventLevel'], key=float):
73  x.append(entry)
74  y.append(data['eventLevel'][entry][args.obs])
75 
76  # Find the units
77  units = 'ms/event' if 'time' in args.obs.lower() else 'kb/event'
78 
79  # Find the indices over which the fit will be performed
80  if args.range:
81  if (args.range[0] not in x or args.range[1] not in x):
82  print(f"Provided range parameters {args.range} are not in data, will use slicing w/ 0.8...")
83  idx_min = round(0.2*len(x))
84  idx_max = len(x)-1
85  else:
86  idx_min = x.index(args.range[0])
87  idx_max = x.index(args.range[1])
88  else:
89  idx_min = round((1-args.slice)*len(x))
90  idx_max = len(x)-1
91 
92  # Print some debug information if asked for
93  if args.debug:
94  print(f"DEBUG:: Inputs were {args.range} and {args.slice}")
95  print(f"DEBUG:: Original data has {len(x)} points:")
96  print(f"DEBUG:: >> x : {x}")
97  print(f"DEBUG:: >> y : {y}")
98  print(f"DEBUG:: Computed minimum and maximum indices are {idx_min} and {idx_max}, respectively")
99  print(f"DEBUG:: Sliced data has {len(x[idx_min:idx_max+1])} points:")
100  print(f"DEBUG:: >> x : {x[idx_min:idx_max+1]}")
101  print(f"DEBUG:: >> y : {y[idx_min:idx_max+1]}")
102 
103  # Perform the fit
104  n_tot = len(x[idx_min:idx_max+1]) # Total number of points used in the fit
105  coeffs = numpy.lib.polyfit( numpy.array(x[idx_min:idx_max+1], numpy.float),
106  numpy.array(y[idx_min:idx_max+1], numpy.float) , deg = 1 )
107 
108  # Print the final result
109  if not args.minimal:
110  print('='*70)
111  print(f" [ Begin - End ] : Slope of {args.obs} in {units} using {n_tot} points")
112  print('='*70)
113  print(f" [ {x[idx_min]:>5} - {x[idx_max]:>5} ] : {coeffs[0]:^.2f}")
114  print('='*70)
115  else:
116  print(f"{x[idx_min]},{x[idx_max]},{coeffs[0]:^.2f}")
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
perfmonmt-refit.parse_range
parse_range
Definition: perfmonmt-refit.py:27
perfmonmt-refit.float
float
Definition: perfmonmt-refit.py:31
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename T::value_type > sorted(T begin, T end)
Helper function to create a sorted vector from an unsorted one.
Trk::open
@ open
Definition: BinningType.h:40
dbg::print
void print(std::FILE *stream, std::format_string< Args... > fmt, Args &&... args)
Definition: SGImplSvc.cxx:70