ATLAS Offline Software
Loading...
Searching...
No Matches
AtlasFieldMapCondAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 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 // // handle for COOL field map filenames
162 // const DataHandle<CondAttrListCollection> mapHandle;
163
164 // Get the validitiy range
165 EventIDRange rangeW;
166 if (!readHandle.range(rangeW)) {
167 ATH_MSG_FATAL("updateFieldMap: Failed to retrieve validity range for "
168 << readHandle.key());
169 return StatusCode::FAILURE;
170 }
171 cache.m_mapCondObjOutputRange = rangeW;
173 "updateFieldMap: Update map from conditions: Range of input/output is "
174 << cache.m_mapCondObjOutputRange);
175
177 "updateFieldMap: reading magnetic field map filenames from COOL");
178
179 for (CondAttrListCollection::const_iterator itr = attrListColl->begin();
180 itr != attrListColl->end();
181 ++itr) {
182 const coral::AttributeList& attr = itr->second;
183 const std::string& mapType = attr["FieldType"].data<std::string>();
184 const std::string& mapFile = attr["MapFileName"].data<std::string>();
185 const float soleCur = attr["SolenoidCurrent"].data<float>();
186 const float toroCur = attr["ToroidCurrent"].data<float>();
187
188 ATH_MSG_INFO("updateFieldMap: found map of type "
189 << mapType << " with soleCur=" << soleCur
190 << " toroCur=" << toroCur << " (path " << mapFile << ")");
191
192 // first 5 letters are reserved (like "file:")
193 const std::string mapFile_decoded = mapFile.substr(5);
194 if (mapType == "GlobalMap") {
195 fullMapFilename = mapFile_decoded;
196 cache.m_mapSoleCurrent = soleCur;
197 cache.m_mapToroCurrent = toroCur;
198 } else if (mapType == "SolenoidMap") {
199 soleMapFilename = mapFile_decoded;
200 } else if (mapType == "ToroidMap") {
201 toroMapFilename = mapFile_decoded;
202 }
203 // note: the idea is that the folder contains exactly three maps
204 // (if it contains more than 3 maps, then this logic doesn't work
205 // perfectly) nominal currents are read from the global map
206 }
207
208 if (m_loadMapOnStart) {
209
210 // For loading map on start - online scenario - take the currents from job
211 // options And set IOV range to current run number to run number + 1
212
215
216 // Create a range for the current run
217 EventIDBase start, stop;
218 start.set_run_number(ctx.eventID().run_number());
219 start.set_lumi_block(0);
220 stop.set_run_number(ctx.eventID().run_number() + 1);
221 stop.set_lumi_block(0);
222 cache.m_mapCondObjOutputRange = EventIDRange(start, stop);
223
224 ATH_MSG_INFO("updateFieldMap: loadMapOnStart is set, overriding currents "
225 "from job options - solCur "
226 << cache.m_mapSoleCurrent << ", torCur "
227 << cache.m_mapToroCurrent << " and setting IOV range: "
228 << cache.m_mapCondObjOutputRange);
229 } else {
230 // For normal athena jobs, check the currents in DCS to check if one of
231 // the two magnets is OFF so that the correct map can be used. If a field
232 // is off, set an IOV validity range to be the current run only. (Note DCS
233 // currents have a timestamp-based IOV, so this is not used.)
234
235 // Note: for the nominal maps from COOL, three maps are available:
236 // - Global with both solenoid and toroid
237 // - Solenoid - just the currents for the solenoid
238 // - Toroid - just the currents for the toroid
239
240 double soleCurrent;
241 double toroCurrent;
242 EventIDRange rangeDCS;
243 ATH_CHECK(
244 checkCurrentFromConditions(ctx, soleCurrent, toroCurrent, rangeDCS));
245
246 bool mustCreateIOVRange = false;
247 if (soleCurrent < m_soleMinCurrent) {
248 cache.m_mapSoleCurrent = 0;
249 mustCreateIOVRange = true;
250 ATH_MSG_INFO("updateFieldMap: set solenoid current to 0 from DCS");
251 }
252 if (toroCurrent < m_toroMinCurrent) {
253 cache.m_mapToroCurrent = 0;
254 mustCreateIOVRange = true;
255 ATH_MSG_INFO("updateFieldMap: set toroid current to 0 from DCS");
256 }
257 if (mustCreateIOVRange) {
258 // The currents from DCS are zero for either solenoid or toroid,
259 // construct an IOV range for one run
260 EventIDBase start, stop;
261 // use ctx run number
262 start.set_run_number(ctx.eventID().run_number());
263 start.set_lumi_block(0);
264 stop.set_run_number(ctx.eventID().run_number() + 1);
265 stop.set_lumi_block(0);
266 cache.m_mapCondObjOutputRange = EventIDRange(start, stop);
267 ATH_MSG_INFO("updateFieldMap: map IOV range "
268 << cache.m_mapCondObjOutputRange);
269 } else {
270 ATH_MSG_INFO("updateFieldMap: currents are OK, will use nominal maps");
271 }
272 }
273 }
274
275 else {
276 // not m_useMapsFromCOOL - set values from job options
277 fullMapFilename = m_fullMapFilename;
278 soleMapFilename = m_soleMapFilename;
279 toroMapFilename = m_toroMapFilename;
281 cache.m_mapSoleCurrent = 0;
282 ATH_MSG_INFO("updateFieldMap: requested solenoid current in JobOpt "
283 << m_mapSoleCurrent << " is below allowed minimum "
284 << m_soleMinCurrent << " setting to 0");
285 } else {
287 }
289 cache.m_mapToroCurrent = 0;
290 ATH_MSG_INFO("updateFieldMap: requested toroid current in JobOpt "
291 << m_mapToroCurrent << " is below allowed minimum "
292 << m_toroMinCurrent << " setting to 0");
293 } else {
295 }
296
297 // Create a range for the current run
298 EventIDBase start, stop;
299 start.set_run_number(ctx.eventID().run_number());
300 start.set_lumi_block(0);
301 stop.set_run_number(ctx.eventID().run_number() + 1);
302 stop.set_lumi_block(0);
303 cache.m_mapCondObjOutputRange = EventIDRange(start, stop);
304
306 "updateFieldMap: useMapsFromCOOL == false, using default range "
307 << cache.m_mapCondObjOutputRange);
308 }
309
310 // We allow to set currents via the TagInfoMgr which adds tags to the TagInfo
311 // object - only allowed for offline
312
313 if (m_useMapsFromCOOL) {
314
315 // get currents via TagInfoMgr
316 ServiceHandle<ITagInfoMgr> tagInfoMgr("TagInfoMgr", name());
317 if (tagInfoMgr.retrieve().isSuccess()) {
318 ATH_MSG_INFO("updateFieldMap: found TagInfoMgr ");
319 bool resetCurrentsFromTagInfo = false;
320 std::string mapSoleCurrent = tagInfoMgr->findTag("MapSoleCurrent");
321 if (not mapSoleCurrent.empty()) {
322 cache.m_mapSoleCurrent = std::stof(mapSoleCurrent);
323 resetCurrentsFromTagInfo = true;
324 ATH_MSG_INFO("updateFieldMap: found MapSoleCurrent in TagInfo, setting "
325 "the solenoid current "
326 << cache.m_mapSoleCurrent);
327 }
328 std::string mapToroCurrent = tagInfoMgr->findTag("MapToroCurrent");
329 if (not mapToroCurrent.empty()) {
330 cache.m_mapToroCurrent = std::stof(mapToroCurrent);
331 resetCurrentsFromTagInfo = true;
332 ATH_MSG_INFO("updateFieldMap: found MapToroCurrent in TagInfo, setting "
333 "the toroid current "
334 << cache.m_mapToroCurrent);
335 }
336 if (resetCurrentsFromTagInfo)
337 ATH_MSG_INFO("updateFieldMap: reset currents from TagInfo");
338 else
339 ATH_MSG_INFO("updateFieldMap: DID NOT reset currents from TagInfo");
340 } else {
341 ATH_MSG_INFO("updateFieldMap: TagInfoMgr NOT found. ");
342 }
343 }
344
345 // Select map file according to the value of the currents which indicate which
346 // map is 'on'
347
348 // determine the map to load
349 std::string mapFile;
350 if (cache.solenoidOn() && cache.toroidOn())
351 mapFile = fullMapFilename;
352 else if (cache.solenoidOn())
353 mapFile = soleMapFilename;
354 else if (cache.toroidOn())
355 mapFile = toroMapFilename;
356 else {
357 // all magnets OFF. no need to read map
358 return StatusCode::SUCCESS;
359 }
360
362 "updateFieldMap: Set map currents from FieldSvc: solenoid/toroid "
363 << cache.m_mapSoleCurrent << "," << cache.m_mapToroCurrent);
364 ATH_MSG_INFO("updateFieldMap: Use map file " << mapFile);
365
366 // find the path to the map file
367 std::string resolvedMapFile = PathResolver::find_file(mapFile, "CALIBPATH");
368 if (resolvedMapFile.empty()) {
369 ATH_MSG_ERROR("Field map file " << mapFile << " not found");
370 return StatusCode::FAILURE;
371 }
372 // Do checks and extract root file to initialize the map
373 if (resolvedMapFile.find(".root") == std::string::npos) {
374 ATH_MSG_ERROR("updateFieldMap: input file name '"
375 << resolvedMapFile << "' does not end with .root");
376 return StatusCode::FAILURE;
377 }
378 TFile* rootfile = new TFile(resolvedMapFile.c_str(), "OLD");
379 if (!rootfile) {
380 ATH_MSG_ERROR("updateFieldMap: failed to open " << resolvedMapFile);
381 return StatusCode::FAILURE;
382 }
383 if (!rootfile->cd()) {
384 // could not make it current directory
386 "updateFieldMap: unable to cd() into the ROOT field map TFile");
387 rootfile->Close();
388 delete rootfile;
389 return StatusCode::FAILURE;
390 }
391 // open the tree
392 TTree* tree = (TTree*)rootfile->Get("BFieldMap");
393 if (tree == nullptr) {
394 // no tree
396 "updateFieldMap: TTree 'BFieldMap' does not exist in ROOT field map");
397 rootfile->Close();
398 delete rootfile;
399 return StatusCode::FAILURE;
400 }
401
402 // create map
403 cache.m_fieldMap = std::make_unique<MagField::AtlasFieldMap>();
404
405 // initialize map
406 if (!cache.m_fieldMap->initializeMap(
408 // failed to initialize the map
410 "updateFieldMap: unable to initialize the map for AtlasFieldMap for file "
411 << resolvedMapFile);
412 rootfile->Close();
413 delete rootfile;
414 return StatusCode::FAILURE;
415 }
416
417 rootfile->Close();
418 delete rootfile;
419
420 ATH_MSG_INFO("updateFieldMap: Initialized the field map from "
421 << resolvedMapFile);
422
423 return StatusCode::SUCCESS;
424}
425
426StatusCode
428 const EventContext& ctx,
429 double& soleCurrent,
430 double& toroCurrent,
431 EventIDRange& rangeDCS) const
432{
433
434 // readin current value
436 const CondAttrListCollection* attrListColl{ *readHandle };
437 if (attrListColl == nullptr) {
438 ATH_MSG_ERROR("checkCurrentFromConditions: Failed to retrieve "
439 "CondAttributeListCollection with key "
440 << m_currInputKey.key());
441 return StatusCode::FAILURE;
442 }
443
444 // Get the validitiy range
445 if (!readHandle.range(rangeDCS)) {
447 "checkCurrentFromConditions: Failed to retrieve validity range for "
448 << readHandle.key());
449 return StatusCode::FAILURE;
450 }
451 ATH_MSG_INFO("checkCurrentFromConditions: Range of input currents is "
452 << rangeDCS);
453
454 // get magnet currents from DCS
455 double solcur{ 0. };
456 double torcur{ 0. };
457 bool gotsol{ false };
458 bool gottor{ false };
459
460 /*
461 * due to inconsistencies between CONDBR2 and OFLP200/COMP200 (the former
462 * includes channel names in the /EXT/DCS/MAGNETS/SENSORDATA folder, the
463 * latter don't), we try to read currents in both ways
464 */
465 bool hasChanNames{ false };
466 ATH_MSG_INFO("checkCurrentFromConditions: Attempt 1 at reading currents from "
467 "DCS (using channel name)");
468 for (CondAttrListCollection::const_iterator itr = attrListColl->begin();
469 itr != attrListColl->end();
470 ++itr) {
471 const std::string& name = attrListColl->chanName(itr->first);
472 ATH_MSG_INFO("checkCurrentFromConditions: Trying to read from DCS: "
473 "[channel name, index, value] "
474 << name << " , " << itr->first << " , "
475 << itr->second["value"].data<float>());
476 if (name.compare("") != 0) {
477 hasChanNames = true;
478 }
479 if (name.compare("CentralSol_Current") == 0) {
480 // channel 1 is solenoid current
481 solcur = itr->second["value"].data<float>();
482 gotsol = true;
483 } else if (name.compare("Toroids_Current") == 0) {
484 // channel 3 is toroid current
485 torcur = itr->second["value"].data<float>();
486 gottor = true;
487 }
488 }
489 if (!hasChanNames) {
490 ATH_MSG_INFO("checkCurrentFromConditions: Attempt 2 at reading currents "
491 "from DCS (using channel index)");
492 // in no channel is named, try again using channel index instead
493 for (CondAttrListCollection::const_iterator itr = attrListColl->begin();
494 itr != attrListColl->end();
495 ++itr) {
496
497 if (itr->first == 1) {
498 // channel 1 is solenoid current
499 solcur = itr->second["value"].data<float>();
500 gotsol = true;
501 } else if (itr->first == 3) {
502 // channel 3 is toroid current
503 torcur = itr->second["value"].data<float>();
504 gottor = true;
505 }
506 }
507 }
508 if (!gotsol || !gottor) {
509 if (!gotsol)
510 ATH_MSG_ERROR("checkCurrentFromConditions: Missing solenoid current in "
511 "DCS information");
512 if (!gottor)
513 ATH_MSG_ERROR("checkCurrentFromConditions: Missing toroid current in DCS "
514 "information");
515 return StatusCode::FAILURE;
516 }
517
518 ATH_MSG_INFO("checkCurrentFromConditions: Currents read from DCS - solenoid "
519 << solcur << " toroid " << torcur);
520
521 // round to zero if close to zero
522 if (solcur < m_soleMinCurrent) {
523 solcur = 0.0;
524 ATH_MSG_INFO("checkCurrentFromConditions: Solenoid is off");
525 }
526 if (torcur < m_toroMinCurrent) {
527 torcur = 0.0;
528 ATH_MSG_INFO("checkCurrentFromConditions: Toroids are off");
529 }
530
531 soleCurrent = solcur;
532 toroCurrent = torcur;
533
534 return StatusCode::SUCCESS;
535}
536
#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