int pp6day3_muonanalysis() {
  std::string muonFile;
  //int resultCode(0);

  // Obtain filename from user
  std::cout << "Enter filename to analyse: ";
  muonFile = getString();

  // Create EventArrays of muons/antimuons in input file
  std::string runID("run4.dat");
  double muonMass = 0.105658366; // GeV
  EventArray* p = readParticles(muonFile, "mu-", muonMass, runID);
  EventArray* q = readParticles(muonFile, "mu+", muonMass, runID);

  // Create an array of suffcient size to hold the invariant masses
  // formed between each muon/antimuon pair, plus an array
  // to hold the flattened indices
  int combinations = p->size * q->size;
  double *invMasses = new double[combinations];
  int *indices = new int[combinations];

  for (size_t i(0); i < q->size; ++i) {
    for (size_t j(0); j < p->size; ++j) {
      int flatIndex = i * p->size + j;
      indices[flatIndex] = flatIndex;
      invMasses[flatIndex] = calculate_invariant_mass(q->particles[i],
                                                      p->particles[j]);
    }
  }

  // Sort the invariant masses using an associative sort over the indices
  associative_sort(invMasses, indices, combinations);

  //--------------------------------------------------------------------
  // - Present results
  //
  std::cout << "Results:" << std::endl;
  std::cout << "========" << std::endl;
  std::cout << "Analysed File : " << muonFile << std::endl;
  std::cout << "Number of Muons     = " << p->size << std::endl;
  std::cout << "Number of AntiMuons = " << q->size << std::endl;
  std::cout << "----------------------------" << std::endl;

  for (int i(0); i < 10; ++i) {
    int muonIndex(indices[i] % p->size);
    int antimuonIndex((indices[i] - muonIndex) / p->size);
    std::cout << "{InvariantMass : " << invMasses[indices[i]]
              << ",\n\t"
              << "{Muon : "
              << "Event = " << p->ids[muonIndex] << ", "
              << "(E, P) = ("
              << (p->particles[muonIndex]).getFourMomentum()
              << ")}\n\t"
              << "{AntiMuon : "
              << "Event = " << q->ids[antimuonIndex] << ", "
              << "(E, P) = ("
              << (q->particles[antimuonIndex]).getFourMomentum()
              << ")}\n"
              << "}"
              << std::endl;
    
  }

  destroyEventArray(p);
  destroyEventArray(q);
  delete [] invMasses;
  delete [] indices;
  return 0;
}
int pp6day4_muonanalysis() {
  std::string dbtFilename;
  std::cout << "Enter path to .dbt file for initializing ParticleInfo: ";
  dbtFilename = getString();

  const ParticleInfo& particleDB = ParticleInfo::Instance(dbtFilename);
  std::cout << "Checking ParticleInfo contains entries... ";
  if(!particleDB.size()){
    std::cout << "fail" << std::endl;
    return 1;
  } 

  else{
    std::cout << "ok" << std::endl;
  }

  std::string muonFile;
  std::cout << "Enter filename to analyse: ";
  muonFile = getString();
 
  InvMass::RunMap allRuns;

  if(!read_run_data(muonFile, particleDB, allRuns)){
    std::cerr << "[pp6day4_muonanalysis:error] Failed to read data from " << muonFile
              << std::endl;
    return 1;
  }

  InvMass::RunMap::iterator requiredRun = allRuns.find("run4.dat");
  if(requiredRun == allRuns.end()){
    std::cerr << "[pp6day4_muonanalysis:error] No run4.dat records found in "
              << muonFile << std::endl;
    return 1;
  } 

  InvMass::EventVector negativeMuons;
  InvMass::EventVector positiveMuons;
  InvMass::RunMap::mapped_type::iterator start = (*requiredRun).second.begin();
  InvMass::RunMap::mapped_type::iterator stop = (*requiredRun).second.end();

  std::remove_copy_if(start,stop, std::back_inserter(negativeMuons), 
                      IsNotPDGCode(particleDB.getPDGCode("mu-")));

  std::remove_copy_if(start, stop, std::back_inserter(positiveMuons), 
                      IsNotPDGCode(particleDB.getPDGCode("mu+")));

  InvMass::InvMassTable invMasses;

  InvMass::EventVector::iterator negIter = negativeMuons.begin();
  InvMass::EventVector::iterator negEnd = negativeMuons.end();
  InvMass::EventVector::iterator posIter = positiveMuons.begin();
  InvMass::EventVector::iterator posEnd = positiveMuons.end();
  double invMass;

  for(; negIter != negEnd; ++negIter){
    posIter = positiveMuons.begin();

    for(; posIter != posEnd; ++posIter){
      invMass = calculate_invariant_mass((*negIter).second, (*posIter).second);
      invMasses.insert(std::make_pair(invMass, InvMass::InvMassPair(*negIter, *posIter)));
    }
  }

  InvMass::InvMassTable::iterator imIter = invMasses.begin();
  InvMass::InvMassTable::iterator imStop = invMasses.end();

  for(size_t i ; imIter != imStop, i < 10 ; ++imIter, ++i){
    std::cout << "{InvariantMass : " << (*imIter).first << ",\n\t"
              << (*imIter).second.first << "\n\t" << (*imIter).second.second
              << std::endl;
  }

  return 0;
}