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 = dynamic_cast<AliAODHeader*>(aod->GetHeader());
368 if(!header) AliFatal("Not a standard AOD");
369 header->SetRunNumber(lESD->GetRunNumber());
370 AliAnalysisManager::GetAnalysisManager()->GetOutputEventHandler()->SetFillAOD(kTRUE);
372 } else AliInfo( "Error: invalid output event handler" );
380 //________________________________________________________________________
381 void AliMUONAlignmentTask::FinishTaskOutput()
384 /// Called once per task on the client machine at the end of the analysis.
385 AliInfo( Form( "Processed %i tracks.", fTrackTot ) );
386 AliInfo( Form( "Accepted %i tracks.", fTrackOk ) );
388 // stop here if no alignment is to be performed
389 if( !fDoAlignment ) return;
391 AliLog::SetGlobalLogLevel(AliLog::kInfo);
393 // Perform global fit
394 fAlign->GlobalFit(fParameters,fErrors,fPulls);
395 Int_t idOffset = 0; // 400
396 Int_t lSDetElemCh = 0;
398 for( Int_t iDE=0; iDE<AliMUONAlignment::fgNDetElem; iDE++ )
401 Int_t detElemId = idOffset+100;
404 for(Int_t iCh=0; iCh<9; iCh++)
407 lSDetElemCh += AliMUONAlignment::fgNDetElemCh[iCh];
408 if (iDE>=lSDetElemCh)
411 detElemId -= AliMUONAlignment::fgNDetElemCh[iCh];
418 // Post final data. Write histo list to a file with option "RECREATE"
419 // PostData(1,fList);
421 // store misalignments from OCDB into old transformers
422 if( fMergeAlignmentCDBs )
423 { SaveMisAlignmentData( fOldGeoTransformer ); }
426 fNewGeoTransformer = fAlign->ReAlign( fOldGeoTransformer, fParameters, true );
428 // Generate realigned data in local cdb
429 const TClonesArray* array = fNewGeoTransformer->GetMisAlignmentData();
431 // 100 mum residual resolution for chamber misalignments?
432 fAlign->SetAlignmentResolution( array, -1, 0.01, 0.01, 0.004, 0.003 );
435 AliLog::SetGlobalDebugLevel(2);
437 // recover default storage full name (raw:// cannot be used to set specific storage)
438 AliCDBManager* cdbManager = AliCDBManager::Instance();
440 // unload old alignment path
441 if( cdbManager->GetEntryCache()->Contains("MUON/Align/Data") )
442 { cdbManager->UnloadFromCache("MUON/Align/Data"); }
444 // load new alignment path
445 if( !fNewAlignStorage.IsNull() ) cdbManager->SetSpecificStorage("MUON/Align/Data",fNewAlignStorage.Data());
448 TString defaultStorage(cdbManager->GetDefaultStorage()->GetType());
449 if (defaultStorage == "alien") defaultStorage += Form("://folder=%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
450 else defaultStorage += Form("://%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
451 cdbManager->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
455 // create new DB entry
456 AliCDBMetaData* cdbData = new AliCDBMetaData();
457 cdbData->SetResponsible("Dimuon Offline project");
458 cdbData->SetComment("MUON alignment objects with residual misalignment");
459 AliCDBId id("MUON/Align/Data", 0, AliCDBRunRange::Infinity());
460 cdbManager->Put(const_cast<TClonesArray*>(array), id, cdbData);
464 //________________________________________________________________________
465 void AliMUONAlignmentTask::NotifyRun()
468 /// run number (re)initialization
470 // propagate run number to fAlign
471 if( fAlign ) fAlign->SetRunNumber( fCurrentRunNumber );
474 if (fOCDBLoaded && fLoadOCDBOnce)
476 AliError(Form("OCDB already loaded %d %d",fOCDBLoaded,fLoadOCDBOnce));
480 AliCDBManager* cdbManager = AliCDBManager::Instance();
482 // Initialize default storage
483 if( !( cdbManager->IsDefaultStorageSet() || fDefaultStorage.IsNull() ) )
486 AliInfo( Form( "Initializing default storage: %s", fDefaultStorage.Data() ) );
487 cdbManager->SetDefaultStorage(fDefaultStorage.Data());
489 } else if( !fDefaultStorage.IsNull() ) {
491 AliInfo( "Default storage already set. Ignoring fDefaultStorage" );
495 AliInfo( "Default storage already set" );
499 // Initialize run number
500 if( cdbManager->GetRun() < 0 )
502 AliInfo( Form( "Setting run number: %i", fCurrentRunNumber ) );
503 cdbManager->SetRun(fCurrentRunNumber);
506 // following initialization is not needed when reading records
510 // load magnetic field if needed
511 if( !TGeoGlobalMagField::Instance()->IsLocked() )
514 AliInfo( "Loading magnetic field" );
515 if( !AliMUONCDB::LoadField() )
517 AliError( "Failed to load magnetic field" );
521 } else { AliInfo( "Magnetic field already locked" ); }
523 // checking magnitic field
526 AliInfo( "Reading magnetic field setup from GRP" );
528 // decide bFieldOn value base on dipole current
529 // propagete to Alignment class
531 AliMagF* magF = dynamic_cast<AliMagF*>( TGeoGlobalMagField::Instance()->GetField() );
533 AliError( "Failed to get field" );
537 fBFieldOn = TMath::Abs( magF->GetFactorDip() ) > 1e-5;
538 fAlign->SetBFieldOn( fBFieldOn );
539 AliInfo( Form( "Dipole magnetic field factor: %.2f", magF->GetFactorDip() ) );
540 AliInfo( Form( "fBFieldOn = %s", (fBFieldOn ? "kTRUE":"kFALSE") ) );
543 AliInfo( "Loading muon mapping" );
544 if( !AliMUONCDB::LoadMapping(kFALSE) )
546 AliError( "Failed to load muon mapping" );
550 AliInfo( "Assigning field to Track extrapolator" );
551 AliMUONTrackExtrap::SetField();
555 // load geometry if needed
556 if( !AliGeomManager::GetGeometry() )
559 // reset existing geometry/alignment if any
560 if( cdbManager->GetEntryCache()->Contains("GRP/Geometry/Data") )
562 AliInfo( "Unloading GRP/Geometry/Data" );
563 cdbManager->UnloadFromCache("GRP/Geometry/Data");
566 if( cdbManager->GetEntryCache()->Contains("MUON/Align/Data") )
568 AliInfo( Form( "Unloading MUON/Align/Data from %s", cdbManager->GetSpecificStorage( "MUON/Align/Data" )->GetBaseFolder().Data() ) );
569 cdbManager->UnloadFromCache("MUON/Align/Data");
572 // get original geometry transformer
573 AliInfo( "Loading geometry" );
574 AliGeomManager::LoadGeometry();
575 if (!AliGeomManager::GetGeometry())
577 AliError("Failed to load geometry");
581 if (!fOldAlignStorage.IsNull())
584 AliInfo( Form( "Initializing MUON/Align/Data using: %s", fOldAlignStorage.Data() ) );
585 cdbManager->SetSpecificStorage("MUON/Align/Data",fOldAlignStorage.Data());
589 // recover default storage full name (raw:// cannot be used to set specific storage)
590 TString defaultStorage(cdbManager->GetDefaultStorage()->GetType());
591 if (defaultStorage == "alien") defaultStorage += Form("://folder=%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
592 else defaultStorage += Form("://%s", cdbManager->GetDefaultStorage()->GetBaseFolder().Data());
594 AliInfo( Form( "Re-initializing MUON/Align/Data using: %s", defaultStorage.Data() ) );
595 cdbManager->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
599 AliInfo("Loading muon Alignment objects");
600 AliGeomManager::ApplyAlignObjsFromCDB("MUON");
602 } else { AliInfo( "Geometry already initialized - fOldAlignStorage ignored" ); }
604 // update geometry transformer and pass to Alignment object
605 AliInfo("Loading muon geometry in transformer");
606 fOldGeoTransformer->LoadGeometryData();
607 fAlign->SetGeometryTransformer(fOldGeoTransformer);
613 //_____________________________________________________________________________________
614 void AliMUONAlignmentTask::SaveMisAlignmentData( AliMUONGeometryTransformer* transformer ) const
618 transformer->ClearMisAlignmentData();
620 // load MUON/Align/Data from OCDB
621 AliCDBManager* cdbManager = AliCDBManager::Instance();
622 AliCDBEntry* cdbEntry = cdbManager->Get( "MUON/Align/Data" );
626 AliError( "unable to load entry for path MUON/Align/Data" );
631 // get TClonesArray and check
632 TClonesArray* misArray = (TClonesArray*)cdbEntry->GetObject();
636 AliError( "unable to load old misalignment array" );
641 // loop over stored entries
642 for (Int_t index=0; index<misArray->GetEntriesFast(); ++index )
645 // load matrix and check
646 AliAlignObjMatrix* matrix = (AliAlignObjMatrix*) misArray->At( index );
649 AliError( Form( "unable to load matrix for index %i", index ) );
654 AliGeomManager::ELayerID layerId;
656 matrix->GetVolUID( layerId, moduleId);
658 // make sure ELayerID is correct
659 assert( layerId == AliGeomManager::kMUON );
662 // AliInfo( Form( "Found matrix for %s %i", matrix->GetSymName(), moduleId ) );
665 TGeoHMatrix misMatrix;
666 matrix->GetMatrix(misMatrix);
668 // add to geometry transformer
669 // need the detector element
670 // "detElement->GetId()"
671 // see fOldGeoTransformer->GetMisAlignmentData( ... )
673 if( TString( matrix->GetSymName() ).Contains( "DE" ) ) transformer->AddMisAlignDetElement( moduleId, misMatrix);
674 else transformer->AddMisAlignModule( moduleId, misMatrix);