53 #include "G4SDManager.hh" 56 #include "G4ThreeVector.hh" 57 #include "G4VProcess.hh" 58 #include "G4HCofThisEvent.hh" 60 #include <CLHEP/Random/RandGaussQ.h> 61 #include <CLHEP/Random/Randomize.h> 62 #include <CLHEP/Units/GlobalSystemOfUnits.h> 63 #include <CLHEP/Units/GlobalPhysicalConstants.h> 70 class HepRandomEngine;
75 public Observer<const BeginOfEvent*>,
114 const std::vector<std::string>
names;
152 hcalOnly(m_Anal.getParameter<
bool>(
"HcalOnly")),
153 mode(m_Anal.getParameter<
int>(
"Mode")),
154 type(m_Anal.getParameter<
int>(
"Type")),
155 ecalNoise(m_Anal.getParameter<double>(
"EcalNoise")),
156 beamOffset(-m_Anal.getParameter<double>(
"BeamPosition") *
CLHEP::cm),
157 scaleHB0(m_Anal.getParameter<double>(
"ScaleHB0")),
158 scaleHB16(m_Anal.getParameter<double>(
"ScaleHB16")),
159 scaleHO(m_Anal.getParameter<double>(
"ScaleHO")),
160 scaleHE0(m_Anal.getParameter<double>(
"ScaleHE0")),
168 double beamEta = (fMaxEta + fMinEta) / 2.;
169 double beamPhi = (fMaxPhi + fMinPhi) / 2.;
170 double beamThet = 2 * atan(
exp(-beamEta));
173 iceta =
static_cast<int>(beamEta / 0.087) + 1;
174 icphi =
static_cast<int>(std::fabs(beamPhi) / 0.087) + 5;
178 produces<PHcalTB04Info>();
185 <<
"HcalTB04:: Initialised as observer of BeginOf Job/BeginOfRun/BeginOfEvent/G4Step/EndOfEvent with Parameter " 186 "values:\n \thcalOnly = " 187 <<
hcalOnly <<
"\tecalNoise = " <<
ecalNoise <<
"\n\tMode = " <<
mode <<
" (0: HB2 Standard; 1:HB2 Segmented)" 188 <<
"\tType = " <<
type <<
" (0: HB; 1 HE; 2 HB+HE)\n\tbeamOffset = " <<
beamOffset <<
"\ticeta = " <<
iceta 199 edm::LogVerbatim(
"HcalTBSim") <<
"\n --------> Total number of selected entries : " <<
count <<
"\nPointers:: QIE " 242 for (
int lay = 1; lay < 8; lay++) {
243 for (
int icr = 1; icr < 8; icr++) {
266 for (
int i = 0;
i < 5;
i++) {
270 for (
int i = 0;
i < 3;
i++) {
274 for (
int i = 0;
i < 20;
i++) {
286 int irun = (*run)()->GetRunID();
289 G4SDManager* sd = G4SDManager::GetSDMpointerIfExist();
292 G4VSensitiveDetector* aSD = sd->FindSensitiveDetector(sdname);
293 if (aSD ==
nullptr) {
295 <<
" with name " << sdname <<
" in this " 299 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::beginOfRun: Finds SD with name " << theCaloSD->GetName()
303 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::beginOfRun: set a new numbering scheme";
307 aSD = sd->FindSensitiveDetector(sdname);
308 if (aSD ==
nullptr) {
310 <<
" with name " << sdname <<
" in this " 314 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::beginOfRun: Finds SD with name " << theCaloSD->GetName()
318 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::beginOfRun: set a new numbering scheme";
323 <<
"not get SD Manager!";
330 evNum = (*evt)()->GetEventID();
336 if (aStep !=
nullptr) {
338 G4ThreeVector thePreStepPoint = aStep->GetPreStepPoint()->GetPosition();
339 G4ThreeVector thePostStepPoint;
342 G4Track* aTrack = aStep->GetTrack();
343 int trackID = aTrack->GetTrackID();
344 int parentID = aTrack->GetParentID();
345 const G4ThreeVector&
position = aTrack->GetPosition();
346 G4ThreeVector momentum = aTrack->GetMomentum();
347 G4String partType = aTrack->GetDefinition()->GetParticleType();
348 G4String partSubType = aTrack->GetDefinition()->GetParticleSubType();
349 int partPDGEncoding = aTrack->GetDefinition()->GetPDGEncoding();
351 bool isPDGStable = aTrack->GetDefinition()->GetPDGStable();
353 double pDGlifetime = aTrack->GetDefinition()->GetPDGLifeTime();
354 double gammaFactor = aStep->GetPreStepPoint()->GetGamma();
357 double stepDeltaEnergy = aStep->GetDeltaEnergy();
358 double kinEnergy = aTrack->GetKineticEnergy();
361 if (trackID == 1 && parentID == 0 && ((kinEnergy == 0.) || (std::fabs(stepDeltaEnergy / kinEnergy) > 0.1))) {
363 if (kinEnergy == 0.) {
366 if (std::fabs(stepDeltaEnergy / kinEnergy) > 0.1)
376 G4String thePostPVname =
"NoName";
377 G4StepPoint* thePostPoint = aStep->GetPostStepPoint();
379 thePostStepPoint = thePostPoint->GetPosition();
380 G4VPhysicalVolume* thePostPV = thePostPoint->GetPhysicalVolume();
382 thePostPVname = thePostPV->GetName();
385 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: V1 found at: " << thePostStepPoint
386 <<
" G4VPhysicalVolume: " << thePostPVname;
393 if ((trackID != 1 && parentID == 1 && (aTrack->GetCurrentStepNumber() == 1) && (thePreStepPoint ==
pvPosition)) ||
394 (trackID == 1 && thePreStepPoint ==
pvPosition)) {
396 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::A secondary... PDG:" << partPDGEncoding
397 <<
" TrackID:" << trackID <<
" ParentID:" << parentID
398 <<
" stable: " << isPDGStable <<
" Tau: " << pDGlifetime
399 <<
" cTauGamma=" << c_light * pDGlifetime * gammaFactor * 1000.
400 <<
"um GammaFactor: " << gammaFactor;
405 secEkin.push_back(aTrack->GetKineticEnergy());
408 double ctaugamma_um = CLHEP::c_light * pDGlifetime * gammaFactor * 1000.;
409 if ((ctaugamma_um > 0.) && (ctaugamma_um < 100.)) {
417 if (aTrack->GetCurrentStepNumber() == 1) {
422 std::vector<int>::iterator
pos;
428 <<
"HcalTB04Analysis:: A tertiary... PDG:" << partPDGEncoding <<
" TrackID:" << trackID
429 <<
" ParentID:" << parentID <<
" stable: " << isPDGStable <<
" Tau: " << pDGlifetime
430 <<
" cTauGamma=" << c_light * pDGlifetime * gammaFactor * 1000. <<
"um GammaFactor: " << gammaFactor;
445 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::Fill event " << (*evt)()->GetEventID();
453 CLHEP::HepRandomEngine* engine = G4Random::getTheEngine();
470 int iEvt = (*evt)()->GetEventID();
473 else if ((iEvt < 100) && (iEvt % 10 == 0))
475 else if ((iEvt < 1000) && (iEvt % 100 == 0))
477 else if ((iEvt < 10000) && (iEvt % 1000 == 0))
482 std::vector<CaloHit> hhits, hhitl;
485 std::map<int, float, std::less<int> > primaries;
487 double etot1 = 0, etot2 = 0;
491 G4HCofThisEvent* allHC = (*evt)()->GetHCofThisEvent();
493 idHC = G4SDManager::GetSDMpointer()->GetCollectionID(
sdName);
497 <<
" is obtained at " << theHC <<
" with " << theHC->entries() <<
" entries";
499 int thehc_entries = theHC->entries();
500 if (idHC >= 0 && theHC !=
nullptr) {
501 hhits.reserve(theHC->entries());
502 hhitl.reserve(theHC->entries());
503 for (
j = 0;
j < thehc_entries;
j++) {
522 hhits.push_back(
hit);
524 hhitl.push_back(hitl);
528 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Hcal Hit i/p " <<
j <<
" ID 0x" << std::hex <<
id <<
" 0x" 529 <<
idx <<
std::dec <<
" time " << std::setw(6) <<
time <<
" " << std::setw(6)
530 << jitter <<
" theta " << std::setw(8) <<
theta <<
" eta " << std::setw(8) <<
eta 531 <<
" phi " << std::setw(8) <<
phi <<
" e " << std::setw(8) <<
e <<
" " 532 << std::setw(8) << escl;
538 std::vector<CaloHit>::iterator itr;
539 int nHit = hhits.size();
540 std::vector<CaloHit*>
hits(nHit);
541 for (
j = 0, itr = hhits.begin(); itr != hhits.end();
j++, itr++) {
545 std::vector<CaloHit*>::iterator k1, k2;
547 for (k1 =
hits.begin(); k1 !=
hits.end(); k1++) {
548 int det = (**k1).det();
549 int layer = (**k1).layer();
550 double ehit = (**k1).e();
551 double eta = (**k1).eta();
552 double phi = (**k1).phi();
553 double jitter = (**k1).t();
554 uint32_t
unitID = (**k1).id();
556 for (k2 = k1 + 1; k2 !=
hits.end() && std::fabs(jitter - (**k2).t()) < 1 &&
unitID == (**k2).id(); k2++) {
566 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Hcal Hit store " << nhit <<
" ID 0x" << std::hex <<
unitID 567 <<
std::dec <<
" time " << std::setw(6) << jitter <<
" eta " << std::setw(8) <<
eta 568 <<
" phi " << std::setw(8) <<
phi <<
" e " << std::setw(8) << ehit;
572 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Stores " << nhit <<
" HCal hits from " << nHit
573 <<
" input hits E(Hcal) " << etot1 <<
" " << etot2;
576 for (
j = 0, itr = hhitl.begin(); itr != hhitl.end();
j++, itr++) {
584 for (k1 =
hits.begin(); k1 !=
hits.end(); k1++) {
585 int det = (**k1).det();
586 int layer = (**k1).layer();
587 double ehit = (**k1).e();
588 double eta = (**k1).eta();
589 double phi = (**k1).phi();
590 double jitter = (**k1).t();
591 uint32_t
unitID = (**k1).id();
593 for (k2 = k1 + 1; k2 !=
hits.end() && std::fabs(jitter - (**k2).t()) < 1 &&
unitID == (**k2).id(); k2++) {
605 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Hcal Hit store " << nhitl <<
" ID 0x" << std::hex <<
unitID 606 <<
std::dec <<
" time " << std::setw(6) << jitter <<
" eta " << std::setw(8) <<
eta 607 <<
" phi " << std::setw(8) <<
phi <<
" e " << std::setw(8) << ehit;
611 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Stores " << nhitl <<
" HCal hits from " << nHit
612 <<
" input hits E(Hcal) " << etot1 <<
" " << etotl;
615 std::vector<CaloHit> ehits;
617 idHC = G4SDManager::GetSDMpointer()->GetCollectionID(
sdName);
622 <<
" is obtained at " << theHC <<
" with " << theHC->entries() <<
" entries";
624 if (idHC >= 0 && theHC !=
nullptr) {
625 thehc_entries = theHC->entries();
626 ehits.reserve(theHC->entries());
627 for (
j = 0;
j < thehc_entries;
j++) {
631 if (e < 0 || e > 100000.)
642 ehits.push_back(
hit);
646 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Ecal Hit i/p " <<
j <<
" ID 0x" << std::hex <<
id 647 <<
std::dec <<
" time " << std::setw(6) <<
time <<
" theta " << std::setw(8)
648 <<
theta <<
" eta " << std::setw(8) <<
eta <<
" phi " << std::setw(8) <<
phi 649 <<
" e " << std::setw(8) <<
e;
657 std::vector<CaloHit*> hite(nHit);
658 for (
j = 0, itr = ehits.begin(); itr != ehits.end();
j++, itr++) {
663 for (k1 = hite.begin(); k1 != hite.end(); k1++) {
664 int det = (**k1).det();
665 int layer = (**k1).layer();
666 double ehit = (**k1).e();
667 double eta = (**k1).eta();
668 double phi = (**k1).phi();
669 double jitter = (**k1).t();
670 uint32_t
unitID = (**k1).id();
672 for (k2 = k1 + 1; k2 != hite.end() && std::fabs(jitter - (**k2).t()) < 1 &&
unitID == (**k2).id(); k2++) {
682 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Ecal Hit store " << nhit <<
" ID 0x" << std::hex <<
unitID 683 <<
std::dec <<
" time " << std::setw(6) << jitter <<
" eta " << std::setw(8) <<
eta 684 <<
" phi " << std::setw(8) <<
phi <<
" e " << std::setw(8) << ehit;
688 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Stores " << nhit <<
" ECal hits from " << nHit
689 <<
" input hits E(Ecal) " << etot1 <<
" " << etot2;
692 nPrimary =
static_cast<int>(primaries.size());
694 G4PrimaryParticle* thePrim =
nullptr;
695 int nvertex = (*evt)()->GetNumberOfPrimaryVertex();
697 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Event has " << nvertex <<
" verteices";
700 edm::LogWarning(
"HcalTBSim") <<
"HcalTB04Analysis::EndOfEvent ERROR: no vertex found for event " <<
evNum;
701 for (
int i = 0;
i < nvertex;
i++) {
702 G4PrimaryVertex* avertex = (*evt)()->GetPrimaryVertex(
i);
703 if (avertex ==
nullptr) {
704 edm::LogWarning(
"HcalTBSim") <<
"HcalTB04Analysis::EndOfEvent ERR: pointer to vertex = 0 for event " <<
evNum;
706 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::Vertex number :" <<
i <<
" " << avertex->GetPosition();
707 int npart = avertex->GetNumberOfParticle();
709 edm::LogWarning(
"HcalTBSim") <<
"HcalTB04Analysis::End Of Event ERR: no primary!";
710 if (thePrim ==
nullptr)
711 thePrim = avertex->GetPrimary(trackID);
715 if (thePrim !=
nullptr) {
716 double px = thePrim->GetPx();
717 double py = thePrim->GetPy();
718 double pz = thePrim->GetPz();
722 edm::LogWarning(
"HcalTBSim") <<
"HcalTB04Analysis:: EndOfEvent ERR: primary has p=0 ";
724 double costheta = pz /
p;
727 if (
px != 0 ||
py != 0)
732 edm::LogWarning(
"HcalTBSim") <<
"HcalTB04Analysis::EndOfEvent ERR: could not find primary";
739 std::vector<CaloHit>
hits(hittot);
747 for (
unsigned int k1 = 0; k1 <
hcalHitCache.size(); k1++) {
749 uint32_t
id =
hit.
id();
751 double esim =
hit.e();
753 for (
unsigned int k2 = k1 + 1; k2 <
hcalHitCache.size(); k2++) {
767 <<
" energy from " << nhit <<
" hits starting with hit # " << k1
768 <<
" energy with noise " << eq;
770 for (
int k2 = 0; k2 <
nTower; k2++) {
780 for (
int k2 = 0; k2 <
nTower; k2++) {
788 <<
" registers " <<
esimh[k2] <<
" energy from hits and energy after QIE analysis " 796 CLHEP::RandGaussQ randGauss(*engine);
801 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::xtalAnalysis: Size " << iok.size() <<
" " <<
idEcal.size() <<
" " 804 for (
unsigned int k1 = 0; k1 <
ecalHitCache.size(); k1++) {
808 for (
unsigned int k2 = k1 + 1; k2 <
ecalHitCache.size(); k2++) {
816 double eq = esim + randGauss.fire(0.,
ecalNoise);
819 <<
" energy from " << nhit <<
" hits starting with hit # " << k1
820 <<
" energy with noise " << eq;
822 for (
int k2 = 0; k2 <
nCrystal; k2++) {
832 for (
int k2 = 0; k2 <
nCrystal; k2++) {
838 <<
" registers " <<
esime[k2] <<
" energy from hits and energy from noise " 862 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Energy deposit at Sim Level (Total) " <<
etots <<
" (ECal) " 864 <<
"\nHcalTB04Analysis:: Energy deposit at Qie Level (Total) " <<
etotq <<
" (ECal) " 870 for (
int i = 0;
i < 5;
i++) {
874 for (
int i = 0;
i < 3;
i++) {
878 double e1 = 0, e2 = 0;
893 if (
iphi >= 0 && iphi < 3 && ieta >= 0 &&
ieta < 5) {
902 for (
int i = 0;
i < 3;
i++) {
908 for (
int i = 0;
i < 5;
i++) {
915 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Energy fraction along Eta and Phi (Sim/Qie)";
916 for (
int i = 0;
i < 5;
i++)
923 for (
int i = 0;
i < 20;
i++) {
935 if (
iphi >= 0 && iphi < 3 && layer >= 0 &&
layer < 20) {
942 for (
int i = 0;
i < 20;
i++) {
949 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Energy fraction along Layer";
950 for (
int i = 0;
i < 20;
i++)
978 std::vector<CaloHit>::iterator itr;
980 uint32_t
id = itr->id();
986 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Save Hit " << std::setw(3) <<
i + 1 <<
" ID 0x" << std::hex
987 <<
group <<
std::dec <<
" " << std::setw(2) << det <<
" " << std::setw(2) << lay
988 <<
" " << std::setw(1) <<
z <<
" " << std::setw(3) <<
ieta <<
" " << std::setw(3)
989 <<
iphi <<
" T " << std::setw(6) << itr->t() <<
" E " << std::setw(6) << itr->e();
992 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Saves " << nhit <<
" hits from Crystals";
997 uint32_t
id = itr->
id();
1003 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Save Hit " << std::setw(3) <<
i + 1 <<
" ID 0x" << std::hex
1004 <<
group <<
std::dec <<
" " << std::setw(2) << det <<
" " << std::setw(2) << lay
1005 <<
" " << std::setw(1) <<
z <<
" " << std::setw(3) <<
ieta <<
" " << std::setw(3)
1006 <<
iphi <<
" T " << std::setw(6) << itr->t() <<
" E " << std::setw(6) << itr->e();
1009 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis:: Saves " << nhit <<
" hits from HCal";
1034 pvUVW = G4ThreeVector();
1052 esimh.push_back(0.);
1060 esime.push_back(0.);
1061 enois.push_back(0.);
1068 group = (det & 15) << 20;
1069 group += ((lay - 1) & 31) << 15;
1081 else if (
layer == 17)
1083 else if (
layer > 17)
1096 const double rLay[19] = {1836.0,
1118 const double zLay[19] = {4034.0,
1141 double tmp = dist / c_light / ns;
1143 edm::LogVerbatim(
"HcalTBSim") <<
"HcalTB04Analysis::timeOfFlight " <<
tmp <<
" for det/lay " << det <<
" " <<
layer 1144 <<
" eta/theta " <<
eta <<
" " <<
theta / deg <<
" dist " << dist;
Log< level::Info, true > LogVerbatim
#define DEFINE_SIMWATCHER(type)
T getParameter(std::string const &) const
std::vector< double > secEkin
void setLongProf(const std::vector< double > &es, const std::vector< double > &eq)
std::vector< int > idHcal
void fillPrimary(double energy, double eta, double phi)
std::vector< CaloHit > hcalHitLayer
std::vector< double > eqeta
std::vector< double > eqie
void fillTrnsProf(const std::vector< double > &es1, const std::vector< double > &eq1, const std::vector< double > &es2, const std::vector< double > &eq2)
Sin< T >::type sin(const T &t)
void fillBuffer(const EndOfEvent *evt)
std::vector< int > shortLivedSecondaries
std::vector< int > secTrackID
std::vector< double > eqphi
void setPrimary(int primary, int id, double energy, double eta, double phi)
const edm::ParameterSet m_Anal
void setNumberingScheme(HcalNumberingScheme *)
void update(const BeginOfRun *run) override
This routine will be called when the appropriate signal arrives.
const std::string names[nVars_]
void setEdep(double simtot, double sime, double simh, double digtot, double dige, double digh)
void setTrnsProf(const std::vector< double > &es1, const std::vector< double > &eq1, const std::vector< double > &es2, const std::vector< double > &eq2)
void saveHit(int det, int lay, int eta, int phi, double e, double t)
constexpr std::array< uint8_t, layerIndexSize< TrackerTraits > > layer
std::vector< int > secPartID
static uint32_t packHcalIndex(int det, int z, int depth, int eta, int phi, int lay)
std::vector< uint32_t > idEcal
std::vector< double > eseta
math::XYZPoint getEntry() const
void setIDs(const std::vector< int > &, const std::vector< int > &)
void setVtxSec(int id, int pdg, double px, double py, double pz, double ek)
void setEdepHcal(const std::vector< double > &esim, const std::vector< double > &edig)
double getEnergy(const std::vector< int > &)
Cos< T >::type cos(const T &t)
Tan< T >::type tan(const T &t)
static void unpackHcalIndex(const uint32_t &idx, int &det, int &z, int &depth, int &eta, int &phi, int &lay)
G4RotationMatrix * beamline_RM
std::vector< double > esime
static std::vector< uint32_t > getUnitIDs(const int type, const int mode)
double scale(int det, int layer)
std::vector< double > esphi
double timeOfFlight(int det, int layer, double eta)
const std::vector< std::string > names
std::vector< CaloHit > hcalHitCache
void xtalAnalysis(CLHEP::HepRandomEngine *)
static uint32_t getUnitID(const uint32_t id, const int mode)
HcalTB04Analysis(const edm::ParameterSet &p)
~HcalTB04Analysis() override
XYZPointD XYZPoint
point in space with cartesian internal representation
std::vector< int > idXtal
std::vector< CaloHit > ecalHitCache
double getEnergyDeposit() const
uint32_t getUnitID() const
std::vector< double > enois
void setVtxPrim(int evNum, int type, double x, double y, double z, double u, double v, double w, double px, double py, double pz)
std::vector< G4ThreeVector > secMomentum
std::vector< int > getCode(int, const std::vector< CaloHit > &, CLHEP::HepRandomEngine *)
G4THitsCollection< CaloG4Hit > CaloG4HitCollection
static int position[264][3]
double getTimeSlice() const
std::vector< uint32_t > idTower
void qieAnalysis(CLHEP::HepRandomEngine *)
std::vector< double > eslay
std::vector< double > eqlay
Log< level::Warning, false > LogWarning
void setNumberingScheme(EcalNumberingScheme *)
Geom::Theta< T > theta() const
Power< A, B >::type pow(const A &a, const B &b)
void fillEdep(double etots, double eecals, double ehcals, double etotq, double eecalq, double ehcalq)
void fillEvent(PHcalTB04Info &)
const HcalTB04Analysis & operator=(const HcalTB04Analysis &)=delete
std::vector< double > esimh
void fillLongProf(const std::vector< double > &es, const std::vector< double > &eq)
void produce(edm::Event &, const edm::EventSetup &) override