Newer
Older
Markus Frank
committed
//==========================================================================
Markus Frank
committed
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
Markus Frank
committed
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
// @author P.Kostka (main author)
// @author M.Frank (code reshuffeling into new DDG4 scheme)
//
//====================================================================
// Framework include files
#include "DD4hep/Memory.h"
#include "DD4hep/Plugins.h"
#include "DDG4/Geant4Primary.h"
#include "DDG4/Geant4Context.h"
Andre Sailer
committed
#include "DDG4/Geant4Kernel.h"
#include "DDG4/Geant4InputAction.h"
Andre Sailer
committed
#include "DDG4/Geant4RunAction.h"
#include "G4Event.hh"
using namespace std;
using namespace dd4hep::sim;
typedef dd4hep::detail::ReferenceBitMask<int> PropertyMask;
typedef Geant4InputAction::Vertices Vertices ;
/// Initializing constructor
Markus Frank
committed
Geant4EventReader::Geant4EventReader(const std::string& nam)
: m_name(nam), m_directAccess(false), m_currEvent(0), m_inputAction(0)
{
}
/// Default destructor
Geant4EventReader::~Geant4EventReader() {
}
/// Get the context (from the input action)
Geant4Context* Geant4EventReader::context() const {
if( 0 == m_inputAction ) {
printout(FATAL,"Geant4EventReader", "No input action registered!");
throw std::runtime_error("Geant4EventReader: No input action registered!");
}
return m_inputAction->context();
}
/// Set the input action
void Geant4EventReader::setInputAction(Geant4InputAction* action) {
m_inputAction = action;
}
/// Skip event. To be implemented for sequential sources
Markus Frank
committed
Geant4EventReader::EventReaderStatus Geant4EventReader::skipEvent() {
if ( hasDirectAccess() ) {
++m_currEvent;
return EVENT_READER_OK;
}
std::vector<Particle*> particles;
EventReaderStatus sc = readParticles(m_currEvent,vertices,particles);
for_each(particles.begin(),particles.end(),detail::deleteObject<Particle>);
for_each(vertices.begin(),vertices.end(),detail::deleteObject<Vertex>);
Andre Sailer
committed
/// check if all parameters have been consumed by the reader, otherwise throws exception
void Geant4EventReader::checkParameters(std::map< std::string, std::string > ¶meters) {
if( parameters.empty() ) {
return;
}
for (auto const& pairNV : parameters ) {
printout(FATAL,"EventReader::checkParameters","Unknown parameter name: %s with value %s",
pairNV.first.c_str(),
pairNV.second.c_str());
}
throw std::runtime_error("Unknown parameter for event reader");
}
Markus Frank
committed
Geant4EventReader::EventReaderStatus
Geant4EventReader::moveToEvent(int event_number) {
if ( event_number >= INT_MIN ) {
return EVENT_READER_OK; // Logic below does not work as expected.
} // This shortcuts it!
Andre Sailer
committed
// APS: would have been nice to know what exactly doesn't work...
return EVENT_READER_OK;
}
else if ( hasDirectAccess() ) {
return EVENT_READER_OK;
}
else if ( event_number<m_currEvent ) {
return EVENT_READER_ERROR;
}
else {
for(int i=m_currEvent; i<event_number;++i)
skipEvent();
return EVENT_READER_OK;
}
return EVENT_READER_ERROR;
}
#else
/// Move to the indicated event number.
Geant4EventReader::EventReaderStatus
Markus Frank
committed
Geant4EventReader::moveToEvent(int /* event_number */) {
return EVENT_READER_OK;
}
#endif
/// Standard constructor
Markus Frank
committed
Geant4InputAction::Geant4InputAction(Geant4Context* ctxt, const string& nam)
: Geant4GeneratorAction(ctxt,nam), m_reader(0), m_currentEventNumber(0)
{
declareProperty("Input", m_input);
declareProperty("Sync", m_firstEvent=0);
declareProperty("Mask", m_mask = 0);
declareProperty("MomentumScale", m_momScale = 1.0);
declareProperty("HaveAbort", m_abort = true);
Andre Sailer
committed
declareProperty("Parameters", m_parameters = {});
m_needsControl = true;
Andre Sailer
committed
runAction().callAtBegin(this, &Geant4InputAction::beginRun);
}
/// Default destructor
Geant4InputAction::~Geant4InputAction() {
}
Andre Sailer
committed
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
///Intialize the event reader before the run starts
void Geant4InputAction::beginRun(const G4Run*) {
createReader();
}
void Geant4InputAction::createReader() {
if(m_reader) {
return;
}
if ( m_input.empty() ) {
except("InputAction: No input file declared!");
}
string err;
TypeName tn = TypeName::split(m_input,"|");
try {
m_reader = PluginService::Create<Geant4EventReader*>(tn.first,tn.second);
if ( 0 == m_reader ) {
PluginDebug dbg;
m_reader = PluginService::Create<Geant4EventReader*>(tn.first,tn.second);
abortRun("Error creating reader plugin.",
"Failed to create file reader of type %s. Cannot open dataset %s",
tn.first.c_str(),tn.second.c_str());
}
m_reader->setParameters( m_parameters );
m_reader->checkParameters( m_parameters );
m_reader->setInputAction( this );
m_reader->registerRunParameters();
} catch(const exception& e) {
err = e.what();
}
if ( !err.empty() ) {
abortRun(err,"Error when creating reader for file %s",m_input.c_str());
}
}
/// helper to report Geant4 exceptions
string Geant4InputAction::issue(int i) const {
stringstream str;
str << "Geant4InputAction[" << name() << "]: Event " << i << " ";
return str.str();
}
/// Read an event and return a LCCollection of MCParticles.
int Geant4InputAction::readParticles(int evt_number,
std::vector<Particle*>& particles)
{
Andre Sailer
committed
//in case readParticles is called diractly outside of having a run, we make sure a reader exists
createReader();
int evid = evt_number + m_firstEvent;
int status = m_reader->moveToEvent(evid);
Andre Sailer
committed
if(status == Geant4EventReader::EVENT_READER_EOF ) {
long nEvents = context()->kernel().property("NumEvents").value<long>();
if(nEvents < 0) {
//context()->kernel().runManager().AbortRun(true);
throw DD4hep_End_Of_File();
}
}
if ( Geant4EventReader::EVENT_READER_OK != status ) {
Markus Frank
committed
string msg = issue(evid)+"Error when moving to event - ";
if ( status == Geant4EventReader::EVENT_READER_EOF ) msg += " EOF: [end of file].";
else msg += " Unknown error condition";
if ( m_abort ) {
abortRun(msg,"Error when reading file %s",m_input.c_str());
return status;
}
error(msg.c_str());
except("Error when reading file %s.", m_input.c_str());
Markus Frank
committed
}
status = m_reader->readParticles(evid, vertices, particles);
Andre Sailer
committed
if(status == Geant4EventReader::EVENT_READER_EOF ) {
long nEvents = context()->kernel().property("NumEvents").value<long>();
if(nEvents < 0) {
//context()->kernel().runManager().AbortRun(true);
throw DD4hep_End_Of_File();
}
}
if ( Geant4EventReader::EVENT_READER_OK != status ) {
Markus Frank
committed
string msg = issue(evid)+"Error when moving to event - ";
if ( status == Geant4EventReader::EVENT_READER_EOF ) msg += " EOF: [end of file].";
else msg += " Unknown error condition";
if ( m_abort ) {
abortRun(msg,"Error when reading file %s",m_input.c_str());
return status;
}
error(msg.c_str());
except("Error when reading file %s.", m_input.c_str());
}
return status;
}
/// Callback to generate primary particles
void Geant4InputAction::operator()(G4Event* event) {
vector<Particle*> primaries;
Geant4Event& evt = context()->event();
Geant4PrimaryEvent* prim = evt.extension<Geant4PrimaryEvent>();
result = readParticles(m_currentEventNumber, vertices, primaries);
event->SetEventID(m_firstEvent + m_currentEventNumber);
++m_currentEventNumber;
if ( result != Geant4EventReader::EVENT_READER_OK ) { // handle I/O error, but how?
return;
}
Geant4PrimaryInteraction* inter = new Geant4PrimaryInteraction();
prim->add(m_mask, inter);
// check if there is at least one particle
if ( primaries.empty() ) return;
// check if there is at least one primary vertex
if ( vertices.empty() ) return;
print("+++ Particle interaction with %d generator particles and %d vertices ++++++++++++++++++++++++",
int(primaries.size()), int(vertices.size()) );
for(size_t i=0; i<vertices.size(); ++i ) {
inter->vertices[m_mask].emplace_back( vertices[i] );
// build collection of MCParticles
for(auto* primPart : primaries) {
Geant4ParticleHandle p(primPart);
const double mom_scale = m_momScale;
PropertyMask status(p->status);
p->psx = mom_scale*p->psx;
p->psy = mom_scale*p->psy;
p->psz = mom_scale*p->psz;
//FIXME: this needs to be done now in the readers ...
// // if ( p->parents.size() == 0 ) {
// // if ( status.isSet(G4PARTICLE_GEN_EMPTY) || status.isSet(G4PARTICLE_GEN_DOCUMENTATION) )
// // vtx->in.insert(p->id); // Beam particles and primary quarks etc.
// // else
// // vtx->out.insert(p->id); // Stuff, to be given to Geant4 together with daughters
// // }
inter->particles.emplace(p->id,p);
Markus Frank
committed
p.dumpWithMomentumAndVertex(outputLevel()-1,name(),"->");