#ifndef TOADATABASE_HXX_SEEN #define TOADATABASE_HXX_SEEN #include #include #include #include #include "EoaCore.hxx" #include "IPackageSet.hxx" #include "ISHAHashValue.hxx" #include "IAlignmentId.hxx" class TGeoManager; class TDatabasePDG; class TFile; class TTree; class TGeoMatrix; namespace COMET { class ICOMETEvent; class IFieldDescription; class IOADatabase; class IDigitManager; class IGeomIdManager; class ICOMETInput; class IGeometryId; /// An exception from the data base. OA_EXCEPTION(EOADatabase,EoaCore); /// Flag that no file was found. OA_EXCEPTION(ENoInputFile,EOADatabase); /// Flag that geometry data base was not found. OA_EXCEPTION(ENoGeometry,EOADatabase); /// Flag that EM field data base was not found. OA_EXCEPTION(ENoEMFieldDescription,EOADatabase); /// Flag that something went wrong with the alignment. OA_EXCEPTION(EBadAlignment, ENoGeometry); } /// Static access to the various geometry and calibration databases. The main /// table provided by this class are the ROOT geometry using /// COMET::IOADatabase::Get().UpdateGeometry(). It also provides several managers such /// as Digits(), GeomId(), TPCPads, and the PDG particle table in Particles(). /// /// This class is mostly used to access the root geometry using the UpdateGeometry() /// method. This method takes an event pointer as an argument, or uses the /// current event in memory, and verifies that the correct geometry is /// available. In addition, if the oaApplyAlign library is available, it will /// apply the alignment constant to the current event. /// /// If user code needs to fill tables with geometry information (e.g. the /// internal RECPACK sensor geometry), a COMET::IOADatabase::IGeometryChange call /// back should be registered using RegisterGeometryCallback(). See the /// COMET::IOADatabase::IGeometryChange class documentation for more details. /// class COMET::IOADatabase { friend class COMET::ICOMETInput; friend class COMET::IGeomIdManager; public: /// A base class to be registered by users providing a callback whenever /// the geometry has changed. The callback is registered using the /// COMET::IOADatabase::RegisterGeometryCallback() method. /// /// This class is most usefule whenever the a user has tables that need to /// be reinitialized after a geometry change. For example, if a user /// builds a table of sub-detector masses. To use this class, a user will /// declare a local class derived from IGeometryChange that overrides the /// Callback method. /// /// \code /// class IMyChangeClass: public COMET::IOADatabase::IGeometryChange { /// public: /// void Callback(const COMET::ICOMETEvent* const event) { /// // Do something with the current geometry /// TGeoManager* newGeom = COMET::IOADatabase::Get().UpdateGeometry(); /// } /// }; /// \endcode /// /// This callback must then be registered with IOADatabase. /// /// \code /// IMyChangeClass* myChangeClass = new IMyChangeClass; /// COMET::IOADatabase::Get().RegisterGeometryCallback(myChangeClass); /// \endcode /// /// All of the callbacks registered with IOADatabase will then be called /// when the geometry changes. The order of callbacks is unspecified /// (meaning don't count on a particular call order). class IGeometryChange { public: IGeometryChange() {} virtual ~IGeometryChange() {} // A method to be implemented by the user that will be called each // time the geometry has changed. The call back is called after the // alignment has been applied. This method should not modify the // event. In addition, don't depend on the order in which the // registered callbacks will be executed. virtual void Callback(const COMET::ICOMETEvent* const event) = 0; }; /// A base class to be registered to find the geometry associated with an /// event. In general, a derived class will be implemented in a separate /// package and use off-line calibration database to associate an event /// context with a particular geometry. The derived class must implement /// the GetHash method. class IGeometryLookup { public: IGeometryLookup() {} virtual ~IGeometryLookup() {} /// Return the hash value of the geometry that should be used with the /// event. If the hash value cannot be determined, an invalid hash /// should be returned. If an invalid hash is returned, then a /// default geometry file will be used. /// /// Note: The hash value is the last method of finding a geometry file /// and can be overridden by providing a geometry directly in the data /// file, setting the geometry file explicitly using /// COMET::IOADatabase::SetGeometryFile(), or setting the hash value /// explicitly using COMET::IOADatabase::SetGeometryHash(). /// /// This class is used in the FindEventGeometry method. virtual ISHAHashValue GetHash(const COMET::ICOMETEvent* const event) { return ISHAHashValue(); } }; /// A base class to be registered to find the alignment parameters /// associated with a particular geometry. In general, a derived class /// will be implemented in a separate package and use off-line calibration /// database to associate an event context with a particular alignment. /// /// The derived class must implement the Align method. The StartAlignment /// methods can be optionally implemented and is used to notify the /// IAlignmentLookup class that a new alignment is being started. /// /// This class is used in the AlignGeometry method. class IAlignmentLookup { public: IAlignmentLookup() {} virtual ~IAlignmentLookup() {} /// Called to find out if the alignment should be reapplied. If the /// alignment should be reapplied this will return true. If the /// geometry has been changed, then the alignment will be reapplied /// regardless of the CheckAlignment return value. virtual bool CheckAlignment(const COMET::ICOMETEvent* const event) { return true; } /// Called before the geometry alignment for an event is begun. This /// is used to notify the implemented class that a new alignment is /// about to start. It will generally trigger initialization. If an /// alignment should not be applied, then this should return an empty /// alignment. virtual COMET::IAlignmentId StartAlignment(const COMET::ICOMETEvent* const event) { return COMET::IAlignmentId(); } /// Return the alignment for a particular geometry id. This will be /// called multiple times. The alignment correction is returned as a /// TGeoMatrix pointer. When there is no more alignment to be /// returned, this should return a NULL TGeoMatrix pointer. The /// geomId argument is used to return the geometry identifier of the /// volume to be aligned. The ownership of the TGeoMatrix is claimed /// by the calling routine, so it must be generated using "new". /// /// The returned alignment is relative to the nominal position and /// rotation of the volume, and is specified in the master coordinate /// system. virtual TGeoMatrix* Align(const COMET::ICOMETEvent* const event, IGeometryId& geomId) {return NULL;} }; virtual ~IOADatabase() {;}; /// Get a pointer to the singleton instance of the database. static IOADatabase& Get(void); /// Return a pointer to the correct detector geometry for the event. If /// the argument is NULL, then this will try to get the geometry for the /// current event (as available from IEventFolder::GetCurrentEvent(), or /// the most recent available geometry. This method leaves the geometry /// unchanged if the current geometry is valid, and the current event /// context has not changed. /// /// \note This method may change the state of the geometry. This cannot /// be changed since the geometry may or may not needed to be reloaded /// depending on the state of the event. Users should plan on either /// checking the state of the geometry after using this method, or setting /// the geometry state using CdNode, or FindNode. In addition, users /// should assume that calling this method could invalidate any node /// identifiers they may be using. (e.g. the result of /// TGeoManager::GetCurrentNodeId()). /// /// The geometry is searched for in the following order: If the geometry /// file has been explicity set using COMET::IOADatabase::SetGeometryFile(), /// then use that geometry. Otherwise, if an explicit geometry hash value /// has been set using COMET::IOADatabase::SetGeometryHash(), use that /// geometry. Otherwise, if the event file contains a geometry, try to /// use that geometry. Otherwise, use the geometry associated with a hash /// value returned by the registered COMET::IOADatabase::IGeometryLookup class /// which generally looks up the hash value using the calibration /// database. /// /// \note The new geometry will only be loaded if there is a current /// event. If there isn't a current event, a previously loaded geometry /// will be returned. If there isn't a current and there isn't a /// previously loaded geometry, this will throw a ENoGeometry exception. /// If you want to force a geometry to be loaded even though you don't /// currently have access to an event, you can use /// COMET::IOADatabase::Get().GeomId().ReadEvent(COMET::ISHAHashValue()). While /// this isn't convenient, loading a geometry without an event is also /// rather unusual. /// /// If none of the attempts to find a geometry work this throws an /// ENoGeometry exception; however, since not having a geometry is a very /// serious error you will probably want your program to crash so you /// don't need to catch the ENoGeometry exception. /// /// After the geometry is loaded alignment parameters are applied. The /// alignment is applied using the AlignGeometry() method which uses /// COMET::IOADatabase::IAlignmentLookup class to lookup the coeficients. /// /// Users should register the COMET::IOADatabase::IGeometryLookup and /// COMET::IOADatabase::IAlignmentLookup classes using the /// RegisterGeometryLookup and RegisterAlignmentLookup methods. /// /// If you need to use tables that get initialized for each new geometry /// (for instance, you might want to cache the locations of various /// detectors for use in RECPACK), then you need to define and register a /// COMET::IOADatabase::IGeometryChange class using /// COMET::IOADatabase::RegisterGeometryCallback. See the /// COMET::IOADatabase::IGeometryChange for details and an example. TGeoManager* UpdateGeometry(ICOMETEvent* event=NULL); /// Get the pointer to the geometry TGeoManager* GetGeometry(); /// Return a reference to the ROOT TDatabasePDG. TDatabasePDG& ParticleData(void); /// Return a reference to the set of packages linked to the current /// executable. IPackageSet& PackageSet(void); /// Return a reference to the IDigitManager. IDigitManager& Digits(void); /// Return a reference to the IGeomIdManager. The IGeomIdManager class /// manages the geometries and alignments that are loaded to use with an /// event. It provides the implementation required to implement /// IOADatabase::UpdateGeometry(). All book keeping information about the /// current geometry (such as it's hashcode or the alignment id) should be /// accessed through IGeomIdManager. IGeomIdManager& GeomId(void); /// @{ Provide a file to override the standard geometry. Setting the /// geometry file to any value other than "" will cause IOADatabase to /// override the standard (default) geometry with the one found in the /// geometry file. You can generate a geometry file using the RunSimG4.exe /// /comet/export macro command. This resets the required geometry if /// called without an argument. void SetGeometryOverride(const std::string& geoName =""); void SetGeometryOverride(const COMET::ISHAHashValue& hc); void SetGeometryOverride(TGeoManager * geo); /// @} /// Register a user callback that will be called whenever the geometry /// changes (see the COMET::IOADatabase::IGeometryChange class). void RegisterGeometryCallback(COMET::IOADatabase::IGeometryChange* callback); /// Remove a user callback. void RemoveGeometryCallback(COMET::IOADatabase::IGeometryChange* callback); /// Remove all user callbacks. void ClearGeometryCallbacks(); /// Register a class implementing the search for the correct geometry to /// be used for an event. If called with "NULL", the default geometry /// lookup is installed. COMET::IOADatabase::IGeometryLookup* RegisterGeometryLookup( COMET::IOADatabase::IGeometryLookup* lookup); /// Register a class implementing the search for the correct geometry to /// be used for an event. A pointer to the previous alignment lookup /// class is returned. COMET::IOADatabase::IAlignmentLookup* RegisterAlignmentLookup( COMET::IOADatabase::IAlignmentLookup* lookup); /// Apply the alignment to the current geometry. The alignment is usually /// done automatically when the geometry is loaded, but this can be called /// multiple times by the user as well. Each time it is called, the /// current set of physical nodes is cleared and the alignment is /// reapplied to the baseline geometry. /// /// Be careful, the ROOT physical geometry alignment code is a relatively /// slow. In practical terms, the alignment should only be applied when /// the geometry is loaded. /// /// If this applies an alignment, it will return the IAlignmentId /// associated with the new alignment. Otherwise, it will return an /// invalid alignment. virtual void AlignGeometry(const COMET::ICOMETEvent* const event); /// Provide a file name (and path) for a file that should provide the EM /// field description object, rather than searching in the current input file void SetEMFieldDescriptionOverride(const std::string& fieldFileName ){ fEMFieldDescriptionOverride=fieldFileName; } /// Obtain the description object for the EM field for this event /// In the future this may be defined event by event as the geometry is, but /// for now the event parameter is not used COMET::IFieldDescription* EMFieldDescription(const ICOMETEvent* event=NULL); /// Obtain the directory of the input root file. TDirectory* GetInputFileDirectory() const; private: IOADatabase(); IOADatabase(const IOADatabase&); IOADatabase& operator=(const IOADatabase&); /// Find the hash code for a particular event. This uses the /// IGeometryLookup class to lookup the correct hash code for the event. /// If the event hash code is not found, then this returns an invalid hash /// code. This is used by IGeomIdManager to access the IGeometryLookup /// class. ISHAHashValue FindEventGeometry(const ICOMETEvent *const event) const; /// Call the registered geometry callbacks. This is used by /// IGeomIdManager to notify the user routines when the geometry changes. void ApplyGeometryCallbacks(const COMET::ICOMETEvent* event); /// Use the IAlignmentLookup method to check if a new alignment should be /// applied. If this returns true, the we need a new alignment. This is /// used by IGeomIdManager to short circuit the alignment application. bool CheckAlignment(const COMET::ICOMETEvent* const event); /// Use the IAlignmentLookup class to get the actual alignment. virtual COMET::IAlignmentId ApplyAlignmentLookup(const COMET::ICOMETEvent* event); /// Set the current input file for the data base. This must be set for /// many of the methods to work correctly. This is used by ICOMETInput to /// notify IOADatabase when the input file changes. void SetCurrentInputFile(TFile* input); /// Get the current input event file. This is used by IGeomIdManager to /// find the file with the geometry. TFile* CurrentInputFile(void) {return fCurrentInputFile;} static IOADatabase *fOADatabase; /// The current event file. This is only valid for a ROOT input file. TFile* fCurrentInputFile; /// A pointer to a class which will find the correct geometry to be used /// with an event. IGeometryLookup* fGeometryLookup; /// A pointer to a class which will find the alignment associated with the /// current geometry used for this event. IAlignmentLookup* fAlignmentLookup; /// A connection to the ROOT particle data book data base. TDatabasePDG* fParticleData; /// The set of packages linked with the executable. IPackageSet fPackageSet; /// Manage the connection to the oaRawEvent digitized data. IDigitManager* fDigits; /// Manage the mapping of the root TGeoManager node identifiers to the /// geometry identifiers. IGeomIdManager* fGeomId; /// A vector of call backs that will be called whenever the geometry /// changes. std::set fGeometryCallbacks; /// A string to specify a fieldmap description over-ride file std::string fEMFieldDescriptionOverride; /// Pointer to the current field description object COMET::IFieldDescription* fEMFieldDescription; ClassDef(IOADatabase,0); }; #endif