ATLAS Offline Software
Loading...
Searching...
No Matches
AtlasFieldMapCondAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
15
16// ISF_Services include
18
19// Concurrency
20#include "GaudiKernel/ConcurrencyFlags.h"
21
22// PathResolver
24
25// For TagInfo access for special case of turning off toroid or solenoid
27
28// ROOT
29#include "TClass.h"
30#include "TFile.h"
31#include "TTree.h"
32
34 ISvcLocator* pSvcLocator)
35 : AthCondAlgorithm(name, pSvcLocator)
36{}
37
39
40StatusCode
42{
43 // Read Handle for the map
45
46 // Read Handle for the current
48
49 // Output handle for the field map
50 ATH_CHECK(m_mapCondObjOutputKey.initialize());
51
52 ATH_MSG_DEBUG("Initialize: Key " << m_mapCondObjOutputKey.fullKey()
53 << " has been succesfully registered ");
54
55 ATH_MSG_INFO("Initialize: Will update the field map from " <<
56 (m_useMapsFromCOOL ? "conditions" : "jobOpt file name") );
57
58 // Load these dictionaries now, so we don't need to try to do so
59 // while multiple threads are running.
60 TClass::GetClass("TLeafI");
61 TClass::GetClass("TLeafD");
62 TClass::GetClass("TLeafO");
63 TClass::GetClass("TLeafS");
64
65 return StatusCode::SUCCESS;
66}
67
68StatusCode
70{
71 ATH_MSG_DEBUG("start: entering ");
72
73 // Load map on start, we assume that the current context is valid
74 if (m_loadMapOnStart) {
75 return (execute(Gaudi::Hive::currentContext()));
76 }
77
78 return StatusCode::SUCCESS;
79}
80
81StatusCode
82MagField::AtlasFieldMapCondAlg::execute(const EventContext& ctx) const
83{
84
85 ATH_MSG_DEBUG("execute: entering " << ctx.eventID());
86
87 // Check if output conditions object with field map object is still valid, if
88 // not replace it with new map
91 };
92 if (mapWriteHandle.isValid()) {
93 ATH_MSG_DEBUG("execute: CondHandle " << mapWriteHandle.fullKey()
94 << " is still valid. ");
95 return StatusCode::SUCCESS;
96 }
97
98 // This will need to be filled before we construct the condition object
99 Cache cache{};
100
101 ATH_CHECK(updateFieldMap(ctx, cache));
102
103 if (cache.m_fieldMap) {
104 ATH_MSG_INFO("execute: solenoid zone id "
105 << cache.m_fieldMap->solenoidZoneId());
106 } else {
107 ATH_MSG_INFO("execute: no map read (currents == 0");
108 }
109
110 // Save newly created map in conditions object, and record it in the
111 // conditions store, with its own range
112 auto fieldMapCondObj = std::make_unique<AtlasFieldMapCondObj>();
113 // move ownership of the field map to the fieldMapCondObj
114 if (cache.m_fieldMap)
115 fieldMapCondObj->setFieldMap(std::move(cache.m_fieldMap));
116 if (mapWriteHandle
117 .record(cache.m_mapCondObjOutputRange, std::move(fieldMapCondObj))
118 .isFailure()) {
119 ATH_MSG_ERROR("execute: Could not record AtlasFieldMapCondObj object with "
120 << mapWriteHandle.key() << " with EventRange "
121 << cache.m_mapCondObjOutputRange << " into Conditions Store");
122 return StatusCode::FAILURE;
123 }
124 ATH_MSG_INFO("execute: recorded AtlasFieldMapCondObj with EventRange "
125 << cache.m_mapCondObjOutputRange);
126
127 return StatusCode::SUCCESS;
128}
129
130StatusCode
132 Cache& cache) const
133{
134 // We get here only for the first creation of the field map, or if the
135 // AtlasFieldMapCondObj object, where the map is stored, is no longer valid,
136 // i.e. the IOV is out of range
137
138 // Update the map either with the file names from cool or from alg properties,
139 // according to m_useMapsFromCOOL
140
141 // Get file names from COOL, or use local ones:
142 std::string fullMapFilename;
143 std::string soleMapFilename;
144 std::string toroMapFilename;
145
146 if (m_useMapsFromCOOL) {
147
148 ATH_MSG_INFO("updateFieldMap: Update map from conditions");
149
150 // readin map file name from cool
152 ctx };
153 const CondAttrListCollection* attrListColl{ *readHandle };
154 if (attrListColl == nullptr) {
155 ATH_MSG_ERROR("updateFieldMap: Failed to retrieve "
156 "CondAttributeListCollection with key "
157 << readHandle.key());
158 return StatusCode::FAILURE;
159 }
160
161 // Get the validitiy range
162 EventIDRange rangeW;
163 if (!readHandle.range(rangeW)) {
164 ATH_MSG_FATAL("updateFieldMap: Failed to retrieve validity range for "
165 << readHandle.key());
166 return StatusCode::FAILURE;
167 }
168 cache.m_mapCondObjOutputRange = rangeW;
170 "updateFieldMap: Update map from conditions: Range of input/output is "
171 << cache.m_mapCondObjOutputRange);
172
174 "updateFieldMap: reading magnetic field map filenames from COOL");
175
176 for (CondAttrListCollection::const_iterator itr = attrListColl->begin();
177 itr != attrListColl->end();
178 ++itr) {
179 const coral::AttributeList& attr = itr->second;
180 const std::string& mapType = attr["FieldType"].data<std::string>();
181 const std::string& mapFile = attr["MapFileName"].data<std::string>();
182 const float soleCur = attr["SolenoidCurrent"].data<float>();
183 const float toroCur = attr["ToroidCurrent"].data<float>();
184
185 ATH_MSG_INFO("updateFieldMap: found map of type "
186 << mapType << " with soleCur=" << soleCur
187 << " toroCur=" << toroCur << " (path " << mapFile << ")");
188
189 // first 5 letters are reserved (like "file:")
190 const std::string mapFile_decoded = mapFile.substr(5);
191 if (mapType == "GlobalMap") {
192 fullMapFilename = mapFile_decoded;
193 cache.m_mapSoleCurrent = soleCur;
194 cache.m_mapToroCurrent = toroCur;
195 } else if (mapType == "SolenoidMap") {
196 soleMapFilename = mapFile_decoded;
197 } else if (mapType == "ToroidMap") {
198 toroMapFilename = mapFile_decoded;
199 }
200 // note: the idea is that the folder contains exactly three maps
201 // (if it contains more than 3 maps, then this logic doesn't work
202 // perfectly) nominal currents are read from the global map
203 }
204
205 if (m_loadMapOnStart) {
206
207 // For loading map on start - online scenario - take the currents from job
208 // options And set IOV range to current run number to run number + 1
209
212
213 // Create a range for the current run
214 EventIDBase start, stop;
215 start.set_run_number(ctx.eventID().run_number());
216 start.set_lumi_block(0);
217 stop.set_run_number(ctx.eventID().run_number() + 1);
218 stop.set_lumi_block(0);
219 cache.m_mapCondObjOutputRange = EventIDRange(start, stop);
220
221 ATH_MSG_INFO("updateFieldMap: loadMapOnStart is set, overriding currents "
222 "from job options - solCur "
223 << cache.m_mapSoleCurrent << ", torCur "
224 << cache.m_mapToroCurrent << " and setting IOV range: "
225 << cache.m_mapCondObjOutputRange);
226 } else {
227 // For normal athena jobs, check the currents in DCS to check if one of
228 // the two magnets is OFF so that the correct map can be used. If a field
229 // is off, set an IOV validity range to be the current run only. (Note DCS
230 // currents have a timestamp-based IOV, so this is not used.)
231
232 // Note: for the nominal maps from COOL, three maps are available:
233 // - Global with both solenoid and toroid
234 // - Solenoid - just the currents for the solenoid
235 // - Toroid - just the currents for the toroid
236
237 double soleCurrent;
238 double toroCurrent;
239 EventIDRange rangeDCS;
240 ATH_CHECK(
241 checkCurrentFromConditions(ctx, soleCurrent, toroCurrent, rangeDCS));
242
243 bool mustCreateIOVRange = false;
244 if (soleCurrent < m_soleMinCurrent) {
245 cache.m_mapSoleCurrent = 0;
246 mustCreateIOVRange = true;
247 ATH_MSG_INFO("updateFieldMap: set solenoid current to 0 from DCS");
248 }
249 if (toroCurrent < m_toroMinCurrent) {
250 cache.m_mapToroCurrent = 0;
251 mustCreateIOVRange = true;
252 ATH_MSG_INFO("updateFieldMap: set toroid current to 0 from DCS");
253 }
254 if (mustCreateIOVRange) {
255 // The currents from DCS are zero for either solenoid or toroid,
256 // construct an IOV range for one run
257 EventIDBase start, stop;
258 // use ctx run number
259 start.set_run_number(ctx.eventID().run_number());
260 start.set_lumi_block(0);
261 stop.set_run_number(ctx.eventID().run_number() + 1);
262 stop.set_lumi_block(0);
263 cache.m_mapCondObjOutputRange = EventIDRange(start, stop);
264 ATH_MSG_INFO("updateFieldMap: map IOV range "
265 << cache.m_mapCondObjOutputRange);
266 } else {
267 ATH_MSG_INFO("updateFieldMap: currents are OK, will use nominal maps");
268 }
269 }
270 }
271
272 else {
273 // not m_useMapsFromCOOL - set values from job options
274 fullMapFilename = m_fullMapFilename;
275 soleMapFilename = m_soleMapFilename;
276 toroMapFilename = m_toroMapFilename;
278 cache.m_mapSoleCurrent = 0;
279 ATH_MSG_INFO("updateFieldMap: requested solenoid current in JobOpt "
280 << m_mapSoleCurrent << " is below allowed minimum "
281 << m_soleMinCurrent << " setting to 0");
282 } else {
284 }
286 cache.m_mapToroCurrent = 0;
287 ATH_MSG_INFO("updateFieldMap: requested toroid current in JobOpt "
288 << m_mapToroCurrent << " is below allowed minimum "
289 << m_toroMinCurrent << " setting to 0");
290 } else {
292 }
293
294 // Create a range for the current run
295 EventIDBase start, stop;
296 start.set_run_number(ctx.eventID().run_number());
297 start.set_lumi_block(0);
298 stop.set_run_number(ctx.eventID().run_number() + 1);
299 stop.set_lumi_block(0);
300 cache.m_mapCondObjOutputRange = EventIDRange(start, stop);
301
303 "updateFieldMap: useMapsFromCOOL == false, using default range "
304 << cache.m_mapCondObjOutputRange);
305 }
306
307 // We allow to set currents via the TagInfoMgr which adds tags to the TagInfo
308 // object - only allowed for offline
309
310 if (m_useMapsFromCOOL) {
311
312 // get currents via TagInfoMgr
313 ServiceHandle<ITagInfoMgr> tagInfoMgr("TagInfoMgr", name());
314 if (tagInfoMgr.retrieve().isSuccess()) {
315 ATH_MSG_INFO("updateFieldMap: found TagInfoMgr ");
316 bool resetCurrentsFromTagInfo = false;
317 std::string mapSoleCurrent = tagInfoMgr->findTag("MapSoleCurrent");
318 if (not mapSoleCurrent.empty()) {
319 cache.m_mapSoleCurrent = std::stof(mapSoleCurrent);
320 resetCurrentsFromTagInfo = true;
321 ATH_MSG_INFO("updateFieldMap: found MapSoleCurrent in TagInfo, setting "
322 "the solenoid current "
323 << cache.m_mapSoleCurrent);
324 }
325 std::string mapToroCurrent = tagInfoMgr->findTag("MapToroCurrent");
326 if (not mapToroCurrent.empty()) {
327 cache.m_mapToroCurrent = std::stof(mapToroCurrent);
328 resetCurrentsFromTagInfo = true;
329 ATH_MSG_INFO("updateFieldMap: found MapToroCurrent in TagInfo, setting "
330 "the toroid current "
331 << cache.m_mapToroCurrent);
332 }
333 if (resetCurrentsFromTagInfo)
334 ATH_MSG_INFO("updateFieldMap: reset currents from TagInfo");
335 else
336 ATH_MSG_INFO("updateFieldMap: DID NOT reset currents from TagInfo");
337 } else {
338 ATH_MSG_INFO("updateFieldMap: TagInfoMgr NOT found. ");
339 }
340 }
341
342 // Select map file according to the value of the currents which indicate which
343 // map is 'on'
344
345 // determine the map to load
346 std::string mapFile;
347 if (cache.solenoidOn() && cache.toroidOn())
348 mapFile = fullMapFilename;
349 else if (cache.solenoidOn())
350 mapFile = soleMapFilename;
351 else if (cache.toroidOn())
352 mapFile = toroMapFilename;
353 else {
354 // all magnets OFF. no need to read map
355 return StatusCode::SUCCESS;
356 }
357
359 "updateFieldMap: Set map currents from FieldSvc: solenoid/toroid "
360 << cache.m_mapSoleCurrent << "," << cache.m_mapToroCurrent);
361 ATH_MSG_INFO("updateFieldMap: Use map file " << mapFile);
362
363 // find the path to the map file
364 std::string resolvedMapFile = PathResolver::find_file(mapFile, "CALIBPATH");
365 if (resolvedMapFile.empty()) {
366 ATH_MSG_ERROR("Field map file " << mapFile << " not found");
367 return StatusCode::FAILURE;
368 }
369 // Do checks and extract root file to initialize the map
370 if (resolvedMapFile.find(".root") == std::string::npos) {
371 ATH_MSG_ERROR("updateFieldMap: input file name '"
372 << resolvedMapFile << "' does not end with .root");
373 return StatusCode::FAILURE;
374 }
375 TFile* rootfile = new TFile(resolvedMapFile.c_str(), "OLD");
376 if (!rootfile) {
377 ATH_MSG_ERROR("updateFieldMap: failed to open " << resolvedMapFile);
378 return StatusCode::FAILURE;
379 }
380 if (!rootfile->cd()) {
381 // could not make it current directory
383 "updateFieldMap: unable to cd() into the ROOT field map TFile");
384 rootfile->Close();
385 delete rootfile;
386 return StatusCode::FAILURE;
387 }
388 // open the tree
389 TTree* tree = (TTree*)rootfile->Get("BFieldMap");
390 if (tree == nullptr) {
391 // no tree
393 "updateFieldMap: TTree 'BFieldMap' does not exist in ROOT field map");
394 rootfile->Close();
395 delete rootfile;
396 return StatusCode::FAILURE;
397 }
398
399 // create map
400 cache.m_fieldMap = std::make_unique<MagField::AtlasFieldMap>();
401
402 // initialize map
403 if (!cache.m_fieldMap->initializeMap(
405 // failed to initialize the map
407 "updateFieldMap: unable to initialize the map for AtlasFieldMap for file "
408 << resolvedMapFile);
409 rootfile->Close();
410 delete rootfile;
411 return StatusCode::FAILURE;
412 }
413
414 rootfile->Close();
415 delete rootfile;
416
417 ATH_MSG_INFO("updateFieldMap: Initialized the field map from "
418 << resolvedMapFile);
419
420 return StatusCode::SUCCESS;
421}
422
423StatusCode
425 const EventContext& ctx,
426 double& soleCurrent,
427 double& toroCurrent,
428 EventIDRange& rangeDCS) const
429{
430
431 // readin current value
433 const CondAttrListCollection* attrListColl{ *readHandle };
434 if (attrListColl == nullptr) {
435 ATH_MSG_ERROR("checkCurrentFromConditions: Failed to retrieve "
436 "CondAttributeListCollection with key "
437 << m_currInputKey.key());
438 return StatusCode::FAILURE;
439 }
440
441 // Get the validitiy range
442 if (!readHandle.range(rangeDCS)) {
444 "checkCurrentFromConditions: Failed to retrieve validity range for "
445 << readHandle.key());
446 return StatusCode::FAILURE;
447 }
448 ATH_MSG_INFO("checkCurrentFromConditions: Range of input currents is "
449 << rangeDCS);
450
451 // get magnet currents from DCS
452 double solcur{ 0. };
453 double torcur{ 0. };
454 bool gotsol{ false };
455 bool gottor{ false };
456
457 /*
458 * due to inconsistencies between CONDBR2 and OFLP200/COMP200 (the former
459 * includes channel names in the /EXT/DCS/MAGNETS/SENSORDATA folder, the
460 * latter don't), we try to read currents in both ways
461 */
462 bool hasChanNames{ false };
463 ATH_MSG_INFO("checkCurrentFromConditions: Attempt 1 at reading currents from "
464 "DCS (using channel name)");
465 for (CondAttrListCollection::const_iterator itr = attrListColl->begin();
466 itr != attrListColl->end();
467 ++itr) {
468 const std::string& name = attrListColl->chanName(itr->first);
469 ATH_MSG_INFO("checkCurrentFromConditions: Trying to read from DCS: "
470 "[channel name, index, value] "
471 << name << " , " << itr->first << " , "
472 << itr->second["value"].data<float>());
473 if (name.compare("") != 0) {
474 hasChanNames = true;
475 }
476 if (name.compare("CentralSol_Current") == 0) {
477 // channel 1 is solenoid current
478 solcur = itr->second["value"].data<float>();
479 gotsol = true;
480 } else if (name.compare("Toroids_Current") == 0) {
481 // channel 3 is toroid current
482 torcur = itr->second["value"].data<float>();
483 gottor = true;
484 }
485 }
486 if (!hasChanNames) {
487 ATH_MSG_INFO("checkCurrentFromConditions: Attempt 2 at reading currents "
488 "from DCS (using channel index)");
489 // in no channel is named, try again using channel index instead
490 for (CondAttrListCollection::const_iterator itr = attrListColl->begin();
491 itr != attrListColl->end();
492 ++itr) {
493
494 if (itr->first == 1) {
495 // channel 1 is solenoid current
496 solcur = itr->second["value"].data<float>();
497 gotsol = true;
498 } else if (itr->first == 3) {
499 // channel 3 is toroid current
500 torcur = itr->second["value"].data<float>();
501 gottor = true;
502 }
503 }
504 }
505 if (!gotsol || !gottor) {
506 if (!gotsol)
507 ATH_MSG_ERROR("checkCurrentFromConditions: Missing solenoid current in "
508 "DCS information");
509 if (!gottor)
510 ATH_MSG_ERROR("checkCurrentFromConditions: Missing toroid current in DCS "
511 "information");
512 return StatusCode::FAILURE;
513 }
514
515 ATH_MSG_INFO("checkCurrentFromConditions: Currents read from DCS - solenoid "
516 << solcur << " toroid " << torcur);
517
518 // round to zero if close to zero
519 if (solcur < m_soleMinCurrent) {
520 solcur = 0.0;
521 ATH_MSG_INFO("checkCurrentFromConditions: Solenoid is off");
522 }
523 if (torcur < m_toroMinCurrent) {
524 torcur = 0.0;
525 ATH_MSG_INFO("checkCurrentFromConditions: Toroids are off");
526 }
527
528 soleCurrent = solcur;
529 toroCurrent = torcur;
530
531 return StatusCode::SUCCESS;
532}
533
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
Base class for conditions algorithms.
This class is a collection of AttributeLists where each one is associated with a channel number.
const_iterator end() const
const_iterator begin() const
Access to Chan/AttributeList pairs via iterators.
const std::string & chanName(ChanNum chanNum) const
find name for particular channel
ChanAttrListMap::const_iterator const_iterator
StatusCode start() override final
Gaudi::Property< std::string > m_toroMapFilename
Gaudi::Property< double > m_mapToroCurrent
AtlasFieldMapCondAlg(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode checkCurrentFromConditions(const EventContext &ctx, double &soleCurrent, double &toroCurrent, EventIDRange &rangeDCS) const
StatusCode initialize() override final
StatusCode updateFieldMap(const EventContext &ctx, Cache &cache) const
Gaudi::Property< bool > m_loadMapOnStart
Gaudi::Property< std::string > m_soleMapFilename
Gaudi::Property< std::string > m_fullMapFilename
map file names - if not read from cool
SG::ReadCondHandleKey< CondAttrListCollection > m_mapsInputKey
Gaudi::Property< double > m_soleMinCurrent
SG::WriteCondHandleKey< AtlasFieldMapCondObj > m_mapCondObjOutputKey
Gaudi::Property< double > m_toroMinCurrent
Gaudi::Property< bool > m_useMapsFromCOOL
Gaudi::Property< double > m_mapSoleCurrent
nominal current for the maps
SG::ReadCondHandleKey< CondAttrListCollection > m_currInputKey
StatusCode execute(const EventContext &ctx) const override final
bool initializeMap(TFile *rootfile, float solenoidCurrent, float toroidCurrent)
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
bool range(EventIDRange &r)
const std::string & key() const
const std::string & key() const
const DataObjID & fullKey() const
static std::vector< std::string > rootfile
Definition iLumiCalc.h:30
std::unique_ptr< MagField::AtlasFieldMap > m_fieldMap
TChain * tree