ATLAS Offline Software
CopyBlobFromCrest.py
Go to the documentation of this file.
1 #!/bin/env python
2 
3 # Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
4 #
5 # CopyBlobFromCrest.py
6 """
7 @author Laura.Sargsyan@cern.ch 2025-04-16
8 CopyBlobFromCrest.py - Tool for retrieving TileCal calibration data from CREST
9 
10 Description:
11 ------------
12 This script connects to the CREST service to fetch calibration data (blobs) for TileCal. Users can specify which calibration tag, run number, luminosity
13 block, and channels to retrieve for fine-grained control of the data. The fetched calibration data is then saved into a JSON file whose name typically
14 includes metadata such as the tag, run, and luminosity block.
15 
16 Command-line Parameters:
17 -----------------------
18 -s, --server
19  CREST server URL. Default: http://crest-j23.cern.ch:8080/api-v5.0
20 
21 -t, --tag
22  Calibration tag to fetch from CREST (e.g., TileOfl02CalibCes-RUN2-UPD4-29). Default: TileOfl02CalibCes-RUN2-UPD4-29)
23 
24 -r, --run
25  The run number. Default: 2147483647 (retrieves the latest IOV).
26 
27 -l, --lumi
28  Luminosity block number. Default: 0
29 
30 -c, --channel
31  Space or comma-separated list of COOL channel IDs to retrieve (e.g., 0,1,2). Default: [0..275] plus channel 1000.
32 
33 -o, --output
34  Output filename (JSON). If omitted, a default is generated, typically
35  structured as: <tag>.<run>.<lumi>.json. For example: UPD4.2147483647.0.json
36 
37 Usage Example:
38 --------------
39 python CopyBlobFromCrest.py --tag TileOfl02CalibCes-RUN2-UPD4-29 --channel 0,1,2 --output fetched_data.json
40 
41 What the Script Does:
42 ---------------------
43 1. Connects to the specified CREST service (-s/--server).
44 2. Fetches calibration data (blobs) for the given tag, run, lumi block,
45  and channels.
46 3. Saves the data into a JSON file with a filename either provided via
47  --output or auto-generated from the tag, run, and lumi.
48 
49 The output JSON file stores the calibration data keyed by the channel IDs.
50 Each channel’s data includes the calibration blob(s) retrieved from CREST.
51 """
52 
53 import json
54 from TileCalibBlobPython import TileCalibCrest
55 from TileCalibBlobPython.TileCalibLogger import getLogger
56 import argparse
57 import logging
58 
59 # Logger setup (reusing the framework's logger)
60 log = getLogger("CopyBlobFromCrest")
61 logLevel = logging.DEBUG
62 log.setLevel(logLevel)
63 
64 log1 = getLogger("TileCalibTools")
65 log1.setLevel(logLevel)
66 schema = 'CREST'
67 
68 def fetch_calib_data(server, tag, run, lumi, channels):
69  """
70  Fetch calibration data from TileBlobReaderCrest.
71 
72  Args:
73  server (str): CREST server URL.
74  tag (str): Tag identifying the calibration data.
75  run (int): Run number to fetch data for.
76  lumi (int): Lumi block to fetch data for.
77  channels (list of int): List of COOL channel numbers.
78 
79  Returns:
80  list: List of calibration data entries retrieved.
81  """
82  try:
83  log.info("Initializing TileBlobReaderCrest...")
84  folderTag = tag
85  if folderTag.startswith("Tile") or folderTag.startswith("CALO"):
86  folderPath = ""
87 
88  # Create the TileBlobReaderCrest object and pass the relevant arguments
89  blob_reader = TileCalibCrest.TileBlobReaderCrest(schema, folderPath, tag, run, lumi,copyBlob=True)
90  # blob_reader = TileCalibCrest.TileBlobReaderCrest(server, tag, run, lumi, min(channels), max(channels))
91 
92 
93  blobs = blob_reader.payload # Retrieve the calibration data
94  log.info(f"Successfully fetched {len(blobs)} calibration entries.")
95  return blobs
96 
97  except Exception as e:
98  log.error(f"Error while retrieving calibration data: {e}")
99  raise
100 
101 def process_channel_list(channel_list):
102  """
103  Process a list of channel identifiers, handling comma-separated values.
104 
105  Args: channel_list (list): List of channel identifiers, which may contain comma-separated value
106  Returns: list: Processed list of individual channel identifiers
107  """
108  processed_channels = []
109  if channel_list:
110  for item in channel_list:
111  # If an item contains commas, split it and add each part
112  if isinstance(item, str) and ',' in item:
113  parts = [part.strip() for part in item.split(',')]
114  processed_channels.extend(parts)
115  else:
116  processed_channels.append(str(item))
117 
118  return processed_channels
119 
120 
121 def output_filename(args):
122  if not args.output:
123  # Format run and lumi as strings to ensure they're properly handled
124  run_str = str(args.run)
125  lumi_str = str(args.lumi)
126 
127  # Construct filename from components
128  tag = args.tag if args.tag else "default"
129 
130  # Add channel numbers in name if they were defined in args
131  if hasattr(args, 'channel') and args.channel:
132  # Process the channel list using the utility function
133  processed_channels = args.channel[0].split(',')
134  channel_str = '-'.join(processed_channels)
135  return f"{tag}.{run_str}.{lumi_str}.ch{channel_str}.json"
136  else:
137  # Return filename without channel information if default value is used
138  return f"{tag}.{run_str}.{lumi_str}.json"
139 
140  return args.output
141 
142 def save_calib_data_to_file(blobs, output_file, requested_channels=None):
143  """
144  Save fetched calibration data to a file.
145  Parameters:
146  -----------
147  blobs : dict containing calibration data blobs
148  output_file : str Path to the output file where data will be saved
149  requested_channels : list, optional
150  List of specific channels to include in the output file.
151  If None, all channels from the blobs will be included.
152  """
153  try:
154  log.info(f"Saving calibration data to {output_file}")
155 
156  if requested_channels is not None:
157  # Process the channel list using the utility function
158  processed_channels = set(process_channel_list(requested_channels))
159 
160  # Filter blobs to only include requested channels
161  filtered_blobs = {channel: data for channel, data in blobs.items()
162  if channel in processed_channels}
163 
164  blobs_to_save = filtered_blobs
165  else:
166  # Save all blobs if no channel filtering is requested
167  blobs_to_save = blobs
168 
169  with open(output_file, "w") as f:
170  json.dump(blobs_to_save, f)
171 
172  log.info("Calibration data successfully written to output file.")
173 
174  except Exception as e:
175  log.error(f"Error while saving calibration data: {e}")
176  raise
178  """
179  Set up command-line argument parser.
180 
181  Returns:
182  argparse.ArgumentParser: Configured argument parser
183  """
184  parser = argparse.ArgumentParser(description="Read TileCal blobs from CREST and convert them to JSON format.")
185 
186  parser = argparse.ArgumentParser(description="Read TileCal blobs from CREST and convert them to JSON format.")
187  parser.add_argument(
188  "-s", "--server",
189  default="http://crest-j23.cern.ch:8080/api-v5.0",
190  help="Specify CREST server URL (default is %(default)s)."
191  )
192 
193  parser.add_argument(
194  "-t", "--tag",
195  default='TileOfl02CalibCes-RUN2-UPD4-29',
196  help="Specify the tag to use (e.g., RUN2-UPD4-04). Default is %(default)s."
197  )
198  parser.add_argument(
199  "-r", "--run",
200  type=int,
201  default=2147483647, # Largest IOV value (default for latest run)
202  help="Specify the run number (default is the latest IOV, %(default)s)."
203  )
204  parser.add_argument(
205  "-l", "--lumi",
206  type=int,
207  default=0,
208  help="Specify the lumi block number (default is %(default)s)."
209  )
210  parser.add_argument(
211  "-c", "--channel",
212  type=str, # Changed to str to accept comma values
213  nargs="+",
214  help="Specify COOL channels (default includes all channels from 0-275 and 1000). Use space or comma-separated values."
215  )
216 
217  parser.add_argument(
218  "-o", "--output",
219  default=None,
220  help="Specify the output JSON file for saving calibration data. If not provided, will use '[tag].[run].[lumi].json'"
221  )
222 
223  # Parse arguments from the command line
224  args = parser.parse_args()
225 
226  return args
227 
228 if __name__ == "__main__":
229 
231  try:
232  log.info("Starting the calibration data fetching process.")
233 
234  # Fetch calibration data using provided CLI arguments
235  payload_data = fetch_calib_data(
236  server=args.server,
237  tag=args.tag,
238  run=args.run,
239  lumi=args.lumi,
240  channels=args.channel,
241  )
242 
243  # Save fetched calibration data to the output file
244  ofile = output_filename(args)
245  save_calib_data_to_file(payload_data, ofile, args.channel)
246 
247  log.info(f"Finished fetching and saving calibration data in {ofile} successfully.")
248  except Exception as ex:
249  log.error(f"An error occurred during execution: {ex}")
CopyBlobFromCrest.setup_argparser
def setup_argparser()
Definition: CopyBlobFromCrest.py:177
CopyBlobFromCrest.save_calib_data_to_file
def save_calib_data_to_file(blobs, output_file, requested_channels=None)
Definition: CopyBlobFromCrest.py:142
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
CopyBlobFromCrest.fetch_calib_data
def fetch_calib_data(server, tag, run, lumi, channels)
Definition: CopyBlobFromCrest.py:68
Trk::open
@ open
Definition: BinningType.h:40
CopyBlobFromCrest.output_filename
def output_filename(args)
Definition: CopyBlobFromCrest.py:121
CopyBlobFromCrest.process_channel_list
def process_channel_list(channel_list)
Definition: CopyBlobFromCrest.py:101
str
Definition: BTagTrackIpAccessor.cxx:11
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.CaloCondLogger.getLogger
def getLogger(name="CaloCond")
Definition: CaloCondLogger.py:16