ROOT logo
// module identifier line...
// Author: Brian Thorsbro, 24/6-2014

#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <set>
#include <time.h>

#include "THepMCParser.h"
#include "TObject.h"
#include "TTree.h"
#include "TClonesArray.h"
#include "TFile.h"
#include "TParticle.h"
#include "TDatabasePDG.h"
#include "HepMC/IO_GenEvent.h"


using namespace std;


THepMCParser::THepMCParser(const char * infile) : fTree(0)
{
   HepMC::IO_BaseClass * events = new HepMC::IO_GenEvent(infile, std::ios::in);
   init(events);
   delete events;
   events = 0; // nullptr
}
THepMCParser::THepMCParser(HepMC::IO_BaseClass * events) : fTree(0)
{
   init(events);
}
void THepMCParser::init(HepMC::IO_BaseClass * events)
{
   int particlecount = 0;
   fTree = new TTree("treeEPOS","Tree EPOS");
   TClonesArray * array = new TClonesArray("TParticle");
   // array->BypassStreamer();
   fTree->Branch("Particles",&array); // more flags?
   THepMCParser::HeavyIonHeader_t heavyIonHeader;
   fTree->Branch("HeavyIonInfo", &heavyIonHeader, THepMCParser::fgHeavyIonHeaderBranchString);
   THepMCParser::PdfHeader_t pdfHeader;
   fTree->Branch("PdfInfo", &pdfHeader, THepMCParser::fgPdfHeaderBranchString);
   HepMC::GenEvent* evt =  0; // nullptr
   while ((evt = events->read_next_event())) {
      string errMsg1 = ParseGenEvent2TCloneArray(evt,array);
      string errMsg2 = ParseGenEvent2HeaderStructs(evt,heavyIonHeader,pdfHeader);
      if (errMsg1.length() == 0 && errMsg2.length() == 0) {
         fTree->Fill();
      } else {
         if (errMsg1.length() != 0) cerr << errMsg1 << endl;
         if (errMsg2.length() != 0) cerr << errMsg2 << endl;
      }
      particlecount += array->Capacity();
   }
//   array->Clear();
//   delete array;
//   array = 0; // nullptr
   cout << " parsed " << particlecount << " particles" << endl;
}


TTree * THepMCParser::GetTTree()
{
   return fTree;
}
void THepMCParser::WriteTTreeToFile(const char *outfile)
{
   TFile * f = new TFile(outfile, "recreate");
   fTree->Write();
   delete f;
   f = 0; // nullptr
}



// Based on a validator written by Peter Hristov, CERN
bool THepMCParser::IsValidMotherDaughtersConsitency(bool useStdErr, bool requireSecondMotherBeforeDaughters)
{
   bool valid = true;
   TClonesArray * array = new TClonesArray("TParticle");
   TBranch* branch = fTree->GetBranch("Particles");
   branch->SetAddress(&array);
   Int_t count = branch->GetEntries();
   for (Int_t idx=0; idx<count; ++idx) {
      array->Clear();
      branch->GetEntry(idx); // "fill" the array
      Int_t nkeep = array->GetEntriesFast();
      for (Int_t i=0; i<nkeep; i++) {
         TParticle * part = (TParticle*)array->AddrAt(i);
         Int_t mum1 = part->GetFirstMother();
         Int_t mum2 = part->GetSecondMother();
         Int_t fd = part->GetFirstDaughter();
         Int_t ld = part->GetLastDaughter();
         if (mum1>-1 && i<mum1) {
            valid = false;
            if (useStdErr) cerr << "Problem: first_mother(" << mum1 << ") after daughter(" << i << ")" << endl;
         }
         if (mum2>-1 && i<mum2 && requireSecondMotherBeforeDaughters) {
            valid = false;
            if (useStdErr) cerr << "Problem: second_mother(" << mum2 << ") after daughter(" << i << ")" << endl;
         }
         if (fd > ld ) {
            valid = false;
            if (useStdErr) cerr << "Problem: first_daughter(" << fd << ") > last_daughter(" << ld << ")" << endl;
         }
         for (Int_t id=TMath::Max(fd,0); id<=ld; id++) {
            TParticle * daughter = (TParticle*)array->AddrAt(id);
            if (daughter->GetFirstMother() != i && daughter->GetSecondMother() != i) {
               valid = false;
               if (useStdErr) cerr << "Problem: mother("<< i << ") not registered as mother for either first_daughter("
                     << daughter->GetFirstMother() << ") or second_daughter("
                     << daughter->GetSecondMother() << ")" << endl;
            }
         }
      }
   }
   delete array;
   array = 0;
   return valid;
}

bool THepMCParser::IsValidParticleInvariantMass(bool useStdErr, bool includeStatusCode2Particles)
{
   bool valid = true;
   TClonesArray *array = new TClonesArray("TParticle");
   TBranch* branch = fTree->GetBranch("Particles");
   branch->SetAddress(&array);
   Int_t count = branch->GetEntries();
   for (Int_t idx=0; idx<count; ++idx) {
      array->Clear();
      branch->GetEntry(idx);
      Int_t nkeep = array->GetEntries();
      for (Int_t i=0; i<nkeep; i++) {
         TParticle * parton = (TParticle*)array->AddrAt(i);
         if (parton->GetStatusCode()==2 && !includeStatusCode2Particles) {
            continue;
         }
         TLorentzVector v;
         parton->Momentum(v);
         Double_t m1 = v.M(); // invariant mass from the particle in the HepMC event
         TParticlePDG *dbParton = parton->GetPDG();
         if (!dbParton) {
            if (useStdErr) cerr << "Warning: could not look up particle with PDG Code: " << parton->GetPdgCode() << endl << endl;
            continue;
         }
         Double_t m2 = dbParton->Mass();
         bool checkok;
         if (m2 == 0) {
            checkok = abs(m1) < 0.0001; // no such thing as negative mass...
         } else {
            checkok = abs(1 - m1/m2) < 0.01;
         }
         if (!checkok && useStdErr) {
            cerr << "Problem: " << GetParticleName(parton) << " HepMC:" << m1 << endl;
            cerr << ListReactionChain(array,i);
            cerr << endl;
         }
         if (!checkok)
            valid = false;
      }
   }
   delete array;
   array = 0;
   return valid;
}

bool THepMCParser::IsValidVertexInvariantMass(bool useStdErr, bool includeStatusCode2Particles)
{
   bool valid = true;
   TClonesArray * array = new TClonesArray("TParticle");
   TBranch* branch = fTree->GetBranch("Particles");
   branch->SetAddress(&array);
   Int_t count = branch->GetEntries();
   for (Int_t idx=0; idx<count; ++idx) {
      array->Clear();
      branch->GetEntry(idx); // "fill" the array
      TLorentzVector v_st1;
      TLorentzVector v_st4;
      Int_t nkeep = array->GetEntriesFast();
      for (Int_t i=0; i<nkeep; i++) {
         TParticle * parton = (TParticle*)array->AddrAt(i);
         TLorentzVector v_in;
         parton->Momentum(v_in);
         if (parton->GetStatusCode()==4) {
            v_st4 += v_in;
         } else if (parton->GetStatusCode()==1) {
            v_st1 += v_in;
         }
         if (!includeStatusCode2Particles) { // only check beam particles vs final particles
            continue;
         }
         Int_t fd = parton->GetFirstDaughter();
         Int_t ld = parton->GetLastDaughter();
         if (fd == -1) continue; // no daughters, continue loop
         Int_t mother2 = -1;
         TLorentzVector v_out;
         bool oneok = false; bool allok = true; bool agreemother2 = true;
         ostringstream daughterpdg;
         ostringstream motherpdg;
         for (Int_t id=TMath::Max(fd,0); id<=ld; id++) {
            TParticle * daughter = (TParticle*)array->AddrAt(id);
            if (fd==id) {
               daughter->Momentum(v_out);
               mother2 = daughter->GetSecondMother();
            } else {
               TLorentzVector d;
               daughter->Momentum(d);
               v_out += d;
               if (daughter->GetSecondMother() != mother2) agreemother2 = false;
            }
            if (daughter->GetFirstMother() == i) {
               oneok = true;
            } else {
               allok = false;
            }
            daughterpdg << " " << daughter->GetPdgCode();
         }
         motherpdg << " " << parton->GetPdgCode();
         if (mother2 > -1 && agreemother2) {
            TParticle * m2 = (TParticle*)array->AddrAt(mother2);
            TLorentzVector m2v;
            m2->Momentum(m2v);
            v_in += m2v;
            motherpdg << " " << m2->GetPdgCode();
         }
         if (oneok && allok && agreemother2) {
            bool checkok = abs(1 - v_in.M()/v_out.M()) < 0.1;
            if (!checkok) valid=false;
            if (!checkok && useStdErr) {
               //             cerr << "Problem: " << i << "[" << fd << "," << ld << "] PDG:" << motherpdg.str() << " ->" << daughterpdg.str() << "  Inv.mass: " << v_in.M() << " -> " << v_out.M() << endl;
               cerr << ListReactionChain(array,i);
               cerr << endl;
               //             cerr << v_in.Px() << " " << v_in.Py() << " " << v_in.Pz() << " " << v_in.E() << endl;
            } else if (useStdErr) {
               //             cerr << "OK: " << i << "[" << fd << "," << ld << "] PDG:" << motherpdg.str() << " ->" << daughterpdg.str() << "  Inv.mass: " << v_in.M() << " -> " << v_out.M() << endl;
            }
         }
      }
      bool checkok = abs(1 - v_st4.M()/v_st1.M()) < 0.001;
      if (!checkok) valid=false;
      if (!checkok && useStdErr) {
         cerr << " BEAM PARTICLES -> FINAL PARTICLES " << endl;
         cerr << " status 4 (" << v_st4.M() << ") -> status 1 (" << v_st1.M() << ")" << endl << endl;
      }
   }
   delete array;
   array = 0;
   return valid;
}

string THepMCParser::GetParticleName(TParticle * thisPart)
{
   TParticlePDG *dbPart = thisPart->GetPDG();
   ostringstream name;
   if (dbPart) {
      name << dbPart->GetName() << "(" << dbPart->PdgCode() << "," << dbPart->Mass() << ")";
   } else {
      name << thisPart->GetPdgCode() << "(NoDBinfo)";
   }
   return name.str();
}

string THepMCParser::ListReactionChain(TClonesArray * particles, Int_t particleId)
{
   ostringstream output;

   TParticle * part = (TParticle*)particles->AddrAt(particleId);
   Int_t m1id = part->GetFirstMother();
   Int_t m2id = part->GetSecondMother();
   if (m1id > 1) { // ignore the initial collision with beam particles
      ostringstream inStr;
      ostringstream outStr;
      TParticle * m1 = (TParticle*)particles->AddrAt(m1id);
      TLorentzVector v_in;
      m1->Momentum(v_in);
      inStr << GetParticleName(m1) << "[" << v_in.M() << "]";
      if (m2id > 1) {
         TParticle * m2 = (TParticle*)particles->AddrAt(m2id);
         TLorentzVector v_m2;
         m2->Momentum(v_m2);
         v_in += v_m2;
         inStr << " " << GetParticleName(m2) << "[" << v_m2.M() << "]";
      }
      Int_t fd = m1->GetFirstDaughter();
      Int_t ld = m1->GetLastDaughter();
      TLorentzVector v_out;
      part->Momentum(v_out);
      outStr << GetParticleName(part) << "[" << v_out.M() << "]";
      for (Int_t i=fd; i<=ld; ++i) {
         if (i!=particleId) {
            TParticle * d = (TParticle*)particles->AddrAt(i);
            TLorentzVector v_d;
            d->Momentum(v_d);
            v_out += v_d;
            outStr << " " << GetParticleName(d) << "[" << v_d.M() << "]";
         }
      }
      output << "Parent reaction, inv mass: " << v_in.M() << " -> " << v_out.M() << endl;
      output << " - partons: " << inStr.str() << " -> " << outStr.str() << endl;
   }
   Int_t fd = part->GetFirstDaughter();
   Int_t ld = part->GetLastDaughter();
   if (fd > -1) {
      ostringstream inStr;
      ostringstream outStr;
      TLorentzVector v_in;
      part->Momentum(v_in);
      inStr << GetParticleName(part) << "[" << v_in.M() << "]";

      TParticle * f = (TParticle*)particles->AddrAt(fd);
      m2id = f->GetSecondMother();
      if (m2id == particleId) {
         m2id = f->GetFirstMother();
      }
      if (m2id > -1) {
         TParticle * m2 = (TParticle*)particles->AddrAt(m2id);
         TLorentzVector v_m2;
         m2->Momentum(v_m2);
         v_in += v_m2;
         inStr << " " << GetParticleName(m2) << "[" << v_m2.M() << "]";
      }
      TLorentzVector v_out;
      f->Momentum(v_out);
      outStr << GetParticleName(f) << "[" << v_out.M() << "]";
      for (Int_t i=fd+1; i<=ld; ++i) {
         TParticle * d = (TParticle*)particles->AddrAt(i);
         TLorentzVector v_d;
         d->Momentum(v_d);
         v_out += v_d;
         outStr << " " << GetParticleName(d) << "[" << v_d.M() << "]";
      }
      output << "Child reaction, inv mass: " << v_in.M() << " -> " << v_out.M() << endl;
      output << " - partons: " << inStr.str() << " -> " << outStr.str() << endl;
   } else {
      output << "Child reaction" << endl << " - none" << endl;
   }

   return output.str();
}


string THepMCParser::ParseGenEvent2TCloneArray(HepMC::GenEvent * genEvent, TClonesArray * array, string momUnit, string lenUnit, bool requireSecondMotherBeforeDaughters)
{
   if (requireSecondMotherBeforeDaughters) {
      return "requireSecondMotherBeforeDaughters not implemented yet!";
   }
   genEvent->use_units(momUnit, lenUnit);
   array->Clear();
   ostringstream errMsgStream;
   map<int,Int_t> partonMemory; // unordered_map in c++11 - but probably not much performance gain from that: log(n) vs log(1) where constant can be high

   // Check event with HepMC's internal validation algorithm
   if (!genEvent->is_valid()) {
      errMsgStream << "Error with event id: " << genEvent->event_number() << ", event is not valid!";
      return errMsgStream.str();
   }

   // Pull out the beam particles from the event
   const pair<HepMC::GenParticle *,HepMC::GenParticle *> beamparts = genEvent->beam_particles();

   // Four sanity checks:
   // - Beam particles exists and are not the same
   // - Both beam particles should have no production vertices, they come from the beams
   // - Both beam particles should have defined end vertices, as they both should contribute
   // - Both beam particles should have the exact same end vertex
   if (!beamparts.first || !beamparts.second || beamparts.first->barcode()==beamparts.second->barcode()) {
      errMsgStream << "Error with event id: " << genEvent->event_number() << ", beam particles doesn't exists or are the same";
      return errMsgStream.str();
   }
   if (beamparts.first->production_vertex() || beamparts.second->production_vertex()) {
      errMsgStream << "Error with event id: " << genEvent->event_number() << ", beam particles have production vertex/vertices...";
      return errMsgStream.str();
   }
   if (!beamparts.first->end_vertex() || !beamparts.second->end_vertex()) {
      errMsgStream << "Error with event id: " << genEvent->event_number() << ", beam particles have undefined end vertex/vertices...";
      return errMsgStream.str();
   }
   if (beamparts.first->end_vertex() != beamparts.second->end_vertex()) {
      errMsgStream << "Error with event id: " << genEvent->event_number() << ", beam particles do not collide in the same end vertex.";
      return errMsgStream.str();
   }

   // Set the array to hold the number of particles in the event
   array->Expand(genEvent->particles_size());

   // Create a TParticle for each beam particle
   new((*array)[0]) TParticle(
         beamparts.first->pdg_id(),
         beamparts.first->status(), // check if status has the same meaning
         -1, // no mother1
         -1, // no mother2
         -1, // first daughter not known yet
         -1, // last daughter not known yet
         beamparts.first->momentum().px(),
         beamparts.first->momentum().py(),
         beamparts.first->momentum().pz(),
         beamparts.first->momentum().e(),
         0, // no production vertex, so zero?
         0,
         0,
         0
   );
   partonMemory[beamparts.first->barcode()] = 0;
   new((*array)[1]) TParticle(
         beamparts.second->pdg_id(),
         beamparts.second->status(),
         -1, // no mother1
         -1, // no mother2
         -1, // first daughter not known yet
         -1, // last daughter not known yet
         beamparts.second->momentum().px(),
         beamparts.second->momentum().py(),
         beamparts.second->momentum().pz(),
         beamparts.second->momentum().e(),
         0, // no production vertex, so zero?
         0,
         0,
         0
   );
   partonMemory[beamparts.second->barcode()] = 1;
   Int_t arrayID = 2; // start counting IDs after the beam particles

   // Do first vertex as a special case for performance, since its often has the most daughters and both mothers are known
   Int_t firstDaughter = arrayID;
   for (HepMC::GenVertex::particles_out_const_iterator iter = beamparts.first->end_vertex()->particles_out_const_begin();
         iter != beamparts.first->end_vertex()->particles_out_const_end();
         ++iter) {
      new((*array)[arrayID]) TParticle(
            (*iter)->pdg_id(),
            (*iter)->status(),
            0, // beam particle 1
            1, // beam particle 2
            -1, // first daughter not known yet
            -1, // last daughter not known yet
            (*iter)->momentum().px(),
            (*iter)->momentum().py(),
            (*iter)->momentum().pz(),
            (*iter)->momentum().e(),
            beamparts.first->end_vertex()->position().x(),
            beamparts.first->end_vertex()->position().y(),
            beamparts.first->end_vertex()->position().z(),
            beamparts.first->end_vertex()->position().t()
      );
      partonMemory[(*iter)->barcode()] = arrayID;
      ++arrayID;
   }
   Int_t lastDaughter = arrayID-1;
   ((TParticle*)array->AddrAt(0))->SetFirstDaughter(firstDaughter); // beam particle 1
   ((TParticle*)array->AddrAt(0))->SetLastDaughter(lastDaughter);
   ((TParticle*)array->AddrAt(1))->SetFirstDaughter(firstDaughter); // beam particle 2
   ((TParticle*)array->AddrAt(1))->SetLastDaughter(lastDaughter);

   // Build vertex list by exploring tree and sorting such that daughters comes after mothers
   list<HepMC::GenVertex*> vertexList;
   set<int> vertexSearchSet;
   ExploreVertex(beamparts.first->end_vertex(),vertexList,vertexSearchSet,requireSecondMotherBeforeDaughters);

   // Analyze each vertex
   for (list<HepMC::GenVertex*>::iterator i = vertexList.begin(); i != vertexList.end(); ++i) {
      HepMC::GenVertex * vertex = (*i);

      // first establish mother relations
      HepMC::GenVertex::particles_in_const_iterator iter = vertex->particles_in_const_begin();
      if (iter == vertex->particles_in_const_end()) {
         return "Particle without a mother, and its not a beam particle!";
      }
      int motherA = partonMemory[(*iter)->barcode()];
      if (((TParticle*)array->AddrAt(motherA))->GetFirstDaughter() > -1) {
         return "Trying to assign new daughters to a particle that already has daughters defined!";
      }
      ++iter;
      int motherB = -1;
      if (iter != vertex->particles_in_const_end()) {
         motherB = partonMemory[(*iter)->barcode()];
         if (((TParticle*)array->AddrAt(motherB))->GetFirstDaughter() > -1) {
            return "Trying to assign new daughters to a particle that already has daughters defined!";
         }
         ++iter;
         if (iter != vertex->particles_in_const_end()) {
            return "Particle with more than two mothers!";
         }
      }
      if (motherB > -1 && motherB < motherA) {
         int swap = motherA; motherA = motherB; motherB = swap;
      }

      // add the particles to the array, important that they are add in succession with respect to arrayID
      firstDaughter = arrayID;
      for (iter = vertex->particles_out_const_begin();
            iter != vertex->particles_out_const_end();
            ++iter) {
         new((*array)[arrayID]) TParticle(
               (*iter)->pdg_id(),
               (*iter)->status(),
               motherA, // mother 1
               motherB, // mother 2
               -1, // first daughter, if applicable, not known yet
               -1, // last daughter, if applicable, not known yet
               (*iter)->momentum().px(),
               (*iter)->momentum().py(),
               (*iter)->momentum().pz(),
               (*iter)->momentum().e(),
               vertex->position().x(),
               vertex->position().y(),
               vertex->position().z(),
               vertex->position().t()
         );
         partonMemory[(*iter)->barcode()] = arrayID;
         ++arrayID;
      }
      lastDaughter = arrayID-1;
      if (lastDaughter < firstDaughter) {
         return "Vertex with no out particles, should not be possible!";
      }
      // update mother with daughter interval
      ((TParticle*)array->AddrAt(motherA))->SetFirstDaughter(firstDaughter);
      ((TParticle*)array->AddrAt(motherA))->SetLastDaughter(lastDaughter);
      if (motherB > -1) {
         ((TParticle*)array->AddrAt(motherB))->SetFirstDaughter(firstDaughter);
         ((TParticle*)array->AddrAt(motherB))->SetLastDaughter(lastDaughter);
      }
   }

   return "";
}


void THepMCParser::ExploreVertex(HepMC::GenVertex * vertex, list<HepMC::GenVertex*> & vertexList, set<int> & vertexSearchSet, bool requireSecondMotherBeforeDaughters)
{
   for (HepMC::GenVertex::particles_out_const_iterator iter = vertex->particles_out_const_begin();
         iter != vertex->particles_out_const_end();
         ++iter) {
      HepMC::GenVertex * testVertex = (*iter)->end_vertex();
      if (testVertex) {
         bool foundVertex = vertexSearchSet.find((*iter)->end_vertex()->barcode()) != vertexSearchSet.end();
         if (requireSecondMotherBeforeDaughters) {
            // redo this algorithem to move subtree instead of node....
            // its not completely error proof in its current implementation even though the error is extremely rare

            if (foundVertex) for (list<HepMC::GenVertex*>::iterator i = vertexList.begin(); i != vertexList.end(); ++i) {
               if ((*i)->barcode() == testVertex->barcode()) {
                  vertexList.erase(i);
                  cout << " it happened, the vertex parsing order had to be changed " << endl;
                  break;
               }
            } else {
               vertexSearchSet.insert((*iter)->end_vertex()->barcode());
            }
            vertexList.push_back(testVertex);
            if (!foundVertex) ExploreVertex(testVertex,vertexList,vertexSearchSet,requireSecondMotherBeforeDaughters);

         } else {
            if (!foundVertex) {
               vertexSearchSet.insert((*iter)->end_vertex()->barcode());
               vertexList.push_back(testVertex);
               ExploreVertex(testVertex,vertexList,vertexSearchSet,requireSecondMotherBeforeDaughters);
            }
         }
      }
   }
}



const char * THepMCParser::fgHeavyIonHeaderBranchString = "Ncoll_hard/I:Npart_proj:Npart_targ:Ncoll:spectator_neutrons:spectator_protons:N_Nwounded_collisions:Nwounded_N_collisions:Nwounded_Nwounded_collisions:impact_parameter/F:event_plane_angle:eccentricity:sigma_inel_NN";
const char * THepMCParser::fgPdfHeaderBranchString = "id1/I:id2:pdf_id1:pdf_id2:x1/D:x2:scalePDF:pdf1:pdf2";

string THepMCParser::ParseGenEvent2HeaderStructs(HepMC::GenEvent * genEvent, HeavyIonHeader_t & heavyIonHeader, PdfHeader_t & pdfHeader, bool fillZeroOnMissingHeavyIon, bool fillZeroOnMissingPdf)
{
   HepMC::HeavyIon * heavyIon = genEvent->heavy_ion();
   HepMC::PdfInfo * pdfInfo = genEvent->pdf_info();
   if ((!heavyIon && !fillZeroOnMissingHeavyIon) || (!pdfInfo && !fillZeroOnMissingPdf)) {
      return "HeavyIonInfo and/or PdfInfo not defined for this event, did you read it with IO_GenEvent?";
   }
   if (heavyIon) {
      heavyIonHeader.Ncoll_hard = heavyIon->Ncoll_hard();
      heavyIonHeader.Npart_proj = heavyIon->Npart_proj();
      heavyIonHeader.Npart_targ = heavyIon->Npart_targ();
      heavyIonHeader.Ncoll = heavyIon->Ncoll();
      heavyIonHeader.spectator_neutrons = heavyIon->spectator_neutrons();
      heavyIonHeader.spectator_protons = heavyIon->spectator_protons();
      heavyIonHeader.N_Nwounded_collisions = heavyIon->N_Nwounded_collisions();
      heavyIonHeader.Nwounded_N_collisions = heavyIon->Nwounded_N_collisions();
      heavyIonHeader.Nwounded_Nwounded_collisions = heavyIon->Nwounded_Nwounded_collisions();
      heavyIonHeader.impact_parameter = heavyIon->impact_parameter();
      heavyIonHeader.event_plane_angle = heavyIon->event_plane_angle();
      heavyIonHeader.eccentricity = heavyIon->eccentricity();
      heavyIonHeader.sigma_inel_NN = heavyIon->sigma_inel_NN();
   } else {
      heavyIonHeader.Ncoll_hard = 0;
      heavyIonHeader.Npart_proj = 0;
      heavyIonHeader.Npart_targ = 0;
      heavyIonHeader.Ncoll = 0;
      heavyIonHeader.spectator_neutrons = 0;
      heavyIonHeader.spectator_protons = 0;
      heavyIonHeader.N_Nwounded_collisions = 0;
      heavyIonHeader.Nwounded_N_collisions = 0;
      heavyIonHeader.Nwounded_Nwounded_collisions = 0;
      heavyIonHeader.impact_parameter = 0.0;
      heavyIonHeader.event_plane_angle = 0.0;
      heavyIonHeader.eccentricity = 0.0;
      heavyIonHeader.sigma_inel_NN = 0.0;
   }
   if (pdfInfo) {
      pdfHeader.id1 = pdfInfo->id1();
      pdfHeader.id2 = pdfInfo->id2();
      pdfHeader.pdf_id1 = pdfInfo->pdf_id1();
      pdfHeader.pdf_id2 = pdfInfo->pdf_id2();
      pdfHeader.x1 = pdfInfo->x1();
      pdfHeader.x2 = pdfInfo->x2();
      pdfHeader.scalePDF = pdfInfo->scalePDF();
      pdfHeader.pdf1 = pdfInfo->pdf1();
      pdfHeader.pdf2 = pdfInfo->pdf2();
   } else {
      pdfHeader.id1 = 0;
      pdfHeader.id2 = 0;
      pdfHeader.pdf_id1 = 0;
      pdfHeader.pdf_id2 = 0;
      pdfHeader.x1 = 0.0;
      pdfHeader.x2 = 0.0;
      pdfHeader.scalePDF = 0.0;
      pdfHeader.pdf1 = 0.0;
      pdfHeader.pdf2 = 0.0;
   }
   return "";
}







 THepMCParser.cxx:1
 THepMCParser.cxx:2
 THepMCParser.cxx:3
 THepMCParser.cxx:4
 THepMCParser.cxx:5
 THepMCParser.cxx:6
 THepMCParser.cxx:7
 THepMCParser.cxx:8
 THepMCParser.cxx:9
 THepMCParser.cxx:10
 THepMCParser.cxx:11
 THepMCParser.cxx:12
 THepMCParser.cxx:13
 THepMCParser.cxx:14
 THepMCParser.cxx:15
 THepMCParser.cxx:16
 THepMCParser.cxx:17
 THepMCParser.cxx:18
 THepMCParser.cxx:19
 THepMCParser.cxx:20
 THepMCParser.cxx:21
 THepMCParser.cxx:22
 THepMCParser.cxx:23
 THepMCParser.cxx:24
 THepMCParser.cxx:25
 THepMCParser.cxx:26
 THepMCParser.cxx:27
 THepMCParser.cxx:28
 THepMCParser.cxx:29
 THepMCParser.cxx:30
 THepMCParser.cxx:31
 THepMCParser.cxx:32
 THepMCParser.cxx:33
 THepMCParser.cxx:34
 THepMCParser.cxx:35
 THepMCParser.cxx:36
 THepMCParser.cxx:37
 THepMCParser.cxx:38
 THepMCParser.cxx:39
 THepMCParser.cxx:40
 THepMCParser.cxx:41
 THepMCParser.cxx:42
 THepMCParser.cxx:43
 THepMCParser.cxx:44
 THepMCParser.cxx:45
 THepMCParser.cxx:46
 THepMCParser.cxx:47
 THepMCParser.cxx:48
 THepMCParser.cxx:49
 THepMCParser.cxx:50
 THepMCParser.cxx:51
 THepMCParser.cxx:52
 THepMCParser.cxx:53
 THepMCParser.cxx:54
 THepMCParser.cxx:55
 THepMCParser.cxx:56
 THepMCParser.cxx:57
 THepMCParser.cxx:58
 THepMCParser.cxx:59
 THepMCParser.cxx:60
 THepMCParser.cxx:61
 THepMCParser.cxx:62
 THepMCParser.cxx:63
 THepMCParser.cxx:64
 THepMCParser.cxx:65
 THepMCParser.cxx:66
 THepMCParser.cxx:67
 THepMCParser.cxx:68
 THepMCParser.cxx:69
 THepMCParser.cxx:70
 THepMCParser.cxx:71
 THepMCParser.cxx:72
 THepMCParser.cxx:73
 THepMCParser.cxx:74
 THepMCParser.cxx:75
 THepMCParser.cxx:76
 THepMCParser.cxx:77
 THepMCParser.cxx:78
 THepMCParser.cxx:79
 THepMCParser.cxx:80
 THepMCParser.cxx:81
 THepMCParser.cxx:82
 THepMCParser.cxx:83
 THepMCParser.cxx:84
 THepMCParser.cxx:85
 THepMCParser.cxx:86
 THepMCParser.cxx:87
 THepMCParser.cxx:88
 THepMCParser.cxx:89
 THepMCParser.cxx:90
 THepMCParser.cxx:91
 THepMCParser.cxx:92
 THepMCParser.cxx:93
 THepMCParser.cxx:94
 THepMCParser.cxx:95
 THepMCParser.cxx:96
 THepMCParser.cxx:97
 THepMCParser.cxx:98
 THepMCParser.cxx:99
 THepMCParser.cxx:100
 THepMCParser.cxx:101
 THepMCParser.cxx:102
 THepMCParser.cxx:103
 THepMCParser.cxx:104
 THepMCParser.cxx:105
 THepMCParser.cxx:106
 THepMCParser.cxx:107
 THepMCParser.cxx:108
 THepMCParser.cxx:109
 THepMCParser.cxx:110
 THepMCParser.cxx:111
 THepMCParser.cxx:112
 THepMCParser.cxx:113
 THepMCParser.cxx:114
 THepMCParser.cxx:115
 THepMCParser.cxx:116
 THepMCParser.cxx:117
 THepMCParser.cxx:118
 THepMCParser.cxx:119
 THepMCParser.cxx:120
 THepMCParser.cxx:121
 THepMCParser.cxx:122
 THepMCParser.cxx:123
 THepMCParser.cxx:124
 THepMCParser.cxx:125
 THepMCParser.cxx:126
 THepMCParser.cxx:127
 THepMCParser.cxx:128
 THepMCParser.cxx:129
 THepMCParser.cxx:130
 THepMCParser.cxx:131
 THepMCParser.cxx:132
 THepMCParser.cxx:133
 THepMCParser.cxx:134
 THepMCParser.cxx:135
 THepMCParser.cxx:136
 THepMCParser.cxx:137
 THepMCParser.cxx:138
 THepMCParser.cxx:139
 THepMCParser.cxx:140
 THepMCParser.cxx:141
 THepMCParser.cxx:142
 THepMCParser.cxx:143
 THepMCParser.cxx:144
 THepMCParser.cxx:145
 THepMCParser.cxx:146
 THepMCParser.cxx:147
 THepMCParser.cxx:148
 THepMCParser.cxx:149
 THepMCParser.cxx:150
 THepMCParser.cxx:151
 THepMCParser.cxx:152
 THepMCParser.cxx:153
 THepMCParser.cxx:154
 THepMCParser.cxx:155
 THepMCParser.cxx:156
 THepMCParser.cxx:157
 THepMCParser.cxx:158
 THepMCParser.cxx:159
 THepMCParser.cxx:160
 THepMCParser.cxx:161
 THepMCParser.cxx:162
 THepMCParser.cxx:163
 THepMCParser.cxx:164
 THepMCParser.cxx:165
 THepMCParser.cxx:166
 THepMCParser.cxx:167
 THepMCParser.cxx:168
 THepMCParser.cxx:169
 THepMCParser.cxx:170
 THepMCParser.cxx:171
 THepMCParser.cxx:172
 THepMCParser.cxx:173
 THepMCParser.cxx:174
 THepMCParser.cxx:175
 THepMCParser.cxx:176
 THepMCParser.cxx:177
 THepMCParser.cxx:178
 THepMCParser.cxx:179
 THepMCParser.cxx:180
 THepMCParser.cxx:181
 THepMCParser.cxx:182
 THepMCParser.cxx:183
 THepMCParser.cxx:184
 THepMCParser.cxx:185
 THepMCParser.cxx:186
 THepMCParser.cxx:187
 THepMCParser.cxx:188
 THepMCParser.cxx:189
 THepMCParser.cxx:190
 THepMCParser.cxx:191
 THepMCParser.cxx:192
 THepMCParser.cxx:193
 THepMCParser.cxx:194
 THepMCParser.cxx:195
 THepMCParser.cxx:196
 THepMCParser.cxx:197
 THepMCParser.cxx:198
 THepMCParser.cxx:199
 THepMCParser.cxx:200
 THepMCParser.cxx:201
 THepMCParser.cxx:202
 THepMCParser.cxx:203
 THepMCParser.cxx:204
 THepMCParser.cxx:205
 THepMCParser.cxx:206
 THepMCParser.cxx:207
 THepMCParser.cxx:208
 THepMCParser.cxx:209
 THepMCParser.cxx:210
 THepMCParser.cxx:211
 THepMCParser.cxx:212
 THepMCParser.cxx:213
 THepMCParser.cxx:214
 THepMCParser.cxx:215
 THepMCParser.cxx:216
 THepMCParser.cxx:217
 THepMCParser.cxx:218
 THepMCParser.cxx:219
 THepMCParser.cxx:220
 THepMCParser.cxx:221
 THepMCParser.cxx:222
 THepMCParser.cxx:223
 THepMCParser.cxx:224
 THepMCParser.cxx:225
 THepMCParser.cxx:226
 THepMCParser.cxx:227
 THepMCParser.cxx:228
 THepMCParser.cxx:229
 THepMCParser.cxx:230
 THepMCParser.cxx:231
 THepMCParser.cxx:232
 THepMCParser.cxx:233
 THepMCParser.cxx:234
 THepMCParser.cxx:235
 THepMCParser.cxx:236
 THepMCParser.cxx:237
 THepMCParser.cxx:238
 THepMCParser.cxx:239
 THepMCParser.cxx:240
 THepMCParser.cxx:241
 THepMCParser.cxx:242
 THepMCParser.cxx:243
 THepMCParser.cxx:244
 THepMCParser.cxx:245
 THepMCParser.cxx:246
 THepMCParser.cxx:247
 THepMCParser.cxx:248
 THepMCParser.cxx:249
 THepMCParser.cxx:250
 THepMCParser.cxx:251
 THepMCParser.cxx:252
 THepMCParser.cxx:253
 THepMCParser.cxx:254
 THepMCParser.cxx:255
 THepMCParser.cxx:256
 THepMCParser.cxx:257
 THepMCParser.cxx:258
 THepMCParser.cxx:259
 THepMCParser.cxx:260
 THepMCParser.cxx:261
 THepMCParser.cxx:262
 THepMCParser.cxx:263
 THepMCParser.cxx:264
 THepMCParser.cxx:265
 THepMCParser.cxx:266
 THepMCParser.cxx:267
 THepMCParser.cxx:268
 THepMCParser.cxx:269
 THepMCParser.cxx:270
 THepMCParser.cxx:271
 THepMCParser.cxx:272
 THepMCParser.cxx:273
 THepMCParser.cxx:274
 THepMCParser.cxx:275
 THepMCParser.cxx:276
 THepMCParser.cxx:277
 THepMCParser.cxx:278
 THepMCParser.cxx:279
 THepMCParser.cxx:280
 THepMCParser.cxx:281
 THepMCParser.cxx:282
 THepMCParser.cxx:283
 THepMCParser.cxx:284
 THepMCParser.cxx:285
 THepMCParser.cxx:286
 THepMCParser.cxx:287
 THepMCParser.cxx:288
 THepMCParser.cxx:289
 THepMCParser.cxx:290
 THepMCParser.cxx:291
 THepMCParser.cxx:292
 THepMCParser.cxx:293
 THepMCParser.cxx:294
 THepMCParser.cxx:295
 THepMCParser.cxx:296
 THepMCParser.cxx:297
 THepMCParser.cxx:298
 THepMCParser.cxx:299
 THepMCParser.cxx:300
 THepMCParser.cxx:301
 THepMCParser.cxx:302
 THepMCParser.cxx:303
 THepMCParser.cxx:304
 THepMCParser.cxx:305
 THepMCParser.cxx:306
 THepMCParser.cxx:307
 THepMCParser.cxx:308
 THepMCParser.cxx:309
 THepMCParser.cxx:310
 THepMCParser.cxx:311
 THepMCParser.cxx:312
 THepMCParser.cxx:313
 THepMCParser.cxx:314
 THepMCParser.cxx:315
 THepMCParser.cxx:316
 THepMCParser.cxx:317
 THepMCParser.cxx:318
 THepMCParser.cxx:319
 THepMCParser.cxx:320
 THepMCParser.cxx:321
 THepMCParser.cxx:322
 THepMCParser.cxx:323
 THepMCParser.cxx:324
 THepMCParser.cxx:325
 THepMCParser.cxx:326
 THepMCParser.cxx:327
 THepMCParser.cxx:328
 THepMCParser.cxx:329
 THepMCParser.cxx:330
 THepMCParser.cxx:331
 THepMCParser.cxx:332
 THepMCParser.cxx:333
 THepMCParser.cxx:334
 THepMCParser.cxx:335
 THepMCParser.cxx:336
 THepMCParser.cxx:337
 THepMCParser.cxx:338
 THepMCParser.cxx:339
 THepMCParser.cxx:340
 THepMCParser.cxx:341
 THepMCParser.cxx:342
 THepMCParser.cxx:343
 THepMCParser.cxx:344
 THepMCParser.cxx:345
 THepMCParser.cxx:346
 THepMCParser.cxx:347
 THepMCParser.cxx:348
 THepMCParser.cxx:349
 THepMCParser.cxx:350
 THepMCParser.cxx:351
 THepMCParser.cxx:352
 THepMCParser.cxx:353
 THepMCParser.cxx:354
 THepMCParser.cxx:355
 THepMCParser.cxx:356
 THepMCParser.cxx:357
 THepMCParser.cxx:358
 THepMCParser.cxx:359
 THepMCParser.cxx:360
 THepMCParser.cxx:361
 THepMCParser.cxx:362
 THepMCParser.cxx:363
 THepMCParser.cxx:364
 THepMCParser.cxx:365
 THepMCParser.cxx:366
 THepMCParser.cxx:367
 THepMCParser.cxx:368
 THepMCParser.cxx:369
 THepMCParser.cxx:370
 THepMCParser.cxx:371
 THepMCParser.cxx:372
 THepMCParser.cxx:373
 THepMCParser.cxx:374
 THepMCParser.cxx:375
 THepMCParser.cxx:376
 THepMCParser.cxx:377
 THepMCParser.cxx:378
 THepMCParser.cxx:379
 THepMCParser.cxx:380
 THepMCParser.cxx:381
 THepMCParser.cxx:382
 THepMCParser.cxx:383
 THepMCParser.cxx:384
 THepMCParser.cxx:385
 THepMCParser.cxx:386
 THepMCParser.cxx:387
 THepMCParser.cxx:388
 THepMCParser.cxx:389
 THepMCParser.cxx:390
 THepMCParser.cxx:391
 THepMCParser.cxx:392
 THepMCParser.cxx:393
 THepMCParser.cxx:394
 THepMCParser.cxx:395
 THepMCParser.cxx:396
 THepMCParser.cxx:397
 THepMCParser.cxx:398
 THepMCParser.cxx:399
 THepMCParser.cxx:400
 THepMCParser.cxx:401
 THepMCParser.cxx:402
 THepMCParser.cxx:403
 THepMCParser.cxx:404
 THepMCParser.cxx:405
 THepMCParser.cxx:406
 THepMCParser.cxx:407
 THepMCParser.cxx:408
 THepMCParser.cxx:409
 THepMCParser.cxx:410
 THepMCParser.cxx:411
 THepMCParser.cxx:412
 THepMCParser.cxx:413
 THepMCParser.cxx:414
 THepMCParser.cxx:415
 THepMCParser.cxx:416
 THepMCParser.cxx:417
 THepMCParser.cxx:418
 THepMCParser.cxx:419
 THepMCParser.cxx:420
 THepMCParser.cxx:421
 THepMCParser.cxx:422
 THepMCParser.cxx:423
 THepMCParser.cxx:424
 THepMCParser.cxx:425
 THepMCParser.cxx:426
 THepMCParser.cxx:427
 THepMCParser.cxx:428
 THepMCParser.cxx:429
 THepMCParser.cxx:430
 THepMCParser.cxx:431
 THepMCParser.cxx:432
 THepMCParser.cxx:433
 THepMCParser.cxx:434
 THepMCParser.cxx:435
 THepMCParser.cxx:436
 THepMCParser.cxx:437
 THepMCParser.cxx:438
 THepMCParser.cxx:439
 THepMCParser.cxx:440
 THepMCParser.cxx:441
 THepMCParser.cxx:442
 THepMCParser.cxx:443
 THepMCParser.cxx:444
 THepMCParser.cxx:445
 THepMCParser.cxx:446
 THepMCParser.cxx:447
 THepMCParser.cxx:448
 THepMCParser.cxx:449
 THepMCParser.cxx:450
 THepMCParser.cxx:451
 THepMCParser.cxx:452
 THepMCParser.cxx:453
 THepMCParser.cxx:454
 THepMCParser.cxx:455
 THepMCParser.cxx:456
 THepMCParser.cxx:457
 THepMCParser.cxx:458
 THepMCParser.cxx:459
 THepMCParser.cxx:460
 THepMCParser.cxx:461
 THepMCParser.cxx:462
 THepMCParser.cxx:463
 THepMCParser.cxx:464
 THepMCParser.cxx:465
 THepMCParser.cxx:466
 THepMCParser.cxx:467
 THepMCParser.cxx:468
 THepMCParser.cxx:469
 THepMCParser.cxx:470
 THepMCParser.cxx:471
 THepMCParser.cxx:472
 THepMCParser.cxx:473
 THepMCParser.cxx:474
 THepMCParser.cxx:475
 THepMCParser.cxx:476
 THepMCParser.cxx:477
 THepMCParser.cxx:478
 THepMCParser.cxx:479
 THepMCParser.cxx:480
 THepMCParser.cxx:481
 THepMCParser.cxx:482
 THepMCParser.cxx:483
 THepMCParser.cxx:484
 THepMCParser.cxx:485
 THepMCParser.cxx:486
 THepMCParser.cxx:487
 THepMCParser.cxx:488
 THepMCParser.cxx:489
 THepMCParser.cxx:490
 THepMCParser.cxx:491
 THepMCParser.cxx:492
 THepMCParser.cxx:493
 THepMCParser.cxx:494
 THepMCParser.cxx:495
 THepMCParser.cxx:496
 THepMCParser.cxx:497
 THepMCParser.cxx:498
 THepMCParser.cxx:499
 THepMCParser.cxx:500
 THepMCParser.cxx:501
 THepMCParser.cxx:502
 THepMCParser.cxx:503
 THepMCParser.cxx:504
 THepMCParser.cxx:505
 THepMCParser.cxx:506
 THepMCParser.cxx:507
 THepMCParser.cxx:508
 THepMCParser.cxx:509
 THepMCParser.cxx:510
 THepMCParser.cxx:511
 THepMCParser.cxx:512
 THepMCParser.cxx:513
 THepMCParser.cxx:514
 THepMCParser.cxx:515
 THepMCParser.cxx:516
 THepMCParser.cxx:517
 THepMCParser.cxx:518
 THepMCParser.cxx:519
 THepMCParser.cxx:520
 THepMCParser.cxx:521
 THepMCParser.cxx:522
 THepMCParser.cxx:523
 THepMCParser.cxx:524
 THepMCParser.cxx:525
 THepMCParser.cxx:526
 THepMCParser.cxx:527
 THepMCParser.cxx:528
 THepMCParser.cxx:529
 THepMCParser.cxx:530
 THepMCParser.cxx:531
 THepMCParser.cxx:532
 THepMCParser.cxx:533
 THepMCParser.cxx:534
 THepMCParser.cxx:535
 THepMCParser.cxx:536
 THepMCParser.cxx:537
 THepMCParser.cxx:538
 THepMCParser.cxx:539
 THepMCParser.cxx:540
 THepMCParser.cxx:541
 THepMCParser.cxx:542
 THepMCParser.cxx:543
 THepMCParser.cxx:544
 THepMCParser.cxx:545
 THepMCParser.cxx:546
 THepMCParser.cxx:547
 THepMCParser.cxx:548
 THepMCParser.cxx:549
 THepMCParser.cxx:550
 THepMCParser.cxx:551
 THepMCParser.cxx:552
 THepMCParser.cxx:553
 THepMCParser.cxx:554
 THepMCParser.cxx:555
 THepMCParser.cxx:556
 THepMCParser.cxx:557
 THepMCParser.cxx:558
 THepMCParser.cxx:559
 THepMCParser.cxx:560
 THepMCParser.cxx:561
 THepMCParser.cxx:562
 THepMCParser.cxx:563
 THepMCParser.cxx:564
 THepMCParser.cxx:565
 THepMCParser.cxx:566
 THepMCParser.cxx:567
 THepMCParser.cxx:568
 THepMCParser.cxx:569
 THepMCParser.cxx:570
 THepMCParser.cxx:571
 THepMCParser.cxx:572
 THepMCParser.cxx:573
 THepMCParser.cxx:574
 THepMCParser.cxx:575
 THepMCParser.cxx:576
 THepMCParser.cxx:577
 THepMCParser.cxx:578
 THepMCParser.cxx:579
 THepMCParser.cxx:580
 THepMCParser.cxx:581
 THepMCParser.cxx:582
 THepMCParser.cxx:583
 THepMCParser.cxx:584
 THepMCParser.cxx:585
 THepMCParser.cxx:586
 THepMCParser.cxx:587
 THepMCParser.cxx:588
 THepMCParser.cxx:589
 THepMCParser.cxx:590
 THepMCParser.cxx:591
 THepMCParser.cxx:592
 THepMCParser.cxx:593
 THepMCParser.cxx:594
 THepMCParser.cxx:595
 THepMCParser.cxx:596
 THepMCParser.cxx:597
 THepMCParser.cxx:598
 THepMCParser.cxx:599
 THepMCParser.cxx:600
 THepMCParser.cxx:601
 THepMCParser.cxx:602
 THepMCParser.cxx:603
 THepMCParser.cxx:604
 THepMCParser.cxx:605
 THepMCParser.cxx:606
 THepMCParser.cxx:607
 THepMCParser.cxx:608
 THepMCParser.cxx:609
 THepMCParser.cxx:610
 THepMCParser.cxx:611
 THepMCParser.cxx:612
 THepMCParser.cxx:613
 THepMCParser.cxx:614
 THepMCParser.cxx:615
 THepMCParser.cxx:616
 THepMCParser.cxx:617
 THepMCParser.cxx:618
 THepMCParser.cxx:619
 THepMCParser.cxx:620
 THepMCParser.cxx:621
 THepMCParser.cxx:622
 THepMCParser.cxx:623
 THepMCParser.cxx:624
 THepMCParser.cxx:625
 THepMCParser.cxx:626
 THepMCParser.cxx:627
 THepMCParser.cxx:628
 THepMCParser.cxx:629
 THepMCParser.cxx:630
 THepMCParser.cxx:631
 THepMCParser.cxx:632
 THepMCParser.cxx:633
 THepMCParser.cxx:634
 THepMCParser.cxx:635
 THepMCParser.cxx:636