// InZDABProducer.cc // Contact person: Matthew Strait // See InZDABProducer.hh for more details. //—————————————————————---------------------------------------------——// #include #include #include #include #include #include #include #include #include #include #include #include namespace RAT { InZDABProducer::InZDABProducer() : fRunStarted(false),fRun(NULL), fCount(0), fDefaultNumEvents(-1) { fMainBlock = 0; Init(); } InZDABProducer::InZDABProducer(ProcBlock *block) : fRunStarted(false),fRun(NULL), fCount(0), fDefaultNumEvents(-1) { SetMainBlock(block); Init(); } InZDABProducer::~InZDABProducer() { delete fLoadCmd; delete fReadCmd; delete loadDefaultCmd; delete readDefaultCmd; if (fRun) delete fRun; fInputFiles.clear(); } void InZDABProducer::Init() { fInputFiles.clear(); // Build commands G4UIdirectory* DebugDir = new G4UIdirectory("/rat/inzdab/"); DebugDir->SetGuidance("Read Events from ZDAB file"); fLoadCmd = new G4UIcmdWithAString("/rat/inzdab/load",this); fLoadCmd->SetParameterName( "filename", false ); fLoadCmd->SetGuidance( "Load the filename" ); fLoadCmd->AvailableForStates( G4State_PreInit ); fReadCmd = new G4UIcommand("/rat/inzdab/read", this); fReadCmd->SetGuidance( "Start reading in the ZDAB file(s)" ); fReadCmd->AvailableForStates( G4State_Idle ); loadDefaultCmd = new G4UIcommand("/rat/inzdab/load_default", this); loadDefaultCmd->SetGuidance("read from IO.default_input_filename and add to the stack to be processed"); loadDefaultCmd->AvailableForStates( G4State_PreInit ); readDefaultCmd = new G4UIcommand("/rat/inzdab/read_default", this); readDefaultCmd->SetGuidance("read from IO.default_input_filename and start processing"); readDefaultCmd->AvailableForStates( G4State_PreInit ); } G4String InZDABProducer::GetCurrentValue(G4UIcommand* /*command*/) { Log::Die("Invalid InZDAB command"); return G4String("You never see this."); } void InZDABProducer::SetNewValue(G4UIcommand * command, G4String newValue) { std::string tmp_file_name; std::vector tmp_file_list; if(command == fLoadCmd) { if(!fMainBlock) Log::Die("InZDAB: No main block declared! (can't happen)"); // -- Add files to the input file list tmp_file_name = newValue; fInputFiles.push_back(tmp_file_name); } else if ( command == loadDefaultCmd){ if(!fMainBlock) Log::Die("InZDAB: No main block declared! (can't happen)"); DBLinkPtr lIO = DB::Get()->GetLink("IO"); tmp_file_list = lIO->GetSArray("default_input_filename"); fInputFiles.reserve(fInputFiles.size() + tmp_file_list.size()); fInputFiles.insert(fInputFiles.end(),tmp_file_list.begin(),tmp_file_list.end()); } else if (command == fReadCmd || command == readDefaultCmd) { if (command == readDefaultCmd) { // override the existing contents DBLinkPtr lIO = DB::Get()->GetLink("IO"); tmp_file_list = lIO->GetSArray("default_input_filename"); // wipe the array and reset it fInputFiles.clear(); fInputFiles.reserve(fInputFiles.size() + tmp_file_list.size()); fInputFiles.insert(fInputFiles.end(),tmp_file_list.begin(),tmp_file_list.end()); } fDefaultNumEvents = DB::Get()->GetLink( "IO" )->GetI( "default_num_events" ); for (std::vector::iterator it = fInputFiles.begin(); it != fInputFiles.end(); ++it) { try{ info << "Processing file " << (*it) << newline; ReadEvents(*it); // If it returned from ReadEvents because a signal was raised // Do not continue the loop either if (SignalHandler::IsTermRequested()) break; } catch(ratzdab::zdabfile::zdab_file_read_error & ){ Log::Die(dformat("Could not read from %s", (*it).c_str())); } } // for // -- It is out of the loop. End the last // processed run if (fRunStarted) EndOfRun(*fRun); } else{ Log::Die("invalid InZDAB command"); } } /* * Takes a zdabfile zdab and reads the next record. Writes the results * into inds if it is event data, run if it is run data, and/or updates * internal variables without modifying either, or does nothing if it * doesn't know how to handle the current record. Sets gotevent to true * if it read an event (as opposed to a run header, etc.). Returns true * if it was able to read something, regardless of whether it knew what * to do with it. Returns false when zdab.next() returns NULL, normally * at the end of the file. */ static bool ReadNextRecord(DS::Entry * & inds, DS::Run * & run, ratzdab::zdabfile & zdab) { TObject* const r = zdab.next(); if(!r) return false; const TClass * const risa = r->IsA(); /// NFB : This does not work if one wants to process more than one file /// with different runs /// The way this was coded, in the case there were multiple runs /// the MC flag was set to false only on the first run processed /// Static variables are dangerous // This and other static variables in this function are not // thread-safe. This is fine as long as we don't try to use threads, // which we don't and are not planning to. static bool run_active = false; // containers for data that spans multiple events static DS::TrigHeader* current_trig = NULL; static DS::ECAHeader* current_eped = NULL; static bool run_level_data_set = false; // handle record types if(risa == DS::Entry::Class()) { inds = dynamic_cast(r); // some run-level data has to come from an event if(run_active && !run_level_data_set) { run->SetMCFlag(0); // no mc zdabs run_level_data_set = true; } // set event headers if available DS::HeaderInfo header; if(current_trig) header.SetTrigHeader( *current_trig ); if(current_eped) header.SetECAHeader( *current_eped ); inds->SetHeaderInfo( header ); } else if(risa == DS::Run::Class()) { DS::Run * tmp_run = dynamic_cast(r); // If it is the same as a coming run header, don't overwrite if (!run || run->GetRunID() != tmp_run->GetRunID()) { run = tmp_run; run_level_data_set = false; #ifdef RAT_INZDAB_DEBUG debug << "InZDABProducer::ReadNextRecord : Run assigned" << newline; #endif run_active = true; detail << "InZDAB: RHDR: Run " << run->GetRunID() << newline; } else { detail << "InZDAB: RHDR: Run " << run->GetRunID() << " has already been initialized. Ignoring record." << newline; } } else if(risa == DS::TrigHeader::Class()) { delete current_trig; current_trig = dynamic_cast(r); detail << "InZDAB: TrigHeader\n"; } else if(risa == DS::ECAHeader::Class()) { delete current_eped; current_eped = dynamic_cast(r); detail << "InZDAB: ECA\n"; } else if(risa == TObject::Class()) { //a record has been swallowed by converter on purpose } else { warn << "InZDAB: Unhandled ROOT object, type " << r->ClassName() << newline; } return true; } void InZDABProducer::ReadEvents(const G4String & filename) { info << "InZDABProducer::ReadEvents: Reading from " << filename << newline; ratzdab::zdabfile zdf(filename); DS::Run *run = NULL; while(!SignalHandler::IsTermRequested()) { DS::Entry *inds = NULL; try { if(!ReadNextRecord(inds, run, zdf)) break; } catch(ratzdab::unknown_record_error& e) { continue; } // Call the BeginOfRun. // It will check if we are still inthe same run or a new run should be initialized BeginOfRun(*run); if(inds){ fMainBlock->DSEvent(*run, *inds); delete inds; } if (fDefaultNumEvents == fCount) break; ++fCount; } } void InZDABProducer::BeginOfRun(DS::Run& run) { // If a run has already been initialized and the run number is the same // return and do nothing if (fRunStarted) { if (run.GetRunID() == fRun->GetRunID()) { // We are still in the same run...do nothing return; } else { // -- We have different runs // -- End the current run and start a new one EndOfRun(*fRun); delete fRun; fRun = NULL; } } fRun = &run; Producer::BeginOfRun(run); // NFB : Force these tables to be fetched from the database before the main block forces the database connection to close // It is not elegant, but it avoids a common warning about accessing the database outside BeginOfRun RAT::DB::Get()->GetLink("DAQ_RUN_LEVEL"); RAT::DB::Get()->GetLink("PMTINFO"); fMainBlock->BeginOfRun(run); fRunStarted = true; } void InZDABProducer::EndOfRun(DS::Run &run) { Producer::EndOfRun(run); fMainBlock->EndOfRun(run); fRunStarted = false; } } // namespace RAT