Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 14:22:13

0001 /*! \file testJetFinder.cpp
0002  * \brief Procedural unit-test code for the L1GctHardwareJetFinder class.
0003  *
0004  *  This is code that tests each public method of the L1GctTdrJetFinder
0005  *  class.  It takes data from a file to test the methods against known
0006  *  results.  Results are also output to file to allow debugging.
0007  *
0008  * \author Robert Frazier
0009  * \date March 2006
0010  */
0011 
0012 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctHardwareJetFinder.h"  //The class to be tested
0013 
0014 //Custom headers needed for this test
0015 #include "DataFormats/L1CaloTrigger/interface/L1CaloRegion.h"
0016 
0017 #include "L1Trigger/GlobalCaloTrigger/test/produceTrivialCalibrationLut.h"
0018 
0019 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctJet.h"
0020 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctJetEtCalibrationLut.h"
0021 #include "FWCore/Utilities/interface/Exception.h"
0022 
0023 #include "CondFormats/L1TObjects/interface/L1CaloEtScale.h"
0024 
0025 //Standard library headers
0026 #include <fstream>  //for file IO
0027 #include <string>
0028 #include <vector>
0029 #include <iostream>
0030 #include <exception>  //for exception handling
0031 #include <stdexcept>  //for std::runtime_error()
0032 using namespace std;
0033 
0034 //Typedefs for the vector templates and other types used
0035 typedef vector<L1GctRegion> RegionsVector;
0036 typedef vector<L1GctJet> RawJetsVector;
0037 typedef vector<L1GctJetCand> JetsVector;
0038 typedef unsigned long int ULong;
0039 
0040 typedef L1GctJetFinderBase::lutPtr lutPtr;
0041 typedef L1GctJetFinderBase::lutPtrVector lutPtrVector;
0042 
0043 // Name of the files for test input data and results output.
0044 const string testDataFile = "testJetFinderInputMismatch.txt";
0045 const string resultsFile = "testJetFinderOutputMismatch.txt";
0046 
0047 // Global constants to tell the program how many things to read in from file
0048 // THESE ARE TOTAL GUESSES!
0049 const int numInputRegions = 52;  //Num. calorimeter regions given as input
0050 const int numOutputJets = 18;    //Num. jets expected out
0051 //There will be Jet Counts to be added here at some point
0052 
0053 // Test any jetFinder between 0 and 17
0054 const unsigned jfNumber = 5;
0055 
0056 //  FUNCTION PROTOTYPES
0057 /// Runs the test on the L1GctJetFinder instance passed into it.
0058 void classTest(L1GctHardwareJetFinder *myJetFinder, std::vector<L1GctJetFinderBase *> myNeighbours);
0059 /// Loads test input regions and also the known results from a text file.
0060 void loadTestData(
0061     RegionsVector &inputRegions, RawJetsVector &trueJets, ULong &trueHt, ULong &stripSum0, ULong &stripSum1);
0062 /// Function to safely open input files of any name, using a referenced return ifstream
0063 void safeOpenInputFile(ifstream &fin, const string name);
0064 /// Function to safely open output files of any name, using a referenced return ofstream
0065 void safeOpenOutputFile(ofstream &fout, const string name);
0066 /// Reads regions from file and pushes the specified number into a vector of regions
0067 void putRegionsInVector(ifstream &fin, RegionsVector &regions, const int numRegions);
0068 /// Gets the data of a single region from the testDataFile (reasonably safely).
0069 L1GctRegion readSingleRegion(ifstream &fin);
0070 /// Reads jets from file and pushes the specified number into a vector of jets
0071 void putJetsInVector(ifstream &fin, RawJetsVector &jets, const int numJets);
0072 /// Gets the data of a single jet from the testDataFile (reasonably safely).
0073 L1GctJet readSingleJet(ifstream &fin);
0074 /// Compares RegionsVectors, prints a message about the comparison, returns true if identical, else false.
0075 bool compareRegionsVectors(RegionsVector &vector1, RegionsVector &vector2, const string description);
0076 /// Compares JetsVectors, prints a message about the comparison, returns true if identical, else false.
0077 bool compareJetsVectors(RawJetsVector &vector1, RawJetsVector &vector2, const string description);
0078 /// Writes out the entire contents of a RegionsVector to the given file output stream
0079 void outputRegionsVector(ofstream &fout, RegionsVector &regions, string description = "Regions");
0080 /// Writes out the entire contents of a JetsVector to the given file output stream
0081 void outputJetsVector(ofstream &fout, RawJetsVector &jets, string description = "Jets");
0082 
0083 /// Entrypoint of unit test code + error handling
0084 int main(int argc, char **argv) {
0085   cout << "\n*************************************" << endl;
0086   cout << "  L1GctJetFinder class unit tester." << endl;
0087   cout << "*************************************" << endl;
0088 
0089   try {
0090     produceTrivialCalibrationLut *lutProducer = new produceTrivialCalibrationLut();
0091 
0092     // Instance of the class
0093     const lutPtrVector &myJetEtCalLut = lutProducer->produce();
0094     const L1GctJetFinderParams *myJfPars = lutProducer->jfPars();
0095     delete lutProducer;
0096 
0097     // The jetfinder number to be tested is given by jfNumber
0098     if (jfNumber < 18) {
0099       // Work out the numbers of the two neighbours
0100       unsigned jfNeigh0 = (jfNumber + 8) % 9;
0101       unsigned jfNeigh1 = (jfNumber + 1) % 9;
0102       if (jfNumber >= 9) {
0103         jfNeigh0 += 9;
0104         jfNeigh1 += 9;
0105       }
0106 
0107       L1GctHardwareJetFinder *myJetFinder = new L1GctHardwareJetFinder(jfNumber);  //TEST OBJECT on heap;
0108       std::vector<L1GctJetFinderBase *> myNeighbours;
0109       myNeighbours.push_back(new L1GctHardwareJetFinder(jfNeigh0));
0110       myNeighbours.push_back(new L1GctHardwareJetFinder(jfNeigh1));
0111 
0112       myJetFinder->setJetEtCalibrationLuts(myJetEtCalLut);
0113       myJetFinder->setJetFinderParams(myJfPars);
0114       myNeighbours.at(0)->setJetEtCalibrationLuts(myJetEtCalLut);
0115       myNeighbours.at(0)->setJetFinderParams(myJfPars);
0116       myNeighbours.at(1)->setJetEtCalibrationLuts(myJetEtCalLut);
0117       myNeighbours.at(1)->setJetFinderParams(myJfPars);
0118 
0119       myJetFinder->setNeighbourJetFinders(myNeighbours);
0120 
0121       // Connect the jetFinders around in a little circle
0122       std::vector<L1GctJetFinderBase *> dummyNeighbours(2);
0123       dummyNeighbours.at(0) = myNeighbours.at(1);
0124       dummyNeighbours.at(1) = myJetFinder;
0125       myNeighbours.at(0)->setNeighbourJetFinders(dummyNeighbours);
0126       dummyNeighbours.at(0) = myJetFinder;
0127       dummyNeighbours.at(1) = myNeighbours.at(0);
0128       myNeighbours.at(1)->setNeighbourJetFinders(dummyNeighbours);
0129 
0130       classTest(myJetFinder, myNeighbours);
0131 
0132       //clean up
0133       delete myNeighbours.at(0);
0134       delete myNeighbours.at(1);
0135       delete myJetFinder;
0136     } else {
0137       cout << "Invalid jet finder number " << jfNumber << "; should be less than 18" << endl;
0138     }
0139   } catch (cms::Exception &e) {
0140     if (e.category() == "FileReadError") {
0141       std::cout << "No input file - exiting" << std::endl;
0142     } else {
0143       cerr << e.what() << endl;
0144     }
0145   } catch (...) {
0146     cerr << "\nError! An unknown exception has occurred!" << endl;
0147   }
0148 
0149   return 0;
0150 }
0151 
0152 // Runs the test, and returns a string with the test result message in.
0153 void classTest(L1GctHardwareJetFinder *myJetFinder, std::vector<L1GctJetFinderBase *> myNeighbours) {
0154   bool testPass = true;  //flag to mark test failure
0155 
0156   // Vectors for reading in test data from the text file.
0157   RegionsVector inputRegions;  //Size?
0158   RawJetsVector trueJets;      //Size?
0159   ULong trueHt;
0160   ULong outputEt;
0161   ULong stripSum0, stripSum1;
0162 
0163   // Vectors for receiving the output from the object under test.
0164   RegionsVector outputRegions;  //Size?
0165   RawJetsVector outputJets;     //Size?
0166   ULong outputHt;
0167   ULong sumOfJetHt;
0168   //Jet Counts to be added at some point
0169 
0170   // Load our test input data and known results
0171   loadTestData(inputRegions, trueJets, trueHt, stripSum0, stripSum1);
0172 
0173   //Fill the L1GctJetFinder with regions.
0174   for (int i = 0; i < numInputRegions; ++i) {
0175     myJetFinder->setInputRegion(inputRegions.at(i));
0176     myNeighbours.at(0)->setInputRegion(inputRegions.at(i));
0177     myNeighbours.at(1)->setInputRegion(inputRegions.at(i));
0178   }
0179 
0180   // Test the getInputRegion method
0181   RegionsVector centralRegions;
0182   const unsigned COL_OFFSET = L1GctJetFinderBase::COL_OFFSET;
0183   unsigned pos = 0;
0184   for (unsigned col = 0; col < 3; ++col) {
0185     for (unsigned row = 0; row < COL_OFFSET; ++row) {
0186       if (col == 1 || col == 2) {
0187         centralRegions.push_back(inputRegions.at(pos));
0188       }
0189       ++pos;
0190     }
0191   }
0192   outputRegions = myJetFinder->getInputRegions();
0193   if (!compareRegionsVectors(outputRegions, centralRegions, "initial data input/output")) {
0194     testPass = false;
0195   }
0196 
0197   myJetFinder->fetchInput();         //Run algorithm
0198   myNeighbours.at(0)->fetchInput();  //Run algorithm
0199   myNeighbours.at(1)->fetchInput();  //Run algorithm
0200   myJetFinder->process();            //Run algorithm
0201   myNeighbours.at(0)->process();     //Run algorithm
0202   myNeighbours.at(1)->process();     //Run algorithm
0203 
0204   //Get the outputted data and store locally
0205   outputJets = myJetFinder->getRawJets();
0206   RawJetsVector nJets0 = myNeighbours.at(0)->getRawJets();
0207   RawJetsVector nJets1 = myNeighbours.at(1)->getRawJets();
0208   outputJets.insert(outputJets.end(), nJets0.begin(), nJets0.end());
0209   outputJets.insert(outputJets.end(), nJets1.begin(), nJets1.end());
0210   outputHt = myJetFinder->getHtSum().value();
0211 
0212   sumOfJetHt = 0;
0213   for (RawJetsVector::const_iterator it = outputJets.begin(); it != outputJets.end(); ++it) {
0214     sumOfJetHt += it->calibratedEt(myJetFinder->getJetEtCalLuts().at(it->rctEta()));
0215   }
0216 
0217   //Test the outputted jets against the known results
0218   if (!compareJetsVectors(outputJets, trueJets, "outputted jets")) {
0219     testPass = false;
0220   }
0221 
0222   //Test the outputted Ht against known result.
0223   //NOTE: this is lookup table dependent, so the reference file
0224   //needs to change when the lookup table changes.
0225   if (outputHt != sumOfJetHt) {
0226     cout << "output Ht " << outputHt << " true Ht " << sumOfJetHt << endl;
0227     cout << "\nTest class has FAILED Ht comparison!" << endl;
0228     testPass = false;
0229   } else {
0230     cout << "\nTest class has passed Ht comparison." << endl;
0231     if (outputHt != trueHt) {
0232       cout << "The value recorded in the file " << trueHt << " is wrong; should be " << sumOfJetHt << endl;
0233       cout << "Have you changed the calibration function??" << endl;
0234     }
0235   }
0236 
0237   //Test the Et strip sums against known results
0238   if ((stripSum0 + stripSum1) != myJetFinder->getEtSum().value()) {
0239     cout << "Et sum 0 comparison: expected strips " << stripSum0 << " and " << stripSum1 << " found "
0240          << myJetFinder->getEtSum() << endl;
0241     cout << "\nTest class has FAILED Et sum comparison!" << endl;
0242     testPass = false;
0243   } else {
0244     cout << "\nTest class has passed Et strip sum comparison." << endl;
0245   }
0246 
0247   //Write out all outputtable information to file
0248   cout << "\nWriting results of processing to file " << resultsFile << "..." << endl;
0249   ;
0250   ofstream fout;
0251   safeOpenOutputFile(fout, resultsFile);
0252   outputRegionsVector(fout, outputRegions, "Inputted Regions");
0253   outputJetsVector(fout, outputJets, "Outputted Jets");
0254   fout << "Outputted Ht" << endl;
0255   fout << outputHt << endl << endl;
0256   fout << "Outputted Et strip sums" << endl;
0257   fout << stripSum0 << "  " << stripSum1 << endl << endl;
0258   fout.close();
0259   cout << "Done!" << endl;
0260 
0261   //Run the reset method.
0262   myJetFinder->reset();
0263 
0264   //get all the data again - should all be empty
0265   outputRegions = myJetFinder->getInputRegions();
0266   outputJets = myJetFinder->getRawJets();
0267   outputHt = myJetFinder->getHtSum().value();
0268   outputEt = myJetFinder->getEtSum().value();
0269 
0270   //an empty regions vector for reset comparison
0271   vector<L1GctRegion> blankRegionsVec(numInputRegions);
0272   vector<L1GctJet> blankJetsVec(numOutputJets);
0273 
0274   //Test that all the vectors/values are empty/zero
0275   if (compareRegionsVectors(outputRegions, blankRegionsVec, "input regions reset") &&
0276       compareJetsVectors(outputJets, blankJetsVec, "output jets reset") && outputHt == 0 && outputEt == 0) {
0277     cout << "\nTest class has passed reset method testing." << endl;
0278   } else {
0279     cout << "\nTest class has FAILED reset method testing!" << endl;
0280     testPass = false;
0281   }
0282 
0283   //Print overall results summary to screen
0284   if (testPass) {
0285     cout << "\n*************************************" << endl;
0286     cout << "      Class has passed testing." << endl;
0287     cout << "*************************************" << endl;
0288   } else {
0289     cout << "\n*************************************" << endl;
0290     cout << "      Class has FAILED testing!" << endl;
0291     cout << "*************************************" << endl;
0292   }
0293 
0294   return;
0295 }
0296 
0297 // Loads test input regions from a text file.
0298 void loadTestData(
0299     RegionsVector &inputRegions, RawJetsVector &trueJets, ULong &trueHt, ULong &stripSum0, ULong &stripSum1) {
0300   // File input stream
0301   ifstream fin;
0302 
0303   safeOpenInputFile(fin, testDataFile);  //open the file
0304 
0305   putRegionsInVector(fin, inputRegions, numInputRegions);  //How many input regions? See global constants.
0306   putJetsInVector(fin, trueJets, numOutputJets);           //How many?? See global constants.
0307 
0308   if (fin.eof() || fin.bad()) {
0309     throw std::runtime_error("Error reading Ht data from " + testDataFile + "!");
0310   } else {
0311     fin >> trueHt;
0312     fin >> stripSum0;
0313     fin >> stripSum1;
0314   }
0315 
0316   fin.close();
0317 
0318   return;
0319 }
0320 
0321 // Function to safely open input files of any name, using a referenced return ifstream
0322 void safeOpenInputFile(ifstream &fin, const string name) {
0323   //Opens the file
0324   fin.open(name.c_str(), ios::in);
0325 
0326   //Throw an exception if something is wrong
0327   if (!fin.good()) {
0328     throw cms::Exception("FileReadError") << "Couldn't open the file " << name << " for reading!\n";
0329   }
0330   return;
0331 }
0332 
0333 // Function to safely open output files of any name, using a referenced return ofstream
0334 void safeOpenOutputFile(ofstream &fout, const string name) {
0335   //Opens the file
0336   fout.open(name.c_str(), ios::trunc);
0337 
0338   //Throw an exception if something is wrong
0339   if (!fout.good()) {
0340     throw cms::Exception("FileWriteError") << "Couldn't open the file " << name << " for writing!\n";
0341   }
0342   return;
0343 }
0344 
0345 //Reads regions from file and pushes the specified number into a vector of regions
0346 void putRegionsInVector(ifstream &fin, RegionsVector &regions, const int numRegions) {
0347   for (int i = 0; i < numRegions; ++i) {
0348     regions.push_back(readSingleRegion(fin));
0349   }
0350 }
0351 
0352 //Gets the data of a single region from the testDataFile (reasonably safely).
0353 L1GctRegion readSingleRegion(ifstream &fin) {
0354   //Represents how many numbers there are per line for a region in the input file
0355   const int numRegionComponents = 6;  //the id, et, overFlow, tauVeto, mip, quiet, tauVeto.
0356 
0357   ULong regionComponents[numRegionComponents];
0358 
0359   for (int i = 0; i < numRegionComponents; ++i) {
0360     //check to see if the input stream is still ok first
0361     if (fin.eof() || fin.bad()) {
0362       throw cms::Exception("FileReadError") << "Error reading region data from " << testDataFile << "!\n";
0363     } else {
0364       fin >> regionComponents[i];  //read in the components.
0365     }
0366   }
0367 
0368   // First input value is position in JetFinder array.
0369   // Convert to eta and phi in global coordinates.
0370   // Give the two central columns (out of four) the
0371   // (phi, eta) values corresponding to the required RCT crate number.
0372   // These depend on the jetfinder number to be tested
0373   static const unsigned COL_OFFSET = L1GctJetFinderBase::COL_OFFSET;
0374   static const unsigned NEXTRA = L1GctJetFinderBase::N_EXTRA_REGIONS_ETA00;
0375   unsigned localEta = regionComponents[0] % COL_OFFSET;
0376   unsigned localPhi = regionComponents[0] / COL_OFFSET;
0377   unsigned ieta = ((jfNumber < 9) ? (10 + NEXTRA - localEta) : (11 - NEXTRA + localEta));
0378   ;
0379   unsigned phiOffset = 43 - 2 * jfNumber;
0380   unsigned iphi = (phiOffset - localPhi) % 18;
0381   //return object
0382   L1CaloRegion tempRegion(regionComponents[1],
0383                           static_cast<bool>(regionComponents[2]),
0384                           static_cast<bool>(regionComponents[3]),
0385                           static_cast<bool>(regionComponents[4]),
0386                           static_cast<bool>(regionComponents[5]),
0387                           ieta,
0388                           iphi);
0389 
0390   return L1GctRegion::makeJfInputRegion(tempRegion);
0391 }
0392 
0393 //Reads jets from file and pushes the specified number into a vector of jets
0394 void putJetsInVector(ifstream &fin, RawJetsVector &jets, const int numJets) {
0395   for (int i = 0; i < numJets; ++i) {
0396     jets.push_back(readSingleJet(fin));
0397   }
0398 }
0399 
0400 //Gets the data of a single jet from the testDataFile (reasonably safely).
0401 L1GctJet readSingleJet(ifstream &fin) {
0402   //This reperesents how many numbers there are per line for a jet in the input file
0403   const int numJetComponents = 4;  //4 since we have rank, eta, phi & tauVeto.
0404 
0405   ULong jetComponents[numJetComponents];
0406 
0407   //read in the data from the file
0408   for (int i = 0; i < numJetComponents; ++i) {
0409     //check to see if the input stream is still ok first
0410     if (fin.eof() || fin.bad()) {
0411       throw cms::Exception("FileReadError") << "Error reading jet data from " << testDataFile << "!\n";
0412     } else {
0413       fin >> jetComponents[i];  //read in the components.
0414     }
0415   }
0416 
0417   //return object
0418   // Arguments to ctor are: rank, eta, phi, overFlow, forwardJet, tauVeto, bx
0419   L1GctJet tempJet(jetComponents[0],
0420                    jetComponents[1],
0421                    jetComponents[2],
0422                    false,
0423                    ((jetComponents[1] < 4) || (jetComponents[1] >= 18)),
0424                    static_cast<bool>(jetComponents[3]),
0425                    0);
0426   return tempJet;
0427 }
0428 
0429 // Compares RegionsVectors, prints a message about the comparison, returns true if identical, else false.
0430 bool compareRegionsVectors(RegionsVector &vector1, RegionsVector &vector2, const string description) {
0431   bool testPass = true;
0432 
0433   if (vector1.size() != vector2.size())  //First check overall size is the same
0434   {
0435     testPass = false;
0436   } else {
0437     if (!vector1.empty())  //make sure it isn't empty
0438     {
0439       //compare the vectors
0440       for (ULong i = 0; i < vector1.size(); ++i) {
0441         if (vector1[i].id() != vector2[i].id()) {
0442           testPass = false;
0443           break;
0444         }
0445         if (vector1[i].et() != vector2[i].et()) {
0446           testPass = false;
0447           break;
0448         }
0449         if (vector1[i].overFlow() != vector2[i].overFlow()) {
0450           testPass = false;
0451           break;
0452         }
0453         if (vector1[i].tauVeto() != vector2[i].tauVeto()) {
0454           testPass = false;
0455           break;
0456         }
0457         if (vector1[i].mip() != vector2[i].mip()) {
0458           testPass = false;
0459           break;
0460         }
0461         if (vector1[i].quiet() != vector2[i].quiet()) {
0462           testPass = false;
0463           break;
0464         }
0465       }
0466     }
0467   }
0468 
0469   //Print results to screen
0470   if (testPass == false) {
0471     cout << "\nTest class has FAILED " << description << " comparison!" << endl;
0472     return false;
0473   } else {
0474     cout << "\nTest class has passed " << description << " comparison." << endl;
0475   }
0476   return true;
0477 }
0478 
0479 // Compares RawJetsVectors, prints a message about the comparison, returns true if identical, else false.
0480 bool compareJetsVectors(RawJetsVector &vector1, RawJetsVector &vector2, const string description) {
0481   bool testPass = true;
0482 
0483   if (vector1.size() != vector2.size())  //First check overall size is the same
0484   {
0485     cout << "Failed size comparison\n";
0486     testPass = false;
0487   } else {
0488     if (!vector1.empty())  //Make sure it isn't empty
0489     {
0490       //compare the vectors
0491       for (unsigned int i = 0; i < vector1.size(); ++i) {
0492         if (vector1[i].rawsum() != vector2[i].rawsum()) {
0493           cout << "Jet " << i << " Failed rawsum comparison -- ";
0494           cout << "first " << vector1[i].rawsum() << " second " << vector2[i].rawsum() << "\n";
0495           testPass = false;
0496         }
0497         if (vector1[i].rctEta() != vector2[i].rctEta()) {
0498           cout << "Jet " << i << " Failed rctEta comparison\n";
0499           testPass = false;
0500         }
0501         if (vector1[i].rctPhi() != vector2[i].rctPhi()) {
0502           cout << "Jet " << i << " Failed rctPhi comparison\n";
0503           testPass = false;
0504         }
0505         if (vector1[i].tauVeto() != vector2[i].tauVeto()) {
0506           cout << "Jet " << i << " Failed tauV comparison\n";
0507           testPass = false;
0508         }
0509       }
0510     }
0511   }
0512 
0513   //Print results to screen
0514   if (testPass == false) {
0515     cout << "\nTest class has FAILED " << description << " comparison!" << endl;
0516     return false;
0517   } else {
0518     cout << "\nTest class has passed " << description << " comparison." << endl;
0519   }
0520   return true;
0521 }
0522 
0523 // Writes out the entire contents of a RegionsVector to the given file output stream
0524 void outputRegionsVector(ofstream &fout, RegionsVector &regions, string description) {
0525   fout << description << endl;  //brief description of the RegionsVector content
0526 
0527   if (!regions.empty())  //check it isn't an empty vector
0528   {
0529     for (unsigned int i = 0; i < regions.size(); ++i) {
0530       fout << regions[i].et() << "\t" << regions[i].gctEta() << "\t" << regions[i].gctPhi() << "\t"
0531            << regions[i].overFlow() << "\t" << regions[i].tauVeto() << "\t" << regions[i].mip() << "\t"
0532            << regions[i].quiet() << endl;
0533     }
0534   }
0535   fout << endl;  //write a blank line to separate data
0536 }
0537 
0538 // Writes out the entire contents of a JetsVector to the given file output stream
0539 void outputJetsVector(ofstream &fout, RawJetsVector &jets, string description) {
0540   fout << description << endl;  //brief description for each JetsVector content
0541 
0542   if (!jets.empty())  //check it isn't an empty vector
0543   {
0544     for (unsigned int i = 0; i < jets.size(); ++i) {
0545       fout << jets[i].rawsum() << "\t" << jets[i].globalEta() << "\t" << jets[i].globalPhi() << "\t"
0546            << jets[i].tauVeto() << endl;
0547     }
0548   }
0549   fout << endl;  //write a blank line to separate data
0550 }