343 lines
16 KiB
C++
343 lines
16 KiB
C++
// Geant4 simulation for MuSR
|
|
// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI
|
|
// DATE : 2008-05
|
|
//
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
#include "lem4SteppingAction.hh"
|
|
//cksdel#include "lem4RunAction.hh"
|
|
#include "G4SteppingManager.hh"
|
|
#include "G4UnitsTable.hh"
|
|
#include "lem4RootOutput.hh"
|
|
#include "G4RunManager.hh" // needed for the event nr. comparison
|
|
#include "G4Run.hh" // ---------------||------------------
|
|
#include "G4MagneticField.hh" // needed for storing the magnetic field to the Root class
|
|
#include "G4FieldManager.hh" // ---------------||------------------
|
|
#include "G4TransportationManager.hh" // ---------------||------------------
|
|
#include "lem4ErrorMessage.hh"
|
|
#include "lem4Parameters.hh"
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
lem4SteppingAction::lem4SteppingAction() {
|
|
pointer=this;
|
|
// oldEventID=-1000;
|
|
muPlusProcessManager=NULL;
|
|
multipleToCoulombScatteringIsPossible=false;
|
|
coulombScatteringIsActive=false;
|
|
multipleScatteringIndex=1000;
|
|
coulombScatteringIndex=1000;
|
|
boolIsAnySpecialSaveVolumeDefined = false;
|
|
lastActualVolume="Unset";
|
|
}
|
|
|
|
lem4SteppingAction::~lem4SteppingAction() {
|
|
}
|
|
|
|
|
|
lem4SteppingAction* lem4SteppingAction::pointer=0;
|
|
lem4SteppingAction* lem4SteppingAction::GetInstance()
|
|
{
|
|
return pointer;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void lem4SteppingAction::DoAtTheBeginningOfEvent() {
|
|
// G4cout<<"lem4SteppingAction::DoAtTheBeginningOfEvent: KAMIL"<<G4endl;
|
|
radioactiveElectronAlreadySavedInThisEvent=false;
|
|
muAlreadyWasInTargetInThisEvent=false;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void lem4SteppingAction::UserSteppingAction(const G4Step* aStep) {
|
|
// sleep(1);
|
|
// For debugging purposes: To find out the number of steps during one event:
|
|
// G4RunManager* fRunManager = G4RunManager::GetRunManager();
|
|
// G4int debugEventID = fRunManager->GetCurrentEvent()->GetEventID();
|
|
// nrOfSteps++;
|
|
// if (debugOldEventID != debugEventID) {
|
|
// G4cout<<"lem4SteppingAction: Event nr. "<<debugOldEventID<<" has"<<nrOfSteps<<" steps."<<G4endl;
|
|
// nrOfSteps=0;
|
|
// debugOldEventID=debugEventID;
|
|
// }
|
|
|
|
G4Track* aTrack = aStep->GetTrack();
|
|
// if (nrOfSteps > 100000) {
|
|
// G4cout<<"lem4SteppingAction.cc : event nr. "<<debugEventID
|
|
// <<": nrOfSteps>100000 ==> KILL THE CURRENT TRACK with"
|
|
// <<aTrack->GetDynamicParticle()->GetDefinition()->GetParticleName() <<" at"
|
|
// <<aStep->GetPostStepPoint()->GetPosition() <<G4endl;
|
|
// G4cout<<"GetCurrentStepNumber()="<<aTrack->GetCurrentStepNumber() <<G4endl;
|
|
// aTrack->SetTrackStatus(fStopAndKill); // suspend the track if too many steps have already happened
|
|
// // (should be done in a more clever way, but I do not know how yet).
|
|
// nrOfSteps=0;
|
|
// }
|
|
|
|
// suspend the track if too many steps have already happened (relevant at high fields)
|
|
if (aTrack->GetCurrentStepNumber()>100000) {
|
|
lem4ErrorMessage::GetInstance()->lem4Error(WARNING,
|
|
"lem4SteppingAction: Current number of steps for the track > 100000 ==> TRACK KILLED",true);
|
|
//
|
|
// G4cout<<"lem4SteppingAction.cc : event nr. "<<oldEventID
|
|
// <<" Current number of steps for the track > 100000 ==> KILL THIS TRACK: " <<G4endl;
|
|
// <<aTrack->GetDynamicParticle()->GetDefinition()->GetParticleName() <<" at"
|
|
// <<aStep->GetPostStepPoint()->GetPosition()
|
|
// <<" E_kin_vertex="<<aTrack->GetVertexKineticEnergy()/MeV<<" MeV."<<G4endl;
|
|
//
|
|
lem4RootOutput* myRootOutput = lem4RootOutput::GetRootInstance();
|
|
G4double x=aStep->GetPostStepPoint()->GetPosition().x()/mm;
|
|
G4double y=aStep->GetPostStepPoint()->GetPosition().y()/mm;
|
|
G4double z=aStep->GetPostStepPoint()->GetPosition().z()/mm;
|
|
G4double E=aTrack->GetVertexKineticEnergy()/MeV;
|
|
myRootOutput->htest1->Fill(x,y);
|
|
myRootOutput->htest2->Fill(sqrt(x*x+y*y),z);
|
|
myRootOutput->htest3->Fill(E);
|
|
|
|
aTrack->SetTrackStatus(fStopAndKill);
|
|
}
|
|
|
|
|
|
if (aTrack->GetDefinition()) {
|
|
G4ParticleDefinition* p_definition = aTrack->GetDynamicParticle()->GetDefinition();
|
|
G4String p_name = p_definition->GetParticleName();
|
|
// G4ProcessManager* p_manager = p_definition->GetProcessManager();
|
|
// G4String p_name=aTrack->GetDynamicParticle()->GetDefinition()->GetParticleName();
|
|
G4String actualVolume=aTrack->GetVolume()->GetLogicalVolume()->GetName();
|
|
|
|
|
|
|
|
//! First Commented by TS. Currently not in use! or not strictly necessary
|
|
|
|
|
|
// This are the data just for the radioactive decay (when using the radioactive source):
|
|
if ((lem4Parameters::boolG4GeneralParticleSource)) {
|
|
// &&(!radioactiveElectronAlreadySavedInThisEvent)) {
|
|
if (aTrack->GetTrackID() != 1 ){
|
|
if (aTrack->GetCreatorProcess()->GetProcessName() == "RadioactiveDecay") {
|
|
// if (aStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName() == "RadioactiveDecay") { did not work out
|
|
// emitted particles
|
|
// if (fTrack->GetDefinition()->GetParticleType() != "nucleus") {
|
|
// G4String particleName = fTrack->GetDefinition()->GetParticleName();
|
|
if (aTrack->GetDefinition()->GetParticleName()=="e-") {
|
|
// G4double particleName = G4double (fTrack->GetDefinition()->GetPDGEncoding());
|
|
// G4double time = fStep->GetPreStepPoint()->GetGlobalTime() ;
|
|
// //- fStep->GetPreStepPoint()->GetLocalTime();
|
|
// G4double weight = fStep->GetPreStepPoint()->GetWeight() ;
|
|
// G4double energy = fStep->GetPreStepPoint()->GetKineticEnergy();
|
|
//
|
|
// exrdmAnalysisManager::getInstance()->AddParticle(particleName, energy, weight, time);
|
|
//hovno
|
|
// G4cout<<"aTrack->GetCurrentStepNumber()="<<aTrack->GetCurrentStepNumber()<<" ";
|
|
if (aTrack->GetCurrentStepNumber()==1) {
|
|
G4double electron_kinetic_energy=aStep->GetPreStepPoint()->GetKineticEnergy();
|
|
lem4RootOutput* myRootOutput = lem4RootOutput::GetRootInstance();
|
|
myRootOutput->htest4->Fill(electron_kinetic_energy);
|
|
// G4cout<<"First kinetic energy="<<aStep->GetPreStepPoint()->GetKineticEnergy()<<" ";
|
|
// G4cout<<"GetKineticEnergy()="<<aTrack->GetKineticEnergy()<<G4endl;
|
|
}
|
|
// // G4ThreeVector radioactivePositronMomentum = aStep->GetPreStepPoint()->GetMomentum();
|
|
// G4ThreeVector radioactivePositronMomentum = aTrack->GetMomentum();
|
|
// G4double Apx=radioactivePositronMomentum.x();
|
|
// G4double Apy=radioactivePositronMomentum.y();
|
|
// G4double Apz=radioactivePositronMomentum.z();
|
|
// lem4RootOutput* myRootOutput = lem4RootOutput::GetRootInstance();
|
|
// myRootOutput->SetInitialMuonParameters(0,0,0,Apx,Apy,Apz,0,0,0);
|
|
// radioactiveElectronAlreadySavedInThisEvent=true;
|
|
// // G4cout<<"Apx,Apy,Apz="<<Apx<<" "<<Apy<<" "<<Apz<<G4endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//hovno
|
|
// Check if in the special
|
|
if (boolIsAnySpecialSaveVolumeDefined) {
|
|
// G4bool isFirstStepInVolume=aStep->IsFirstStepInVolume();
|
|
// This does not work!!! (aStep->IsFirstStepInVolume() is always zero.) I do not understand why!
|
|
G4bool isFirstStepInVolume=false;
|
|
if (actualVolume!=lastActualVolume) {
|
|
lastActualVolume=actualVolume;
|
|
isFirstStepInVolume=true;
|
|
}
|
|
|
|
if (isFirstStepInVolume) {
|
|
G4int tmpVolumeID=saveVolumeMapping[actualVolume];
|
|
if (tmpVolumeID!=0) {
|
|
G4int particle_id_save=p_definition->GetPDGEncoding();
|
|
G4double ke_save=aStep->GetPreStepPoint()->GetKineticEnergy()/keV;
|
|
G4double x_save=aStep->GetPreStepPoint()->GetPosition().x()/mm;
|
|
G4double y_save=aStep->GetPreStepPoint()->GetPosition().y()/mm;
|
|
G4double z_save=aStep->GetPreStepPoint()->GetPosition().z()/mm;
|
|
G4double px_save=aStep->GetPreStepPoint()->GetMomentum().x()/MeV;
|
|
G4double py_save=aStep->GetPreStepPoint()->GetMomentum().y()/MeV;
|
|
G4double pz_save=aStep->GetPreStepPoint()->GetMomentum().z()/MeV;
|
|
lem4RootOutput* myRootOutput = lem4RootOutput::GetRootInstance();
|
|
myRootOutput->SetSaveDetectorInfo(tmpVolumeID,particle_id_save,ke_save,x_save,y_save,z_save,px_save,py_save,pz_save);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Store information about when mu+ or Mu enter the target for the fist time
|
|
// in a given event (i.e. the code has to be called just once during the event).
|
|
if ((p_name == "mu+") || (p_name == "Mu")) {
|
|
if (actualVolume=="log_target") {
|
|
// G4RunManager* fRunManager = G4RunManager::GetRunManager();
|
|
// G4int eventID = fRunManager->GetCurrentEvent()->GetEventID();
|
|
// if (oldEventID != eventID) {
|
|
// oldEventID=eventID;
|
|
if (!muAlreadyWasInTargetInThisEvent) {
|
|
muAlreadyWasInTargetInThisEvent=true;
|
|
lem4RootOutput* myRootOutput = lem4RootOutput::GetRootInstance();
|
|
myRootOutput->SetPolInTarget(aTrack->GetPolarization());
|
|
myRootOutput->SetTimeInTarget(aTrack->GetGlobalTime());
|
|
//G4cout<<"particle = "<<p_name<<" TOF = "<<(aTrack->GetGlobalTime())/ns<<G4endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Store the pointer to the mu+ process manager, and the indexes of the "msc" and "eCoulombScat" processes.
|
|
// This is needed for switching beween the multiple scattering and coulomb scattering in some volumes.
|
|
if (p_name == "mu+") {
|
|
if (muPlusProcessManager==NULL) { // The muPlusProcessManager should be NULL only once, at the beginning of the run.
|
|
muPlusProcessManager = p_definition->GetProcessManager();
|
|
G4ProcessVector* v = muPlusProcessManager->GetProcessList();
|
|
size_t np = v->size();
|
|
for(size_t i=0; i<np; i++) {
|
|
// std::cout<<" "<<(*v)[i]->GetProcessName();
|
|
if( (*v)[i]->GetProcessName() == "msc" ) {
|
|
multipleScatteringIndex = i;
|
|
}
|
|
if( (*v)[i]->GetProcessName() == "eCoulombScat" ) {
|
|
coulombScatteringIndex = i;
|
|
}
|
|
}
|
|
// std::cout<<std::endl;
|
|
// std::cout<<"multipleScatteringIndex,coulombScatteringIndex ="<<multipleScatteringIndex<<","<<coulombScatteringIndex<<std::endl;
|
|
if ((multipleScatteringIndex<1000)&&(coulombScatteringIndex<1000)) { // Both multiple and Coulomb scattering processes for muon found
|
|
multipleToCoulombScatteringIsPossible=true;
|
|
std::cout<<"lem4SteppingAction: Switching between Coulomb and multiple scattering processes possible"<<std::endl;
|
|
// Ensure that just one of them is active. Let the active one be the multiple scattering at the beginning.
|
|
muPlusProcessManager->SetProcessActivation(multipleScatteringIndex, true);
|
|
muPlusProcessManager->SetProcessActivation(coulombScatteringIndex, false);
|
|
}
|
|
else { // At least one of the "multiple scattering" and "coulomb scattering" was not found.
|
|
// Perhaps they were not defined in the physics list ?
|
|
if (lem4Parameters::GetInstance()->GetMyTypeOfProcesses()=="coulombAndMultiple") {
|
|
if (coulombScatteringIndex==1000) {std::cout<<"lem4SteppingAction: Coulomb scattering process for mu+ not found!"<<std::endl;}
|
|
if (multipleScatteringIndex==1000) {std::cout<<"lem4SteppingAction: Multiple scattering process for mu+ not found!"<<std::endl;}
|
|
lem4ErrorMessage::GetInstance()->lem4Error(SERIOUS,
|
|
"lem4SteppingAction: It is not possible to switch between Coulomb and multiple scattering.",true);
|
|
|
|
muPlusProcessManager->DumpInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
// switch between G4MultipleScattering and G4CoulombScattering
|
|
if (multipleToCoulombScatteringIsPossible) {
|
|
if (strncmp(actualVolume.c_str(),"log_coulomb",11)==0) {
|
|
if (!coulombScatteringIsActive) {
|
|
// std::cout<<"Activating coulomb; volume= "<<actualVolume<<std::endl;
|
|
muPlusProcessManager->SetProcessActivation(multipleScatteringIndex, false);
|
|
muPlusProcessManager->SetProcessActivation(coulombScatteringIndex, true);
|
|
coulombScatteringIsActive=true;
|
|
}
|
|
}
|
|
else if (coulombScatteringIsActive) {
|
|
// std::cout<<"Deactivating coulomb; volume= "<<actualVolume<<std::endl;
|
|
muPlusProcessManager->SetProcessActivation(multipleScatteringIndex, true);
|
|
muPlusProcessManager->SetProcessActivation(coulombScatteringIndex, false);
|
|
coulombScatteringIsActive=false;
|
|
}
|
|
}
|
|
|
|
// Store the information about the muon decay into the Root Class.
|
|
// Pick up process "DecayWithSpin":
|
|
const G4VProcess* process = aStep->GetPostStepPoint()->GetProcessDefinedStep();
|
|
if (process!=NULL) {
|
|
G4String processName = process->GetProcessName();
|
|
if (processName=="DecayWithSpin") {
|
|
lem4Parameters::field_DecayWithSpin=true;
|
|
// std::cout<<"lem4SteppingAction: DecayWithSpin"<<std::endl;
|
|
// store the information about the decaying muon
|
|
lem4RootOutput* myRootOutput = lem4RootOutput::GetRootInstance();
|
|
G4double timeOfDecay_tmp=aTrack->GetGlobalTime();
|
|
myRootOutput->SetDecayTime(timeOfDecay_tmp);
|
|
myRootOutput->SetDecayPolarisation(aTrack->GetPolarization());
|
|
G4ThreeVector positionOfDecay_tmp = aStep->GetPostStepPoint()->GetPosition();
|
|
myRootOutput->SetDecayPosition(positionOfDecay_tmp);
|
|
// store the detector ID in which the muon decayed
|
|
myRootOutput->SetDecayDetectorID(actualVolume);
|
|
// store the information about the magnetic field at the place where the muon decays
|
|
G4double BFieldAtOrigin[6] = {0.,0.,0.,0.,0.,0.};
|
|
G4double PointOfDecay[4] ={positionOfDecay_tmp.x(),positionOfDecay_tmp.y(),positionOfDecay_tmp.z(),timeOfDecay_tmp};
|
|
G4FieldManager *fMgr=G4TransportationManager::GetTransportationManager()->GetFieldManager();
|
|
if (fMgr!=NULL) {
|
|
if(!fMgr->DoesFieldChangeEnergy()) { //then we have a magnetic field
|
|
fMgr->GetDetectorField()->GetFieldValue(PointOfDecay,BFieldAtOrigin);
|
|
myRootOutput->SetBField(BFieldAtOrigin);
|
|
}
|
|
else{
|
|
}
|
|
}
|
|
|
|
// store the information about the emerging positron
|
|
G4TrackVector* secondary = fpSteppingManager->GetSecondary();
|
|
G4int n_secondaries= (*secondary).size();
|
|
for (G4int i=0; i<n_secondaries; i++) {
|
|
// G4cout <<"Secondary ["<<i<<"]="<<(*secondary)[i]->GetDefinition()->GetParticleName()<<", ";
|
|
if ( ((*secondary)[i]->GetDefinition()->GetParticleName()) == "e+" ) {
|
|
myRootOutput->SetInitialPositronMomentum((*secondary)[i]->GetMomentum());
|
|
|
|
// These two times seem to be equivalent: (*secondary)[i]->GetGlobalTime()
|
|
// aTrack->GetGlobalTime()
|
|
// G4cout <<"Positron initial momentum="<<(*secondary)[i]->GetMomentum()<<G4endl;
|
|
// G4cout <<"Positron time="<<(*secondary)[i]->GetGlobalTime()<<G4endl;
|
|
// G4cout <<"astep time="<<aTrack->GetGlobalTime()<<G4endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//csk
|
|
|
|
G4ThreeVector position = aStep->GetPostStepPoint()->GetPosition();
|
|
// G4double tof=aTrack->GetLocalTime();
|
|
// G4double energy=aTrack->GetDynamicParticle()->GetKineticEnergy();
|
|
G4ThreeVector polarization=aTrack->GetDynamicParticle()->GetPolarization();
|
|
|
|
// G4cout << "Stepping action: mu+ properties \n"
|
|
// << "position " << G4BestUnit(position,"Length") <<"; \n"
|
|
// << "time of flight " << G4BestUnit(tof,"Time") <<"; \n"
|
|
// << "kinetic energy "<< G4BestUnit(energy,"Energy") <<"; \n"
|
|
// << "polarization "<< polarization <<";\n"
|
|
// <<G4endl;
|
|
}
|
|
|
|
else { // particle is not muon
|
|
// Delete track if the particle is far away from the detector (i.e. in the "shield" volume).
|
|
// There is an example how to delete the track in example/novice/N04.
|
|
// It is done in a different way here, because the example/novice/N04 was not doing
|
|
// exactly what I wanted.
|
|
/* if ((lem4Parameters::killAllPositrons)&&(p_name == "e+")){
|
|
aTrack->SetTrackStatus(fStopAndKill); // suspend the track
|
|
}
|
|
*/
|
|
if((actualVolume(0,10)=="log_shield")||(actualVolume(0,10)=="log_Shield")) {
|
|
aTrack->SetTrackStatus(fStopAndKill); // suspend the track
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
|
|
void lem4SteppingAction::SetLogicalVolumeAsSpecialSaveVolume(G4String logicName, G4int volumeID) {
|
|
boolIsAnySpecialSaveVolumeDefined = true;
|
|
saveVolumeMapping[logicName]=volumeID;
|
|
}
|