/* * MixedEventGenerator.cc * * Created on: Oct 30, 2014 * Author: aksel */ #include #include #include #include #include #include #include #include #include #include #include using std::vector; using std::string; #define G4std std namespace RAT { std::priority_queue,MixedEventGenerator> MixedEventGenerator::sQueue; G4double MixedEventGenerator::sCoincidenceTime=1e6; //default is 1 ms G4double MixedEventGenerator::sOffset=0; //time of the previous event to those in the queue G4int MixedEventGenerator::sInitialized=-1; MixedEventGenerator::MixedEventGenerator() : GLG4Gen("MixedEvent") { fGenerator=NULL; fTime=0; fOffset=0; fAtomCount=-1; fShouldDeleteThis=false; if(sInitialized<1)sInitialized++; else G4Exception(__FILE__, "Multiple MixedEventGenerators", FatalException, "Error, more than one MixedEventGenerator instantiated.\n" "This results in interference between the timing logic built into MixedEventGenerator and that of GlG4PrimaryGenerator\n" ); runInitDone = false; } /// This constructor is called from the SET command MixedEventGenerator::MixedEventGenerator(GLG4Gen *aGenerator, G4double aRate) : GLG4Gen(aGenerator->GetName()) { fRate=aRate; fGenerator = aGenerator; fShouldDeleteThis = true; fTime=0; NextEvent(); fOffset=0; fAtomCount=-1; runInitDone = false; } MixedEventGenerator::MixedEventGenerator(G4PrimaryVertex *aVertex) : GLG4Gen("MixedEvent") { fRate=0; fGenerator=NULL; fShouldDeleteThis=true; fPrimaryVertex=aVertex; fTime=aVertex->GetT0(); fOffset=0; sQueue.push(this); runInitDone = false; } void MixedEventGenerator::BeginOfRun() { // -- If it is not the generator owned by the GLG4PrimaryGeneratorAction // do nothing and return if (fShouldDeleteThis || runInitDone) return; GLG4Gen::BeginOfRun(); if (fGenerator) { #ifdef RAT_GEN_DEBUG detail << "MixedEventGenerator::BeginOfRun (" << this << ") : Initializing internal generator" << newline; debug << "MixedEventGenerator::BeginOfRun (" << this << ") : Name : " << fGenerator->GetName() << " Pointer : " << fGenerator << newline; #endif fGenerator->BeginOfRun(); } runInitDone = true; // -- Since this generator is self instancing, we need to be careful here. // -- the best is empty the queue into a local queue, then call BeginOfRun // -- and finally refill everything std::queue tmp_queue; while (!sQueue.empty()) { MixedEventGenerator *generator=sQueue.top(); sQueue.pop(); tmp_queue.push(generator); } while(!tmp_queue.empty()) { MixedEventGenerator *generator = tmp_queue.front(); tmp_queue.pop(); generator->BeginOfRun(); sQueue.push(generator); } detail << "MixedEventGenerator::BeginOfRun (" << this << ") : All sub-generators initialized" << newline; } void MixedEventGenerator::EndOfRun() { // -- If it is not the generator owned by the GLG4PrimaryGeneratorAction // do nothing and return if (fShouldDeleteThis || !runInitDone) return; GLG4Gen::EndOfRun(); if (fGenerator) { #ifdef RAT_GEN_DEBUG detail << "MixedEventGenerator::EndOfRun (" << this << ") : Entering internal generator" << newline; debug << "MixedEventGenerator::EndOfRun (" << this << ") : Name : " << fGenerator->GetName() << " Pointer : " << fGenerator << newline; #endif fGenerator->EndOfRun(); } runInitDone = false; std::queue tmp_queue; while (!sQueue.empty()) { MixedEventGenerator *generator=sQueue.top(); sQueue.pop(); tmp_queue.push(generator); } while(!tmp_queue.empty()) { MixedEventGenerator *generator = tmp_queue.front(); tmp_queue.pop(); generator->EndOfRun(); sQueue.push(generator); } detail << "MixedEventGenerator::EndOfRun : All sub-generators Ended" << newline; } void MixedEventGenerator::GenerateEvent(G4Event *anEvent) { double t0=sQueue.top()->GetVertex()->GetT0(); double tlast=t0; double tend=t0+sCoincidenceTime; for(;!sQueue.empty() && (sQueue.top()->GetVertex()->GetT0()GetVertex()->GetT0()GetVertex(); tlast=p->GetT0(); p->SetT0(tlast-sOffset); ///GLG4PrimaryGenerator wants the times as the interval from the previous event anEvent->AddPrimaryVertex(p); generator->NextEvent(); } if(sQueue.empty())G4RunManager::GetRunManager()->AbortRun(true); } void MixedEventGenerator::NextEvent() { if(fGenerator!=NULL ){ fTime=fTime-log(1.0-G4UniformRand())/fRate; if(fAtomCount>0){ fRate=fRate*(fAtomCount-1)/fAtomCount; fAtomCount--; } G4Event *event=new G4Event; //this is a temporary event, that is just used to get the primary vertex information back from the individual generators fGenerator->GenerateEvent(event); if(fAtomCount==0){ delete fGenerator; // cosmological event with no atoms left fGenerator=NULL; } std::list vertices; G4PrimaryVertex *p; if(event->GetNumberOfPrimaryVertex()!=0){ int i; double t0=1e10; //t0 will end up as the shortest time for(i=0;iGetNumberOfPrimaryVertex();i++){ p=event->GetPrimaryVertex(i); double t; t=p->GetT0(); if(t::iterator it; bool first=true; G4PrimaryVertex *out; // output vertex for(it=vertices.begin();it!=vertices.end();++it){ p=*it; double t=p->GetT0(); out=new G4PrimaryVertex(p->GetX0(), p->GetY0(),p->GetZ0(),t-t0+fTime); //Note that this will be deleted when after the event is processed. // I couldn't see any way to use the same G4PrimaryVertex in two different events, because of the built in linked list and the ownership. for(i=0;iGetNumberOfParticle();i++)out->SetPrimary(new G4PrimaryParticle(*p->GetPrimary(i))); out->SetWeight(p->GetWeight()); ParentPrimaryVertexInformation *vertexInfo=static_cast(p->GetUserInformation()); ParentPrimaryVertexInformation *vertexInfoOut=new ParentPrimaryVertexInformation(); if(vertexInfo!=NULL && vertexInfo->ExistParentParticle())vertexInfoOut->SetVertexParentParticle(vertexInfo->GetVertexParentParticle()); out->SetUserInformation(vertexInfoOut); if(t==t0 && first){ first=false; fPrimaryVertex=out; sQueue.push(this); //this MixedEventGenerator contains fGenerator, and when the event is popped it will generate a new event }else{ new MixedEventGenerator(out); //the constructor pushes the PrimaryVertex onto the queue; out will be deleted when G4Run deletes its G4Event. } } } delete event; }else{ if(fShouldDeleteThis) delete this; } } void MixedEventGenerator::SetState(G4String state) { // arguments are G1:I1:R1 // G1 = first generator type, required fGenerator =&aGenerator; // I1 = first isotope type, required fString=aName; // R1 = overall rate type, required fRate=aRate; state = util_strip_default(state); std::string compare1= "vtx" ; std::string compare2 = "pos" ; std::string compare3= "rate" ; std::string compare4= "halflife" ; std::string whitespaces (" \t\f\v\n\r"); unsigned int vtxInt=0, posInt=0, rateInt=0, halflifeInt=0 ; std::string chain = "" ; vector parts = util_split(state, ":"); double halfLife ; size_t nArgs = parts.size(); if(nArgs==0)return; int count =0; try { if(parts.size()!=0) { for(unsigned int h=0; h< parts.size(); h++) { size_t p = parts[h].find_first_not_of(" "); parts[h].erase(0,p); std::size_t found = parts[h].find_last_not_of(whitespaces); if(found!=std::string::npos) parts[h].erase(found+1); if(parts[h]==compare1) vtxInt = h ; else if(parts[h]==compare2) posInt = h ; else if(parts[h]==compare3) rateInt = h ; else if(parts[h]==compare4) halflifeInt = h ; count++ ; } unsigned int leastcount =100; for(int t=0; t<20; t++ ) { if( leastcount > halflifeInt && halflifeInt!=0 )leastcount = halflifeInt ; else if ( leastcount > posInt && posInt!=0 )leastcount = posInt ; else if( leastcount > rateInt && rateInt!=0 )leastcount = rateInt ; else if( leastcount > vtxInt && vtxInt!=0 )leastcount = vtxInt ; } for(unsigned int sc=1; sc< leastcount; sc++ ) { if(sc !=vtxInt-1) chain = chain+ parts[sc]+":" ; else chain = chain+ parts[sc] ; } fGenerator = RAT::GlobalFactory::New(parts[0]); fGenerator->SetState(chain); fGenerator->SetVertexState(parts[vtxInt+1]); for(unsigned int p=posInt+1 ; p< rateInt; p++) { fGenerator->SetPosState(parts[p]); } fRate = util_to_double(parts[rateInt+1])/1e9 ; if(halflifeInt!=0) { halfLife =util_to_double(parts[halflifeInt+1])*1e9 ; fAtomCount=fRate*halfLife/log(2.) ; } NextEvent(); } else{ G4Exception(__FILE__, "Invalid Parameter", FatalException, ("Mixed event generator syntax error: "+state).c_str()); } } catch (RAT::FactoryUnknownID &unknown) { } } void MixedEventGenerator::SetVertexState(G4String state) { sInitialized--; MixedEventGenerator *nextGenerator=new MixedEventGenerator(); nextGenerator->SetState(state); } void MixedEventGenerator::SetPosState(__attribute__((unused)) G4String state) { } void MixedEventGenerator::ResetTime(double) { } } /* namespace RAT */