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