diff --git a/Detector/DetCommon/compact/HcalBarrelAir.xml b/Detector/DetCommon/compact/HcalBarrelAir.xml new file mode 100644 index 000000000..6dc41bd68 --- /dev/null +++ b/Detector/DetCommon/compact/HcalBarrelAir.xml @@ -0,0 +1,51 @@ + + + + + HCal Place-Holder + + + + + + + + + + + + + Envelope for HCal barrel + + + + + + + + diff --git a/Detector/DetCommon/compact/TrackerBarrelAir.xml b/Detector/DetCommon/compact/TrackerBarrelAir.xml new file mode 100644 index 000000000..b0e8614f9 --- /dev/null +++ b/Detector/DetCommon/compact/TrackerBarrelAir.xml @@ -0,0 +1,37 @@ + + + + + Tracker Place-Holder + + + + + + + + + + Envelope for Tracker + + + + + + diff --git a/Detector/DetComponents/src/RedoSegmentation.cpp b/Detector/DetComponents/src/RedoSegmentation.cpp index b22163226..97c76691b 100644 --- a/Detector/DetComponents/src/RedoSegmentation.cpp +++ b/Detector/DetComponents/src/RedoSegmentation.cpp @@ -17,6 +17,7 @@ DECLARE_ALGORITHM_FACTORY(RedoSegmentation) RedoSegmentation::RedoSegmentation(const std::string& aName, ISvcLocator* aSvcLoc) : GaudiAlgorithm(aName, aSvcLoc) { declareProperty("inhits", m_inHits, "Hit collection with old segmentation (input)"); declareProperty("outhits", m_outHits, "Hit collection with modified segmentation (output)"); + } RedoSegmentation::~RedoSegmentation() {} @@ -83,11 +84,17 @@ StatusCode RedoSegmentation::execute() { // cellID contains the volumeID that needs to be copied to the new id uint64_t oldid = 0; uint debugIter = 0; + + int nhits = 0; + for (const auto& hit : *inHits) { + fcc::CaloHit newHit = outHits->create(); newHit.energy(hit.energy()); newHit.time(hit.time()); - m_oldDecoder->setValue(hit.cellId()); + + nhits++; + if (debugIter < m_debugPrint) { debug() << "OLD: " << m_oldDecoder->valueString() << endmsg; } @@ -107,6 +114,7 @@ StatusCode RedoSegmentation::execute() { debugIter++; } } + info() << "nhits = " << nhits << endmsg; return StatusCode::SUCCESS; } diff --git a/Detector/DetComponents/src/RedoSegmentation.h b/Detector/DetComponents/src/RedoSegmentation.h index cf1238ba1..382b4598c 100644 --- a/Detector/DetComponents/src/RedoSegmentation.h +++ b/Detector/DetComponents/src/RedoSegmentation.h @@ -83,5 +83,6 @@ class RedoSegmentation : public GaudiAlgorithm { std::vector m_detectorIdentifiers; /// Limit of debug printing Gaudi::Property m_debugPrint{this, "debugPrint", 10, "Limit of debug printing"}; + }; #endif /* DETCOMPONENTS_REDOSEGMENTATION_H */ diff --git a/Detector/DetComponents/tests/options/redoSegmentationXYZ_DEcal.py b/Detector/DetComponents/tests/options/redoSegmentationXYZ_DEcal.py new file mode 100644 index 000000000..2638a7db8 --- /dev/null +++ b/Detector/DetComponents/tests/options/redoSegmentationXYZ_DEcal.py @@ -0,0 +1,61 @@ +from Gaudi.Configuration import * +from Configurables import ApplicationMgr + +from Configurables import FCCDataSvc +inputfile = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/batch_eos/50Layers_2.1mmW_50umPixels_18umThick_FCCSW0.8/100GeV_BFIELD4T_ETAMIN-0.001_ETAMAX0.001/output_100GeV_BFIELD4T_1.root" +podiosvc = FCCDataSvc("EventDataSvc", input=inputfile) + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=["positionedCaloHits"], OutputLevel=DEBUG) + +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_50Layers_2.1mmW_50umPixels_18umThick.xml' + ], + OutputLevel = DEBUG) + +from Configurables import RedoSegmentation +resegment = RedoSegmentation("ReSegmentation", + # old bitfield (readout) + oldReadoutName = "BarDECal_Readout", + # specify which fields are going to be deleted + oldSegmentationIds = ["x","y","z"], + # new bitfield (readout), with new segmentation + newReadoutName="BarDECal_Pads", + OutputLevel = DEBUG) +# clusters are needed, with deposit position and cellID in bits +resegment.inhits.Path = "positionedCaloHits" +resegment.outhits.Path = "newCaloHits" + +from Configurables import CreateCaloCells +createcells = CreateCaloCells("CreateCaloCells", + doCellCalibration = False, + addCellNoise = False, filterCellNoise = False, + OutputLevel = DEBUG) +createcells.hits.Path="newCaloHits" +createcells.cells.Path="newCaloCells" + +from Configurables import DECalLongitudinalTest +hist = DECalLongitudinalTest("hists", + readoutName = "BarDECal_Readout", + layerFieldName = "layer", + numLayers = 50, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = DEBUG) +hist.deposits.Path="positionedCaloHits" + +THistSvc().Output = ["rec DATAFILE='./hist_test.root' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=True +THistSvc().AutoSave=True +THistSvc().AutoFlush=False +THistSvc().OutputLevel=INFO + +from Configurables import FCCDataSvc, PodioOutput +#podiosvc = FCCDataSvc("EventDataSvc") +podioout = PodioOutput("out", filename="/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/batch_eos/50Layers_2.1mmW_50umPixels_18umThick_FCCSW0.8/100GeV_BFIELD4T_ETAMIN-0.001_ETAMAX0.001/testResegmentationXYZ_100GeV.root") +podioout.outputCommands = ["keep *"] + +ApplicationMgr(EvtSel='NONE', + EvtMax=5000, + TopAlg=[podioinput, resegment, createcells,hist, podioout], + ExtSvc = [podiosvc, geoservice], + OutputLevel=DEBUG) diff --git a/Detector/DetFCChhECalDigital/CMakeLists.txt b/Detector/DetFCChhECalDigital/CMakeLists.txt new file mode 100644 index 000000000..6404a80c8 --- /dev/null +++ b/Detector/DetFCChhECalDigital/CMakeLists.txt @@ -0,0 +1,27 @@ +################################################################################ +# Package: DetFCChhECalDigital +################################################################################ +gaudi_subdir(DetFCChhECalDigital v1r0) + +gaudi_depends_on_subdirs(GaudiKernel + Detector/DetExtensions) + + +find_package(DD4hep) +find_package(Geant4) +include(${Geant4_USE_FILE}) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${DD4hep_ROOT}/cmake ) +include( DD4hep ) + +find_package(ROOT COMPONENTS MathCore GenVector Geom REQUIRED) + +gaudi_add_module(DetFCChhECalDigital + src/*.cpp + INCLUDE_DIRS DD4hep ROOT DetExtensions Geant4 + LINK_LIBRARIES GaudiKernel DD4hep ROOT Geant4) + +set(LIBRARY_OUTPUT_PATH ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) +message(STATUS "LIBRARY_OUTPUT_PATH -> ${LIBRARY_OUTPUT_PATH}") +dd4hep_generate_rootmap(DetFCChhECalDigital) + diff --git a/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_50Layers_2.1mmW_50umPixels_18umThick_RRB.xml b/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_50Layers_2.1mmW_50umPixels_18umThick_RRB.xml new file mode 100644 index 000000000..c6048ab9e --- /dev/null +++ b/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_50Layers_2.1mmW_50umPixels_18umThick_RRB.xml @@ -0,0 +1,84 @@ + + + + + + DECal very conceptual design + + + + + + + + + + + + + + + + + + + + + + + + + system:3,active:1,EM_barrel:1,layer:6,digital:1,x:-17,y:-17,z:-18 + + + + + + + + + system:3,active:1,EM_barrel:1,layer:6,digital:1,x:-15,y:-15,z:-18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Detector/DetFCChhECalDigital/src/ECalBarrel_geo.cpp b/Detector/DetFCChhECalDigital/src/ECalBarrel_geo.cpp new file mode 100644 index 000000000..50b374caa --- /dev/null +++ b/Detector/DetFCChhECalDigital/src/ECalBarrel_geo.cpp @@ -0,0 +1,356 @@ +// DD4hep includes +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Shapes.h" +#include "DD4hep/Objects.h" + +#include "XML/XMLElements.h" + +// Gaudi +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/IMessageSvc.h" +#include "GaudiKernel/MsgStream.h" + +#include "cmath" + + +namespace det { + +static dd4hep::detail::Ref_t createECal (dd4hep::Detector& lcdd,dd4hep::xml::Handle_t xmlElement, + dd4hep::SensitiveDetector sensDet) +{ + + ServiceHandle msgSvc("MessageSvc", "DECalConstruction"); + MsgStream lLog(&(*msgSvc), "DECalConstruction"); + + lLog << MSG::DEBUG << "++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endmsg; + lLog << MSG::DEBUG << "\t\t\t Building DECAL " << endmsg; + lLog << MSG::DEBUG << " +++++++++++++++++++++++++++++++++++++++++++++++++++++" << endmsg; + + // Getting the detectors various values from the xml file + + dd4hep::xml::DetElement xmlDet = xmlElement; + std::string detName = xmlDet.nameStr(); + //Make DetElement + dd4hep::DetElement eCal(detName, xmlDet.id()); + + + + dd4hep::xml::DetElement calo = xmlDet.child(_Unicode(calorimeter)); + dd4hep::xml::Dimension calo_dims(calo.dimensions()); + std::string calo_name=calo.nameStr(); + double calo_id=calo.id(); + + //dd4hep::xml::DetElement trkr = calo.child(_Unicode(tracker)); + std::string trkr_mat = "Silicon";//trkr.materialStr(); + double trkr_tck = 0;//trkr.thickness(); + + dd4hep::xml::DetElement active = calo.child(_Unicode(active)); + std::string active_mat=active.materialStr(); + double active_tck=active.thickness(); + + + dd4hep::xml::DetElement samples_xml = calo.child(_Unicode(layers)); + int active_samples = samples_xml.repeat(); + + dd4hep::xml::DetElement substrate = calo.child(_Unicode(substrate)); + std::string substrate_mat=substrate.materialStr(); + double substrate_tck=substrate.thickness(); + + dd4hep::xml::DetElement passive = calo.child(_Unicode(passive)); + std::string passive_mat=passive.materialStr(); + double passive_tck=passive.thickness(); + + dd4hep::xml::DetElement padding = calo.child(_Unicode(spacing)); + std::string padding_mat=padding.materialStr(); + double padding_tck=padding.thickness(); + + + + + // here we take the fabs value of padding as if it is negative it goes before the W volume + double module_tck = active_tck+substrate_tck+passive_tck+std::fabs(padding_tck); + double calo_tck=(active_samples*module_tck) + trkr_tck; + + //Introduce number of staves, modules from the xml file: + int nStaves = calo_dims.numsides(); + int nModules = calo_dims.nmodules(); + int testing = 1; + + lLog << MSG::INFO << "Tracker Material Thickness = " << trkr_tck << endmsg; + + lLog << MSG::INFO << "ECAL Epitaxial Thickness = " << active_tck << endmsg; + lLog << MSG::INFO << "ECAL Substrate Thickness = " << substrate_tck << endmsg; + lLog << MSG::INFO << "ECAL Passive Thickness = " << passive_tck << endmsg; + lLog << MSG::INFO << "ECAL Between Layers Thickness = " << padding_tck << endmsg; + lLog << MSG::INFO << "ECAL Module Thickness = " << module_tck << endmsg; + + lLog << MSG::INFO << "nSamplings Layers = " << active_samples << endmsg; + lLog << MSG::INFO << "Total Calorimeter thickness = " << calo_tck << endmsg; + + //Log number of staves/modules in the log file: + lLog << MSG::INFO << "nStaves = " << nStaves << endmsg; + lLog << MSG::INFO << "nModules = " << nModules << endmsg; + + // Make volume that envelopes the whole barrel; set material to air + dd4hep::xml::Dimension dimensions(xmlDet.dimensions()); + dd4hep::Tube envelopeShape(dimensions.rmin(), dimensions.rmax(), dimensions.dz()); + dd4hep::Volume envelopeVolume(detName, envelopeShape, lcdd.air()); + // Invisibility seems to be broken in visualisation tags, have to hardcode that + std::cout << "dimensions.visStr() = " << dimensions.visStr()<< std::endl; + envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); + + // create a lump of air the entire size of the barrel ECAL (Cylindrical) + // place it within the ECAL envelope + dd4hep::DetElement caloDet(calo_name, calo_id); + dd4hep::Tube caloShape(calo_dims.rmin() , calo_dims.rmax(), calo_dims.dz()); + lLog << MSG::INFO << "ECAL: Building the calorimeter from " << calo_dims.rmin() << " to " << calo_dims.rmax() << endmsg; + dd4hep::Volume caloVolume(padding_mat, caloShape, lcdd.material(padding_mat)); + lLog << MSG::DEBUG << "ECAL: Filling the calorimeter volume with " << padding_mat << endmsg; + dd4hep::PlacedVolume placedCalo = envelopeVolume.placeVolume(caloVolume); + placedCalo.addPhysVolID("EM_barrel", calo_id); + caloDet.setPlacement(placedCalo); + + // set the sensitive detector type to the DD4hep calorimeter + sensDet.setType("DigitalCalorimeterSD"); + + // if we add material for the tracker then it needs to be placed first + if(trkr_tck > 0.0) { + dd4hep::DetElement trkrLayer(trkr_mat, 0); + dd4hep::Tube trkrShape(calo_dims.rmin(), calo_dims.rmin()+trkr_tck, calo_dims.dz()); + lLog << MSG::DEBUG << "TRKR: Tracker from " << calo_dims.rmin() << " to " << calo_dims.rmin()+trkr_tck << endmsg; + dd4hep::Volume trkrVolume(trkr_mat, trkrShape, lcdd.material(trkr_mat)); + dd4hep::PlacedVolume placedTrkrLayer = caloVolume.placeVolume(trkrVolume); + trkrLayer.setPlacement(placedTrkrLayer); + } + + + // START OF TONY's STUFF + // Calorimeter runs + // 1) epitaxial + // 2) substrate + // 3) passive material (absorber) + // 4) air gap between layers (this is the caleVolume made of air + + // STANDARD CONFIGURATION WITH PADDING (air) >= 0 mm + // | MODULE 1 | MODULE 2 | ... | MODULE N | + // | | | | | | | | | ... | | | | | + // | E | S | A | A | E | S | A | A | ... | E | S | A | A | + // | P | U | B | I | P | U | B | I | ... | P | U | B | I | + // | I | B | S | R | I | B | S | R | ... | I | B | S | R | + // | | | | | | | | | ... | | | | | + + // ALTERNATIVE CONFIGURATION WITH PADDING (air) < 0 mm + // | MODULE 1 | MODULE 2 | ... | MODULE N | + // | | | | | | | | | ... | | | | | + // | E | S | A | A | E | S | A | A | ... | E | S | A | A | + // | P | U | I | B | P | U | I | B | ... | P | U | I | B | + // | I | B | R | S | I | B | R | S | ... | I | B | R | S | + // | | | | | | | | | ... | | | | | + + //Leave option for circular geometry if nStaves == 1: + if (nStaves == 1) + { + // loop on the sensitive and substrate layers and place within the caloVolume + int l=1; + for (int i=0;i +#include + +#include "TFile.h" +#include "TH1F.h" + +/** DigitalCalorimeterSD DetectorDescription/DetSensitive/src/DigitalCalorimeterSD.h DigitalCalorimeterSD.h + * + * Simple sensitive detector for calorimeter. + * It is based on DD4hep::Simulation::Geant4GenericSD (but it is not identical). + * In particular, the position of the hit is set to G4Step::GetPreStepPoint() position. + * New hit is created for each energy deposit. + * No timing information is saved. + * + * @author Anna Zaborowska + */ + +struct Strixel +{ + int layer; + int x; + int y; + int z; + + bool operator<(const Strixel &other) const + { + if(layer + struct hash + { + std::size_t operator()(const Strixel& s) const + { + using std::size_t; + using std::hash; + using std::string; + + // Compute individual hash values for first, + // second and third and combine them using XOR + // and bit shifting: + + return hash()( + std::to_string(s.layer) +","+ + std::to_string(s.x) +","+ + std::to_string(s.y) +","+ + std::to_string(s.z) + ); + } + }; + +} + +struct Pad +{ + int layer; + int r; + int z; + + bool operator<(const Pad &other) const + { + if(layer + struct hash + { + std::size_t operator()(const Pad& p) const + { + using std::size_t; + using std::hash; + using std::string; + + // Compute individual hash values for first, + // second and third and combine them using XOR + // and bit shifting: + + return hash()( + std::to_string(p.layer) +","+ + std::to_string(p.r) +","+ + std::to_string(p.z) + ); + } + }; + +} + +namespace det { +class DigitalCalorimeterSD : public G4VSensitiveDetector +{ + public: + /** Constructor. + * @param aDetectorName Name of the detector + * @param aReadoutName Name of the readout (used to name the collection) + * @param aSeg Segmentation of the detector (used to retrieve the cell ID) + */ + DigitalCalorimeterSD(const std::string& aDetectorName, + const std::string& aReadoutName, + const dd4hep::Segmentation& aSeg); + /// Destructor + virtual ~DigitalCalorimeterSD(); + /** Initialization. + * Creates the hit collection with the name passed in the constructor. + * The hit collection is registered in Geant. + * @param aHitsCollections Geant hits collection. + */ + virtual void Initialize(G4HCofThisEvent* aHitsCollections) final; + /** Process hit once the particle hit the sensitive volume. + * Checks if the energy deposit is larger than 0, calculates the position and cellID, + * saves that into the hit collection. + * New hit is created for each energy deposit. + * @param aStep Step in which particle deposited the energy. + */ + virtual bool ProcessHits(G4Step* aStep, G4TouchableHistory*) final; + + virtual void EndOfEvent(G4HCofThisEvent* aHitsCollections) final; + + virtual bool IsAllowedCellID(unsigned long cid) final; + virtual void AddCellIDMask(unsigned long cid) final; + virtual void UpdateCellIDMask() final; + +private: + /// Collection of calorimeter hits + G4THitsCollection* m_calorimeterCollection; + G4THitsCollection* m_tempCollection; + /// Segmentation of the detector used to retrieve the cell Ids + dd4hep::Segmentation m_seg; + + std::string m_pixelsOverThresholdFileName; + std::ofstream m_pixelsOverThresholdFile; + + std::string m_pixelsOverThresholdPerLayerFileName; + std::ofstream m_pixelsOverThresholdPerLayerFile; + + std::string m_mipsPerPixelFileName; + std::ofstream m_mipsPerPixelFile; + + std::string m_padMultiplicityFileName; + std::ofstream m_padMultiplicityFile; + + bool m_headerPrinted; + bool m_countParticlesPerPixel; + int m_incidentParticles; + + std::map m_CellIDsMaskedFromPreviousEvent; + std::map m_TrackIDsPerEvent; + + //TFile* m_rootFile; + //TH1F* m_padMultiplicity; +}; +} + +#endif /* DETSENSITIVE_DIGITALCALORIMETERSD_H */ diff --git a/Detector/DetSensitive/src/DigitalCalorimeterSD.cpp b/Detector/DetSensitive/src/DigitalCalorimeterSD.cpp new file mode 100644 index 000000000..4787a8aaf --- /dev/null +++ b/Detector/DetSensitive/src/DigitalCalorimeterSD.cpp @@ -0,0 +1,400 @@ +#include "DetSensitive/DigitalCalorimeterSD.h" + +// FCCSW +#include "DDSegmentation/BitField64.h" +#include "DetCommon/DetUtils.h" +#include "DDSegmentation/Segmentation.h" +#include "DDSegmentation/CartesianGridXYZ.h" + +// DD4hep +#include "DDG4/Geant4Mapping.h" +#include "DDG4/Geant4VolumeManager.h" + + +// CLHEP +#include "CLHEP/Vector/ThreeVector.h" + +// Geant4 +#include "G4SDManager.hh" +#include "G4ThreeVector.hh" +#include "G4SystemOfUnits.hh" + +#include "iostream" +#include "map" +#include "unordered_map" + +namespace det { +DigitalCalorimeterSD::DigitalCalorimeterSD(const std::string& aDetectorName, + const std::string& aReadoutName, + const dd4hep::Segmentation& aSeg) + : G4VSensitiveDetector(aDetectorName), m_seg(aSeg), m_calorimeterCollection(nullptr) { + // name of the collection of hits is determined byt the readout name (from XML) + collectionName.insert(aReadoutName); + + m_headerPrinted = false; + m_countParticlesPerPixel = true; + +} + +DigitalCalorimeterSD::~DigitalCalorimeterSD(){ +} + +void DigitalCalorimeterSD::Initialize(G4HCofThisEvent* aHitsCollections) +{ + // create a collection of hits and add it to G4HCofThisEvent + // deleted in ~G4Event + m_calorimeterCollection = new G4THitsCollection + (SensitiveDetectorName,collectionName[0]); + aHitsCollections->AddHitsCollection(G4SDManager::GetSDMpointer()->GetCollectionID(m_calorimeterCollection), m_calorimeterCollection); + + //this collection is just a temp and not added to the HitsCollection just used to store raw hits before summing together + m_tempCollection = new G4THitsCollection + (SensitiveDetectorName,"temp"); + + // m_pixelsOverThresholdFile.open("pixelsOverThreshold.txt", std::ios_base::app);. + + if(!m_headerPrinted){ + if(m_countParticlesPerPixel) { + std::cout << "\n\n\n###############################" << std::endl; + std::cout << "#\n#" << std::endl; + std::cout << "## Counting Pixels in DECAL Mode " << std::endl; + std::cout << "#\n#\n###############################" << std::endl; + } + + std::cout << "incident particles\tunique cellIDs\tcells over thresh\tunique strixels\tstrixel pixels (3)\tstrixel pixels (7)\tstrixel pixels (15)\tstrixel pixels (31)" << std::endl; + m_headerPrinted=true; + } + m_incidentParticles = 0; + + m_TrackIDsPerEvent.clear(); + + +} + +bool DigitalCalorimeterSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) +{ + // check if energy was deposited + G4double edep = aStep->GetTotalEnergyDeposit(); + if(edep==0.) + return false; + + CLHEP::Hep3Vector prePos = aStep->GetPreStepPoint()->GetPosition(); + CLHEP::Hep3Vector postPos = aStep->GetPostStepPoint()->GetPosition(); + + + bool isIncident = false; + + // count up the number of particles which enter the epitaxial layer + if(aStep->GetPreStepPoint()->GetStepStatus() == fGeomBoundary){ + m_incidentParticles++; + isIncident = true; + + G4int trackID = aStep->GetTrack()->GetTrackID(); + std::map::iterator trackID_it = m_TrackIDsPerEvent.find(trackID); + if(m_TrackIDsPerEvent.find(trackID) != m_TrackIDsPerEvent.end()) { + (*trackID_it).second++; + } else { + m_TrackIDsPerEvent[trackID] = 1; + } + } + + dd4hep::Position pos(prePos.x(), prePos.y(), prePos.z()); + auto hit = new dd4hep::sim::Geant4CalorimeterHit(pos); + //hit->cellID = segmentation::cellID(m_seg, *aStep); + hit->cellID = utils::cellID(m_seg, *aStep); + + // if we have a step which is not incident make energy negative + // this allows me to count incident particles later on + if(!isIncident) { + edep *= -1; + } + hit->energyDeposit = edep; + m_tempCollection->insert(hit); + + return true; +} + + + +void DigitalCalorimeterSD::EndOfEvent(G4HCofThisEvent*) { + + int nHits = m_tempCollection->entries(); + + std::cout << "Total number of TrackIDs in SD = " << m_TrackIDsPerEvent.size() << std::endl; + + // this map stored the energy per cell + // map.first = cellID + // map.second.first = number of particles into the cell + // map.second.second = total energy deposited in the cell + std::map > counter; + dd4hep::sim::Geant4CalorimeterHit* hit = nullptr; + + //std::cout << "####" << m_seg->type() << std::endl; + + // loop through all of the hits in an event and sum the energy deposited per cell + for(int i=0; i (m_tempCollection->GetHit(i)); + + // this bit of code allows us to check that is incident and that we should count as new particles + // we then make the value of energy +ve again for ease of adding + bool isIncident = true; + if(hit->energyDeposit < 0.0) { + isIncident = false; + hit->energyDeposit *= -1; + //std::cout << "NON INCIDENT STEP" << std::endl; + } + + // ensure that there are no longer energy less than zero + if(hit->energyDeposit < 0.0) { + std::cout << "STILL A HIT WITH NEGATIVE EDEP MORON!" << std::endl; + } + + uint64_t cellID = hit->cellID; + + // for the DEcal chip being designed we have a dead time. This bool ensures the pixel is not dead + // if useMask=false then IsAllowedCellID always returns true + if(IsAllowedCellID(cellID)){ + + std::map >::iterator it = counter.find(cellID); + + if(counter.find(cellID) != counter.end()) { + + // incrimnet the number of incident particles + if(isIncident) { + (*it).second.first++; + } + (*it).second.second->energyDeposit += hit->energyDeposit; + } else { + // this ensures that we only count incident particles + // if not incident set to zero so we do count incident later on but do not double count + int nparts = 0; + if(isIncident) { + nparts = 1; + } + std::pair info = std::make_pair(nparts, hit); + counter[cellID] = info; + } + } + } + + // now loop through all the hits and check the Mask. Cannot do it before as may cut out multiple hits to cells + bool useMask = false; + for(int i=0; i (m_tempCollection->GetHit(i)); + uint64_t cellID = hit->cellID; + AddCellIDMask(cellID); + } + + // apply a threshold of 480 electrons to each cell + double threshold = 0.0; //480*0.0000036; // 480 electrons in MeV which should be default value + int pixelsOverThreshold = 0; + int pixelsOverThresholdPerLayer[50]; + std::vector mipsPerPixel[50]; + for(int n(0); n<50; ++n){ + pixelsOverThresholdPerLayer[n]=0; + mipsPerPixel[n].clear(); + } + + dd4hep::sim::Geant4CalorimeterHit* digi = nullptr; + std::map >::iterator it; + std::map StrixelHitCounter; + for(it=counter.begin(); it!=counter.end(); it++) + { + if(useMask) { + AddCellIDMask((*it).second.second->cellID); + } + + // if the energy deposited in the cellID is gtreather than threshold then do something + if((*it).second.second->energyDeposit>=threshold) { + pixelsOverThreshold++; + // insert the collection to G4 so can be passed on later + digi = dynamic_cast ((*it).second.second); + // this line overwrites the time parameter with the number of particles per pixel + std::vector conts; + dd4hep::sim::Geant4Hit::MonteCarloContrib cont(0,0,0,0); + + if(m_countParticlesPerPixel) { + //digi->energyDeposit = (*it).second.first; // overwrite the energy deposit with the number of mips in the cell + cont.time = (*it).second.first; + } + + conts.push_back(cont); + digi->truth = conts; + m_calorimeterCollection->insert(digi); // this passes to ROOT the readout... interesting! + + } + } + + std::cout << m_TrackIDsPerEvent.size() << " " << m_tempCollection->entries() << " " << m_incidentParticles << " " << m_calorimeterCollection->entries() << std::endl; + + UpdateCellIDMask(); + + // below this point is DECal chip specific where the readout is reconfidured + // not needed for the analogue SiW + + int strixelHits = StrixelHitCounter.size(); + int strixelPixelHits_3 = 0; + int strixelPixelHits_7 = 0; + int strixelPixelHits_15 = 0; + int strixelPixelHits_31 = 0; + //int strixelMaxPixels = 3; + + std::map > PadHitCounter; + std::map::iterator it_strixel; + for(it_strixel=StrixelHitCounter.begin(); it_strixel!=StrixelHitCounter.end(); ++it_strixel) { + + // convert strixel to pad + double x1 = (*it_strixel).first.x; + double y1 = (*it_strixel).first.y; + double r1 = pow((x1*x1+y1*y1),0.5); + + double x0 = r1; + double y0 = 0.0; // set r0 to be at y=0 x=radius + double cord = pow(pow((x1-x0),2)+pow((y1-y0),2),0.5); + double theta = 2*asin(cord/(2*r1)); + double pos_round_circ = theta*r1; + + // for pad counting + std::vector counter; + counter.resize(6); + counter.at(0) = 1; + + int npixels = (*it_strixel).second; + + if(npixels<3) { + strixelPixelHits_3 += npixels; + counter.at(1) = npixels; + } + else { + strixelPixelHits_3 += 3; + counter.at(1) = 3; + } + + if(npixels<7) { + strixelPixelHits_7 += npixels; + counter.at(2) = npixels; + } + else { + strixelPixelHits_7 += 7; + counter.at(2) = 7; + } + if(npixels<15) { + strixelPixelHits_15 += npixels; + counter.at(3) = npixels; + } + else { + strixelPixelHits_15 += 15; + counter.at(3) = 15; + } + + if(npixels<31) { + strixelPixelHits_31 += npixels; + counter.at(4) = npixels; + } + else { + strixelPixelHits_31 += 31; + counter.at(4) = 31; + } + + counter.at(5) = npixels; + + //------------------------------------------------- + Pad pad; + pad.layer = (*it_strixel).first.layer; + pad.r = floor(pos_round_circ/5.0); + pad.z = (*it_strixel).first.z; + + std::map >::iterator it_pad = PadHitCounter.find(pad); + if( PadHitCounter.find(pad) != PadHitCounter.end() ) { + // add to the relevant int part + (*it_pad).second.at(0) += counter.at(0); // count hits in pad limited by 1 hit per column + (*it_pad).second.at(1) += counter.at(1); // count hits in pad limited by 3 hits per column + (*it_pad).second.at(2) += counter.at(2); // count hits in pad limited by 7 hits per column + (*it_pad).second.at(3) += counter.at(3); // count hits in pad limited by 15 hits per column + (*it_pad).second.at(4) += counter.at(4); // count hits in pad limited by 31 hits per column + (*it_pad).second.at(5) += counter.at(5); // count all hits in pad + } else { + PadHitCounter[pad] = counter; + } + + } + + // now we loop through the map of pads to get total hits + if(!m_padMultiplicityFile.is_open()) { + std::map >::iterator it_pad; + m_padMultiplicityFile.open(m_padMultiplicityFileName, std::ios_base::app); + for(it_pad=PadHitCounter.begin(); it_pad!=PadHitCounter.end(); ++it_pad) { + + //std::cout << (*it_pad).second.at(1) << " "; + m_padMultiplicityFile << (*it_pad).second.at(1) << " "; + + } + m_padMultiplicityFile << "\n"; + m_padMultiplicityFile.close(); + } + +// std::cout << std::endl; +// std::cout << nHits << " " << pixelsOverThreshold << std::endl; +// std::cout << "Total number of unique cellIDs = " << pixelsOverThreshold << std::endl; +// std::cout << "Total number of unique strixels = " << strixelHits << std::endl; +// std::cout << "Total number of strixel pixels (3) = " << strixelPixelHits_3 << std::endl ; +// std::cout << "Total number of strixel pixels (7) = " << strixelPixelHits_7 << std::endl; +// std::cout << "Total number of strixel pixels (15) = " << strixelPixelHits_15 << std::endl; +// std::cout << "Total number of strixel pixels (31) = " << strixelPixelHits_31 << std::endl; +// std::cout << "Total number of unique pads = " << PadHitCounter.size() << std::endl << std::endl; + + + std::cout << "Counters\t"<< m_incidentParticles << "\t" << counter.size() << "\t" << pixelsOverThreshold << "\t" << strixelHits << "\t" << strixelPixelHits_3 << "\t" << strixelPixelHits_7 << "\t" << strixelPixelHits_15 << "\t" << strixelPixelHits_31 << "\t" << PadHitCounter.size() << std::endl; + + + + + +} + + +bool DigitalCalorimeterSD::IsAllowedCellID(unsigned long cid) { + // check if the cellID occurred in the previous event + // if the counter is zero the cell is allowed and can remove cell from the mask + std::map::iterator valid_it = m_CellIDsMaskedFromPreviousEvent.find(cid); + if(m_CellIDsMaskedFromPreviousEvent.find(cid) != m_CellIDsMaskedFromPreviousEvent.end()) { + if((*valid_it).second > 0) { + //std::cout << "CellID " << cid << " is inactive for the next " << (*valid_it).second << " events" << std::endl; + return false; + } else { + m_CellIDsMaskedFromPreviousEvent.erase(valid_it); + return true; + } + } else { + return true; + } +} + +void DigitalCalorimeterSD::AddCellIDMask(unsigned long cid) { + // look for the cellID in the std::map. If it exists then reset the dead time + // if it does not exist then add it to the map + int nEventsMasked = 40; + std::map::iterator add_it = m_CellIDsMaskedFromPreviousEvent.find(cid); + if(m_CellIDsMaskedFromPreviousEvent.find(cid) != m_CellIDsMaskedFromPreviousEvent.end()) { + (*add_it).second = nEventsMasked; + } else { + m_CellIDsMaskedFromPreviousEvent[cid] = nEventsMasked; + } +} + +void DigitalCalorimeterSD::UpdateCellIDMask() { + // loop through the mask and remove one from each mask ID. + // if it reaches zero then remove from the list. + std::map::iterator update_it; + for (update_it = m_CellIDsMaskedFromPreviousEvent.begin(); update_it != m_CellIDsMaskedFromPreviousEvent.end(); update_it++){ + (*update_it).second -= 1; + } + for (update_it = m_CellIDsMaskedFromPreviousEvent.begin(); update_it != m_CellIDsMaskedFromPreviousEvent.end(); update_it++){ + if((*update_it).second == 0) m_CellIDsMaskedFromPreviousEvent.erase(update_it); + } + std::cout << "There are currently " << m_CellIDsMaskedFromPreviousEvent.size() << " pixels masked out" << std::endl; +} + + +} + diff --git a/Detector/DetSensitive/src/SDWrapper.cpp b/Detector/DetSensitive/src/SDWrapper.cpp index 2a76e12fc..53da0c58e 100644 --- a/Detector/DetSensitive/src/SDWrapper.cpp +++ b/Detector/DetSensitive/src/SDWrapper.cpp @@ -5,6 +5,7 @@ #include "DetSensitive/BirksLawCalorimeterSD.h" #include "DetSensitive/FullParticleAbsorptionSD.h" #include "DetSensitive/GflashCalorimeterSD.h" +#include "DetSensitive/DigitalCalorimeterSD.h" #include "DetSensitive/MiddleStepTrackerSD.h" #include "DetSensitive/SimpleCalorimeterSD.h" #include "DetSensitive/SimpleTrackerSD.h" @@ -47,6 +48,13 @@ static G4VSensitiveDetector* create_aggregate_calorimeter_sd(const std::string& return new det::AggregateCalorimeterSD( aDetectorName, readoutName, aLcdd.sensitiveDetector(aDetectorName).readout().segmentation()); } +// Factory method to create an instance of DigitalCalorimeterSD +static G4VSensitiveDetector* create_digital_calorimeter_sd(const std::string& aDetectorName, + dd4hep::Detector& aLcdd) { + std::string readoutName = aLcdd.sensitiveDetector(aDetectorName).readout().name(); + return new det::DigitalCalorimeterSD( + aDetectorName,readoutName,aLcdd.sensitiveDetector(aDetectorName).readout().segmentation()); +} // Factory method to create an instance of GflashCalorimeterSD static G4VSensitiveDetector* create_gflash_calorimeter_sd(const std::string& aDetectorName, dd4hep::Detector& aLcdd) { @@ -70,3 +78,4 @@ DECLARE_EXTERNAL_GEANT4SENSITIVEDETECTOR(BirksLawCalorimeterSD, dd4hep::sim::cre DECLARE_EXTERNAL_GEANT4SENSITIVEDETECTOR(AggregateCalorimeterSD, dd4hep::sim::create_aggregate_calorimeter_sd) DECLARE_EXTERNAL_GEANT4SENSITIVEDETECTOR(GflashCalorimeterSD, dd4hep::sim::create_gflash_calorimeter_sd) DECLARE_EXTERNAL_GEANT4SENSITIVEDETECTOR(FullParticleAbsorptionSD, dd4hep::sim::create_full_particle_absorbtion_sd) +DECLARE_EXTERNAL_GEANT4SENSITIVEDETECTOR(DigitalCalorimeterSD, dd4hep::sim::create_digital_calorimeter_sd) diff --git a/Detector/DetStudies/src/components/DECalAnalysis.cpp b/Detector/DetStudies/src/components/DECalAnalysis.cpp new file mode 100644 index 000000000..334e21c18 --- /dev/null +++ b/Detector/DetStudies/src/components/DECalAnalysis.cpp @@ -0,0 +1,295 @@ + +#include "DECalAnalysis.h" + +// FCCSW +#include "DetInterface/IGeoSvc.h" + +// datamodel +#include "datamodel/PositionedCaloHitCollection.h" +#include "datamodel/CaloHitCollection.h" +#include "datamodel/MCParticleCollection.h" + +#include "CLHEP/Vector/ThreeVector.h" +#include "GaudiKernel/ITHistSvc.h" +#include "TH1F.h" +#include "TVector2.h" +#include "TMath.h" +#include "TString.h" +#include "string" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DD4hep/Readout.h" + +DECLARE_ALGORITHM_FACTORY(DECalAnalysis) + +DECalAnalysis::DECalAnalysis(const std::string& aName, ISvcLocator* aSvcLoc) + : GaudiAlgorithm(aName, aSvcLoc), + m_histSvc("THistSvc", "DECalAnalysis"), + m_geoSvc("GeoSvc", "DECalAnalysis") +{ + declareProperty("pixels", m_deposits, "Energy deposits in sampling calorimeter (input)"); + declareProperty("pads", m_pads, "Energy deposits in Pad mode (input)"); + declareProperty("truth", m_truth, "Generated particle truth"); + + m_calP0 = 239.74; + m_calP1 = 99.1602; + m_calP2 = -0.0143; + +} +DECalAnalysis::~DECalAnalysis() {} + +StatusCode DECalAnalysis::initialize() { + if (GaudiAlgorithm::initialize().isFailure()) { + return StatusCode::FAILURE; + } + // check if readouts exist + if (m_geoSvc->lcdd()->readouts().find(m_pixelReadoutName) == m_geoSvc->lcdd()->readouts().end()) { + error() << "Readout <<" << m_pixelReadoutName << ">> does not exist." << endmsg; + return StatusCode::FAILURE; + } + + m_sumPixelsLayers.assign(m_numLayers+1,0); + m_sumPadsLayers.assign(m_numLayers+1,0); + m_sumParticlesLayers.assign(m_numLayers+1,0); + + m_treeInfo = new TTree("decal_info", "for Kostas"); + m_treeInfo->Branch("event_number", &m_treeEvtNumber); + m_treeInfo->Branch("truth_energy", &m_truthEnergy); + m_treeInfo->Branch("edep_tot", &m_sumEnergyDep); + m_treeInfo->Branch("pixels_cal", &m_calPixels); + m_treeInfo->Branch("pixels_tot", &m_sumPixels); + m_treeInfo->Branch("particles_tot", &m_sumParticles); + for(uint l(0); lBranch(Form("pixels_l%i", l), &m_sumPixelsLayers[l]); + } + m_treeInfo->Branch("pads_tot", &m_sumPads); + for(uint l(0); lBranch(Form("pads_l%i", l), &m_sumPadsLayers[l]); + } + for(uint l(0); lBranch(Form("particles_l%i", l), &m_sumParticlesLayers[l]); + } + if(m_histSvc->regTree("/rec/decalInfo", m_treeInfo).isFailure()) { + error() << "Couldn't register tree" << endmsg; + return StatusCode::FAILURE; + } + // create histograms + m_particlesPerPixel = new TProfile("decal_ParticlesPerPixel", "Particles Per Pixels; Layer Number; Particles / Pixel", m_numLayers+1, -0.5, m_numLayers+0.5); + if (m_histSvc->regHist("/rec/profile_test", m_particlesPerPixel).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + + m_totalHits = new TH1F("decal_totalHits", "Total hits in an event", 15000, 0, 150000); + if (m_histSvc->regHist("/rec/decal_hits", m_totalHits).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + m_totalHitsVsLayer = new TH1F("decal_totalHitsVsLayer", "Total hits per layer", m_numLayers+1, -0.5, m_numLayers+0.5); + m_totalHitsVsLayer->Sumw2(kFALSE); + if(m_histSvc->regHist("/rec/decal_hitsVsLayer", m_totalHitsVsLayer).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_totalPadsVsLayer = new TH1F("decal_totalPadsVsLayer", "Total pads per layer", m_numLayers+1, -0.5, m_numLayers+0.5); + m_totalPadsVsLayer->Sumw2(kFALSE); + if(m_histSvc->regHist("/rec/decal_padsVsLayer", m_totalPadsVsLayer).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + for(uint n(0); n<100; n++) { + m_hitsVsLayerEvent[n] = new TH1F(("decal_hitsVsLayerEvent"+std::to_string(n)).c_str(), "", m_numLayers+1, -0.5, m_numLayers+0.5); + m_hitsVsLayerEvent[n]->Sumw2(kFALSE); + if(m_histSvc->regHist("/rec/decal_hitsVsLayerEvent"+std::to_string(n), m_hitsVsLayerEvent[n]).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + } + + m_hitsInMaxLayer = new TH1F("decal_hitsInMaxLayer", "Total hits in max layer", 150, 0, 15000); + if (m_histSvc->regHist("/rec/decal_hitsInMaxLayer", m_hitsInMaxLayer).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_maxLayer = new TH1F("decal_maxLayer", "Layer with the maximum hits in an event",m_numLayers+1, -0.5, m_numLayers+0.5 ); + if (m_histSvc->regHist("/rec/decal_maxLayer", m_maxLayer).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_totalPadsAbovePixelThreshold = new TH1F("decal_totalPadsAbovePixelThreshold","", 1000,0,10000); + if (m_histSvc->regHist("/rec/decal_totalPadsAbovePixelThreshold", m_totalPadsAbovePixelThreshold).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_totalPads = new TH1F("decal_totalPads","", 1000,0,10000); + if (m_histSvc->regHist("/rec/decal_totalPads", m_totalPads).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + for (uint i = 0; i < m_numLayers+1; i++) { + m_totalHitsLayers.push_back(new TH1F(("decal_Hits_layer" + std::to_string(i)).c_str(), + ("Total pixel hits in layer " + std::to_string(i)).c_str(), 1000, 0, + 10000)); + if (m_histSvc->regHist("/rec/decal_total_hits_layer" + std::to_string(i), m_totalHitsLayers.back()).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_totalPadsLayers.push_back(new TH1F(("decal_Pads_layer" + std::to_string(i)).c_str(), + ("Total pads with hits in layer " + std::to_string(i)).c_str(), 100, 0, + 1000)); + if (m_histSvc->regHist("/rec/decal_total_pads_layer" + std::to_string(i), m_totalPadsLayers.back()).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + + m_totalPixelsPerPadLayers.push_back(new TH1F(("decal_Pixels_Per_Pad_layer" + std::to_string(i)).c_str(), + ("Total pixels per pad in layer " + std::to_string(i)).c_str(), 200, 0, + 200)); + if (m_histSvc->regHist("/rec/decal_Pixels_Per_Pad_layer" + std::to_string(i), m_totalPixelsPerPadLayers.back()).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + } + m_XYEvent0 = new TH2F("decal_XYEvent0", "XY Positions for Event 0", 5000, -2500, 2500, 5000, -2500, 2500); + if (m_histSvc->regHist("/rec/decal_XYEvent0", m_XYEvent0).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_EtaPhiEvent0 = new TH2F("decal_EtaPhiEvent0", "Eta Phi Positions for Event 0", 222, -0.004, 0.002, 222, -0.8305,-0.8245); + if (m_histSvc->regHist("/rec/decal_EtaPhiEvent0", m_EtaPhiEvent0).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_EtaPhiSeparation = new TH1F("decal_EtaSeparation", "Eta Phi Positions", 1200, 0, 1); + if (m_histSvc->regHist("/rec/decal_EtaPhiSeparation", m_EtaPhiSeparation).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_nEventsFilled = 0; + + m_calFit = new TF1("calFit", "pol2", 0,3000); + m_calFit->SetParameter("p0", m_calP0); + m_calFit->SetParameter("p1", m_calP1); + m_calFit->SetParameter("p2", m_calP2); + + // if it gets to here then it has registered all histograms + return StatusCode::SUCCESS; +} + +StatusCode DECalAnalysis::execute() { + // get the decoder for the readout + // this will allow to extract layers etc. + auto decoder = m_geoSvc->lcdd()->readout(m_pixelReadoutName).idSpec().decoder(); + + // calculate the MC truth energy of the incident particle + const auto truth = m_truth.get(); + for (const auto& t : *truth) { + double px = t.core().p4.px; + double py = t.core().p4.py; + double pz = t.core().p4.pz; + double m = t.core().p4.mass; + + m_truthEnergy = TMath::Sqrt(m*m + px*px + py*py + pz*pz); + } + + // added a little print out to ensure it is still working + if(m_treeEvtNumber < 10 or m_treeEvtNumber % 100 == 0) { + info() << "Event Number " << m_treeEvtNumber << endmsg; + info() << "Truth energy of single particle = " << m_truthEnergy << endmsg; + } + + + // set some variables to hold information for an event + m_sumPixels = 0.; + m_sumParticles = 0.; + m_sumPixelsLayers.assign(m_numLayers+1, 0); + m_sumParticlesLayers.assign(m_numLayers+1, 0); + m_meanEta.assign(m_numLayers+1, 0); + m_meanPhi.assign(m_numLayers+1, 0); + + m_sumEnergyDep = 0; + + bool fillXY = true; + if (m_XYEvent0->GetEntries()>0) { + fillXY = false; + } + + int isdigital = 0, notdigital = 0; + + const auto deposits = m_deposits.get(); + for (const auto& hit : *deposits) { + decoder->setValue(hit.core().cellId); + + int layer = (*decoder)[m_layerFieldName]; + m_sumPixelsLayers[layer] += 1; + + // check if energy was deposited in the calorimeter (active/passive material) + // layers are numbered starting from 1, layer == 0 is cryostat/bath + if (layer > 0) { + m_sumPixels++; + decoder->setValue(hit.core().cellId); + int layer = (*decoder)[m_layerFieldName]; + // get the energy deposited in the active area + double edep = hit.core().energy; + m_sumEnergyDep += edep; + double particles = hit.core().time; // I overwrite now the time for number of particles + m_sumParticles += particles; + m_sumParticlesLayers[layer] += particles; // call this particles for DEcal as changed SD readout to pass nparticles / pixel not enerrgy dep / pixel + m_particlesPerPixel->Fill(layer, particles); + // calculate eta and phi + double r = TMath::Sqrt(hit.position().x*hit.position().x + hit.position().y*hit.position().y + hit.position().z*hit.position().z); + double theta = TMath::ACos(hit.position().z/r); + double eta = -TMath::Log2(TMath::Tan(theta/2.0)); + double phi = TMath::ATan(hit.position().y / hit.position().x); + + m_meanEta[layer] += eta; + m_meanPhi[layer] += phi; + + } + } + + std::cout << "isdigital = " << isdigital << std::endl; + std::cout << "notdigital = " << notdigital << std::endl; + + if(m_sumPixels>0 || m_sumPads>0) { + m_treeInfo->Fill(); + } + + m_treeEvtNumber++; + + return StatusCode::SUCCESS; +} + +StatusCode DECalAnalysis::finalize() { + debug() << "StatusCode DECalAnalysis::finalize()" << endmsg; + + // count from 1 to avoid the hits in the Trkr volume + for (uint i = 1; i < m_numLayers+1; i++) { + m_totalHitsVsLayer->SetBinContent(i+1,m_totalHitsLayers[i]->GetMean()); + m_totalPadsVsLayer->SetBinContent(i+1,m_totalPadsLayers[i]->GetMean()); + } + +return GaudiAlgorithm::finalize(); } + +Double_t DECalAnalysis::FitLongProfile( Double_t *x, Double_t *par) +{ + double E_0 = par[0]; + double a = par[1]; + double b = par[2]; + double led = E_0*b * (pow( (b*x[0]), a-1 )* exp(-(b*x[0])) ) / TMath::Gamma(a); + + return led; +} diff --git a/Detector/DetStudies/src/components/DECalAnalysis.h b/Detector/DetStudies/src/components/DECalAnalysis.h new file mode 100644 index 000000000..9c1ca574f --- /dev/null +++ b/Detector/DetStudies/src/components/DECalAnalysis.h @@ -0,0 +1,140 @@ +#ifndef DETSTUDIES_DECalAnalysis_H +#define DETSTUDIES_DECalAnalysis_H + +// GAUDI +#include "GaudiAlg/GaudiAlgorithm.h" +#include "GaudiKernel/ServiceHandle.h" + +// FCCSW +#include "FWCore/DataHandle.h" +#include "TH2F.h" +#include "TTree.h" +#include "TF1.h" +#include "TProfile.h" + +class IGeoSvc; + +// datamodel +namespace fcc { +class PositionedCaloHitCollection; +class CaloHitCollection; +class MCParticleCollection; +} + +class TH1F; +class ITHistSvc; +/** @class DECalAnalysis DECalAnalysis.h + * + * Histograms of energy deposited in active material and total energy deposited in the calorimeter. + * Passive material needs to be marked as sensitive. It needs to be divided into layers (cells) as active material. + * Layers (cells) are numbered starting at 1 so that energy depoisted in cryostat and bath could be easily recognised. + * Sampling fraction is calculated for each layer as the ratio of energy deposited in active material to energy + * deposited in the layer (also in passive material). + * + * @author Anna Zaborowska + */ + +class DECalAnalysis : public GaudiAlgorithm { +public: + explicit DECalAnalysis(const std::string&, ISvcLocator*); + virtual ~DECalAnalysis(); + /** Initialize. + * @return status code + */ + virtual StatusCode initialize() final; + /** Fills the histograms. + * @return status code + */ + virtual StatusCode execute() final; + /** Finalize. + * @return status code + */ + virtual StatusCode finalize() final; + + Double_t FitLongProfile( Double_t *x, Double_t *par); + +private: + /// Pointer to the interface of histogram service + ServiceHandle m_histSvc; + /// Pointer to the geometry service + ServiceHandle m_geoSvc; + /// Number of layers/cells + Gaudi::Property m_numLayers{this, "numLayers", 50, "Number of layers"}; + /// Name of the layer/cell field + Gaudi::Property m_layerFieldName{this, "layerFieldName", "", "Identifier of layers"}; + + /// The Pixel analysis + /// Handle for the energy deposits + DataHandle m_deposits{"rec/pixels", Gaudi::DataHandle::Reader, this}; + /// Name of the detector readout + Gaudi::Property m_pixelReadoutName{this, "pixelReadoutName", "", "Name of the detector readout"}; + + /// The Pad analysis + /// Handle for the energy deposits + DataHandle m_pads{"rec/pads", Gaudi::DataHandle::Reader, this}; + /// Name of the detector readout + Gaudi::Property m_padReadoutName{this, "padReadoutName", "", "Name of the detector readout"}; + + DataHandle m_truth{"truth", Gaudi::DataHandle::Reader, this}; + + + // Histograms of total deposited energy within layer + // Histograms for the number of hits per layer + std::vector m_totalHitsLayers; + + // Histogram of total hits in the calorimeter + TH1F* m_totalHits; + // Histogram of number of hits per layer in single histogram + TH1F* m_totalHitsVsLayer; + TH1F* m_hitsVsLayerEvent[100]; + + TH1F* m_totalPadsVsLayer; + std::vector m_totalPadsLayers; + std::vector m_totalPixelsPerPadLayers; + TH1F* m_totalPixelsPerPad; + TH1F* m_totalPads; + TH1F* m_totalPadsAbovePixelThreshold; + + TH2F* m_XYEvent0; + TH2F* m_EtaPhiEvent0; + TH1F* m_EtaPhiSeparation; + + TProfile* m_particlesPerPixel; + + // Histogram of the number of hits in the layer with most hits + TH1F* m_hitsInMaxLayer; + // Histogram of the layer with maximum hits + TH1F* m_maxLayer; + + // calibration factors to compensate non linearity + float m_calP0, m_calP1, m_calP2; + TF1* m_calFit; + + TTree* m_treeInfo; + int m_treeEvtNumber; + + int m_nEventsFilled; + int m_truthEnergy; + float m_calPixels; + int m_sumPixels; + std::vector m_sumPixelsLayers; + std::vector m_sumParticlesLayers; + int m_sumPads; + std::vector m_sumPadsLayers; + + float m_sumEnergyDep; + float m_sumParticles; + + std::vector m_meanEta; + std::vector m_meanPhi; + + double m_fitE0; + double m_fita; + double m_fitb; + double m_rising50; + double m_rising90; + double m_fwhm; + + TF1* m_fitLongProfile; +}; +#endif /* DETSTUDIES_DECalAnalysis_H */ diff --git a/Detector/DetStudies/src/components/DECalLongitudinalTest.cpp b/Detector/DetStudies/src/components/DECalLongitudinalTest.cpp new file mode 100644 index 000000000..6f73960d5 --- /dev/null +++ b/Detector/DetStudies/src/components/DECalLongitudinalTest.cpp @@ -0,0 +1,142 @@ + +#include "DECalLongitudinalTest.h" + +// FCCSW +#include "DetInterface/IGeoSvc.h" + +// datamodel +#include "datamodel/PositionedCaloHitCollection.h" +#include "datamodel/CaloHitCollection.h" + +#include "CLHEP/Vector/ThreeVector.h" +#include "GaudiKernel/ITHistSvc.h" +#include "TH1F.h" +#include "TVector2.h" +#include "TMath.h" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DD4hep/Readout.h" + +DECLARE_ALGORITHM_FACTORY(DECalLongitudinalTest) + +DECalLongitudinalTest::DECalLongitudinalTest(const std::string& aName, ISvcLocator* aSvcLoc) + : GaudiAlgorithm(aName, aSvcLoc), + m_histSvc("THistSvc", "DECalLongitudinalTest"), + m_geoSvc("GeoSvc", "DECalLongitudinalTest") +{ + declareProperty("deposits", m_deposits, "Energy deposits in sampling calorimeter (input)"); +} +DECalLongitudinalTest::~DECalLongitudinalTest() {} + +StatusCode DECalLongitudinalTest::initialize() { + if (GaudiAlgorithm::initialize().isFailure()) { + return StatusCode::FAILURE; + } + // check if readouts exist + if (m_geoSvc->lcdd()->readouts().find(m_readoutName) == m_geoSvc->lcdd()->readouts().end()) { + error() << "Readout <<" << m_readoutName << ">> does not exist." << endmsg; + return StatusCode::FAILURE; + } + // create histograms + m_totalHits = new TH1F("decal_totalHits", "Total hits in an event", 15000, 0, 150000); + if (m_histSvc->regHist("/rec/decal_hits", m_totalHits).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + m_totalHitsVsLayer = new TH1F("decal_totalHitsVsLayer", "Total hits per layer", m_numLayers+1, -0.5, m_numLayers+0.5); + m_totalHitsVsLayer->Sumw2(kFALSE); + if(m_histSvc->regHist("/rec/decal_hitsVsLayer", m_totalHitsVsLayer).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + for (uint i = 0; i < m_numLayers; i++) { + m_totalHitsLayers.push_back(new TH1F(("decal_Hits_layer" + std::to_string(i)).c_str(), + ("Total pixel hits in layer " + std::to_string(i)).c_str(), 1000, 0, + 10000)); + if (m_histSvc->regHist("/rec/decal_total_hits_layer" + std::to_string(i), m_totalHitsLayers.back()).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + } + m_XYEvent0 = new TH2F("decal_XYEvent0", "XY Positions for Event 0", 5000, -2500, 2500, 5000, -2500, 2500); + if (m_histSvc->regHist("/rec/decal_XYEvent0", m_XYEvent0).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_EtaPhiEvent0 = new TH2F("decal_EtaPhiEvent0", "Eta Phi Positions for Event 0", 2000, -0.04, 0.02, 2000, -4,4); + if (m_histSvc->regHist("/rec/decal_EtaPhiEvent0", m_EtaPhiEvent0).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_EtaPhiSeparation = new TH1F("decal_EtaSeparation", "Eta Phi Positions", 1200, 0, 1); + if (m_histSvc->regHist("/rec/decal_EtaPhiSeparation", m_EtaPhiSeparation).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + + + // if it gets to here then it has registered all histograms + return StatusCode::SUCCESS; +} + +StatusCode DECalLongitudinalTest::execute() { + // get the decoder for the readout + // this will allow to extract layers etc. + auto decoder = m_geoSvc->lcdd()->readout(m_readoutName).idSpec().decoder(); + + // set some variables to hold information for an event + double sumHits = 0.; + std::vector sumHitslayers; + sumHitslayers.assign(m_numLayers, 0); + + bool fillXY = true; + if (m_XYEvent0->GetEntries()>0) { + fillXY = false; + } + + const auto deposits = m_deposits.get(); + for (const auto& hit : *deposits) { + decoder->setValue(hit.core().cellId); + sumHitslayers[(*decoder)[m_layerFieldName]] += 1; + // check if energy was deposited in the calorimeter (active/passive material) + // layers are numbered starting from 1, layer == 0 is cryostat/bath + std::cout << (*decoder)[m_layerFieldName] << std::endl; + if ((*decoder)[m_layerFieldName] > 0) { + sumHits++; + decoder->setValue(hit.core().cellId); + // calculate eta and phi + double r = TMath::Sqrt(hit.position().x*hit.position().x + hit.position().y*hit.position().y + hit.position().z*hit.position().z); + double theta = TMath::ACos(hit.position().z/r); + double eta = -TMath::Log2(TMath::Tan(theta/2.0)); + double phi = TMath::ATan(hit.position().y / hit.position().x); + if (fillXY) { + m_XYEvent0->Fill((*decoder)["x"],(*decoder)["y"]); + m_XYEvent0->Fill(hit.position().x, hit.position().y); + if((*decoder)[m_layerFieldName] == 18) { + m_EtaPhiEvent0->Fill(eta,phi); + } + } + } + } + + // Fill histograms + m_totalHits->Fill(sumHits); + for (uint i = 1; i < m_numLayers; i++) { + m_totalHitsLayers[i]->Fill(sumHitslayers[i]); + } + return StatusCode::SUCCESS; +} + +StatusCode DECalLongitudinalTest::finalize() { + debug() << "StatusCode DECalLongitudinalTest::finalize()" << endmsg; + + // count from 1 to avoid the hits in the Trkr volume + for (uint i = 1; i < m_numLayers; i++) { + m_totalHitsVsLayer->SetBinContent(i+1,m_totalHitsLayers[i]->GetMean()); + } + +return GaudiAlgorithm::finalize(); } diff --git a/Detector/DetStudies/src/components/DECalLongitudinalTest.h b/Detector/DetStudies/src/components/DECalLongitudinalTest.h new file mode 100644 index 000000000..ac2f5ff36 --- /dev/null +++ b/Detector/DetStudies/src/components/DECalLongitudinalTest.h @@ -0,0 +1,75 @@ +#ifndef DETSTUDIES_DECALLONGITUDINALTEST_H +#define DETSTUDIES_DECALLONGITUDINALTEST_H + +// GAUDI +#include "GaudiAlg/GaudiAlgorithm.h" +#include "GaudiKernel/ServiceHandle.h" + +// FCCSW +#include "FWCore/DataHandle.h" +#include "TH2F.h" +class IGeoSvc; + +// datamodel +namespace fcc { +class PositionedCaloHitCollection; +class CaloHitCollection; +} + +class TH1F; +class ITHistSvc; +/** @class DECalLongitudinalTest DECalLongitudinalTest.h + * + * Histograms of energy deposited in active material and total energy deposited in the calorimeter. + * Passive material needs to be marked as sensitive. It needs to be divided into layers (cells) as active material. + * Layers (cells) are numbered starting at 1 so that energy depoisted in cryostat and bath could be easily recognised. + * Sampling fraction is calculated for each layer as the ratio of energy deposited in active material to energy + * deposited in the layer (also in passive material). + * + * @author Anna Zaborowska + */ + +class DECalLongitudinalTest : public GaudiAlgorithm { +public: + explicit DECalLongitudinalTest(const std::string&, ISvcLocator*); + virtual ~DECalLongitudinalTest(); + /** Initialize. + * @return status code + */ + virtual StatusCode initialize() final; + /** Fills the histograms. + * @return status code + */ + virtual StatusCode execute() final; + /** Finalize. + * @return status code + */ + virtual StatusCode finalize() final; + +private: + /// Pointer to the interface of histogram service + ServiceHandle m_histSvc; + /// Pointer to the geometry service + ServiceHandle m_geoSvc; + /// Handle for the energy deposits + DataHandle m_deposits{"rec/caloHits", Gaudi::DataHandle::Reader, this}; + /// Name of the layer/cell field + Gaudi::Property m_layerFieldName{this, "layerFieldName", "", "Identifier of layers"}; + /// Number of layers/cells + Gaudi::Property m_numLayers{this, "numLayers", 8, "Number of layers"}; + /// Name of the detector readout + Gaudi::Property m_readoutName{this, "readoutName", "", "Name of the detector readout"}; + + // Histograms of total deposited energy within layer + // Histograms for the number of hits per layer + std::vector m_totalHitsLayers; + // Histogram of total hits in the calorimeter + TH1F* m_totalHits; + // Histogram of number of hits per layer in single histogram + TH1F* m_totalHitsVsLayer; + + TH2F* m_XYEvent0; + TH2F* m_EtaPhiEvent0; + TH1F* m_EtaPhiSeparation; +}; +#endif /* DETSTUDIES_DECALLONGITUDINALTEST_H */ diff --git a/Detector/DetStudies/src/components/FilterSiliconEcalHits.cpp b/Detector/DetStudies/src/components/FilterSiliconEcalHits.cpp new file mode 100644 index 000000000..dc2d4dc8e --- /dev/null +++ b/Detector/DetStudies/src/components/FilterSiliconEcalHits.cpp @@ -0,0 +1,107 @@ + +#include "FilterSiliconEcalHits.h" + +// FCCSW +#include "DetInterface/IGeoSvc.h" + +// datamodel +#include "datamodel/PositionedCaloHitCollection.h" +#include "datamodel/CaloHitCollection.h" +#include "datamodel/MCParticleCollection.h" + +#include "CLHEP/Vector/ThreeVector.h" +#include "GaudiKernel/ITHistSvc.h" +#include "TH1F.h" +#include "TVector2.h" +#include "TMath.h" +#include "TString.h" +#include "string" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DD4hep/Readout.h" + +DECLARE_ALGORITHM_FACTORY(FilterSiliconEcalHits) + +FilterSiliconEcalHits::FilterSiliconEcalHits(const std::string& aName, ISvcLocator* aSvcLoc) + : GaudiAlgorithm(aName, aSvcLoc), + m_histSvc("THistSvc", "FilterSiliconEcalHits"), + m_geoSvc("GeoSvc", "FilterSiliconEcalHits") +{ + declareProperty("deposits", m_deposits, "Energy deposits in sampling calorimeter (input)"); + declareProperty("filtered", m_filtered, "Filtered energy deposits (output)"); + +} +FilterSiliconEcalHits::~FilterSiliconEcalHits() {} + +StatusCode FilterSiliconEcalHits::initialize() { + if (GaudiAlgorithm::initialize().isFailure()) { + return StatusCode::FAILURE; + } + // check if readouts exist + if (m_geoSvc->lcdd()->readouts().find(m_padReadoutName) == m_geoSvc->lcdd()->readouts().end()) { + error() << "Readout <<" << m_padReadoutName << ">> does not exist." << endmsg; + return StatusCode::FAILURE; + } + + // if it gets to here then it has registered all histograms + return StatusCode::SUCCESS; +} + +StatusCode FilterSiliconEcalHits::execute() { + // get the decoder for the readout + // this will allow to extract layers etc. + auto decoder = m_geoSvc->lcdd()->readout(m_padReadoutName).idSpec().decoder(); + + // added a little print out to ensure it is still working + if(m_EvtNumber < 10 or m_EvtNumber % 100 == 0) { + info() << "Event Number " << m_EvtNumber << endmsg; + } + + + // set some variables to hold information for an event + int nFilteredHits = 0; + + const auto deposits = m_deposits.get(); + auto filtered = m_filtered.createAndPut(); + + // if looking at digital need to threshold at this point so the merging of cells takes correct deposits + // the analgoue we can keep all hits and sum at a later date + // eventually this will be passed as a parameter but coding quickly now + double m_threshold = 0; + if(m_digitalFlag==1) { + m_threshold = 480*0.0000000036; + } + + for (const auto& hit : *deposits) { + decoder->setValue(hit.core().cellId); + int digital = (*decoder)["digital"]; + if(digital==m_digitalFlag) { + nFilteredHits++; + + if(hit.energy()>m_threshold) { + fcc::PositionedCaloHit filteredHit = filtered->create(); + filteredHit.energy(hit.energy()); + filteredHit.time(hit.time()); + filteredHit.cellId(hit.cellId()); + filteredHit.bits(hit.bits()); + filteredHit.position(hit.position()); + } + } + + } + + info() << "nFilteredHits = " << nFilteredHits << endmsg; + + m_EvtNumber++; + + return StatusCode::SUCCESS; +} + +StatusCode FilterSiliconEcalHits::finalize() { + debug() << "StatusCode FilterSiliconEcalHits::finalize()" << endmsg; + + +return GaudiAlgorithm::finalize(); } + + diff --git a/Detector/DetStudies/src/components/FilterSiliconEcalHits.h b/Detector/DetStudies/src/components/FilterSiliconEcalHits.h new file mode 100644 index 000000000..7d7bc6f93 --- /dev/null +++ b/Detector/DetStudies/src/components/FilterSiliconEcalHits.h @@ -0,0 +1,70 @@ +#ifndef DETSTUDIES_FilterSiliconEcalHits_H +#define DETSTUDIES_FilterSiliconEcalHits_H + +// GAUDI +#include "GaudiAlg/GaudiAlgorithm.h" +#include "GaudiKernel/ServiceHandle.h" + +// FCCSW +#include "FWCore/DataHandle.h" +#include "TH2F.h" +#include "TTree.h" +#include "TF1.h" +#include "TProfile.h" + +class IGeoSvc; + +// datamodel +namespace fcc { +class PositionedCaloHitCollection; +} + +class ITHistSvc; +/** @class DECalAnalysis DECalAnalysis.h + * + * Histograms of energy deposited in active material and total energy deposited in the calorimeter. + * Passive material needs to be marked as sensitive. It needs to be divided into layers (cells) as active material. + * Layers (cells) are numbered starting at 1 so that energy depoisted in cryostat and bath could be easily recognised. + * Sampling fraction is calculated for each layer as the ratio of energy deposited in active material to energy + * deposited in the layer (also in passive material). + * + * @author Anna Zaborowska + */ + +class FilterSiliconEcalHits : public GaudiAlgorithm { +public: + explicit FilterSiliconEcalHits(const std::string&, ISvcLocator*); + virtual ~FilterSiliconEcalHits(); + /** Initialize. + * @return status code + */ + virtual StatusCode initialize() final; + /** Fills the histograms. + * @return status code + */ + virtual StatusCode execute() final; + /** Finalize. + * @return status code + */ + virtual StatusCode finalize() final; + + +private: + /// Pointer to the interface of histogram service + ServiceHandle m_histSvc; + /// Pointer to the geometry service + ServiceHandle m_geoSvc; + + /// The Pixel analysis + /// Handle for the energy deposits + DataHandle m_deposits{"rec/deposits", Gaudi::DataHandle::Reader, this}; + DataHandle m_filtered{"rec/filtered", Gaudi::DataHandle::Writer, this}; + /// Name of the detector readout + Gaudi::Property m_padReadoutName{this, "readoutName", "", "Name of the detector readout"}; + + Gaudi::Property m_digitalFlag{this, "digitalFlag", 0, "If 1 then filter for digital hits, 0 filter for analgoue hits"}; + + int m_EvtNumber; + +}; +#endif /* DETSTUDIES_FilterSiliconEcalHits_H */ diff --git a/Detector/DetStudies/src/components/SiWAnalysis.cpp b/Detector/DetStudies/src/components/SiWAnalysis.cpp new file mode 100644 index 000000000..34312c6c2 --- /dev/null +++ b/Detector/DetStudies/src/components/SiWAnalysis.cpp @@ -0,0 +1,154 @@ + +#include "SiWAnalysis.h" + +// FCCSW +#include "DetInterface/IGeoSvc.h" + +// datamodel +#include "datamodel/PositionedCaloHitCollection.h" +#include "datamodel/CaloHitCollection.h" +#include "datamodel/MCParticleCollection.h" + +#include "CLHEP/Vector/ThreeVector.h" +#include "GaudiKernel/ITHistSvc.h" +#include "TH1F.h" +#include "TVector2.h" +#include "TMath.h" +#include "TString.h" +#include "string" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DD4hep/Readout.h" + +DECLARE_ALGORITHM_FACTORY(SiWAnalysis) + +SiWAnalysis::SiWAnalysis(const std::string& aName, ISvcLocator* aSvcLoc) + : GaudiAlgorithm(aName, aSvcLoc), + m_histSvc("THistSvc", "SiWAnalysis"), + m_geoSvc("GeoSvc", "SiWAnalysis") +{ + declareProperty("deposits", m_deposits, "Energy deposits in sampling calorimeter (input)"); + declareProperty("truth", m_truth, "Generated particle truth"); + + m_calP0 = 239.74; + m_calP1 = 99.1602; + m_calP2 = -0.0143; + +} +SiWAnalysis::~SiWAnalysis() {} + +StatusCode SiWAnalysis::initialize() { + if (GaudiAlgorithm::initialize().isFailure()) { + return StatusCode::FAILURE; + } + // check if readouts exist + if (m_geoSvc->lcdd()->readouts().find(m_padReadoutName) == m_geoSvc->lcdd()->readouts().end()) { + error() << "Readout <<" << m_padReadoutName << ">> does not exist." << endmsg; + return StatusCode::FAILURE; + } + + + m_treeInfo = new TTree("info", "Analysis Tree"); + m_treeInfo->Branch("event_number", &m_treeEvtNumber); + m_treeInfo->Branch("truth_energy", &m_truthEnergy); + m_treeInfo->Branch("edep_tot", &m_sumEnergyDep); + + + if(m_histSvc->regTree("/rec/Info", m_treeInfo).isFailure()) { + error() << "Couldn't register tree" << endmsg; + return StatusCode::FAILURE; + } + + // create histograms + + m_totalEdep = new TH1F("SiW_totalEdep", "Total edep in an event", 15000, 0, 15); + if (m_histSvc->regHist("/rec/SiW_Edep", m_totalEdep).isFailure()) { + error() << "Couldn't register histogram" << endmsg; + return StatusCode::FAILURE; + } + + m_calFit = new TF1("calFit", "pol2", 0,3000); + m_calFit->SetParameter("p0", m_calP0); + m_calFit->SetParameter("p1", m_calP1); + m_calFit->SetParameter("p2", m_calP2); + + // if it gets to here then it has registered all histograms + return StatusCode::SUCCESS; +} + +StatusCode SiWAnalysis::execute() { + // get the decoder for the readout + // this will allow to extract layers etc. + auto decoder = m_geoSvc->lcdd()->readout(m_padReadoutName).idSpec().decoder(); + + // calculate the MC truth energy of the incident particle + const auto truth = m_truth.get(); + for (const auto& t : *truth) { + double px = t.core().p4.px; + double py = t.core().p4.py; + double pz = t.core().p4.pz; + double m = t.core().p4.mass; + + m_truthEnergy = TMath::Sqrt(m*m + px*px + py*py + pz*pz); + } + + // added a little print out to ensure it is still working + if(m_treeEvtNumber < 10 or m_treeEvtNumber % 100 == 0) { + info() << "Event Number " << m_treeEvtNumber << endmsg; + info() << "Truth energy of single particle = " << m_truthEnergy << endmsg; + } + + + // set some variables to hold information for an event + m_sumEdepLayers.assign(m_numLayers+1, 0); + m_sumEnergyDep = 0; + + int isdigital = 0, notdigital = 0; + + const auto deposits = m_deposits.get(); + for (const auto& hit : *deposits) { + decoder->setValue(hit.core().cellId); + + + int layer = (*decoder)[m_layerFieldName]; + + // check if energy was deposited in the calorimeter (active/passive material) + // layers are numbered starting from 1, layer == 0 is cryostat/bath + if (layer > 0) { + decoder->setValue(hit.core().cellId); + int layer = (*decoder)[m_layerFieldName]; + // get the energy deposited in the active area + double edep = hit.core().energy; + m_sumEnergyDep += edep; + + } + } + +// Fill histograms + m_totalEdep->Fill(m_sumEnergyDep); + + if(m_sumEnergyDep>0) { + m_treeInfo->Fill(); + } + + m_treeEvtNumber++; + + return StatusCode::SUCCESS; +} + +StatusCode SiWAnalysis::finalize() { + debug() << "StatusCode SiWAnalysis::finalize()" << endmsg; + + +return GaudiAlgorithm::finalize(); } + +Double_t SiWAnalysis::FitLongProfile( Double_t *x, Double_t *par) +{ + double E_0 = par[0]; + double a = par[1]; + double b = par[2]; + double led = E_0*b * (pow( (b*x[0]), a-1 )* exp(-(b*x[0])) ) / TMath::Gamma(a); + + return led; +} diff --git a/Detector/DetStudies/src/components/SiWAnalysis.h b/Detector/DetStudies/src/components/SiWAnalysis.h new file mode 100644 index 000000000..6ee703ef4 --- /dev/null +++ b/Detector/DetStudies/src/components/SiWAnalysis.h @@ -0,0 +1,98 @@ +#ifndef DETSTUDIES_SiWAnalysis_H +#define DETSTUDIES_SiWAnalysis_H + +// GAUDI +#include "GaudiAlg/GaudiAlgorithm.h" +#include "GaudiKernel/ServiceHandle.h" + +// FCCSW +#include "FWCore/DataHandle.h" +#include "TH2F.h" +#include "TTree.h" +#include "TF1.h" +#include "TProfile.h" + +class IGeoSvc; + +// datamodel +namespace fcc { +class PositionedCaloHitCollection; +class CaloHitCollection; +class MCParticleCollection; +} + +class TH1F; +class ITHistSvc; +/** @class DECalAnalysis DECalAnalysis.h + * + * Histograms of energy deposited in active material and total energy deposited in the calorimeter. + * Passive material needs to be marked as sensitive. It needs to be divided into layers (cells) as active material. + * Layers (cells) are numbered starting at 1 so that energy depoisted in cryostat and bath could be easily recognised. + * Sampling fraction is calculated for each layer as the ratio of energy deposited in active material to energy + * deposited in the layer (also in passive material). + * + * @author Anna Zaborowska + */ + +class SiWAnalysis : public GaudiAlgorithm { +public: + explicit SiWAnalysis(const std::string&, ISvcLocator*); + virtual ~SiWAnalysis(); + /** Initialize. + * @return status code + */ + virtual StatusCode initialize() final; + /** Fills the histograms. + * @return status code + */ + virtual StatusCode execute() final; + /** Finalize. + * @return status code + */ + virtual StatusCode finalize() final; + + Double_t FitLongProfile( Double_t *x, Double_t *par); + +private: + /// Pointer to the interface of histogram service + ServiceHandle m_histSvc; + /// Pointer to the geometry service + ServiceHandle m_geoSvc; + /// Number of layers/cells + Gaudi::Property m_numLayers{this, "numLayers", 50, "Number of layers"}; + /// Name of the layer/cell field + Gaudi::Property m_layerFieldName{this, "layerFieldName", "", "Identifier of layers"}; + + /// The Pixel analysis + /// Handle for the energy deposits + DataHandle m_deposits{"rec/deposits", Gaudi::DataHandle::Reader, this}; + /// Name of the detector readout + Gaudi::Property m_padReadoutName{this, "padReadoutName", "", "Name of the detector readout"}; + + + DataHandle m_truth{"truth", Gaudi::DataHandle::Reader, this}; + + + + // calibration factors to compensate non linearity + float m_calP0, m_calP1, m_calP2; + TF1* m_calFit; + + TTree* m_treeInfo; + int m_treeEvtNumber; + + int m_truthEnergy; + float m_sumEnergyDep; + std::vector m_sumEdepLayers; + + double m_fitE0; + double m_fita; + double m_fitb; + double m_rising50; + double m_rising90; + double m_fwhm; + + TF1* m_fitLongProfile; + TH1F* m_totalEdep; +}; +#endif /* DETSTUDIES_SiWAnalysis_H */ diff --git a/Detector/DetStudies/tests/options/SiWAnalysis_batch.py b/Detector/DetStudies/tests/options/SiWAnalysis_batch.py new file mode 100644 index 000000000..d7446bf47 --- /dev/null +++ b/Detector/DetStudies/tests/options/SiWAnalysis_batch.py @@ -0,0 +1,96 @@ +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +batch_dir = "/eos/user/t/toprice/private/FCC/FCCSW/v8.0/XYZ/" +fccsw_version = "FCCSW0.8" +det_config = "" +run_config = "" +file = "" +file = file[7:] +#inputfile = batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/"+file +inputfile = batch_dir+"/"+det_config+"/"+run_config+"/output_"+file +podiosvc = FCCDataSvc("EventDataSvc", input=inputfile) + + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=["positionedCaloHits", "GenParticles"], OutputLevel=DEBUG) + +# DD4hep geometry service +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_'+det_config[:-9]+'.xml' +], + OutputLevel = INFO) + + +from Configurables import FilterSiliconEcalHits +filtered = FilterSiliconEcalHits("FilterSiEcal", + readoutName = "BarDECal_Readout", + digitalFlag = 0) +filtered.deposits.Path="positionedCaloHits" +filtered.filtered.Path="filteredCaloHits" + +from Configurables import RedoSegmentation +resegment = RedoSegmentation("ReSegmentation", + # old bitfield (readout) + oldReadoutName = "BarDECal_Readout", + # specify which fields are going to be deleted + oldSegmentationIds = ["x","y","z"], + # new bitfield (readout), with new segmentation + newReadoutName="BarDECal_Pads", + + OutputLevel = INFO) +# clusters are needed, with deposit position and cellID in bits +resegment.inhits.Path = "filteredCaloHits" +resegment.outhits.Path = "newCaloHits" + +from Configurables import CreateCaloCells +createcells = CreateCaloCells("CreateCaloCells", + doCellCalibration = False, + addCellNoise = False, filterCellNoise = False, + OutputLevel = INFO) +createcells.hits.Path="newCaloHits" +createcells.cells.Path="newCaloCells" + +from Configurables import SiWAnalysis +hist = SiWAnalysis("SiWAnalysis", + padReadoutName = "BarDECal_Pads", + layerFieldName = "layer", + numLayers = 50, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = INFO) + +hist.deposits.Path="newCaloCells" +hist.truth.Path="GenParticles" + + + +#THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/' TYP='ROOT' OPT='RECREATE'"] +THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"/"+run_config+"/analogue_"+file+"' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=False +THistSvc().AutoSave=True +THistSvc().AutoFlush=True +THistSvc().OutputLevel=INFO + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +hist.AuditExecute = True + +from Configurables import FCCDataSvc, PodioOutput +#podiosvc = FCCDataSvc("EventDataSvc") +podioout = PodioOutput("out", filename=batch_dir+"/"+det_config+"/"+run_config+"/analogue_podio_"+file) +podioout.outputCommands = ["keep *"] + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [podioinput, filtered, resegment, createcells, hist, podioout], + EvtSel = 'NONE', + # EvtMax = 10, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podiosvc,geoservice, audsvc], + OutputLevel = INFO + +) diff --git a/Detector/DetStudies/tests/options/decalAnalysis_DEcal.py b/Detector/DetStudies/tests/options/decalAnalysis_DEcal.py new file mode 100644 index 000000000..bc1e3a453 --- /dev/null +++ b/Detector/DetStudies/tests/options/decalAnalysis_DEcal.py @@ -0,0 +1,107 @@ +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +batch_dir = "/eos/user/t/toprice/private/FCC/FCCSW/v8.0/XYZ/" +fccsw_version = "FCCSW0.8" +det_config = "50Layers_2.1mmW_50umPixels_18umThick_RRB_FCCSW0.8" +run_config = "100GeV_BFIELD4T_ETAMIN-0.001_ETAMAX0.001" +file = "100GeV_BFIELD4T_0.root" +#inputfile = batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/"+file +inputfile = batch_dir+"/"+det_config+"/"+run_config+"/output_"+file +podiosvc = FCCDataSvc("EventDataSvc", input=inputfile) + + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=["positionedCaloHits", "GenParticles"], OutputLevel=INFO) + +# DD4hep geometry service +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_'+det_config[:-9]+'.xml' +], + OutputLevel = INFO) + +from Configurables import FilterSiliconEcalHits +filtered = FilterSiliconEcalHits("FilterSiEcal", + readoutName = "BarDECal_Readout", + digitalFlag = 1) +filtered.deposits.Path="positionedCaloHits" +filtered.filtered.Path="filteredCaloHits" + +# add a processor which generates noise hits +# input - noise level +# - threshold level +# - segmentation name + +# add a processor which adds noise event in to genuine hits +# take input of noise hits and genuine hits +# output a combination for the event + +from Configurables import RedoSegmentation +resegment = RedoSegmentation("ReSegmentation", + # old bitfield (readout) + oldReadoutName = "BarDECal_Readout", + # specify which fields are going to be deleted + oldSegmentationIds = ["x","y","z"], + # new bitfield (readout), with new segmentation + newReadoutName="BarDECal_Pads", + OutputLevel = INFO) +# clusters are needed, with deposit position and cellID in bits +resegment.inhits.Path = "filteredCaloHits" +resegment.outhits.Path = "newCaloHits" + +from Configurables import CreateCaloCells +createcells = CreateCaloCells("CreateCaloCells", + doCellCalibration = False, + addCellNoise = False, filterCellNoise = False, sumPixelsPerCell = False, + OutputLevel = INFO) +createcells.hits.Path="newCaloHits" +createcells.cells.Path="newCaloCells" + +from Configurables import DECalAnalysis +hist = DECalAnalysis("DECalAnalysis", + pixelReadoutName = "BarDECal_Readout", + padReadoutName = "BarDECal_Pads", + layerFieldName = "layer", + numLayers = 50, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = INFO) +hist.pixels.Path="filteredCaloHits" +hist.pads.Path="newCaloCells" +hist.truth.Path="GenParticles" + +from Configurables import DECalNoiseHits +noise = DECalNoiseHits("DECalNoiseHits", + pixelReadoutName = "BarDECal_Readout", + OutputLevel = INFO) + +noise.pixels.Path="filteredCaloHits" + +#THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/' TYP='ROOT' OPT='RECREATE'"] +THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"/"+run_config+"/digital_"+file+"' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=False +THistSvc().AutoSave=True +THistSvc().AutoFlush=True +THistSvc().OutputLevel=INFO + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +hist.AuditExecute = True + +from Configurables import FCCDataSvc, PodioOutput +#podiosvc = FCCDataSvc("EventDataSvc") +podioout = PodioOutput("out", filename=batch_dir+"/"+det_config+"/"+run_config+"/redoSegmentation_"+file) +podioout.outputCommands = ["keep *"] + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [podioinput, filtered, resegment, createcells,hist, noise, podioout], + EvtSel = 'NONE', + EvtMax = 10, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podiosvc,geoservice, audsvc], + OutputLevel = INFO +) diff --git a/Detector/DetStudies/tests/options/decalAnalysis_DEcal_batch.py b/Detector/DetStudies/tests/options/decalAnalysis_DEcal_batch.py new file mode 100644 index 000000000..ff614f8dc --- /dev/null +++ b/Detector/DetStudies/tests/options/decalAnalysis_DEcal_batch.py @@ -0,0 +1,102 @@ +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +batch_dir = "/eos/user/t/toprice/private/FCC/FCCSW/v8.0/XYZ/" +fccsw_version = "FCCSW0.8" +det_config = "" +run_config = "" +file = "" +file = file[7:] +#inputfile = batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/"+file +inputfile = batch_dir+"/"+det_config+"/"+run_config+"/output_"+file +podiosvc = FCCDataSvc("EventDataSvc", input=inputfile) + + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=["positionedCaloHits", "GenParticles"], OutputLevel=DEBUG) + +# DD4hep geometry service +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_'+det_config[:-9]+'.xml' +], + OutputLevel = INFO) + + +from Configurables import FilterSiliconEcalHits +filtered = FilterSiliconEcalHits("FilterSiEcal", + readoutName = "BarDECal_Readout", + digitalFlag = 1) +filtered.deposits.Path="positionedCaloHits" +filtered.filtered.Path="filteredCaloHits" + +# add a processor which generates noise hits +# input - noise level +# - threshold level +# - segmentation name + +# add a processor which adds noise event in to genuine hits +# take input of noise hits and genuine hits +# output a combination for the event + +from Configurables import RedoSegmentation +resegment = RedoSegmentation("ReSegmentation", + # old bitfield (readout) + oldReadoutName = "BarDECal_Readout", + # specify which fields are going to be deleted + oldSegmentationIds = ["x","y","z"], + # new bitfield (readout), with new segmentation + newReadoutName="BarDECal_Pads", + OutputLevel = INFO) +# clusters are needed, with deposit position and cellID in bits +resegment.inhits.Path = "filteredCaloHits" +resegment.outhits.Path = "newCaloHits" + +from Configurables import CreateCaloCells +createcells = CreateCaloCells("CreateCaloCells", + doCellCalibration = False, + addCellNoise = False, filterCellNoise = False, sumPixelsPerCell = False, + OutputLevel = INFO) +createcells.hits.Path="newCaloHits" +createcells.cells.Path="newCaloCells" + +from Configurables import DECalAnalysis +hist = DECalAnalysis("DECalAnalysis", + pixelReadoutName = "BarDECal_Readout", + padReadoutName = "BarDECal_Pads", + layerFieldName = "layer", + numLayers = 50, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = INFO) +hist.pixels.Path="filteredCaloHits" +hist.pads.Path="newCaloCells" +hist.truth.Path="GenParticles" + +#THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/' TYP='ROOT' OPT='RECREATE'"] +THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"/"+run_config+"/digital_"+file+"' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=False +THistSvc().AutoSave=True +THistSvc().AutoFlush=True +THistSvc().OutputLevel=INFO + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +hist.AuditExecute = True + +from Configurables import FCCDataSvc, PodioOutput +#podiosvc = FCCDataSvc("EventDataSvc") +podioout = PodioOutput("out", filename=batch_dir+"/"+det_config+"/"+run_config+"/digital_podio_"+file) +podioout.outputCommands = ["keep *"] + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [podioinput, filtered, resegment, createcells,hist, podioout], + EvtSel = 'NONE', + # EvtMax = 10, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podiosvc,geoservice, audsvc], + OutputLevel = INFO +) diff --git a/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal.py b/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal.py new file mode 100644 index 000000000..acb082c44 --- /dev/null +++ b/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal.py @@ -0,0 +1,55 @@ +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +batch_dir = "/eos/user/t/toprice/private/FCC/FCCSW/v8.0/XYZ/" +fccsw_version = "FCCSW0.8" +det_config = "30Layers_3.5mmW_50umPixels_18umThick_RRB" +run_config = "10GeV_BFIELD4T_ETAMIN-0.001_ETAMAX-0.001" +file = "output_10GeV_BFIELD4T_0.root" +inputfile = batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/"+file +podiosvc = FCCDataSvc("EventDataSvc", input=inputfile) + + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=["positionedCaloHits"], OutputLevel=DEBUG) + +# DD4hep geometry service +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_30Layers_3.5mmW_50umPixels_18umThick_RRB.xml' +], + OutputLevel = INFO) + + + +from Configurables import DECalLongitudinalTest +hist = DECalLongitudinalTest("hists", + readoutName = "BarDECal_Readout", + layerFieldName = "layer", + numLayers = 30, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = DEBUG) +hist.deposits.Path="positionedCaloHits" + +THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/hist_test.root' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=True +THistSvc().AutoSave=True +THistSvc().AutoFlush=False +THistSvc().OutputLevel=INFO + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +hist.AuditExecute = True + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [podioinput, hist], + EvtSel = 'NONE', +# EvtMax = 10, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podiosvc,geoservice, audsvc], + OutputLevel = DEBUG +) diff --git a/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py b/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py new file mode 100644 index 000000000..318cf9021 --- /dev/null +++ b/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py @@ -0,0 +1,57 @@ +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +batch_dir = "/eos/user/t/toprice/private/FCC/FCCSW/v8.0/XYZ/" +fccsw_version = "FCCSW0.8" +det_config = "" +run_config = "" +file = "" +#inputfile = batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/"+file +inputfile = batch_dir+"/"+det_config+"/"+run_config+"/"+file +podiosvc = FCCDataSvc("EventDataSvc", input=inputfile) + + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=["positionedCaloHits"], OutputLevel=DEBUG) + +# DD4hep geometry service +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_'+det_config[:-9]+'.xml' +], + OutputLevel = INFO) + + + +from Configurables import DECalLongitudinalTest +hist = DECalLongitudinalTest("hists", + readoutName = "BarDECal_Readout", + layerFieldName = "layer", + numLayers = 50, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = DEBUG) +hist.deposits.Path="positionedCaloHits" + +#THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"_"+fccsw_version+"/"+run_config+"/' TYP='ROOT' OPT='RECREATE'"] +THistSvc().Output = ["rec DATAFILE='"+batch_dir+"/"+det_config+"/"+run_config+"/' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=True +THistSvc().AutoSave=True +THistSvc().AutoFlush=False +THistSvc().OutputLevel=INFO + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +hist.AuditExecute = True + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [podioinput, hist], + EvtSel = 'NONE', +# EvtMax = 10, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podiosvc,geoservice, audsvc], + OutputLevel = DEBUG +) diff --git a/Detector/DetStudies/tests/options/longitudinalTest_DEcal.py b/Detector/DetStudies/tests/options/longitudinalTest_DEcal.py new file mode 100644 index 000000000..2f49726a0 --- /dev/null +++ b/Detector/DetStudies/tests/options/longitudinalTest_DEcal.py @@ -0,0 +1,83 @@ +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +podioevent = FCCDataSvc("EventDataSvc") + +# DD4hep geometry service +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_Mockup.xml' +], + OutputLevel = INFO) + +# Geant4 service +# Configures the Geant simulation: geometry, physics list and user actions +from Configurables import SimG4Svc +geantservice = SimG4Svc("SimG4Svc", detector='SimG4DD4hepDetector', physicslist="SimG4FtfpBert", actions="SimG4FullSimActions") +geantservice.G4commands += ["/run/setCut 0.1 mm"] + +# Geant4 algorithm +# Translates EDM to G4Event, passes the event to G4, writes out outputs via tools +# and a tool that saves the calorimeter hits +from Configurables import SimG4Alg, SimG4SaveCalHits, SimG4SingleParticleGeneratorTool +saveecaltool = SimG4SaveCalHits("saveECalHits",readoutNames = ["BarDECal_Readout"]) +#saveecaltool.DataOutputs.caloClusters.Path = "ECalClusters" +saveecaltool.positionedCaloHits.Path = "positionedCaloHits" +saveecaltool.caloHits.Path = "ECalHits" + +from Configurables import SimG4SingleParticleGeneratorTool +pgun=SimG4SingleParticleGeneratorTool("SimG4SingleParticleGeneratorTool", + saveEdm=True, + particleName="e-", + energyMin=100000,energyMax=100000, + etaMin=0,etaMax=0, +# phiMin=0, phiMax=0.001, + vertexX=0,vertexY=0,vertexZ=0, + OutputLevel =DEBUG) + +# next, create the G4 algorithm, giving the list of names of tools ("XX/YY") +geantsim = SimG4Alg("SimG4Alg", + outputs= ["SimG4SaveCalHits/saveECalHits"], + eventProvider = pgun, + OutputLevel = DEBUG) + +from Configurables import DECalLongitudinalTest +hist = DECalLongitudinalTest("hists", + readoutName = "BarDECal_Readout", + layerFieldName = "layer", + numLayers = 50, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = DEBUG) +hist.deposits.Path="positionedCaloHits" + +THistSvc().Output = ["rec DATAFILE='hist_test.root' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=True +THistSvc().AutoSave=True +THistSvc().AutoFlush=False +THistSvc().OutputLevel=INFO + + +# PODIO algorithm +from Configurables import PodioOutput +out = PodioOutput("out", + OutputLevel=DEBUG) +out.outputCommands = ["keep *"] +out.filename = "output_10GeV_1mmAir_0T_SiAirW.root" + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +geantsim.AuditExecute = True +hist.AuditExecute = True + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [geantsim, out, hist], + EvtSel = 'NONE', + EvtMax = 10, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podioevent, geoservice, geantservice, audsvc], + OutputLevel = DEBUG +) diff --git a/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.cpp b/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.cpp index c3869ee67..2c08d83cb 100644 --- a/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.cpp +++ b/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.cpp @@ -76,7 +76,13 @@ StatusCode CreateCaloCells::execute() { // If running with noise map already was prepared. Otherwise it is being // created below for (const auto& hit : *hits) { - m_cellsMap[hit.core().cellId] += hit.core().energy; + + if(m_sumPixelsPerCell) { + m_cellsMap[hit.core().cellId] += 1; + } else { + m_cellsMap[hit.core().cellId] += hit.core().energy; + } + } debug() << "Number of calorimeter cells after merging of hits: " << m_cellsMap.size() << endmsg; diff --git a/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.h b/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.h index f8e421425..67ea0513a 100644 --- a/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.h +++ b/Reconstruction/RecCalorimeter/src/components/CreateCaloCells.h @@ -64,10 +64,13 @@ class CreateCaloCells : public GaudiAlgorithm { /// Save only cells with energy above threshold? Gaudi::Property m_filterCellNoise{this, "filterCellNoise", false, "Save only cells with energy above threshold?"}; + /// Add energy deposit or sum number of pixels in the cell (DECal) + Gaudi::Property m_sumPixelsPerCell{this, "sumPixelsPerCell", false, + "Sum the number of pixels in the cell rather than energy?"}; /// Handle for calo hits (input collection) DataHandle m_hits{"hits", Gaudi::DataHandle::Reader, this}; /// Handle for calo cells (output collection) - DataHandle m_cells{"cells", Gaudi::DataHandle::Writer, this}; + DataHandle m_cells{"cellsm", Gaudi::DataHandle::Writer, this}; /// Name of the detector readout Gaudi::Property m_readoutName{this, "readoutName", "ECalHitsPhiEta", "Name of the detector readout"}; /// Name of active volumes diff --git a/Sim/SimG4Components/src/SimG4SaveCalHits.cpp b/Sim/SimG4Components/src/SimG4SaveCalHits.cpp index 6ab617707..a2d179599 100644 --- a/Sim/SimG4Components/src/SimG4SaveCalHits.cpp +++ b/Sim/SimG4Components/src/SimG4SaveCalHits.cpp @@ -69,6 +69,13 @@ StatusCode SimG4SaveCalHits::saveOutput(const G4Event& aEvent) { auto edmHit = edmHits->create(); auto& edmHitCore = edmHit.core(); edmHitCore.cellId = hit->cellID; + // added by Tony Price for timing + auto contributions = hit->truth; + if(contributions.size()>0) { + // for now just get the first entry + // for DECAL SD this is overwritten with particles per pixel + edmHitCore.time = hit->truth[0].time; + } edmHitCore.energy = hit->energyDeposit * sim::g42edm::energy; auto position = fcc::Point(); position.x = hit->position.x() * sim::g42edm::length; diff --git a/Test/TestGeometry/data/TestDECal_segmentation.xml b/Test/TestGeometry/data/TestDECal_segmentation.xml new file mode 100644 index 000000000..32111e7b0 --- /dev/null +++ b/Test/TestGeometry/data/TestDECal_segmentation.xml @@ -0,0 +1,52 @@ + + + + + + + + + + Simple box to test dd4hep geometry (and segmentation) + + + + + + + + + + + + + + + + + + + + + z:-4,y:-4,x:-4,system:1 + + + + + + + + + + + + + + diff --git a/Test/TestReconstruction/tests/options/testcellcountingXYZ.py b/Test/TestReconstruction/tests/options/testcellcountingXYZ.py index d94ca9a28..ef2e13a01 100644 --- a/Test/TestReconstruction/tests/options/testcellcountingXYZ.py +++ b/Test/TestReconstruction/tests/options/testcellcountingXYZ.py @@ -1,14 +1,21 @@ from Gaudi.Configuration import * from Configurables import ApplicationMgr +#from Configurables import GeoSvc +#geoservice = GeoSvc("GeoSvc", detectors=[ 'Test/TestGeometry/data/TestBoxCaloSD_segmentation.xml'], OutputLevel = DEBUG) + from Configurables import GeoSvc -geoservice = GeoSvc("GeoSvc", detectors=[ 'Test/TestGeometry/data/TestBoxCaloSD_segmentation.xml'], OutputLevel = DEBUG) +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_50Layers_2.1mmW.xml' +], + OutputLevel = DEBUG) from Configurables import TestCellCounting -cells = TestCellCounting("cells", readoutName="ECalHits", - fieldNames=["system"], - fieldValues=[0], - volumeMatchName="BoxECal", +cells = TestCellCounting("cells", + readoutName="BarDECal_Readout",#ECalHits", + fieldNames=["layer"], + fieldValues=[50], + volumeMatchName="Silicon_sensitive", OutputLevel = DEBUG) # ApplicationMgr ApplicationMgr(EvtSel='NONE', diff --git a/analyse_DEcal_particles.py b/analyse_DEcal_particles.py new file mode 100644 index 000000000..fcf3449f8 --- /dev/null +++ b/analyse_DEcal_particles.py @@ -0,0 +1,267 @@ +from ROOT import TH1F, TTree, TChain, TFile, TF1, TH2F, TGraphErrors, TCanvas, TPaveText +import os +import numpy as np +from array import array + + +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +ETAMIN = -0.001 +ETAMAX = 0.001 + +p0 = 3.28652e+02 +p1 = 9.89744e+01 +p2 = -1.25638e-02 + +calibration = TF1("calibration", "pol2", 0, 3000) +calibration.SetParameter("p0", p0) +calibration.SetParameter("p1", p1) +calibration.SetParameter("p2", p2) + +gaus = TF1("gaus", "gaus", 0, 3000) + +RESOLUTION_PART = {} +RESOLUTION_PART_SIGMA = {} +LINEARITY_PART = {} +LINEARITY_PART_SIGMA = {} + +RESOLUTION = {} +RESOLUTION_SIGMA = {} +LINEARITY = {} +LINEARITY_SIGMA = {} + +CONFIGS = ["30Layers_3.5mmW_50umPixels_18umThick_RRB_modules_FCCSW0.8"] #[ c for c in os.listdir(FCCSW_DIR+"/batch_eos/") if "50Layers_2.1mmW_50umPixels_18umThick" in c and "Edep" not in c] +print CONFIGS + +for CONFIG in CONFIGS: + print CONFIG + + fout = TFile(CONFIG+".root", "RECREATE") + fout.cd() + partperpixvspix = TH2F("partperpixvspix", ";Pixels per event;Particles / Pixel; Count", 2000,0,120000,100, 0.8,1.4) + + RUNCONFIGS = [ e for e in os.listdir(FCCSW_DIR+"/batch_eos/"+CONFIG) ] + for RUNCONFIG in RUNCONFIGS: + #print "\t",RUNCONFIG + + dir="batch_eos/"+CONFIG+"/"+RUNCONFIG+"/" + #print "\n",dir + + chain = TChain("decal_info") + + if os.path.isdir(dir): + + FILES = [f for f in os.listdir(dir) if "digital_" in f and "500GeV" not in f and "300GeV" not in f and "700GeV" not in f and "1GeV" not in f and "podio" not in f and "root.root" not in f] + for f in FILES: + temp_file = TFile(dir+f) + if temp_file.IsZombie(): + continue + else: + chain.Add(dir+f) + + if chain.GetEntries() > 0: + + #schain.Print() + + chain.SetBranchStatus("*",0) + chain.SetBranchStatus("particles_tot",1) # this is the number of particles per pixel summed in an event + chain.SetBranchStatus("pixels_tot",1) + chain.SetBranchStatus("particles_l*", 1) + chain.SetBranchStatus("pixels_l*",1) + + truth_energy = float(RUNCONFIG[:RUNCONFIG.find("GeV")]) + + temp_energy = TH1F("energy_"+str(truth_energy)+"GeV", "Reconstructed energy from pol2; E_{truth}; E_{reco}", 2000, 0, 1200) + temp_particles = TH1F("particles_"+str(truth_energy)+"GeV", "Particles per event; Particles per event; Count", 2000, 0, 120000) + temp_pixels = TH1F("pixels_"+str(truth_energy)+"GeV", "Pixels per event; Pixels per event; Count", 2000, 0, 1200) + temp_partvspix = TH2F("partvspix_"+str(truth_energy)+"GeV", ";Pixels per event; Particles per event", 2000,0,120000,2000,0,120000) + temp_partperpix = TH1F("partperpix_"+str(truth_energy)+"GeV", ";Particles / Pixel; Count", 100, 0.8, 1.4) + temp_partperpixvspix = TH2F("partperpixvspix_"+str(truth_energy)+"GeV", ";Pixels per event;Particles / Pixel; Count", 2000,0,120000,100, 0.8, 1.4) + + + pixels_energy = TF1("cal", "pol2", 0, 1200) + pixels_energy.SetParameter(0, 1.757E02) + pixels_energy.SetParameter(1, 5.754E01) + pixels_energy.SetParameter(2, -8.625E-03) + + for i in np.arange(0,chain.GetEntries()): + + chain.GetEntry(i) + pixels_tot = chain.pixels_tot + particles_tot = chain.particles_tot + + temp_pixels.Fill(pixels_energy.GetX(pixels_tot)) + temp_particles.Fill(particles_tot) + temp_partvspix.Fill(pixels_tot,particles_tot) + temp_partperpix.Fill(particles_tot/pixels_tot) + temp_partperpixvspix.Fill(pixels_tot, particles_tot/pixels_tot) + partperpixvspix.Fill(pixels_tot, particles_tot/pixels_tot) + + energy = calibration.GetX(pixels_tot) + temp_energy.Fill(energy) + + #loop through the layers to get particles / pixel + + + #if i == 0 or i%100==0: + # print i, "/", chain.GetEntries() + # print "\t", pixels_tot, energy + + + #temp_partperpix.Draw("") + #temp_ereco.Fit("gaus","N") + + fout.cd() + + # fit info for the particles + gaus.SetRange(0,120000) + temp_particles.Fit("gaus", "NQR") + temp_particles.Write() + mean_particles = gaus.GetParameter(1) + sigma_particles = gaus.GetParameter(2) + + if mean_particles > 0: + + RESOLUTION_PART[str(truth_energy)] = sigma_particles/ mean_particles + RESOLUTION_PART_SIGMA[str(truth_energy)] = pow(pow(gaus.GetParError(1)/gaus.GetParameter(1),2) + pow(gaus.GetParError(2)/gaus.GetParameter(2),2),0.5) * RESOLUTION_PART[str(truth_energy)] + LINEARITY_PART[str(truth_energy)] = mean_particles + LINEARITY_PART_SIGMA[str(truth_energy)] = gaus.GetParError(1) + + # fit info for the pixels + gaus.SetRange(0,120000) + temp_pixels.Fit("gaus", "NQR") + temp_pixels.Write() + mean_pixels = gaus.GetParameter(1) + sigma_pixels = gaus.GetParameter(2) + + if mean_pixels > 0: + + RESOLUTION[str(truth_energy)] = sigma_pixels/ mean_pixels + RESOLUTION_SIGMA[str(truth_energy)] = pow(pow(gaus.GetParError(1)/gaus.GetParameter(1),2) + pow(gaus.GetParError(2)/gaus.GetParameter(2),2),0.5) * RESOLUTION[str(truth_energy)] + LINEARITY[str(truth_energy)] = mean_pixels + LINEARITY_SIGMA[str(truth_energy)] = gaus.GetParError(1) + + # fit info for the calibrated energy + gaus.SetRange(0,3000) + temp_energy.Fit("gaus", "NQR") + temp_energy.Write() + mean_ereco = gaus.GetParameter(1) + sigma_ereco = gaus.GetParameter(2) + + temp_partperpix.Write() + temp_partvspix.Write() + temp_partperpixvspix.Write() + + if mean_particles > 0: + + print "\n\nTruth Energy = ", truth_energy + print "nEvts = ", chain.GetEntries() + print "Particles = ", mean_particles, "+/-", sigma_particles + print "Pixels = ", mean_pixels, "+/-", sigma_pixels + print "Ereco = ", mean_ereco, "+/-", sigma_ereco + # print "Reco Energy = ", mean, "+/-", sigma + # print "Resolution = ", sigma/mean + + + + partperpixvspix.Write() + + res_plot = TGraphErrors(len(RESOLUTION), array("d",[float(x) for x in RESOLUTION.keys()]), + array("d",[float(y) for y in RESOLUTION.values()]), + array("d",[float(0.1) for xe in RESOLUTION.keys()]), + array("d",[float(ye) for ye in RESOLUTION_SIGMA.values()])) + + res_part_plot = TGraphErrors(len(RESOLUTION_PART), array("d",[float(x) for x in RESOLUTION_PART.keys()]), + array("d",[float(y) for y in RESOLUTION_PART.values()]), + array("d",[float(0.1) for xe in RESOLUTION_PART.keys()]), + array("d",[float(ye) for ye in RESOLUTION_PART_SIGMA.values()])) + + lin_plot = TGraphErrors(len(LINEARITY), array("d",[float(x) for x in LINEARITY.keys()]), + array("d",[float(y) for y in LINEARITY.values()]), + array("d",[float(0.1) for xe in LINEARITY.keys()]), + array("d",[float(ye) for ye in LINEARITY_SIGMA.values()])) + + + lin_part_plot = TGraphErrors(len(LINEARITY_PART), array("d",[float(x) for x in LINEARITY_PART.keys()]), + array("d",[float(y) for y in LINEARITY_PART.values()]), + array("d",[float(0.1) for xe in LINEARITY_PART.keys()]), + array("d",[float(ye) for ye in LINEARITY_PART_SIGMA.values()])) + + + c_res = TCanvas("Resolution") + + fit_min = 50 + fit_max = 500 + fit = TF1("fit", "[0]/sqrt(x)+[1]+[2]/x", fit_min, fit_max) + fit_part = TF1("fit_part", "[0]/sqrt(x)+[1]", fit_min, 1000) + + fit.FixParameter(2, 0) + + res_plot.SetMarkerStyle(22); + res_plot.SetMaximum(0.08); + res_plot.SetMinimum(0.0); + res_plot.SetTitle("Resolution: 50um Pixels") + res_plot.GetXaxis().SetTitle("Energy [GeV]") + res_plot.GetYaxis().SetTitle("sigma_N / mu_N") + res_plot.Fit(fit, "NR") + fit.SetRange(0,1000); + + res_part_plot.SetMarkerStyle(23); + res_part_plot.SetTitle("Resolution: Particles") + res_part_plot.GetXaxis().SetTitle("Energy [GeV]") + res_part_plot.GetYaxis().SetTitle("sigma_N / mu_N") + res_part_plot.Fit(fit_part, "NR") + fit_part.SetRange(0,1000); + + #res_part_plot.Draw("ap") + #fit_part.Draw("same") + res_plot.Draw("ap") + fit.Draw("same") + + pt = TPaveText(0.55,0.55,0.8,0.85, "NDC") + pt.SetBorderSize(0) + pt.SetFillColor(0) + pt.AddText('Fit Range: {fit_min} - {fit_max} '.format(fit_min=fit_min, fit_max=fit_max)) + #pt.AddText('#frac{{{stoch:.1%}}}{{{sqrt}}} #oplus {leakage:.1%} '.format(stoch=fit_part.GetParameter(0), sqrt="#sqrt{E}", leakage=fit_part.GetParameter(1),E="E")) + if fit.GetParameter(2) != 0: + pt.AddText('#frac{{{noise:.1%}}}{{{E}}} #oplus #frac{{{stoch:.1%}}}{{{sqrt}}} #oplus {leakage:.1%} '.format(stoch=fit.GetParameter(0), sqrt="#sqrt{E}", leakage=fit.GetParameter(1),E="E", noise=fit.GetParameter(2))) + else: + pt.AddText('#frac{{{stoch:.1%}}}{{{sqrt}}} #oplus {leakage:.1%} '.format(stoch=fit.GetParameter(0), sqrt="#sqrt{E}", leakage=fit.GetParameter(1),E="E")) + pt.Draw() + c_res.Print("DECal_resolution.png") + + lin_plot.SetMarkerStyle(22) + lin_plot.SetTitle("Linearity: ") + lin_plot.GetXaxis().SetTitle("Energy [GeV]") + lin_plot.GetYaxis().SetTitle("Mean pixels per event") + lin_fit = TF1("lin_fit", "pol2", fit_min, fit_max) + lin_plot.Fit(lin_fit, "NR") + lin_fit.SetRange(0,1000) + + lin_part_plot.SetMarkerStyle(23) + lin_part_plot.SetTitle("Linearity: ") + lin_part_plot.GetXaxis().SetTitle("Energy [GeV]") + lin_part_plot.GetYaxis().SetTitle("Mean particles per event") + lin_part_fit = TF1("lin_part_fit", "pol1", fit_min, fit_max) + lin_part_plot.Fit(lin_part_fit, "NR") + lin_part_fit.SetRange(0,1000) + + c_lin = TCanvas("lin_plot") + #lin_part_plot.Draw("ap") + #lin_part_fit.Draw("same") + lin_plot.Draw("ap") + lin_fit.Draw("same") + pt_lin = TPaveText(0.25,0.7,0.5,0.85, "NDC") + pt_lin.SetBorderSize(0) + pt_lin.SetFillColor(0) + #pt_lin.AddText('Fit Range: {fit_min} - {fit_max} '.format(fit_min, fit_max)) + #pt_lin.AddText('{x2:.4g}x^2 #plus {x:.4g}x #plus {c:.4g} '.format(x2=lin_fit.GetParameter(2), x=lin_fit.GetParameter(1), c=lin_fit.GetParameter(0))) + #pt_lin.AddText(' {x:.4g}x #plus {c:.4g} '.format(x=lin_fit.GetParameter(1), c=lin_fit.GetParameter(0))) + pt_lin.Draw() + c_lin.Print("DEcal_linearity.png") + + res_plot.Write() + lin_plot.Write() + fout.Write() + fout.Close() + +closeInput = raw_input("Press ENTER to exit") diff --git a/analyse_SiW.py b/analyse_SiW.py new file mode 100644 index 000000000..34ae00936 --- /dev/null +++ b/analyse_SiW.py @@ -0,0 +1,132 @@ +from ROOT import TH1F, TTree, TChain, TFile, TF1, TCanvas, TGraphErrors, TPaveText +from array import array +import os +import numpy as np + +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +ETAMIN = -0.001 +ETAMAX = 0.001 + +RESOLUTION= {} +RESOLUTION_SIGMA = {} +LINEARITY = {} +LINEARITY_SIGMA = {} + +CONFIGS = [ c for c in os.listdir(FCCSW_DIR+"/batch_eos/") if "30Layers" in c and "RRB" in c] +print CONFIGS + +for CONFIG in CONFIGS: + print CONFIG + + RUNCONFIGS = [ e for e in os.listdir(FCCSW_DIR+"/batch_eos/"+CONFIG)] + for RUNCONFIG in RUNCONFIGS: + #print "\t",RUNCONFIG + + dir="batch_eos/"+CONFIG+"/"+RUNCONFIG+"/" + print "\n",dir + + chain = TChain("info") + + if os.path.isdir(dir): + + FILES = [f for f in os.listdir(dir) if "analogue" in f and "root.root" not in f] + for f in FILES: + temp_file = TFile(dir+f) + if temp_file.IsZombie(): + continue + else: + chain.Add(dir+f) + #print f + + print chain.GetEntries() + + if chain.GetEntries() > 0: + + #schain.Print() + + chain.SetBranchStatus("*",0) + chain.SetBranchStatus("edep_tot",1) # this is the number of particles per pixel summed in an event + + + truth_energy = float(RUNCONFIG[:RUNCONFIG.find("GeV")]) + temp_edep = TH1F("edep_"+str(truth_energy)+"GeV", "Energy deposited per event; Energy Deposited [keV]; Count", 400, 0, 20) + + for i in np.arange(0,chain.GetEntries()): + + chain.GetEntry(i) + temp_edep.Fill(chain.edep_tot); + + gaus = TF1("gaus","gaus",0,20) + temp_edep.Fit("gaus", "NQR") + mean = gaus.GetParameter(1) + sigma = gaus.GetParameter(2) + + if mean > 0: + + RESOLUTION[str(truth_energy)] = sigma/ mean + RESOLUTION_SIGMA[str(truth_energy)] = pow(pow(gaus.GetParError(1)/gaus.GetParameter(1),2) + pow(gaus.GetParError(2)/gaus.GetParameter(2),2),0.5) * RESOLUTION[str(truth_energy)] + LINEARITY[str(truth_energy)] = mean + LINEARITY_SIGMA[str(truth_energy)] = gaus.GetParError(1) + + + print RESOLUTION + + res_plot = TGraphErrors(len(RESOLUTION), array("d",[float(x) for x in RESOLUTION.keys()]), + array("d",[float(y) for y in RESOLUTION.values()]), + array("d",[float(0.1) for xe in RESOLUTION.keys()]), + array("d",[float(ye) for ye in RESOLUTION_SIGMA.values()])) + + + lin_plot = TGraphErrors(len(LINEARITY), array("d",[float(x) for x in LINEARITY.keys()]), + array("d",[float(y) for y in LINEARITY.values()]), + array("d",[float(0.1) for xe in LINEARITY.keys()]), + array("d",[float(ye) for ye in LINEARITY_SIGMA.values()])) + + c_res = TCanvas("Resolution") + + fit_min = 50 + fit_max = 1000 + fit = TF1("fit", "[0]/sqrt(x)+[1]", fit_min, fit_max) + + res_plot.SetMarkerStyle(22); + res_plot.SetMaximum(0.08); + res_plot.SetMinimum(0.0); + res_plot.SetTitle("Resolution: 5x5mm Pads") + res_plot.GetXaxis().SetTitle("Energy [GeV]") + res_plot.GetYaxis().SetTitle("sigma_E / mu_E") + res_plot.Fit(fit, "NR") + fit.SetRange(0,1000); + + res_plot.Draw("ap") + fit.Draw("same") + + pt = TPaveText(0.55,0.55,0.8,0.85, "NDC") + pt.SetBorderSize(0) + pt.SetFillColor(0) + pt.AddText('Fit Range: {fit_min} - {fit_max} '.format(fit_min=fit_min, fit_max=fit_max)) + #pt.AddText('#frac{{{noise:.1%}}}{{{E}}} #oplus #frac{{{stoch:.1%}}}{{{sqrt}}} #oplus {leakage:.1%} '.format(stoch=fit_0mm.GetParameter(0), sqrt="#sqrt{E}", leakage=fit_0mm.GetParameter(1),E="E", noise=fit_0mm.GetParameter(2))) + pt.AddText('#frac{{{stoch:.1%}}}{{{sqrt}}} #oplus {leakage:.1%} '.format(stoch=fit.GetParameter(0), sqrt="#sqrt{E}", leakage=fit.GetParameter(1),E="E")) + pt.Draw() + c_res.Print("SiW_300um_resolution.png") + + lin_plot.SetMarkerStyle(22) + lin_plot.SetTitle("Linearity: ") + lin_plot.GetXaxis().SetTitle("Energy [GeV]") + lin_plot.GetYaxis().SetTitle("Energy Deposited [keV]") + lin_fit = TF1("lin_fit", "pol1", fit_min, fit_max) + lin_plot.Fit(lin_fit, "NR") + lin_fit.SetRange(0,1000) + + c_lin = TCanvas("lin_plot") + lin_plot.Draw("ap") + lin_fit.Draw("same") + pt_lin = TPaveText(0.25,0.7,0.5,0.85, "NDC") + pt_lin.SetBorderSize(0) + pt_lin.SetFillColor(0) + #pt_lin.AddText('Fit Range: {fit_min} - {fit_max} '.format(fit_min, fit_max)) + #pt_lin.AddText('{x2:.4g}x^2 #plus {x:.4g}x #plus {c:.4g} '.format(x2=lin_fit.GetParameter(2), x=lin_fit.GetParameter(1), c=lin_fit.GetParameter(0))) + #pt_lin.AddText(' {x:.4g}x #plus {c:.4g} '.format(x=lin_fit.GetParameter(1), c=lin_fit.GetParameter(0))) + #pt_lin.Draw() + c_lin.Print("SiW_300um_linearity.png") + +closeInput = raw_input("Press ENTER to exit") diff --git a/calculate_nonLinFactor.py b/calculate_nonLinFactor.py new file mode 100644 index 000000000..69ed73a8d --- /dev/null +++ b/calculate_nonLinFactor.py @@ -0,0 +1,60 @@ +from ROOT import TH1F, TTree, TChain, TFile, TGraphErrors, TF1 +import numpy as np +import os +from array import array + +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +ETAMIN = -0.001 +ETAMAX = 0.001 + +CONFIGS = [ c for c in os.listdir(FCCSW_DIR+"/batch_eos/") if "50Layers_2.1mmW" in c and "Pixels" not in c] +print CONFIGS + +PIXELS = {} +PIXELS_SIGMA = {} + +for CONFIG in CONFIGS: + print CONFIG + + RUNCONFIGS = [ e for e in os.listdir(FCCSW_DIR+"/batch_eos/"+CONFIG) ] + for RUNCONFIG in RUNCONFIGS: + #print "\t",RUNCONFIG + + dir="batch_eos/"+CONFIG+"/"+RUNCONFIG+"/" + print "\n",dir + + chain = TChain("decal_info") + + if os.path.isdir(dir): + + FILES = [f for f in os.listdir(dir) if "analysis" in f] + for f in FILES: + temp_file = TFile(dir+f) + if temp_file.IsZombie(): + continue + else: + chain.Add(dir+f) + + print chain.GetEntries() + + temp_hist = TH1F("temp_hist", "temp hist", 2000, 0, 100000)#20) + chain.Draw("pixels_tot>>temp_hist","", "GOFF" ) + + energy = float(RUNCONFIG[:RUNCONFIG.find("GeV")]) + mean = temp_hist.GetMean() + sigma = temp_hist.GetRMS() + if mean > 0: + print energy, mean, sigma, sigma/mean + PIXELS[str(energy)] = mean + PIXELS_SIGMA[str(energy)] = sigma / np.sqrt(chain.GetEntries()) + +print PIXELS +lin_plot = TGraphErrors(len(PIXELS), array("d",[float(x) for x in PIXELS.keys()]), + array("d",[float(y) for y in PIXELS.values()]), + array("d",[float(0.1) for xe in PIXELS.keys()]), + array("d",[float(ye) for ye in PIXELS_SIGMA.values()])) + +fit = TF1("fit", "pol2", 0, 1000) +lin_plot.Fit(fit) +lin_plot.Draw("ape") +closeInput = raw_input("Press ENTER to exit") diff --git a/geant_batch_temp.py b/geant_batch_temp.py new file mode 100644 index 000000000..e59118283 --- /dev/null +++ b/geant_batch_temp.py @@ -0,0 +1,117 @@ +#JANA: variables ENE (energy in MeV!!!!), BFIELD (0,1), EVTMAX (number of events) to be defined before running +ENE = 000 +BFIELD = +EVTMAX = +ETAMIN = +ETAMAX = + +if ENE == 0000: + ENEMIN = 100000 + ENEMAX = 1000000 +else: + ENEMIN=ENE + ENEMAX=ENE + +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +podioevent = FCCDataSvc("EventDataSvc") + +# DD4hep geometry service +# Parses the given xml file +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_.xml' + ], + OutputLevel = INFO) + +# Geant4 service +# Configures the Geant simulation: geometry, physics list and user actions +from Configurables import SimG4Svc +# Configures the Geant simulation: geometry, physics list and user actions +geantservice = SimG4Svc("SimG4Svc", detector='SimG4DD4hepDetector', physicslist="SimG4FtfpBert", actions="SimG4FullSimActions") + + +# Magnetic field +from Configurables import SimG4ConstantMagneticFieldTool +if BFIELD==0.0: + field = SimG4ConstantMagneticFieldTool("SimG4ConstantMagneticFieldTool",FieldOn=False) +else: + field = SimG4ConstantMagneticFieldTool("SimG4ConstantMagneticFieldTool",FieldOn=True,IntegratorStepper="ClassicalRK4",FieldComponentZ="-0.00"+str(BFIELD)) + +#Setting random seeds for Geant4 simulations +#Two parameters required (don't know why), Anna suggested to fix the second one to 0 and change only the first one +import random +x=random.randrange(1, 384649202, 1) +print "random seed=",x +#geantservice.G4commands += ["/random/setSeeds "+str(x)+" 0"] #where x is the number you want + +#range cut +#geantservice.G4commands += ["/run/setCut 0.1 mm"] + +# Geant4 algorithm +# Translates EDM to G4Event, passes the event to G4, writes out outputs via tools +from Configurables import SimG4Alg, SimG4SaveCalHits +# and a tool that saves the calorimeter hits with a name "G4SaveCalHits/saveHCalHits" + +saveecaltool = SimG4SaveCalHits("saveECalHits",readoutNames = ["BarDECal_Readout"]) +#saveecaltool.DataOutputs.caloClusters.Path = "ECalClusters" +saveecaltool.positionedCaloHits.Path = "positionedCaloHits" +saveecaltool.caloHits.Path = "ECalHits" + +# next, create the G4 algorithm, giving the list of names of tools ("XX/YY") +from Configurables import SimG4SingleParticleGeneratorTool +pgun=SimG4SingleParticleGeneratorTool("SimG4SingleParticleGeneratorTool", + saveEdm=True, + particleName="e-", + energyMin=ENEMIN,energyMax=ENEMAX, + etaMin=ETAMIN,etaMax=ETAMAX, +# phiMin=0, phiMax=0.001, + vertexX=0,vertexY=0,vertexZ=0, + OutputLevel =DEBUG) +#Following lines do not work, no idea why: +#pgun.DataOutputs.genParticles.Path = "genParticles" +#pgun.DataOutputs.genVertices.Path="genVertices" +geantsim = SimG4Alg("SimG4Alg", + outputs= ["SimG4SaveCalHits/saveECalHits"], + eventProvider=pgun) + +from Configurables import DECalLongitudinalTest +hist = DECalLongitudinalTest("hists", + readoutName = "BarDECal_Readout", + layerFieldName = "layer", + numLayers = 51, # one more because index starts at 1 - layer 0 will be always empty + OutputLevel = DEBUG) +hist.deposits.Path="positionedCaloHits" + +THistSvc().Output = ["rec DATAFILE='hist_GeV_BFIELDT_.root' TYP='ROOT' OPT='RECREATE'"] +THistSvc().PrintAll=True +THistSvc().AutoSave=True +THistSvc().AutoFlush=False +THistSvc().OutputLevel=INFO + +# PODIO algorithm +from Configurables import PodioOutput +out = PodioOutput("out", + OutputLevel=INFO) +out.outputCommands = ["keep *"] +out.filename = "output_GeV_BFIELDT_.root" + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +geantsim.AuditExecute = True + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [geantsim, out],# hist], + EvtSel = 'NONE', + EvtMax = EVTMAX, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podioevent, geoservice, geantservice, audsvc], + OutputLevel=INFO +) + diff --git a/geant_fullsim_ecal_SPG_new.py b/geant_fullsim_ecal_SPG_new.py new file mode 100644 index 000000000..990fb7fe6 --- /dev/null +++ b/geant_fullsim_ecal_SPG_new.py @@ -0,0 +1,100 @@ +#JANA: variables ENE (energy in MeV!!!!), BFIELD (0,1), EVTMAX (number of events) to be defined before running +ENE = 100000 +BFIELD = 4 +EVTMAX = 100 +ETAMIN = -0.001 +ETAMAX = 0.001 + +from Gaudi.Configuration import * + +# Data service +from Configurables import FCCDataSvc +podioevent = FCCDataSvc("EventDataSvc") + +# DD4hep geometry service +# Parses the given xml file +from Configurables import GeoSvc +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_Mockup.xml' + ], + OutputLevel = DEBUG) + +# Geant4 service +# Configures the Geant simulation: geometry, physics list and user actions +from Configurables import SimG4Svc +# Configures the Geant simulation: geometry, physics list and user actions +geantservice = SimG4Svc("SimG4Svc", detector='SimG4DD4hepDetector', physicslist="SimG4FtfpBert", actions="SimG4FullSimActions") + + +# Magnetic field +from Configurables import SimG4ConstantMagneticFieldTool +#if BFIELD==1: +# field = SimG4ConstantMagneticFieldTool("SimG4ConstantMagneticFieldTool",FieldOn=True,IntegratorStepper="ClassicalRK4",FieldComponentZ="-0.0040") +if BFIELD==0.0: + field = SimG4ConstantMagneticFieldTool("SimG4ConstantMagneticFieldTool",FieldOn=False) +else: + field = SimG4ConstantMagneticFieldTool("SimG4ConstantMagneticFieldTool",FieldOn=True,IntegratorStepper="ClassicalRK4",FieldComponentZ="-0.00"+str(BFIELD)) + +#Setting random seeds for Geant4 simulations +#Two parameters required (don't know why), Anna suggested to fix the second one to 0 and change only the first one +#x=12768674 +import random +x=random.randrange(1, 384649202, 1) + +print x +#geantservice.G4commands += ["/random/setSeeds "+str(x)+" 0"] #where x is the number you want + +#range cut +#geantservice.G4commands += ["/run/setCut 0.1 mm"] + +# Geant4 algorithm +# Translates EDM to G4Event, passes the event to G4, writes out outputs via tools +from Configurables import SimG4Alg, SimG4SaveCalHits +# and a tool that saves the calorimeter hits with a name "G4SaveCalHits/saveHCalHits" + +saveecaltool = SimG4SaveCalHits("saveECalHits",readoutNames = ["BarDECal_Readout"]) +#saveecaltool.DataOutputs.caloClusters.Path = "ECalClusters" +saveecaltool.positionedCaloHits.Path = "positionedCaloHits" +saveecaltool.caloHits.Path = "ECalHits" + +# next, create the G4 algorithm, giving the list of names of tools ("XX/YY") +from Configurables import SimG4SingleParticleGeneratorTool +pgun=SimG4SingleParticleGeneratorTool("SimG4SingleParticleGeneratorTool", + saveEdm=True, + particleName="e-", + energyMin=ENE,energyMax=ENE, + etaMin=ETAMIN,etaMax=ETAMAX, +# phiMin=0, phiMax=0.001, + vertexX=0,vertexY=0,vertexZ=0, + OutputLevel =INFO) +#Following lines do not work, no idea why: +#pgun.DataOutputs.genParticles.Path = "genParticles" +#pgun.DataOutputs.genVertices.Path="genVertices" +geantsim = SimG4Alg("SimG4Alg", + outputs= ["SimG4SaveCalHits/saveECalHits"], + eventProvider=pgun) + +# PODIO algorithm +from Configurables import PodioOutput +out = PodioOutput("out", + OutputLevel=INFO) +out.outputCommands = ["keep *"] +out.filename = "output_100GeV_1mmAir_0T_SiAirW.root" + +#CPU information +from Configurables import AuditorSvc, ChronoAuditor +chra = ChronoAuditor() +audsvc = AuditorSvc() +audsvc.Auditors = [chra] +geantsim.AuditExecute = True + +# ApplicationMgr +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg = [geantsim, out], + EvtSel = 'NONE', + EvtMax = EVTMAX, + # order is important, as GeoSvc is needed by G4SimSvc + ExtSvc = [podioevent, geoservice, geantservice, audsvc], + OutputLevel=INFO +) + diff --git a/geant_pile_up_batch_temp.py b/geant_pile_up_batch_temp.py new file mode 100644 index 000000000..cceec0902 --- /dev/null +++ b/geant_pile_up_batch_temp.py @@ -0,0 +1,97 @@ + +### \file +### \ingroup SimulationExamples +### | **input (alg)** | other algorithms | | | | **output (alg)** | +### |-------------------------------|----------------------------------|---------------------------------------------------------|------------------------|----------------------------------|-----------------------------------------------| +### | generating single particle events from a given list of types, with momentum, phi and theta from a given range, saving to HepMC | convert `HepMC::GenEvent` to EDM | geometry parsed from XML (TestHCal.xml) by DD4hep using GeoSvc | FTFP_BERT physics list | saving HCal hits | write the EDM output to ROOT file using PODIO | + +from Gaudi.Configuration import * + +from Configurables import FCCDataSvc +## Data service +podioevent = FCCDataSvc("EventDataSvc") + +### Example of pythia configuration file to generate events +#pythiafile="Generation/data/Pythia_standard.cmd" +pythiafile="/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Generation/data/Pythia_minbias_pp_100TeV.cmd" +# Example of pythia configuration file to read LH event file +#pythiafile="options/Pythia_LHEinput.cmd" + +from Configurables import FCCDataSvc +#### Data service +podioevent = FCCDataSvc("EventDataSvc") + +from Configurables import ConstPileUp + +pileuptool = ConstPileUp(numPileUpEvents=, filename="/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Generation/data/Pythia_minbias_pp_100TeV.cmd") + +from Configurables import PythiaInterface, GenAlg +### PYTHIA algorithm +pythia8gentool = PythiaInterface("Pythia8Interface", Filename=pythiafile) +pythia8gen = GenAlg("Pythia8", SignalProvider=pythia8gentool) +pythia8gen.hepmc.Path = "hepmcevent" + +gen = GenAlg("ParticleGun", SignalProvider=pythia8gentool, PileUpTool=pileuptool) +gen.hepmc.Path = "hepmc" + +from Configurables import HepMCToEDMConverter +### Reads an HepMC::GenEvent from the data service and writes a collection of EDM Particles +hepmc_converter = HepMCToEDMConverter("Converter") +hepmc_converter.hepmc.Path="hepmc" +hepmc_converter.genparticles.Path="allGenParticles" +hepmc_converter.genvertices.Path="allGenVertices" + +from Configurables import GenParticleFilter +### Filters generated particles +#genfilter = GenParticleFilter("StableParticles") +#genfilter.genparticles_in.Path = "all_genparticles" +#genfilter.genparticles_out.Path = "StableParticles" + + +from Configurables import GeoSvc +## DD4hep geometry service +# Parses the given xml file +geoservice = GeoSvc("GeoSvc", detectors=[ 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhBaseline1/compact/FCChh_DectEmptyMaster.xml', + 'file:/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/Detector/DetFCChhECalDigital/compact/FCChh_DECalBarrel_.xml' + ], + OutputLevel = INFO) + +from Configurables import SimG4Svc +## Geant4 service +# Configures the Geant simulation: geometry, physics list and user actions +geantservice = SimG4Svc("SimG4Svc", detector='SimG4DD4hepDetector', physicslist="SimG4FtfpBert", + actions="SimG4FullSimActions") + + +# Magnetic field +from Configurables import SimG4ConstantMagneticFieldTool +field = SimG4ConstantMagneticFieldTool("SimG4ConstantMagneticFieldTool",FieldOn=True,IntegratorStepper="ClassicalRK4",FieldComponentZ="-0.004") + + +from Configurables import SimG4Alg, SimG4SaveCalHits, SimG4PrimariesFromEdmTool +## Geant4 algorithm +saveecaltool = SimG4SaveCalHits("saveECalHits",readoutNames = ["BarDECal_Readout"]) +saveecaltool.positionedCaloHits.Path = "positionedCaloHits" +saveecaltool.caloHits.Path = "ECalHits" + +# next, create the G4 algorithm, giving the list of names of tools ("XX/YY") +particle_converter = SimG4PrimariesFromEdmTool("EdmConverter") +particle_converter.genParticles.Path = "allGenParticles" + +geantsim = SimG4Alg("SimG4Alg", + outputs= ["SimG4SaveCalHits/saveECalHits"], + eventProvider=particle_converter) + +from Configurables import PodioOutput +out = PodioOutput("out", + OutputLevel=DEBUG) +out.outputCommands = ["keep *"] + +from Configurables import ApplicationMgr +ApplicationMgr( TopAlg=[gen, hepmc_converter, geantsim, out], + EvtSel='NONE', + EvtMax=, + ## order is important, as GeoSvc is needed by SimG4Svc + ExtSvc=[podioevent, geoservice, geantservice], + OutputLevel=INFO + ) diff --git a/init.sh b/init.sh index 9a9e8c6b9..d93a91151 100644 --- a/init.sh +++ b/init.sh @@ -5,3 +5,6 @@ export FCCSWBASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" weekday=`date +%a` source /cvmfs/fcc.cern.ch/testing/sw/views/stable/x86_64-slc6-gcc62-opt/setup.sh + +#export EOS_MGM_URL="root://eosuser.cern.ch" +#source /afs/cern.ch/project/eos/installation/client/etc/setup.sh diff --git a/submit_SiWAnalysis.py b/submit_SiWAnalysis.py new file mode 100644 index 000000000..2363cf898 --- /dev/null +++ b/submit_SiWAnalysis.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +import os, re +import commands +import math, time +import sys + +print +print 'START' +print +######## YOU ONLY NEED TO FILL THE AREA BELOW ######### +######## customization area ######### +CONFIG="30Layers_3.5mmW_50umPixels_18umThick_RRB_modules" +FCCSW_VERSION="FCCSW0.8" +BFIELD = "4" +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +queue = "1nh" +######## customization end ######### + +path = os.getcwd() + +##### loop for creating and sending jobs ##### +#e = 100 +CONFIGS = os.listdir(FCCSW_DIR+"/batch_eos/") +CONFIGS = [ c for c in CONFIGS if CONFIG in c and "300" not in c]# and "Pixels" not in c] +#for e in ENERGIES: +for CONFIG in CONFIGS: + print CONFIG + for RUNCONFIG in os.listdir(FCCSW_DIR+"/batch_eos/"+CONFIG): + ##### creates directory and file list for job ####### + #RUNCONFIG=str(e)+"GeV_BFIELD"+str(BFIELD)+"T_ETAMIN"+str(ETAMIN)+"_ETAMAX"+str(ETAMAX) + # dir="batch_eos/"+CONFIG+"_"+FCCSW_VERSION+"/"+RUNCONFIG + dir="batch_eos/"+CONFIG+"/"+RUNCONFIG + print dir + + if os.path.isdir(dir): + + files = [ f for f in os.listdir(dir) if "output" in f and "_0.root" in f] + print files + + os.chdir(dir) + + for f in files: + #print "hist_"+f[7:] + #os.chdir(dir) + #os.system('pwd') + #os.system('cp -v '+FCCSW_DIR+'/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py run.py') + #os.system("sed -i 's//"+str(CONFIG)+"/' run.py") + #os.system("sed -i 's//"+str(RUNCONFIG)+"/' run.py") + #os.system("sed -i 's//"+f+"/' run.py") + #os.system("sed -i 's//hist_"+f[7:]+"/' run.py") + #os.chdir(path) + #os.system("./run gaudirun.py "+dir+"/run.py") + N = f[f.find("4T")+3:f.find(".root")] + if len(N) == 0: + N = 0 + continue + print f + + with open('analyse'+str(N)+'.sh', 'w') as fout: + fout.write("#!/bin/sh\n") + fout.write("echo\n") + fout.write("echo 'START---------------'\n") + fout.write("echo 'WORKDIR ' ${PWD}\n") + + fout.write('cp -v '+FCCSW_DIR+'/Detector/DetStudies/tests/options/SiWAnalysis_batch.py ana.py\n') + fout.write("sed -i 's//"+str(CONFIG)+"/' ana.py\n") + fout.write("sed -i 's//"+str(RUNCONFIG)+"/' ana.py\n") + fout.write("sed -i 's//"+f+"/' ana.py\n") + fout.write("sed -i 's//analysis_"+f[7:]+"/' ana.py\n") + fout.write("echo\n") + fout.write("cat ana.py\n") + fout.write("echo\n") + fout.write("source "+FCCSW_DIR+"init.sh\n") + fout.write(FCCSW_DIR+"run gaudirun.py ana.py\n") + fout.write("echo 'STOP---------------'\n") + fout.write("echo\n") + fout.write("cp -v *.root "+path+"/"+dir+"\n") + fout.write("echo\n") + + + os.system("chmod 755 analyse"+str(N)+".sh") + os.system("bsub -q "+queue+" analyse"+str(N)+".sh") + + os.chdir(path) + + diff --git a/submit_decalAnalysis.py b/submit_decalAnalysis.py new file mode 100644 index 000000000..e7d33c18e --- /dev/null +++ b/submit_decalAnalysis.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +import os, re +import commands +import math, time +import sys + +print +print 'START' +print +######## YOU ONLY NEED TO FILL THE AREA BELOW ######### +######## customization area ######### +CONFIG="30Layers_3.5mmW_50umPixels_18umThick_RRB_modules" +FCCSW_VERSION="FCCSW0.8" +BFIELD = "4" +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +queue = "1nh" +######## customization end ######### + +path = os.getcwd() + +##### loop for creating and sending jobs ##### +#e = 100 +CONFIGS = os.listdir(FCCSW_DIR+"/batch_eos/") +CONFIGS = [ c for c in CONFIGS if CONFIG in c and "300" not in c]# and "Pixels" not in c] +#for e in ENERGIES: +for CONFIG in CONFIGS: + print CONFIG + for RUNCONFIG in os.listdir(FCCSW_DIR+"/batch_eos/"+CONFIG): + ##### creates directory and file list for job ####### + #RUNCONFIG=str(e)+"GeV_BFIELD"+str(BFIELD)+"T_ETAMIN"+str(ETAMIN)+"_ETAMAX"+str(ETAMAX) + # dir="batch_eos/"+CONFIG+"_"+FCCSW_VERSION+"/"+RUNCONFIG + dir="batch_eos/"+CONFIG+"/"+RUNCONFIG + print dir + + if os.path.isdir(dir): + + files = [ f for f in os.listdir(dir) if "output" in f and "_0.root" in f] + print files + + os.chdir(dir) + + for f in files: + #print "hist_"+f[7:] + #os.chdir(dir) + #os.system('pwd') + #os.system('cp -v '+FCCSW_DIR+'/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py run.py') + #os.system("sed -i 's//"+str(CONFIG)+"/' run.py") + #os.system("sed -i 's//"+str(RUNCONFIG)+"/' run.py") + #os.system("sed -i 's//"+f+"/' run.py") + #os.system("sed -i 's//hist_"+f[7:]+"/' run.py") + #os.chdir(path) + #os.system("./run gaudirun.py "+dir+"/run.py") + N = f[f.find("4T")+3:f.find(".root")] + if len(N) == 0: + N = 0 + continue + print f + + with open('analyse'+str(N)+'.sh', 'w') as fout: + fout.write("#!/bin/sh\n") + fout.write("echo\n") + fout.write("echo 'START---------------'\n") + fout.write("echo 'WORKDIR ' ${PWD}\n") + + fout.write('cp -v '+FCCSW_DIR+'/Detector/DetStudies/tests/options/decalAnalysis_DEcal_batch.py ana.py\n') + fout.write("sed -i 's//"+str(CONFIG)+"/' ana.py\n") + fout.write("sed -i 's//"+str(RUNCONFIG)+"/' ana.py\n") + fout.write("sed -i 's//"+f+"/' ana.py\n") + fout.write("sed -i 's//analysis_"+f[7:]+"/' ana.py\n") + fout.write("echo\n") + fout.write("cat ana.py\n") + fout.write("echo\n") + fout.write("source "+FCCSW_DIR+"init.sh\n") + fout.write(FCCSW_DIR+"run gaudirun.py ana.py\n") + fout.write("echo 'STOP---------------'\n") + fout.write("echo\n") + fout.write("cp -v *.root "+path+"/"+dir+"\n") + fout.write("echo\n") + + + os.system("chmod 755 analyse"+str(N)+".sh") + os.system("bsub -q "+queue+" analyse"+str(N)+".sh") + + os.chdir(path) + + diff --git a/submit_energy_res_to_lxbatch.py b/submit_energy_res_to_lxbatch.py new file mode 100644 index 000000000..ccacbdfcd --- /dev/null +++ b/submit_energy_res_to_lxbatch.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +import os, re +import commands +import math, time +import sys + +print +print 'START' +print +######## YOU ONLY NEED TO FILL THE AREA BELOW ######### +######## customization area ######### +CONFIG="50Layers_2.1mmW_50umPixels_18umThick_RRB" +FCCSW_VERSION="FCCSW0.9" +#ENERGIES = ["10","20","50","70","100","200", "300", "500","700","1000"] +#ENERGIES = ["10", "50","100","200", "300", "500","700","1000"] +#ENERGIES = ["101","501","1001" ] # number of jobs to be submitted +ENERGIES = ["10"]#,"20","30","40","60","70","80","90","100"] # number of jobs to be submitted +BFIELD = "4" +EVENTS = 10 +ETAMIN = -0.001 +ETAMAX = 0.001 +NRUNS = 1 +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +queue = "8nm" # give bsub queue -- 8nm (8 minutes), 1nh (1 hour), 8nh, 1nd (1day), 2nd, 1nw (1 week), 2nw +######## customization end ######### + +path = os.getcwd() +print +#print 'do not worry about folder creation:' +#os.system("rm -r tmp") +os.system("mkdir batch_eos") +#os.system("mkdir res") +print + +##### loop for creating and sending jobs ##### +#e = 100 +for e in ENERGIES: +#for BFIELD in range(0,7): + ##### creates directory and file list for job ####### + dir="batch_eos/"+CONFIG+"_"+FCCSW_VERSION+"/"+str(e)+"GeV_BFIELD"+str(BFIELD)+"T_ETAMIN"+str(ETAMIN)+"_ETAMAX"+str(ETAMAX) + #os.system("rm -r "+dir) + os.system("mkdir -p "+dir) + os.chdir(dir) + + ##### creates steering file ####### + #os.system("cp ../../geant_batch_temp.py run.py") + #os.system("sed -i 's//"+str(e)+"/' run.py") + #os.system("sed -i 's//"+str(BFIELD)+"/' run.py") + #os.system("sed -i 's//"+str(EVENTS)+"/' run.py") + + for N in range(0,0+NRUNS): + + ##### creates jobs ####### + with open('job'+str(N)+'.sh', 'w') as fout: + fout.write("#!/bin/sh\n") + fout.write("echo\n") + fout.write("echo 'START---------------'\n") + fout.write("echo 'WORKDIR ' ${PWD}\n") + + fout.write("##### creates steering file #######\n") + fout.write("cp "+FCCSW_DIR+"/geant_batch_temp.py run.py\n") + fout.write("sed -i 's//"+str(e)+"/' run.py\n") + fout.write("sed -i 's//"+str(BFIELD)+"/' run.py\n") + fout.write("sed -i 's//"+str(EVENTS)+"/' run.py\n\n") + fout.write("sed -i 's//"+str(ETAMIN)+"/' run.py\n\n") + fout.write("sed -i 's//"+str(ETAMAX)+"/' run.py\n\n") + fout.write("sed -i 's//"+str(CONFIG)+"/' run.py\n\n") + fout.write("sed -i 's//"+str(N)+"/' run.py\n\n") + + fout.write("source "+FCCSW_DIR+"init.sh\n") + fout.write(FCCSW_DIR+"run gaudirun.py run.py\n") + fout.write("echo 'STOP---------------'\n") + fout.write("echo\n") + fout.write("cp -v *.root "+path+"/"+dir+"\n") + fout.write("echo\n") + os.system("chmod 755 job"+str(N)+".sh") + + ###### sends bjobs ###### + os.system("bsub -q "+queue+" job"+str(N)+".sh") + print "job nr " + str(e) + " " + str(N) +" submitted" + + os.chdir(path) + +print +print "your jobs:" +os.system("bjobs") +print +print 'END' +print diff --git a/submit_longitudinalAnalysis.py b/submit_longitudinalAnalysis.py new file mode 100644 index 000000000..491e60157 --- /dev/null +++ b/submit_longitudinalAnalysis.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +import os, re +import commands +import math, time +import sys + +print +print 'START' +print +######## YOU ONLY NEED TO FILL THE AREA BELOW ######### +######## customization area ######### +CONFIG="50Layers_2.1mmW_50umPixels_18umThick" +FCCSW_VERSION="FCCSW0.8" +ENERGIES = ["10","20","50","100","200","300","400","500","1000"] +#ENERGIES = ["200","300","400","500","1000" ] # number of jobs to be submitted +#ENERGIES = ["30","40","60","70","80","90"] # number of jobs to be submitted +#ENERGIES = ["1000" ] # number of jobs to be submitted +BFIELD = "4" +EVENTS = 2000 +ETAMIN = -0.001 +ETAMAX = 0.001 +NRUNS = 20 +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +queue = "1nh" +######## customization end ######### + +path = os.getcwd() + +##### loop for creating and sending jobs ##### +#e = 100 +CONFIGS = os.listdir(FCCSW_DIR+"/batch_eos/") +#CONFIGS = [ c for c in CONFIGS if "50Layers_2.1mmW" in c ] +#for e in ENERGIES: +for CONFIG in CONFIGS: + for e in ENERGIES: + ##### creates directory and file list for job ####### + RUNCONFIG=str(e)+"GeV_BFIELD"+str(BFIELD)+"T_ETAMIN"+str(ETAMIN)+"_ETAMAX"+str(ETAMAX) + # dir="batch_eos/"+CONFIG+"_"+FCCSW_VERSION+"/"+RUNCONFIG + dir="batch_eos/"+CONFIG+"/"+RUNCONFIG + print dir + + if os.path.isdir(dir): + + files = [ f for f in os.listdir(dir) if "output" in f] + print files + + os.chdir(dir) + + for f in files: + #print "hist_"+f[7:] + #os.chdir(dir) + #os.system('pwd') + #os.system('cp -v '+FCCSW_DIR+'/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py run.py') + #os.system("sed -i 's//"+str(CONFIG)+"/' run.py") + #os.system("sed -i 's//"+str(RUNCONFIG)+"/' run.py") + #os.system("sed -i 's//"+f+"/' run.py") + #os.system("sed -i 's//hist_"+f[7:]+"/' run.py") + #os.chdir(path) + #os.system("./run gaudirun.py "+dir+"/run.py") + N = f[f.find("4T")+3:f.find(".root")] + if len(N) == 0: + N = 0 + print N + + with open('analyse'+str(N)+'.sh', 'w') as fout: + fout.write("#!/bin/sh\n") + fout.write("echo\n") + fout.write("echo 'START---------------'\n") + fout.write("echo 'WORKDIR ' ${PWD}\n") + + fout.write('cp -v '+FCCSW_DIR+'/Detector/DetStudies/tests/options/longitudinalAnalysis_DEcal_batch.py ana.py\n') + fout.write("sed -i 's//"+str(CONFIG)+"/' ana.py\n") + fout.write("sed -i 's//"+str(RUNCONFIG)+"/' ana.py\n") + fout.write("sed -i 's//"+f+"/' ana.py\n") + fout.write("sed -i 's//hist_"+f[7:]+"/' ana.py\n") + fout.write("echo\n") + fout.write("cat ana.py\n") + fout.write("echo\n") + fout.write("source "+FCCSW_DIR+"init.sh\n") + fout.write(FCCSW_DIR+"run gaudirun.py ana.py\n") + fout.write("echo 'STOP---------------'\n") + fout.write("echo\n") + fout.write("cp -v *.root "+path+"/"+dir+"\n") + fout.write("echo\n") + + + os.system("chmod 755 analyse"+str(N)+".sh") + os.system("bsub -q "+queue+" analyse"+str(N)+".sh") + + os.chdir(path) + + diff --git a/submit_pile_up_to_lxbatch.py b/submit_pile_up_to_lxbatch.py new file mode 100644 index 000000000..af59c34d6 --- /dev/null +++ b/submit_pile_up_to_lxbatch.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +import os, re +import commands +import math, time +import sys + +print +print 'START' +print +######## YOU ONLY NEED TO FILL THE AREA BELOW ######### +######## customization area ######### +CONFIG="50Layers_2.1mmW_50umPixels_18umThick_RRB" +NPILEUPEVENTS = ["1","100","1000"] +BFIELD = "1" +EVENTS = "100" +FCCSW_DIR = "/afs/cern.ch/user/t/toprice/private/FCC/FCCSW/" +queue = "8nm" # give bsub queue -- 8nm (8 minutes), 1nh (1 hour), 8nh, 1nd (1day), 2nd, 1nw (1 week), 2nw +######## customization end ######### + +path = os.getcwd() +print +#print 'do not worry about folder creation:' +#os.system("rm -r tmp") +os.system("mkdir batch_eos") +#os.system("mkdir res") +print + +##### loop for creating and sending jobs ##### +for npu in NPILEUPEVENTS: + ##### creates directory and file list for job ####### + dir="batch_eos/"+CONFIG+"_FCCSW0.9/"+str(npu)+"PILEUPEVENTS" + + os.system("rm -r "+dir) + os.system("mkdir -p "+dir) + os.chdir(dir) + + ##### creates jobs ####### + with open('job.sh', 'w') as fout: + fout.write("#!/bin/sh\n") + fout.write("echo\n") + fout.write("echo 'START---------------'\n") + fout.write("echo 'WORKDIR ' ${PWD}\n") + + fout.write("##### creates steering file #######\n") + fout.write("cp "+FCCSW_DIR+"/geant_pile_up_batch_temp.py run.py\n") + fout.write("sed -i 's//"+str(npu)+"/' run.py\n") + fout.write("sed -i 's//"+str(EVENTS)+"/' run.py\n\n") + fout.write("sed -i 's//"+str(CONFIG)+"/' run.py\n\n") + fout.write("source "+FCCSW_DIR+"init.sh\n") + fout.write(FCCSW_DIR+"run gaudirun.py run.py\n") + fout.write("echo 'STOP---------------'\n") + fout.write("echo\n") + fout.write("cp *.txt "+path+"/"+dir+"\n") + fout.write("cp *.root "+path+"/"+dir+"\n") + fout.write("echo\n") + os.system("chmod 755 job.sh") + + ###### sends bjobs ###### + os.system("bsub -q "+queue+" -o logs job.sh") + print "job nr " + str(npu) + " submitted" + + os.chdir(path) + +print +print "your jobs:" +os.system("bjobs") +print +print 'END' +print