1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
18 //-----------------------------------------------------------------------------
19 /// \class AliMUONAlignmentTask
20 /// AliAnalysisTask to align the MUON spectrometer.
21 /// The Task reads as input ESDs and feeds the MUONTracks to AliMUONAlignment.
22 /// The alignment itself is performed by AliMillePede2.
23 /// A OCDB entry is written with the alignment parameters.
25 /// \author Javier Castillo, CEA/Saclay - Irfu/SPhN
26 /// \author Hugo Pereira Da Costa, CEA/Saclay - Irfu/SPhN
27 //-----------------------------------------------------------------------------
29 // this class header must always come first
30 #include "AliMUONAlignmentTask.h"
32 // local header must come before system headers
33 #include "AliAnalysisManager.h"
34 #include "AliAlignObjMatrix.h"
35 #include "AliAODInputHandler.h"
36 #include "AliAODHandler.h"
37 #include "AliAODEvent.h"
38 #include "AliAODHeader.h"
39 #include "AliCDBEntry.h"
40 #include "AliESDInputHandler.h"
41 #include "AliESDEvent.h"
42 #include "AliESDMuonTrack.h"
43 #include "AliCDBStorage.h"
44 #include "AliCDBManager.h"
45 #include "AliGRPManager.h"
46 #include "AliCDBMetaData.h"
48 #include "AliGeomManager.h"
51 #include "AliMillePedeRecord.h"
53 #include "AliMUONCDB.h"
54 #include "AliMUONAlignment.h"
55 #include "AliMUONConstants.h"
56 #include "AliMUONRecoParam.h"
57 #include "AliMUONTrack.h"
58 #include "AliMUONTrackExtrap.h"
59 #include "AliMUONTrackParam.h"
60 #include "AliMUONGeometryTransformer.h"
61 #include "AliMUONESDInterface.h"
71 #include <TGraphErrors.h>
74 #include <TClonesArray.h>
75 #include <TGeoGlobalMagField.h>
76 #include <TGeoManager.h>
77 #include <Riostream.h>
80 ClassImp(AliMUONAlignmentTask)
83 //________________________________________________________________________
84 AliMUONAlignmentTask::AliMUONAlignmentTask( const char *name ):
85 AliAnalysisTaskSE(name),
86 fReadRecords( kFALSE ),
87 fWriteRecords( kFALSE ),
88 fDoAlignment( kTRUE ),
89 fMergeAlignmentCDBs( kTRUE ),
90 fForceBField( kFALSE ),
95 fNewAlignStorage( "local://ReAlignOCDB" ),
96 fOldGeoTransformer(0x0),
97 fNewGeoTransformer(0x0),
98 fLoadOCDBOnce(kFALSE),
108 /// Default Constructor
109 // Define input and output slots here
110 // Input slot #0 works with a TChain
111 DefineInput(0, TChain::Class());
113 // initialize parameters ...
114 for(Int_t k=0;k<AliMUONAlignment::fNGlobal;k++)
121 // create alignment object
122 fAlign = new AliMUONAlignment();
124 // create old geometry transformer
125 fOldGeoTransformer = new AliMUONGeometryTransformer();
129 //________________________________________________________________________
130 AliMUONAlignmentTask::~AliMUONAlignmentTask()
134 delete fOldGeoTransformer;
135 delete fNewGeoTransformer;
138 //________________________________________________________________________
139 void AliMUONAlignmentTask::LocalInit()
142 Local initialization, called once per task on the client machine
143 where the analysis train is assembled
146 /* must run alignment when reading records */
147 if( fReadRecords && !fDoAlignment )
150 AliInfo( "Automatically setting fDoAlignment to kTRUE because fReadRecords is kTRUE" );
151 SetDoAlignment( kTRUE );
155 // print configuration
156 if( fRunNumberMin > 0 || fRunNumberMax > 0 )
157 { AliInfo( Form( "run range: %i - %i", fRunNumberMin, fRunNumberMax ) ); }
159 AliInfo( Form( "fReadRecords: %s", (fReadRecords ? "kTRUE":"kFALSE" ) ) );
160 AliInfo( Form( "fWriteRecords: %s", (fWriteRecords ? "kTRUE":"kFALSE" ) ) );
161 AliInfo( Form( "fDoAlignment: %s", (fDoAlignment ? "kTRUE":"kFALSE" ) ) );
165 // merge alignment DB flag is irrelevant if not actually performing the alignemnt
166 AliInfo( Form( "fMergeAlignmentCDBs: %s", (fMergeAlignmentCDBs ? "kTRUE":"kFALSE" ) ) );
170 if( !fDefaultStorage.IsNull() ) AliInfo( Form( "fDefaultStorage: %s", fDefaultStorage.Data() ) );
171 if( !fOldAlignStorage.IsNull() ) AliInfo( Form( "fOldAlignStorage: %s", fOldAlignStorage.Data() ) );
175 // new alignment storage is irrelevant if not actually performing the alignemnt
176 if( !fNewAlignStorage.IsNull() ) AliInfo( Form( "fNewAlignStorage: %s", fNewAlignStorage.Data() ) );
177 else AliFatal( "Invalid new alignment storage path" );
182 // following flags are only relevant if not reading records
183 if( fForceBField ) AliInfo( Form( "fBFieldOn: %s", (fBFieldOn ? "kTRUE":"kFALSE" ) ) );
184 else AliInfo( "fBFieldOn: from GRP" );
187 // consistency checks between flags
188 /* need at least one of the flags set to true */
189 if( !( fReadRecords || fWriteRecords || fDoAlignment ) )
190 { AliFatal( "Need at least one of the three flags fReadRecords, fWriteRecords and fDoAlignment set to kTRUE" ); }
192 /* cannot read and write records at the same time */
193 if( fReadRecords && fWriteRecords )
194 { AliFatal( "Cannot set both fReadRecords and fWriteRecords to kTRUE at the same time" ); }
198 warning, counting chambers from 1.
199 this must be done before calling the Init method
204 fAlign->FixChamber(1);
205 fAlign->FixChamber(10);
209 AliInfo( "Not fixing detector elements, since alignment is not required" );
216 // Do alignment with magnetic field off
217 fAlign->SetBFieldOn( fBFieldOn );
219 // Set expected resolution (see AliMUONAlignment)
220 fAlign->SetSigmaXY(0.15,0.10);
222 // initialize global parameters to provided values
223 fAlign->InitGlobalParameters(fParameters);
227 //________________________________________________________________________
228 void AliMUONAlignmentTask::UserCreateOutputObjects()
231 // connect AOD output
234 AliAODHandler* handler = dynamic_cast<AliAODHandler*>( AliAnalysisManager::GetAnalysisManager()->GetOutputEventHandler() );
238 // get AOD output handler and add Branch
239 fRecords = new TClonesArray( "AliMillePedeRecord", 0 );
240 fRecords->SetName( "records" );
241 handler->AddBranch("TClonesArray", &fRecords);
245 } else AliFatal( "Error: invalid output event handler" );
251 //________________________________________________________________________
252 void AliMUONAlignmentTask::UserExec(Option_t *)
255 // do nothing if run number not in range
256 if( fRunNumberMin > 0 && fCurrentRunNumber < fRunNumberMin ) return;
257 if( fRunNumberMax > 0 && fCurrentRunNumber > fRunNumberMax ) return;
259 // increase event count
263 if( fWriteRecords && fRecords )
272 AliAODEvent* lAOD( dynamic_cast<AliAODEvent*>(InputEvent() ) );
277 AliInfo("Error: AOD event not available");
282 TClonesArray* records = static_cast<TClonesArray*>( lAOD->FindListObject( "records" ) );
285 AliInfo( "Unable to read object name \"records\"" );
289 // get number of records and print
290 const Int_t lRecordsCount( records->GetEntriesFast() );
291 fTrackTot += lRecordsCount;
294 for( Int_t index = 0; index < lRecordsCount; ++index )
297 if( AliMillePedeRecord* record = dynamic_cast<AliMillePedeRecord*>( records->UncheckedAt(index) ) )
300 fAlign->ProcessTrack( record );
304 { AliInfo( Form( "Processed %i Tracks and %i were fitted.", fTrackTot, fTrackOk ) ); }
306 } else AliInfo( Form( "Invalid record at %i", index ) );
312 /// Main loop, called for each event
313 AliESDEvent* lESD( dynamic_cast<AliESDEvent*>(InputEvent()) );
318 AliInfo("Error: ESD event not available");
322 Int_t nTracks = Int_t(lESD->GetNumberOfMuonTracks());
323 for( Int_t iTrack = 0; iTrack < nTracks; iTrack++ )
326 AliESDMuonTrack* esdTrack = lESD->GetMuonTrack(iTrack);
327 if (!esdTrack->ContainTrackerData()) continue;
328 if (!esdTrack->ContainTriggerData()) continue;
330 Double_t invBenMom = esdTrack->GetInverseBendingMomentum();
331 if (TMath::Abs(invBenMom)<=1.04)
335 AliMUONESDInterface::ESDToMUON(*esdTrack, track);
337 // process track and retrieve corresponding records, for storage
338 const AliMillePedeRecord* lRecords( fAlign->ProcessTrack( &track, fDoAlignment ) );
342 if( fWriteRecords && fRecords )
344 new((*fRecords)[fRecordCount]) AliMillePedeRecord( *lRecords );
353 { AliInfo( Form( "Processed %i Tracks and %i were fitted.", fTrackTot, fTrackOk ) ); }
355 // Post final data. Write histo list to a file with option "RECREATE"
356 // PostData(1,fList);
361 if( fWriteRecords && fRecordCount > 0 )
363 AliAODHandler* handler = dynamic_cast<AliAODHandler*>( AliAnalysisManager::GetAnalysisManager()->GetOutputEventHandler() );
366 AliAODEvent* aod = handler->GetAOD();
367 AliAODHeader* header = aod->GetHeader();
368 header->SetRunNumber(lESD->GetRunNumber());
369 AliAnalysisManager::GetAnalysisManager()->GetOutputEventHandler()->SetFillAOD(kTRUE);
371 } else AliInfo( "Error: invalid output event handler" );
379 //________________________________________________________________________
380 void AliMUONAlignmentTask::FinishTaskOutput()
383 /// Called once per task on the client machine at the end of the analysis.
384 AliInfo( Form( "Processed %i tracks.", fTrackTot ) );
385 AliInfo( Form( "Accepted %i tracks.", fTrackOk ) );
387 // stop here if no alignment is to be performed
388 if( !fDoAlignment ) return;
390 AliLog::SetGlobalLogLevel(AliLog::kInfo);
392 // Perform global fit
393 fAlign->GlobalFit(fParameters,fErrors,fPulls);
394 Int_t idOffset = 0; // 400
395 Int_t lSDetElemCh = 0;
397 for( Int_t iDE=0; iDE<AliMUONAlignment::fgNDetElem; iDE++ )
400 Int_t detElemId = idOffset+100;
403 for(Int_t iCh=0; iCh<9; iCh++)
406 lSDetElemCh += AliMUONAlignment::fgNDetElemCh[iCh];
407 if (iDE>=lSDetElemCh)
410 detElemId -= AliMUONAlignment::fgNDetElemCh[iCh];
417 // Post final data. Write histo list to a file with option "RECREATE"
418 // PostData(1,fList);
420 // store misalignments from OCDB into old transformers
421 if( fMergeAlignmentCDBs )
422 { SaveMisAlignmentData( fOldGeoTransformer ); }
425 fNewGeoTransformer = fAlign->ReAlign( fOldGeoTransformer, fParameters, true );
427 // Generate realigned data in local cdb
428 const TClonesArray* array = fNewGeoTransformer->GetMisAlignmentData();
430 // 100 mum residual resolution for chamber misalignments?
431 fAlign->SetAlignmentResolution( array, -1, 0.01, 0.01, 0.004, 0.003 );
434 AliLog::SetGlobalDebugLevel(2);
436 // recover default storage full name (raw:// cannot be used to set specific storage)
437 AliCDBManager* cdbManager = AliCDBManager::Instance();
439 // unload old alignment path
440 if( cdbManager->GetEntryCache()->Contains("MUON/Align/Data") )
441 { cdbManager->UnloadFromCache("MUON/Align/Data"); }
443 // load new alignment path
444 if( !fNewAlignStorage.IsNull() ) cdbManager->SetSpecificStorage("MUON/Align/Data",fNewAlignStorage.Data());
447 TString defaultStorage(cdbManager->GetDefaultStorage()->GetType());
448 if (defaultStorage == "alien") defaultStorage += Form("://folder=%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
449 else defaultStorage += Form("://%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
450 cdbManager->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
454 // create new DB entry
455 AliCDBMetaData* cdbData = new AliCDBMetaData();
456 cdbData->SetResponsible("Dimuon Offline project");
457 cdbData->SetComment("MUON alignment objects with residual misalignment");
458 AliCDBId id("MUON/Align/Data", 0, AliCDBRunRange::Infinity());
459 cdbManager->Put(const_cast<TClonesArray*>(array), id, cdbData);
463 //________________________________________________________________________
464 void AliMUONAlignmentTask::NotifyRun()
467 /// run number (re)initialization
469 // propagate run number to fAlign
470 if( fAlign ) fAlign->SetRunNumber( fCurrentRunNumber );
473 if (fOCDBLoaded && fLoadOCDBOnce)
475 AliError(Form("OCDB already loaded %d %d",fOCDBLoaded,fLoadOCDBOnce));
479 AliCDBManager* cdbManager = AliCDBManager::Instance();
481 // Initialize default storage
482 if( !( cdbManager->IsDefaultStorageSet() || fDefaultStorage.IsNull() ) )
485 AliInfo( Form( "Initializing default storage: %s", fDefaultStorage.Data() ) );
486 cdbManager->SetDefaultStorage(fDefaultStorage.Data());
488 } else if( !fDefaultStorage.IsNull() ) {
490 AliInfo( "Default storage already set. Ignoring fDefaultStorage" );
494 AliInfo( "Default storage already set" );
498 // Initialize run number
499 if( cdbManager->GetRun() < 0 )
501 AliInfo( Form( "Setting run number: %i", fCurrentRunNumber ) );
502 cdbManager->SetRun(fCurrentRunNumber);
505 // following initialization is not needed when reading records
509 // load magnetic field if needed
510 if( !TGeoGlobalMagField::Instance()->IsLocked() )
513 AliInfo( "Loading magnetic field" );
514 if( !AliMUONCDB::LoadField() )
516 AliError( "Failed to load magnetic field" );
520 } else { AliInfo( "Magnetic field already locked" ); }
522 // checking magnitic field
525 AliInfo( "Reading magnetic field setup from GRP" );
527 // decide bFieldOn value base on dipole current
528 // propagete to Alignment class
530 AliMagF* magF = dynamic_cast<AliMagF*>( TGeoGlobalMagField::Instance()->GetField() );
531 fBFieldOn = TMath::Abs( magF->GetFactorDip() ) > 1e-5;
532 fAlign->SetBFieldOn( fBFieldOn );
533 AliInfo( Form( "Dipole magnetic field factor: %.2f", magF->GetFactorDip() ) );
534 AliInfo( Form( "fBFieldOn = %s", (fBFieldOn ? "kTRUE":"kFALSE") ) );
537 AliInfo( "Loading muon mapping" );
538 if( !AliMUONCDB::LoadMapping(kFALSE) )
540 AliError( "Failed to load muon mapping" );
544 AliInfo( "Assigning field to Track extrapolator" );
545 AliMUONTrackExtrap::SetField();
549 // load geometry if needed
550 if( !AliGeomManager::GetGeometry() )
553 // reset existing geometry/alignment if any
554 if( cdbManager->GetEntryCache()->Contains("GRP/Geometry/Data") )
556 AliInfo( "Unloading GRP/Geometry/Data" );
557 cdbManager->UnloadFromCache("GRP/Geometry/Data");
560 if( cdbManager->GetEntryCache()->Contains("MUON/Align/Data") )
562 AliInfo( Form( "Unloading MUON/Align/Data from %s", cdbManager->GetSpecificStorage( "MUON/Align/Data" )->GetBaseFolder().Data() ) );
563 cdbManager->UnloadFromCache("MUON/Align/Data");
566 // get original geometry transformer
567 AliInfo( "Loading geometry" );
568 AliGeomManager::LoadGeometry();
569 if (!AliGeomManager::GetGeometry())
571 AliError("Failed to load geometry");
575 if (!fOldAlignStorage.IsNull())
578 AliInfo( Form( "Initializing MUON/Align/Data using: %s", fOldAlignStorage.Data() ) );
579 cdbManager->SetSpecificStorage("MUON/Align/Data",fOldAlignStorage.Data());
583 // recover default storage full name (raw:// cannot be used to set specific storage)
584 TString defaultStorage(cdbManager->GetDefaultStorage()->GetType());
585 if (defaultStorage == "alien") defaultStorage += Form("://folder=%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
586 else defaultStorage += Form("://%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
588 AliInfo( Form( "Re-initializing MUON/Align/Data using: %s", defaultStorage.Data() ) );
589 cdbManager->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
593 AliInfo("Loading muon Alignment objects");
594 AliGeomManager::ApplyAlignObjsFromCDB("MUON");
596 } else { AliInfo( "Geometry already initialized - fOldAlignStorage ignored" ); }
598 // update geometry transformer and pass to Alignment object
599 AliInfo("Loading muon geometry in transformer");
600 fOldGeoTransformer->LoadGeometryData();
601 fAlign->SetGeometryTransformer(fOldGeoTransformer);
607 //_____________________________________________________________________________________
608 void AliMUONAlignmentTask::SaveMisAlignmentData( AliMUONGeometryTransformer* transformer ) const
612 transformer->ClearMisAlignmentData();
614 // load MUON/Align/Data from OCDB
615 AliCDBManager* cdbManager = AliCDBManager::Instance();
616 AliCDBEntry* cdbEntry = cdbManager->Get( "MUON/Align/Data" );
620 AliError( "unable to load entry for path MUON/Align/Data" );
625 // get TClonesArray and check
626 TClonesArray* misArray = (TClonesArray*)cdbEntry->GetObject();
630 AliError( "unable to load old misalignment array" );
635 // loop over stored entries
636 for (Int_t index=0; index<misArray->GetEntriesFast(); ++index )
639 // load matrix and check
640 AliAlignObjMatrix* matrix = (AliAlignObjMatrix*) misArray->At( index );
643 AliError( Form( "unable to load matrix for index %i", index ) );
648 AliGeomManager::ELayerID layerId;
650 matrix->GetVolUID( layerId, moduleId);
652 // make sure ELayerID is correct
653 assert( layerId == AliGeomManager::kMUON );
656 // AliInfo( Form( "Found matrix for %s %i", matrix->GetSymName(), moduleId ) );
659 TGeoHMatrix misMatrix;
660 matrix->GetMatrix(misMatrix);
662 // add to geometry transformer
663 // need the detector element
664 // "detElement->GetId()"
665 // see fOldGeoTransformer->GetMisAlignmentData( ... )
667 if( TString( matrix->GetSymName() ).Contains( "DE" ) ) transformer->AddMisAlignDetElement( moduleId, misMatrix);
668 else transformer->AddMisAlignModule( moduleId, misMatrix);