153 solenoid_current_override=None, toroids_current_override=None):
154 """
155 Create RunParams by reading from IS via the WEBDAQ REST API.
156
157 This uses the webis_server REST API to fetch run parameters, avoiding
158 direct dependencies on TDAQ libraries. The API endpoint is determined by:
159 1. The webdaq_base parameter if provided
160 2. The TDAQ_WEBDAQ_BASE environment variable
161
162 The IS objects accessed are:
163 - RunParams.RunParams: run_number, det_mask, timeSOR, trigger_type, etc.
164 - Magnets.Magnets: SolenoidCurrent, ToroidsCurrent
165
166 Args:
167 partition: The partition name (default: from TDAQ_PARTITION env var)
168 webdaq_base: Base URL for webis_server (default: from TDAQ_WEBDAQ_BASE env var)
169 strict: If True, raise an exception if IS read fails (for --online-environment)
170 solenoid_current_override: If provided, skip IS fetch for solenoid (command-line override)
171 toroids_current_override: If provided, skip IS fetch for toroids (command-line override)
172
173 Returns:
174 RunParams instance with values from IS, or defaults if unavailable
175
176 Raises:
177 RuntimeError: If strict=True and IS read fails
178 """
179 import requests
180
181
182 if webdaq_base is None:
183 webdaq_base = os.environ.get('TDAQ_WEBDAQ_BASE')
184
185 if not webdaq_base:
186 msg = "TDAQ_WEBDAQ_BASE not set, cannot read from IS"
187 if strict:
188 raise RuntimeError(msg + " (required for --online-environment)")
189 log.warning(msg + ". Using defaults.")
190 return cls()
191
192
193 if partition is None:
194 partition = os.environ.get('TDAQ_PARTITION', 'ATLAS')
195
196 log.info("Reading run parameters from IS via WEBDAQ: %s (partition=%s)", webdaq_base, partition)
197
198 params = {}
199
200
201
202
203 try:
204 url = f"{webdaq_base}/info/current/{partition}/is/RunParams/RunParams.RunParams?format=compact"
205 log.debug("Fetching RunParams from: %s", url)
206
207 response = requests.get(url, timeout=10)
208 if response.status_code == 200:
209 response_data = response.json()
210 log.debug("RunParams response from IS: %s", response_data)
211
212
213 if isinstance(response_data, list) and len(response_data) >= 4:
214 runparams = response_data[3]
215 else:
216 runparams = response_data
217
218 log.debug("RunParams data: %s", runparams)
219
220
221 if 'run_number' in runparams:
222 params['run_number'] = int(runparams['run_number'])
223 if 'lumiblock' in runparams:
224 params['lb_number'] = int(runparams['lumiblock'])
225 if 'det_mask' in runparams:
226 params['detector_mask'] = runparams['det_mask']
227 if 'timeSOR' in runparams:
228 sor_time = runparams['timeSOR']
229
230 if '.' not in sor_time:
231 sor_time += '.000000'
232 params['sor_time'] = sor_time
233 if 'beam_type' in runparams:
234 params['beam_type'] = int(runparams['beam_type'])
235 if 'beam_energy' in runparams:
236 params['beam_energy'] = int(runparams['beam_energy'])
237 if 'run_type' in runparams:
238 params['run_type'] = runparams['run_type']
239 if 'trigger_type' in runparams:
240 params['trigger_type'] = int(runparams['trigger_type'])
241 if 'recording_enabled' in runparams:
242 params['recording_enabled'] = runparams['recording_enabled'] in ('1', 'true', 'True', True, 1)
243
244 log.info("Got run parameters from IS: run=%s, lb=%s",
245 params.get('run_number'), params.get('lb_number'))
246 else:
247 msg = f"Failed to fetch RunParams from IS: HTTP {response.status_code}"
248 if strict:
249 raise RuntimeError(msg + " (required for --online-environment)")
250 log.warning(msg)
251
252 except requests.exceptions.RequestException as e:
253 msg = f"Error fetching RunParams from IS: {e}"
254 if strict:
255 raise RuntimeError(msg + " (required for --online-environment)")
256 log.warning(msg)
257 except (ValueError, KeyError) as e:
258 msg = f"Error parsing RunParams from IS: {e}"
259 if strict:
260 raise RuntimeError(msg + " (required for --online-environment)")
261 log.warning(msg)
262
263
264
265
266 have_solenoid_override = solenoid_current_override is not None
267 have_toroids_override = toroids_current_override is not None
268
269 if have_solenoid_override:
270 params['solenoid_current'] = solenoid_current_override
271 log.info("Using solenoid_current=%.1f from command line override", solenoid_current_override)
272 if have_toroids_override:
273 params['toroids_current'] = toroids_current_override
274 log.info("Using toroids_current=%.1f from command line override", toroids_current_override)
275
276
277 if not (have_solenoid_override and have_toroids_override):
278 try:
279 url = f"{webdaq_base}/info/current/{partition}/is/Magnets/Magnets.Magnets?format=compact"
280 log.debug("Fetching Magnets from: %s", url)
281
282 response = requests.get(url, timeout=10)
283 if response.status_code == 200:
284 response_data = response.json()
285 log.debug("Magnets response from IS: %s", response_data)
286
287 magnets = response_data[3] if isinstance(response_data, list) and len(response_data) >= 4 else response_data
288 log.debug("Magnets data: %s", magnets)
289
290
291
292 if not have_solenoid_override:
293 params['solenoid_current'] = float(magnets['SolenoidCurrent']['value'])
294 if not have_toroids_override:
295 params['toroids_current'] = float(magnets['ToroidsCurrent']['value'])
296
297 log.info("Got magnet currents from IS: solenoid=%s, toroids=%s",
298 params.get('solenoid_current'), params.get('toroids_current'))
299 elif strict:
300 raise RuntimeError(f"Magnets not available from IS: HTTP {response.status_code} "
301 "(required for --online-environment, use --solenoid-current and --toroids-current to override)")
302 else:
303 log.debug("Magnets not available from IS: HTTP %d", response.status_code)
304
305 except requests.exceptions.RequestException as e:
306 if strict:
307 raise RuntimeError(f"Error fetching Magnets from IS: {e} "
308 "(required for --online-environment, use --solenoid-current and --toroids-current to override)")
309 log.debug("Error fetching Magnets from IS: %s", e)
310 except (ValueError, KeyError, TypeError) as e:
311 if strict:
312 raise RuntimeError(f"Error parsing Magnets from IS: {e} "
313 "(required for --online-environment, use --solenoid-current and --toroids-current to override)")
314 log.debug("Error parsing Magnets from IS: %s", e)
315
316
317 if strict and 'run_number' not in params:
318 raise RuntimeError("Failed to get run_number from IS (required for --online-environment)")
319
320 return cls(**params)
321
322