#ifndef __CPPSENSITIVEDETECTORFMWPC_ #define __CPPSENSITIVEDETECTORFMWPC_ using namespace std; #include "G4VSensitiveDetector.hh" #include "CPPUserEventInformation.hh" #include "CPPHitFMWPC.hh" extern double FMWPC_DEAD_RADIUS; extern double FMWPC_DEAD_WIDTH; // These are defined in other headers included alongside this one. #undef TWO_HIT_RESOL #undef THRESH_KEV class CPPSensitiveDetectorFMWPC: public G4VSensitiveDetector { public: CPPSensitiveDetectorFMWPC(const G4String& name):G4VSensitiveDetector(name){ collectionName.insert("fmwpchits"); // CPPHitFMWPC TWO_HIT_RESOL = 100.0; // ns THRESH_KEV = 2.5; // keV DRIFT_VELOCITY = 0.5/100.0; // cm/ns DEAD_RADIUS = FMWPC_DEAD_RADIUS*cm; // cm (n.b. value of variable may not be cm!) DEAD_WIDTH = FMWPC_DEAD_WIDTH *cm; // cm (n.b. value of variable may not be cm!) } virtual ~CPPSensitiveDetectorFMWPC(){} //------------------------------ // Initialize void Initialize(G4HCofThisEvent* hitCollection) { if(hitCollection == (void*)0x1) cout<< "Huh?"; // avoid compiler warning hits.clear(); } //------------------------------ // ProcessHits G4bool ProcessHits(G4Step* step, G4TouchableHistory* history) { if(history == (void*)0x1) cout<< "Huh?"; // avoid compiler warning G4double dEsum = step->GetTotalEnergyDeposit() / GeV; if (dEsum==0.) return false; // Get pre-step and post-step points G4StepPoint *sp_pre = step->GetPreStepPoint(); G4StepPoint *sp_post = step->GetPostStepPoint(); const G4TouchableHandle &touchable = sp_pre->GetTouchableHandle(); // Convert the position from world coordinates to local coordinates within the block G4ThreeVector localPos = touchable->GetHistory()->GetTopTransform().TransformPoint(sp_pre->GetPosition()); // Exclude hits from dead region // Both a round region (DEAD_RADIUS) and a square region (DEAD_WIDTH) // are checked. Usually, one of these should be set to zero so that // the other solely defines the dead region. if( localPos.perp() < DEAD_RADIUS) return false; if( (fabs(localPos.x()) < DEAD_WIDTH/2.0) && (fabs(localPos.y()) < DEAD_WIDTH/2.0) ) return false; double dx = ((sp_post->GetPosition() - sp_pre->GetPosition()).mag()) /cm; // Get Layer number from z-position of hit within MWPC volume. The hierarchy is: // // (SITE) <- Not always present // |_ HALL // |_ MWPC // |_ CPPF // |_ CPPG // // When accessing history, the "depth=0" volume will be the CPPG volume while // "depth=1" is CPPF and so on. // We look for the "depth=2" transform since that should be the MWPC volume. // Note that the MWPC volume is defined as the mother volume of the entire // MWPC detector, including all layers and absorbers. The upstream face of // the gas volume of the most upstream chamber is at z=0 in the MWPC volume. const G4AffineTransform &TransformGlobalToMWPC = touchable->GetHistory()->GetTransform(2); G4ThreeVector pos_mwpc = (TransformGlobalToMWPC.TransformPoint(sp_pre->GetPosition()) - LAB_OFFSET)/cm; // Copy number of CPPF volume is layer number int layer = touchable->GetVolume(1)->GetCopyNo(); // HDDS geometry does not include wires nor plane rotations. Assume 1 cm // wire spacing with wires at 0.5cm on either side of the beamline at // x,y = 0,0. Also assume odd number planes have wires in the vertical // direction and even numbered planes have wires in the horizontal direction. // Vertical wires start with wire 1 at x=-71.5 and wire 144 at x=+71.5 // (the gas volume ends at x=+/-72.0). Horizontal wires start with wire 1 // at y=-71.5 (i.e. closest to the ground) and wire 144 at y=+71.5 // (i.e. closest to the sky). int wire = 0; double pos_hit = 0.0; // position of hit perpendicular to direction of wires if(layer%2){ // Vertical wires pos_hit = pos_mwpc.x(); }else{ // Horizontal wires pos_hit = pos_mwpc.y(); } wire = (int)floor(pos_hit + 73.0); double pos_wire = 0.5 + wire*1.0 - 73.0; // position of wire that was hit perpendicular to direction of wires double doca = fabs( pos_hit - pos_wire ); if(wire < 1 || wire > 144) return false; // wire number out of range // Check if there's already a hit close in time to this one // Time at pre, post and mid step points double t_mid = 0.5*(sp_pre->GetGlobalTime() + sp_post->GetGlobalTime()) / ns; double t_drift = doca / DRIFT_VELOCITY; double t_hit = t_mid + t_drift; CPPHitFMWPC *hit = NULL; for(unsigned int i=0; ilayer != layer ) continue; if( hits[i]->wire != wire ) continue; if (fabs(hits[i]->t - t_hit ) < TWO_HIT_RESOL){ hit = hits[i]; break; } } // If not close to another hit (in time) then make a new hit if(!hit){ hit = new CPPHitFMWPC(layer, wire); hit->t = t_hit; hits.push_back(hit); } if(hit){ hit->dE += dEsum; hit->dx += dx; if( t_hit < hit->t) hit->t = t_hit; } //int N=touchable->GetHistoryDepth(); //for(int i=0; iGetHistory()->GetTransform(i).TransformPoint(sp_pre->GetPosition()) - LAB_OFFSET)/cm; //_DBG_<GetVolume(i)->GetName()<<" copy:"<< touchable->GetVolume(i)->GetCopyNo()<<" "<GetVolume(3)->GetObjectRotationValue().xx()<dE*1.0E6 > THRESH_KEV); if(keep_hit){ aHC->insert(hit); // add hit to collection Nhits++; }else{ delete hit; // reject hit } } // Add hit collection to the event G4int HCID = GetCollectionID(0); // get ID of fmwpchits hitCollection->AddHitsCollection(HCID, aHC); } } private: vector hits; G4double TWO_HIT_RESOL; G4double THRESH_KEV; G4double DRIFT_VELOCITY; G4double DEAD_RADIUS; G4double DEAD_WIDTH; }; #endif // __CPPSENSITIVEDETECTORFMWPC_