| 1 | /** | 
| 2 | * OrbitalRate | 
| 3 | * author  Nagni | 
| 4 | * version 1.0 - 27 April 2006 | 
| 5 | * | 
| 6 | * version 2.0 | 
| 7 | * author De Simone | 
| 8 | * - most of the code rewritten | 
| 9 | * - added graphs, magnetic field, new overflow resolution (AC), tle | 
| 10 | * stuff. | 
| 11 | * | 
| 12 | */ | 
| 13 | #include <physics/anticounter/AnticounterEvent.h> | 
| 14 | #include <physics/trigger/TriggerEvent.h> | 
| 15 | #include <physics/neutronDetector/NeutronEvent.h> | 
| 16 | #include "physics/neutronDetector/NeutronRecord.h" | 
| 17 | #include <mcmd/McmdEvent.h> | 
| 18 | #include <mcmd/McmdRecord.h> | 
| 19 | #include <EventHeader.h> | 
| 20 | #include <PscuHeader.h> | 
| 21 | #include <TTree.h> | 
| 22 | #include "sgp4.h" | 
| 23 | #include "TH2F.h" | 
| 24 | #include "TFrame.h" | 
| 25 | #include "TGraph.h" | 
| 26 | #include "TCanvas.h" | 
| 27 | #include "TASImage.h" | 
| 28 | #include <TDatime.h> | 
| 29 | #include <TFile.h> | 
| 30 |  | 
| 31 | #include <TTimeStamp.h> | 
| 32 | #include "TString.h" | 
| 33 | #include "TObjString.h" | 
| 34 | #include "TStyle.h" | 
| 35 | #include "TPaletteAxis.h" | 
| 36 | #include "TROOT.h" | 
| 37 | #include <sys/stat.h> | 
| 38 | #include <fstream> | 
| 39 | #include <iostream> | 
| 40 |  | 
| 41 | #include <OrbitalRate.h> | 
| 42 |  | 
| 43 | using namespace std; | 
| 44 |  | 
| 45 | int main(int argc, char* argv[]){ | 
| 46 | TString *rootFile = NULL; | 
| 47 | TString outDir  = "./"; | 
| 48 | TString mapFile = ""; | 
| 49 | TString tleFile = ""; | 
| 50 | int offDate = 20060928; | 
| 51 | //  int offDate = 20060614; | 
| 52 | int offTime = 210000; | 
| 53 |  | 
| 54 | if (argc < 2){ | 
| 55 | printf("You have to insert at least the file to analyze and the mapFile \n"); | 
| 56 | printf("Try '--help' for more information. \n"); | 
| 57 | exit(1); | 
| 58 | } | 
| 59 |  | 
| 60 | if (!strcmp(argv[1], "--help")){ | 
| 61 | printf( "Usage: OrbitRate FILE -map mapFile [OPTION] \n"); | 
| 62 | printf( "mapFile have to be a mercator map image [gif|jpg|png] \n"); | 
| 63 | printf( "\t --help                 Print this help and exit \n"); | 
| 64 | printf( "\t -tle[File path]         Path where to find the tle infos \n"); | 
| 65 | printf( "\t\tUse the script retrieve_TLE.sh to create the file.\n "); | 
| 66 | printf( "\t -outDir[path]          Path where to put the output.\n"); | 
| 67 | printf( "\t -offDate               Date of resetting of the Resource counter [format YYMMDD (UTC date) default 20060928] \n"); | 
| 68 | printf( "\t -offTime               Time of resetting of the Resource counter [format HHMMSS (UTC date) default 210000] \n"); | 
| 69 | exit(1); | 
| 70 | } | 
| 71 |  | 
| 72 | // Ok, here we should have at least one root file.  We check that | 
| 73 | // the filename contains ".root". | 
| 74 | if(strstr(argv[1], ".root")) | 
| 75 | rootFile = new TString(argv[1]); | 
| 76 | else { | 
| 77 | cerr << "OrbitalRate: no root file." << endl << "See --help" << endl; | 
| 78 | exit(EXIT_FAILURE); | 
| 79 | } | 
| 80 |  | 
| 81 | for (int i = 2; i < argc; i++){ | 
| 82 | if (!strcmp(argv[i], "-outDir")){ | 
| 83 | if (++i >= argc){ | 
| 84 | printf( "-outDir needs arguments. \n"); | 
| 85 | printf( "Try '--help' for more information. \n"); | 
| 86 | exit(1); | 
| 87 | } else { | 
| 88 | outDir = argv[i]; | 
| 89 | continue; | 
| 90 | } | 
| 91 | } | 
| 92 |  | 
| 93 | if (!strcmp(argv[i], "-tle")){ | 
| 94 | if (++i >= argc){ | 
| 95 | printf( "-tle needs arguments. \n"); | 
| 96 | printf( "Try '--help' for more information. \n"); | 
| 97 | exit(1); | 
| 98 | } else { | 
| 99 | tleFile = argv[i]; | 
| 100 | continue; | 
| 101 | } | 
| 102 | } | 
| 103 |  | 
| 104 | if (!strcmp(argv[i], "-offTime")){ | 
| 105 | if (++i >= argc){ | 
| 106 | printf( "-offTime needs arguments. \n"); | 
| 107 | printf( "Try '--help' for more information. \n"); | 
| 108 | exit(1); | 
| 109 | } | 
| 110 | else{ | 
| 111 | offTime = atol(argv[i]); | 
| 112 | continue; | 
| 113 | } | 
| 114 | } | 
| 115 |  | 
| 116 | if (!strcmp(argv[i], "-offDate")){ | 
| 117 | if (++i >= argc){ | 
| 118 | printf( "-offDate needs arguments. \n"); | 
| 119 | printf( "Try '--help' for more information. \n"); | 
| 120 | exit(1); | 
| 121 | } | 
| 122 | else{ | 
| 123 | offDate = atol(argv[i]); | 
| 124 | continue; | 
| 125 | } | 
| 126 | } | 
| 127 |  | 
| 128 | if (!strcmp(argv[i], "-map")){ | 
| 129 | if (++i >= argc){ | 
| 130 | printf( "-map needs arguments. \n"); | 
| 131 | printf( "Try '--help' for more information. \n"); | 
| 132 | exit(1); | 
| 133 | } else { | 
| 134 | mapFile = argv[i]; | 
| 135 | continue; | 
| 136 | } | 
| 137 | } | 
| 138 | } | 
| 139 |  | 
| 140 | if (mapFile != ""){ | 
| 141 | Rate(rootFile, outDir, mapFile, tleFile, offDate, offTime); | 
| 142 | } else { | 
| 143 | printf("You have to insert at least the file to analyze and the mapFile \n"); | 
| 144 | printf("Try '--help' for more information. \n"); | 
| 145 | } | 
| 146 | } | 
| 147 |  | 
| 148 |  | 
| 149 | void InitStyle() { | 
| 150 | gROOT->SetStyle("Plain"); | 
| 151 |  | 
| 152 | TStyle *myStyle[2], *tempo; | 
| 153 | myStyle[0]=new TStyle("StyleWhite", "white"); | 
| 154 | myStyle[1]=new TStyle("StyleBlack", "black"); | 
| 155 |  | 
| 156 | tempo=gStyle; | 
| 157 | Int_t linecol, bkgndcol, histcol; | 
| 158 |  | 
| 159 | for(Int_t style=0; style<2; style++) { | 
| 160 |  | 
| 161 | linecol=kWhite*style+kBlack*(1-style); | 
| 162 | bkgndcol=kBlack*style+kWhite*(1-style); | 
| 163 | histcol=kYellow*style+kBlack*(1-style); // was 95 | 
| 164 |  | 
| 165 | myStyle[style]->Copy(*tempo); | 
| 166 |  | 
| 167 | myStyle[style]->SetCanvasBorderMode(0); | 
| 168 | myStyle[style]->SetCanvasBorderSize(1); | 
| 169 | myStyle[style]->SetFrameBorderSize(1); | 
| 170 | myStyle[style]->SetFrameBorderMode(0); | 
| 171 | myStyle[style]->SetPadBorderSize(1); | 
| 172 | myStyle[style]->SetStatBorderSize(1); | 
| 173 | myStyle[style]->SetTitleBorderSize(1); | 
| 174 | myStyle[style]->SetPadBorderMode(0); | 
| 175 | myStyle[style]->SetPalette(1,0); | 
| 176 | myStyle[style]->SetPaperSize(20,27); | 
| 177 | myStyle[style]->SetFuncColor(kRed); | 
| 178 | myStyle[style]->SetFuncWidth(1); | 
| 179 | myStyle[style]->SetLineScalePS(1); | 
| 180 | myStyle[style]->SetCanvasColor(bkgndcol); | 
| 181 | myStyle[style]->SetAxisColor(linecol,"XYZ"); | 
| 182 | myStyle[style]->SetFrameFillColor(bkgndcol); | 
| 183 | myStyle[style]->SetFrameLineColor(linecol); | 
| 184 | myStyle[style]->SetLabelColor(linecol,"XYZ"); | 
| 185 | myStyle[style]->SetPadColor(bkgndcol); | 
| 186 | myStyle[style]->SetStatColor(bkgndcol); | 
| 187 | myStyle[style]->SetStatTextColor(linecol); | 
| 188 | myStyle[style]->SetTitleColor(linecol,"XYZ"); | 
| 189 | myStyle[style]->SetTitleFillColor(bkgndcol); | 
| 190 | myStyle[style]->SetTitleTextColor(linecol); | 
| 191 | myStyle[style]->SetLineColor(linecol); | 
| 192 | myStyle[style]->SetMarkerColor(histcol); | 
| 193 | myStyle[style]->SetTextColor(linecol); | 
| 194 |  | 
| 195 | myStyle[style]->SetGridColor((style)?13:kBlack); | 
| 196 | myStyle[style]->SetHistFillStyle(1001*(1-style)); | 
| 197 | myStyle[style]->SetHistLineColor(histcol); | 
| 198 | myStyle[style]->SetHistFillColor((style)?bkgndcol:kYellow); | 
| 199 |  | 
| 200 | myStyle[style]->SetOptStat(0); // Remove statistic summary | 
| 201 | } | 
| 202 |  | 
| 203 | myStyle[1]->cd(); | 
| 204 |  | 
| 205 | gROOT->ForceStyle(); | 
| 206 |  | 
| 207 | } | 
| 208 |  | 
| 209 |  | 
| 210 | void Rate(TString *filename, TString outDirectory = "", TString mapFile = "", TString tleFile = "", int offDate = 20060614, int offTime = 210000) | 
| 211 | { | 
| 212 | // **** Offset to temporarily correct the TDatime bug ****/ | 
| 213 | offTime += 10000; | 
| 214 | //********************************************************/ | 
| 215 |  | 
| 216 | TTree                  *tr         = 0; | 
| 217 | TFile *rootFile; | 
| 218 | FILE *f; | 
| 219 |  | 
| 220 | pamela::McmdEvent      *mcmdev     = 0; | 
| 221 | pamela::McmdRecord     *mcmdrc     = 0; | 
| 222 | pamela::EventHeader    *eh         = 0; | 
| 223 | pamela::PscuHeader     *ph       = 0; | 
| 224 | TArrayC                *mcmddata; | 
| 225 | ULong64_t nevents = 0; | 
| 226 | stringstream  oss; | 
| 227 |  | 
| 228 | Float_t timesync = 0, obt_timesync = 0; | 
| 229 | Long64_t offsetTime = 0; | 
| 230 | Long64_t timeElapsedFromTLE = 0; | 
| 231 | Long64_t deltaTime = 0, oldtimeElapsedFromTLE = 0; | 
| 232 | bool a_second_is_over; | 
| 233 |  | 
| 234 | Float_t lon, lat, alt; | 
| 235 |  | 
| 236 | vector<Double_t> vector_trigAndOr; | 
| 237 | vector<Double_t> vector_trigAndAnd; | 
| 238 | vector<Double_t> vector_trigS11andS12; | 
| 239 | vector<Double_t> vector_trigS12andS21andS22; | 
| 240 | vector<Double_t> vector_trigS111A; | 
| 241 |  | 
| 242 | double mean_trigAndOr; | 
| 243 | double mean_trigAndAnd; | 
| 244 | double mean_trigS11andS12; | 
| 245 | double mean_trigS12andS21andS22; | 
| 246 | double mean_trigS111A; | 
| 247 |  | 
| 248 | // We'll use this size for the generated images. | 
| 249 | TImage *tImage=TImage::Open(mapFile); | 
| 250 | int width=(int)(tImage->GetWidth()*0.80); | 
| 251 | int height=(int)(tImage->GetHeight()*0.80); | 
| 252 | delete tImage; | 
| 253 |  | 
| 254 | // This histogram will store time (in seconds) spent in each bin. | 
| 255 | TH2F *obtBinTime = new TH2F("obtBinTime", "Time of acquisition of background data", 360, -180, 180, 180, -90, 90); | 
| 256 |  | 
| 257 | // Now I create histograms longitude x latitude to hold values.  I | 
| 258 | // use the suffix _counter to say that this values are what I read | 
| 259 | // from Pamela and they are not normalized in any way. | 
| 260 |  | 
| 261 | // This historam will store the number of events occurred in each bin. | 
| 262 | TH2F *event_counter = new TH2F("event_counter", "Event rate", 360, -180, 180, 180, -90, 90); | 
| 263 | TH2F *nd_counter = new TH2F("nd_counter", "Upper background neutrons", 360, -180, 180, 180, -90, 90); | 
| 264 | TH2F *antiCAS4_counter = new TH2F("CAS4_counter", "CAS4 rate", 360, -180, 180, 180, -90, 90); | 
| 265 | TH2F *antiCAS3_counter = new TH2F("CAS3_counter", "CAS3 rate", 360, -180, 180, 180, -90, 90); | 
| 266 | TH2F *trigAndOr_counter = new TH2F("trigAndOr_counter", "Rate of triggering in (S11+S12)*(S21+S22)*(S31+S32) configuration", 360, -180, 180, 180, -90, 90); | 
| 267 | TH2F *trigAndAnd_counter = new TH2F("trigAndAnd_counter", "Rate of triggering in (S11*S12)*(S21*S22)*(S31*S32) configuration", 360, -180, 180, 180, -90, 90); | 
| 268 | TH2F *trigS11andS12_counter = new TH2F("trigS11andS12_counter", "Rate of S1 triggers", 360, -180, 180, 180, -90, 90); //(S11+S12) | 
| 269 | TH2F *trigS12andS21andS22_counter = new TH2F("trigS12andS21andS22_counter", "Rate of S11*S21*S21 triggers", 360, -180, 180, 180, -90, 90); //(S11*S12*S21) | 
| 270 | TH2F *trigS111A_counter = new TH2F("trigS111A_counter", "Rate of S111A counts", 360, -180, 180, 180, -90, 90); //(S111A) | 
| 271 |  | 
| 272 | // Magnetic field histograms.  I use always the suffix _counter | 
| 273 | // because they are not normalized.  Imagine that an instrument | 
| 274 | // give us the value of the magnetic field for each event. | 
| 275 | TH2F *hbabs_counter = new TH2F("hbabs_counter", "B module", 360, -180, 180, 180, -90, 90); | 
| 276 | TH2F *hbnorth_counter = new TH2F("hbnorth_counter", "B north", 360, -180, 180, 180, -90, 90); | 
| 277 | TH2F *hbdown_counter = new TH2F("hbdown_counter", "B down", 360, -180, 180, 180, -90, 90); | 
| 278 | TH2F *hbeast_counter = new TH2F("hbeast_counter", "B east", 360, -180, 180, 180, -90, 90); | 
| 279 | TH2F *hb0_counter = new TH2F("hb0_counter", "B_0", 360, -180, 180, 180, -90, 90); | 
| 280 | TH2F *hl_counter = new TH2F("hl_counter", "l", 360, -180, 180, 180, -90, 90); | 
| 281 |  | 
| 282 | // Get a char* to "file" from "/dir1/dir2/.../file.root" | 
| 283 | TString basename; | 
| 284 | basename = ((TObjString*) filename->Tokenize('/')->Last())->GetString(); // we get file.root | 
| 285 | basename = ((TObjString*)basename.Tokenize('.')->First())->GetString(); // we get file | 
| 286 |  | 
| 287 | // Exit if the map file doesn't exist. | 
| 288 | if(! (f = fopen(mapFile.Data(), "r")) ) { | 
| 289 | cerr << "Error: the file " << mapFile.Data() << " does not exists." << endl; | 
| 290 | exit(EXIT_FAILURE); | 
| 291 | } | 
| 292 |  | 
| 293 | // Open the root file. | 
| 294 | rootFile = new TFile(filename->Data()); | 
| 295 | if (rootFile->IsZombie()) { | 
| 296 | printf("The file %s does not exist\n", (filename->Data())); | 
| 297 | exit(EXIT_FAILURE); | 
| 298 | } | 
| 299 |  | 
| 300 | // Look for a timesync in the TFile rootFile.  We also get the obt | 
| 301 | // of the timesync mcmd. | 
| 302 | bool err; | 
| 303 | err = lookforTimesync(rootFile, ×ync, &obt_timesync); | 
| 304 | if(!err) { | 
| 305 | cerr << "Warning!!! No timesync info has been found in the file " | 
| 306 | << filename->Data() << endl; | 
| 307 | exit(EXIT_FAILURE); | 
| 308 | } | 
| 309 |  | 
| 310 | //Get the Julian date of the Resours offset | 
| 311 | TDatime offRes = TDatime(offDate, offTime); | 
| 312 | // Add to the Resours Offset the timesync.  This is now the date at | 
| 313 | // the moment of the timesync. | 
| 314 | offRes.Set(offRes.Convert() + (UInt_t) timesync); | 
| 315 |  | 
| 316 | // Now I need a pointer to a cTle object.  The class misses a | 
| 317 | // constructor without arguments, so we have to give it a dummy TLE. | 
| 318 | string str1 = "RESURS-DK 1"; | 
| 319 | string str2 = "1 29228U 06021A   06170.19643714  .00009962  00000-0  21000-3 0   196"; | 
| 320 | string str3 = "2 29228 069.9363 054.7893 0167576 127.4359 017.0674 15.31839265   604"; | 
| 321 | cTle *tle1 = new cTle(str1, str2, str3); | 
| 322 |  | 
| 323 | // If we have to use a TLE file, call getTle(). | 
| 324 | if (tleFile != "") | 
| 325 | tle1 = getTle(tleFile, offRes); | 
| 326 |  | 
| 327 | cOrbit       orbit(*tle1); | 
| 328 | cEci         eci; | 
| 329 | cCoordGeo    coo; | 
| 330 |  | 
| 331 | // offRes is now "offset date" + timesync.  Now I subtract the obt | 
| 332 | // of the timesync.  Remember that the time of the event from the | 
| 333 | // tle date is: | 
| 334 | // tle date - (offset date + timesync - obt timesync + obt event). | 
| 335 | offRes.Set(offRes.Convert() - (UInt_t) obt_timesync); | 
| 336 |  | 
| 337 | // Get the Julian date of the TLE epoch | 
| 338 | string datetime = getTleDatetime(tle1); | 
| 339 | TDatime tledate = TDatime(datetime.c_str()); | 
| 340 |  | 
| 341 | cJulian jdatetime = cJulian((int) (tle1->getField(cTle::FLD_EPOCHYEAR)+2e3), tle1->getField(cTle::FLD_EPOCHDAY)); | 
| 342 | int pYear, pMon; double pDOM; | 
| 343 | jdatetime.getComponent(&pYear, &pMon, &pDOM); | 
| 344 |  | 
| 345 | offsetTime = ((Long64_t) offRes.Convert() - (Long64_t) tledate.Convert()); | 
| 346 |  | 
| 347 | /********** Magnetic Field **************/ | 
| 348 | // Check that all this is correct! | 
| 349 | float br, btheta, bphi; | 
| 350 |  | 
| 351 | // I can now compute the magnetic dipole moment at the actual date, | 
| 352 | // using the cJulian date.  I don't to recompute it for every event | 
| 353 | // beacause changes are not relevant at all. | 
| 354 | Int_t y = tledate.GetYear(); | 
| 355 | Int_t m = tledate.GetMonth(); | 
| 356 | Int_t d = tledate.GetDay(); | 
| 357 | float year = (float) y + (m*31+d)/365; | 
| 358 |  | 
| 359 | // Initialize common data for geopack | 
| 360 | recalc_(y, m*31+d, 0, 0, 0); | 
| 361 | /********** Magnetic Field **************/ | 
| 362 |  | 
| 363 | tr = (TTree*)rootFile->Get("Physics"); | 
| 364 | TBranch *headBr = tr->GetBranch("Header"); | 
| 365 | tr->SetBranchAddress("Header", &eh); | 
| 366 |  | 
| 367 | /********** Anticounter **************/ | 
| 368 | pamela::anticounter::AnticounterEvent *antiev = 0; | 
| 369 | tr->SetBranchAddress("Anticounter", &antiev); | 
| 370 |  | 
| 371 | Int_t oldCAS4 = 0; | 
| 372 | Int_t diffCAS4 = 0; | 
| 373 | Int_t oldCAS3 = 0; | 
| 374 | Int_t diffCAS3 = 0; | 
| 375 | /********** Anticounter **************/ | 
| 376 |  | 
| 377 | /********** Trigger **************/ | 
| 378 | pamela::trigger::TriggerEvent *trigger   = 0; | 
| 379 | tr->SetBranchAddress("Trigger", &trigger); | 
| 380 |  | 
| 381 | Int_t oldtrigAndOr = 0; | 
| 382 | Int_t oldtrigAndAnd = 0; | 
| 383 | Int_t oldtrigS11andS12 = 0; | 
| 384 | Int_t oldtrigS12andS21andS22 = 0; | 
| 385 | Int_t oldtrigS111A = 0; | 
| 386 | /********** Trigger **************/ | 
| 387 |  | 
| 388 | /********** ND **************/ | 
| 389 | Int_t    tmpSize=0; | 
| 390 | Int_t    sumTrig=0; | 
| 391 | Int_t    sumUpperBackground=0; | 
| 392 | Int_t    sumBottomBackground=0; | 
| 393 |  | 
| 394 | pamela::neutron::NeutronRecord *nr = 0; | 
| 395 | pamela::neutron::NeutronEvent *ne = 0; | 
| 396 | tr->SetBranchAddress("Neutron", &ne); | 
| 397 | /********** ND **************/ | 
| 398 |  | 
| 399 | nevents = tr->GetEntries(); | 
| 400 |  | 
| 401 | for(UInt_t i = 0; i < nevents; i++) //Fill variables from root-ple | 
| 402 | { | 
| 403 | tr->GetEntry(i); | 
| 404 | ph = eh->GetPscuHeader(); | 
| 405 |  | 
| 406 | // obt in ms | 
| 407 | ULong64_t obt = ph->GetOrbitalTime(); | 
| 408 |  | 
| 409 | // timeElapsedFromTLE is the difference, in seconds, between the | 
| 410 | // event and the tle date.  I use seconds and not milliseconds | 
| 411 | // because the indetermination on the timesync is about 1s. | 
| 412 | timeElapsedFromTLE = offsetTime + obt/1000; | 
| 413 |  | 
| 414 | // I also need the abstime in seconds rounded to the lower | 
| 415 | // value.  Every second, we set a_second_is_over to true.  Only | 
| 416 | // in this case histograms with triggers are filled. | 
| 417 | a_second_is_over = (timeElapsedFromTLE > oldtimeElapsedFromTLE) ? 1 : 0; | 
| 418 | oldtimeElapsedFromTLE = timeElapsedFromTLE; | 
| 419 |  | 
| 420 | // I need the acquisition time between two triggers to fill the | 
| 421 | // obtBinTime (histo of time spent in the bin).  The time is in | 
| 422 | // second. | 
| 423 | deltaTime = timeElapsedFromTLE - oldtimeElapsedFromTLE; | 
| 424 | oldtimeElapsedFromTLE = timeElapsedFromTLE; | 
| 425 |  | 
| 426 | // Finally, we get coordinates from absolute time the orbit | 
| 427 | // object initialised with the TLE data.  cOrbit::getPosition() | 
| 428 | // requires the elapased time from the tle in minutes. | 
| 429 | // Coordinates are stored in the structure eci. | 
| 430 | orbit.getPosition(((double) timeElapsedFromTLE)/60., &eci); | 
| 431 | coo = eci.toGeo(); | 
| 432 |  | 
| 433 | /********** ND **************/ | 
| 434 | // Summing over all stored pamela::neutron::NeutronRecords in | 
| 435 | // this event *ne. | 
| 436 | for(Int_t j = 0; j < ne->Records->GetEntries(); j++) { | 
| 437 | nr = (pamela::neutron::NeutronRecord*)ne->Records->At(j); | 
| 438 | sumTrig += (int)nr->trigPhysics; | 
| 439 | sumUpperBackground += (int)nr->upperBack; | 
| 440 | sumBottomBackground += (int)nr->bottomBack; | 
| 441 | } | 
| 442 | /********** ND **************/ | 
| 443 |  | 
| 444 | /********** Anticounter **************/ | 
| 445 | // Get the difference between the actual counter and the | 
| 446 | // previous counter for anticoincidence, dealing with the | 
| 447 | // overflow with solve_ac_overflow(). | 
| 448 | diffCAS4 = solve_ac_overflow(oldCAS4, antiev->counters[0][6]); | 
| 449 | diffCAS3 = solve_ac_overflow(oldCAS3, antiev->counters[0][10]); | 
| 450 | /********** Anticounter **************/ | 
| 451 |  | 
| 452 | // Build coordinates in the right range.  We want to convert, | 
| 453 | // just for aesthetic, longitude from (0, 2*pi) to (-pi, pi). | 
| 454 | // We also want to convert from radians to degrees. | 
| 455 | lon = (coo.m_Lon > PI) ? rad2deg(coo.m_Lon - 2*PI) : rad2deg(coo.m_Lon); | 
| 456 | lat = rad2deg(coo.m_Lat); | 
| 457 | alt = coo.m_Alt; | 
| 458 |  | 
| 459 | /********** Magnetic Field **************/ | 
| 460 | igrf_geo__((coo.m_Alt+6371.2)/6371.2, M_PI/2.-coo.m_Lat, coo.m_Lon, br, btheta, bphi); | 
| 461 | //      cout<<"("<<(coo.m_Alt+6371.2)/6371.2<<", "<<M_PI/2.-coo.m_Lat<<", "<<coo.m_Lon<<")"<<endl; | 
| 462 | /********** Magnetic Field **************/ | 
| 463 |  | 
| 464 | // serve fare il controllo deltatime < 1? | 
| 465 | if (deltaTime > 1) cout << endl << "******** deltaTime<1 ********" << endl; | 
| 466 | // Does nothing for the first two events or if acquisition time if more | 
| 467 | // than 1s. | 
| 468 | if(i<1 || (deltaTime > 1)) continue; | 
| 469 |  | 
| 470 | // CAS3 and CAS4 are not rates but only counters.  So I fill | 
| 471 | // with the bin with the difference beetween the actual counter | 
| 472 | // and the previous one and then divide with the time (see | 
| 473 | // below) to have rates. | 
| 474 | if(diffCAS3>1e3) // additional cut to avoid the peaks after dead time | 
| 475 | diffCAS3 = (Int_t) antiCAS3_counter->GetBinContent((Int_t)antiCAS3_counter->GetEntries()-1); | 
| 476 | antiCAS3_counter->Fill(lon , lat, diffCAS3); | 
| 477 |  | 
| 478 | if(diffCAS4>1e3) // additional cut to avoid the peaks after dead time | 
| 479 | diffCAS4 = (Int_t) antiCAS4_counter->GetBinContent((Int_t) antiCAS4_counter->GetEntries()-1); | 
| 480 | antiCAS4_counter->Fill(lon, lat, diffCAS4); | 
| 481 |  | 
| 482 | // Magnetic field values should be handled a bit carefully. | 
| 483 | // For every event I get a position and the related magnetic | 
| 484 | // field values.  I can fill the histograms lon x lat with | 
| 485 | // this values but I need to count how many times I fill | 
| 486 | // each bin.  This is done by the histogram event_counter. | 
| 487 | // I will normalize later. | 
| 488 | hbabs_counter->Fill(lon, lat, sqrt(br*br+btheta*btheta+bphi*bphi)*1e-5); | 
| 489 | hbnorth_counter->Fill(lon, lat, -btheta*1e-5); | 
| 490 | hbdown_counter->Fill(lon, lat, -br*1e-5); | 
| 491 | hbeast_counter->Fill(lon, lat, bphi*1e-5); | 
| 492 |  | 
| 493 | // This histograms is now filled with the number of entries. | 
| 494 | // Below we will divide with the time (in seconds) to get | 
| 495 | // event rate per bin. | 
| 496 | event_counter->Fill(lon, lat); | 
| 497 |  | 
| 498 | // counters about triggers are already rates (Hz).  Only | 
| 499 | // every second we fill fill with the mean over all values. | 
| 500 | if(a_second_is_over) { | 
| 501 | // This histograms will hold the time, in seconds, spent | 
| 502 | // in the bin. | 
| 503 | obtBinTime->Fill(lon, lat, 1); | 
| 504 |  | 
| 505 | // get the means | 
| 506 | mean_trigAndOr = getMean(vector_trigAndOr); | 
| 507 | mean_trigAndAnd = getMean(vector_trigAndAnd); | 
| 508 | mean_trigS11andS12 = getMean(vector_trigS11andS12); | 
| 509 | mean_trigS12andS21andS22 = getMean(vector_trigS12andS21andS22); | 
| 510 | mean_trigS111A = getMean(vector_trigS111A); | 
| 511 |  | 
| 512 | // clear data about the last second | 
| 513 | vector_trigAndOr.clear(); | 
| 514 | vector_trigAndAnd.clear(); | 
| 515 | vector_trigS11andS12.clear(); | 
| 516 | vector_trigS12andS21andS22.clear(); | 
| 517 | vector_trigS111A.clear(); | 
| 518 |  | 
| 519 | // Fill with the mean rate value | 
| 520 | trigAndOr_counter->Fill(lon , lat, mean_trigAndOr); | 
| 521 | trigAndAnd_counter->Fill(lon , lat, mean_trigAndAnd); | 
| 522 | trigS11andS12_counter->Fill(lon , lat, mean_trigS11andS12); | 
| 523 | trigS12andS21andS22_counter->Fill(lon , lat, mean_trigS12andS21andS22); | 
| 524 | trigS111A_counter->Fill(lon, lat, mean_trigS111A); | 
| 525 | } | 
| 526 | else { // Collect values for all the second | 
| 527 | vector_trigAndOr.push_back((1/4.)*trigger->trigrate[0]); | 
| 528 | vector_trigAndAnd.push_back((1/4.)*trigger->trigrate[1]); | 
| 529 | // pmtpl[0] is the rate every 60ms but I want Hz. | 
| 530 | vector_trigS11andS12.push_back((1000./60.)*trigger->pmtpl[0]); | 
| 531 | vector_trigS12andS21andS22.push_back((1/4.)*trigger->trigrate[4]); | 
| 532 | vector_trigS111A.push_back(1.*trigger->pmtcount1[0]); | 
| 533 | } | 
| 534 |  | 
| 535 | // Now we discard ND data if: | 
| 536 | // - NeutronEvent is corrupted. | 
| 537 | if((ne->unpackError != 1)) | 
| 538 | nd_counter->Fill(lon, lat, 1.*(sumUpperBackground+sumTrig)); | 
| 539 |  | 
| 540 | // Reset counters for ND. | 
| 541 | sumTrig = 0; | 
| 542 | sumUpperBackground = 0; | 
| 543 | sumBottomBackground = 0; | 
| 544 | } | 
| 545 |  | 
| 546 | // We now need to normalize the histograms to print something | 
| 547 | // meaningful.  I create similar histograms with the suffix _rate or | 
| 548 | // _norm. | 
| 549 | TH2F *event_rate = (TH2F*) event_counter->Clone("event_rate"); | 
| 550 | TH2F *trigS111A_rate = (TH2F*) trigS111A_counter->Clone("trigS111A_rate"); | 
| 551 | TH2F *antiCAS4_rate = (TH2F*) antiCAS4_counter->Clone("antiCAS4_rate"); | 
| 552 | TH2F *antiCAS3_rate = (TH2F*) antiCAS3_counter->Clone("antiCAS3_rate"); | 
| 553 | TH2F *trigS11andS12_rate = (TH2F*) trigS11andS12_counter->Clone("trigS11andS12_rate"); | 
| 554 | TH2F *trigS12andS21andS22_rate = (TH2F*) trigS12andS21andS22_counter->Clone("trigS12andS21andS22_rate"); | 
| 555 | TH2F *trigAndOr_rate = (TH2F*) trigAndOr_counter->Clone("trigAndOr_rate"); | 
| 556 | TH2F *trigAndAnd_rate = (TH2F*) trigAndAnd_counter->Clone("trigAndAnd_rate"); | 
| 557 | TH2F *nd_rate = (TH2F*) nd_counter->Clone("nd_rate"); | 
| 558 | TH2F *hbabs_norm = (TH2F*) hbabs_counter->Clone("hbabs_norm"); | 
| 559 | TH2F *hbnorth_norm = (TH2F*) hbnorth_counter->Clone("hbnorth_norm"); | 
| 560 | TH2F *hbdown_norm = (TH2F*) hbabs_counter->Clone("hbdown_norm"); | 
| 561 | TH2F *hbeast_norm = (TH2F*) hbabs_counter->Clone("hbeast_norm"); | 
| 562 |  | 
| 563 | // Now we divide each histogram _counter with the time histogram | 
| 564 | // obtBinTime to have an histogram _rate.  Note that, when a second | 
| 565 | // is passed in the above cycle, we fill the histogram obtBinTime | 
| 566 | // with 1 (second) together with all the other histograms.  So | 
| 567 | // dividing here does make sense. | 
| 568 | // | 
| 569 | // Then we call printHist() for each filled TH2F.  These are | 
| 570 | // refered to the root file we're now reading.  We also build up a | 
| 571 | // filename to be passed to the function.  Pay attention that the | 
| 572 | // filename must end with a file format (such as .png or .pdf) | 
| 573 | // recognised by TPad::SaveAs(). | 
| 574 | trigS111A_rate->Divide(trigS111A_counter, obtBinTime, 1, 1, ""); | 
| 575 | oss.str(""); | 
| 576 | oss << basename.Data() << "_orbit_trigS111A.png"; | 
| 577 | trigS111A_rate->SetMinimum(9); | 
| 578 | printHist(trigS111A_rate, mapFile, outDirectory, oss.str().c_str(), "S111A (Hz)", -width, height, true, 0); | 
| 579 |  | 
| 580 | antiCAS4_rate->Divide(antiCAS4_counter, obtBinTime, 1, 1, ""); | 
| 581 | oss.str(""); | 
| 582 | oss << basename.Data() << "_orbit_CAS4.png"; | 
| 583 | antiCAS4_rate->SetMinimum(99); | 
| 584 | printHist(antiCAS4_rate, mapFile, outDirectory, oss.str().c_str(), "CAS4 (Hz)", -width, height, true, 0); | 
| 585 |  | 
| 586 | antiCAS3_rate->Divide(antiCAS3_counter, obtBinTime, 1, 1, ""); | 
| 587 | oss.str(""); | 
| 588 | oss << basename.Data() << "_orbit_CAS3.png"; | 
| 589 | antiCAS3_rate->SetMinimum(99); | 
| 590 | printHist(antiCAS3_rate, mapFile, outDirectory, oss.str().c_str(), "CAS3 (Hz)", -width, height, true, 0); | 
| 591 |  | 
| 592 | event_rate->Divide(event_counter, obtBinTime, 1, 1, ""); | 
| 593 | oss.str(""); | 
| 594 | oss << basename.Data() << "_orbit_EventRate.png"; | 
| 595 | printHist(event_rate, mapFile, outDirectory, oss.str().c_str(), "Event rate (Hz)", -width, height, 0, 0); | 
| 596 |  | 
| 597 | trigS11andS12_rate->Divide(trigS11andS12_counter, obtBinTime, 1, 1, ""); | 
| 598 | oss.str(""); | 
| 599 | oss << basename.Data() << "_orbit_trigS11andS12.png"; | 
| 600 | trigS11andS12_rate->SetMinimum(99); | 
| 601 | printHist(trigS11andS12_rate, mapFile, outDirectory, oss.str().c_str(), "(S11*S12) (Hz)", -width, height, 1, 0); | 
| 602 |  | 
| 603 | trigS12andS21andS22_rate->Divide(trigS12andS21andS22_counter, obtBinTime, 1, 1, ""); | 
| 604 | oss.str(""); | 
| 605 | oss << basename.Data() << "_orbit_trigS12andS21andS22.png"; | 
| 606 | trigS12andS21andS22_rate->SetMinimum(9); | 
| 607 | printHist(trigS12andS21andS22_rate, mapFile, outDirectory, oss.str().c_str(), "(S12*S12*S21) (Hz)", -width, height, true, 0); | 
| 608 |  | 
| 609 | trigAndOr_rate->Divide(trigAndOr_counter, obtBinTime, 1, 1, ""); | 
| 610 | oss.str(""); | 
| 611 | oss << basename.Data() << "_orbit_trigANDofOR.png"; | 
| 612 | printHist(trigAndOr_rate, mapFile, outDirectory, oss.str().c_str(), "(S11+S12)*(S21+S22)*(S31+S32) (Hz)", -width, height, 0, 0); | 
| 613 |  | 
| 614 | trigAndAnd_rate->Divide(trigAndAnd_counter, obtBinTime, 1, 1, ""); | 
| 615 | oss.str(""); | 
| 616 | oss << basename.Data() << "_orbit_trigANDofAND.png"; | 
| 617 | printHist(trigAndAnd_rate, mapFile, outDirectory, oss.str().c_str(), "(S11*S12)*(S21*S22)*(S31*S32) (Hz)", -width, height, 0, 0); | 
| 618 |  | 
| 619 | nd_rate->Divide(nd_counter, obtBinTime, 1, 1, ""); | 
| 620 | oss.str(""); | 
| 621 | oss << basename.Data() << "_orbit_ND.png"; | 
| 622 | printHist(nd_rate, mapFile, outDirectory, oss.str().c_str(), "Neutron rate (Hz)", -width, height, 0, 0); | 
| 623 |  | 
| 624 | // Also normalize histograms about magnetic fields.  Beacause we | 
| 625 | // fill the bins with the values of the magnetic field for each | 
| 626 | // event, we need to divide with the number of fills done, that is | 
| 627 | // event_counter. | 
| 628 | hbabs_norm->Divide(hbabs_counter, event_counter, 1, 1, ""); | 
| 629 | oss.str(""); | 
| 630 | oss << basename.Data() << "_orbit_Babs.png"; | 
| 631 | printHist(hbabs_norm, mapFile, outDirectory, oss.str().c_str(), "B abs (G)", -width, height, 0, 0); | 
| 632 |  | 
| 633 | hbnorth_norm->Divide(hbnorth_counter, event_counter, 1, 1, ""); | 
| 634 | oss.str(""); | 
| 635 | oss << basename.Data() << "_orbit_Bnorth.png"; | 
| 636 | printHist(hbnorth_norm, mapFile, outDirectory, oss.str().c_str(), "B north (G)", -width, height, 0, 1); | 
| 637 |  | 
| 638 | hbdown_norm->Divide(hbdown_counter, event_counter, 1, 1, ""); | 
| 639 | oss.str(""); | 
| 640 | oss << basename.Data() << "_orbit_Bdown.png"; | 
| 641 | printHist(hbdown_norm, mapFile, outDirectory, oss.str().c_str(), "B down (G)", -width, height, 0, 1); | 
| 642 |  | 
| 643 | hbeast_norm->Divide(hbeast_counter, event_counter, 1, 1, ""); | 
| 644 | oss.str(""); | 
| 645 | oss << basename.Data() << "_orbit_Beast.png"; | 
| 646 | printHist(hbeast_norm, mapFile, outDirectory, oss.str().c_str(), "B east (G)", -width, height, 0, 1); | 
| 647 |  | 
| 648 |  | 
| 649 | delete obtBinTime; | 
| 650 | delete event_counter; | 
| 651 |  | 
| 652 | delete nd_counter; | 
| 653 | delete antiCAS4_counter; | 
| 654 | delete antiCAS3_counter; | 
| 655 | delete trigAndOr_counter; | 
| 656 | delete trigAndAnd_counter; | 
| 657 | delete trigS11andS12_counter; | 
| 658 | delete trigS111A_counter; | 
| 659 | delete trigS12andS21andS22_counter; | 
| 660 |  | 
| 661 | delete event_rate; | 
| 662 | delete nd_rate; | 
| 663 | delete antiCAS4_rate; | 
| 664 | delete antiCAS3_rate; | 
| 665 | delete trigAndOr_rate; | 
| 666 | delete trigAndAnd_rate; | 
| 667 | delete trigS11andS12_rate; | 
| 668 | delete trigS111A_rate; | 
| 669 | delete trigS12andS21andS22_rate; | 
| 670 |  | 
| 671 | delete hbabs_counter; | 
| 672 | delete hbnorth_counter; | 
| 673 | delete hbdown_counter; | 
| 674 | delete hbeast_counter; | 
| 675 | delete hbabs_norm; | 
| 676 | delete hbnorth_norm; | 
| 677 | delete hbdown_norm; | 
| 678 | delete hbeast_norm; | 
| 679 |  | 
| 680 | rootFile->Close(); | 
| 681 | } | 
| 682 |  | 
| 683 |  | 
| 684 | // Print the istogram *h on the file outputfilename in the direcotry | 
| 685 | // outDirectory, using mapFile as background image, sizing the image | 
| 686 | // width per height.  Log scale will be used if use_log is true. | 
| 687 | // | 
| 688 | // If bool_shift is true a further process is performed to solve a | 
| 689 | // problem with actual root version (5.12).  This should be used when | 
| 690 | // the histrogram is filled also with negative values, because root | 
| 691 | // draws zero filled bins (so I have all the pad colorized and this is | 
| 692 | // really weird!).  To avoid this problem I shift all the values in a | 
| 693 | // positive range and draw again using colz.  Now I will not have zero | 
| 694 | // filled bins painted but the scale will be wrong.  This is why I | 
| 695 | // need to draw a new axis along the palette. | 
| 696 | // | 
| 697 | // Pay attention: you cannot use a mapFile different from the provided | 
| 698 | // one without adjusting the scaling and position of the image (see | 
| 699 | // Scale() and Merge()). | 
| 700 | // | 
| 701 | // This function depends on InitStyle(); | 
| 702 | int printHist(TH2F *h, TString mapFile, TString outDirectory, TString outputFilename, char *title, int width, int height, bool use_log, bool bool_shift) | 
| 703 | { | 
| 704 | InitStyle(); | 
| 705 |  | 
| 706 | // Create a canvas and draw the TH2F with a nice colormap for z | 
| 707 | // values, using log scale for z values, if requested, and setting | 
| 708 | // some title. | 
| 709 | TCanvas *canvas = new TCanvas("h", "h histogram", width*2, height*2); | 
| 710 |  | 
| 711 | if(use_log) canvas->SetLogz(); | 
| 712 |  | 
| 713 | h->SetTitle(title); | 
| 714 | h->SetXTitle("Longitude (deg)"); | 
| 715 | h->SetYTitle("Latitude (deg)"); | 
| 716 | h->SetLabelColor(0, "X"); | 
| 717 | h->SetAxisColor(0, "X"); | 
| 718 | h->SetLabelColor(0, "Y"); | 
| 719 | h->SetAxisColor(0, "Y"); | 
| 720 | h->SetLabelColor(0, "Z"); | 
| 721 | h->SetAxisColor(0, "Z"); | 
| 722 |  | 
| 723 | h->Draw("colz"); | 
| 724 | canvas->Update(); // Update!  Otherwise we can't get any palette. | 
| 725 |  | 
| 726 | // If shift in a positive range required (see comment above). | 
| 727 | if(bool_shift) { | 
| 728 | // Remember the minimum and maximum in this graph. | 
| 729 | Float_t min = h->GetMinimum(); | 
| 730 | Float_t max = h->GetMaximum(); | 
| 731 |  | 
| 732 | // Shift the graph up by 100.  Increase the value if you still get | 
| 733 | // negative filled bins. | 
| 734 | h = shiftHist(h, 100.0); | 
| 735 | h->SetMinimum(min+100.0); | 
| 736 | h->SetMaximum(max+100.0); | 
| 737 |  | 
| 738 | // Hide the current axis of the palette | 
| 739 | TPaletteAxis *palette = (TPaletteAxis*) h->GetListOfFunctions()->FindObject("palette"); | 
| 740 | if(!palette) cout << "palette is null" << endl; | 
| 741 | TGaxis *ax = (TGaxis*) palette->GetAxis(); | 
| 742 | if(!ax) cout << "ax is null" << endl; | 
| 743 | ax->SetLabelOffset(999); | 
| 744 | ax->SetTickSize(0); | 
| 745 |  | 
| 746 | // Create a new axis of the palette using the right min and max and draw it. | 
| 747 | TGaxis *gaxis = new TGaxis(palette->GetX2(), palette->GetY1(), palette->GetX2(), palette->GetY2(), min, max, 510,"+L"); | 
| 748 | gaxis->SetLabelColor(0); | 
| 749 | gaxis->Draw(); | 
| 750 |  | 
| 751 | // Update again. | 
| 752 | canvas->Update(); | 
| 753 | } | 
| 754 |  | 
| 755 | // We merge two images: the image of the earth read from a file on | 
| 756 | // that one of the TPad of canvas (the histogram).  The first one is | 
| 757 | // scaled and adjusted to fit well inside the frame of the second | 
| 758 | // one.  Finally we draw them both. | 
| 759 | // | 
| 760 | // Here there's a trick to avoid blurring during the merging | 
| 761 | // operation.  We get the image from a canvas sized (width*2 x | 
| 762 | // height*2) and draw it on a canvas sized (width x height). | 
| 763 |  | 
| 764 | TCanvas *mergeCanvas = new TCanvas("", "", width, height); | 
| 765 | TImage *img = TImage::Create(); | 
| 766 | TImage *terra = TImage::Create(); | 
| 767 | img->FromPad(canvas); // get the TCanvas canvas as TImage | 
| 768 | terra->ReadImage(mapFile, TImage::kPng); // get the png file as TImage | 
| 769 | terra->Scale(1304,830); | 
| 770 | img->Merge(terra, "add", 166, 112); // add image terra to image img | 
| 771 | img->Draw("X"); // see what we get, eXpanding img all over mergeCanvas. | 
| 772 |  | 
| 773 | stringstream oss; | 
| 774 | oss << outDirectory.Data() << "/" << outputFilename.Data(); | 
| 775 |  | 
| 776 | mergeCanvas->SaveAs(oss.str().c_str()); | 
| 777 | mergeCanvas->Close(); | 
| 778 | canvas->Close(); | 
| 779 |  | 
| 780 | return EXIT_SUCCESS; | 
| 781 | } | 
| 782 |  | 
| 783 | void saveHist(TH1 *h, TString savetorootfile) | 
| 784 | { | 
| 785 | TFile *file = new TFile(savetorootfile.Data(), "update"); | 
| 786 |  | 
| 787 | h->Write(); | 
| 788 | file->Close(); | 
| 789 | } | 
| 790 |  | 
| 791 |  | 
| 792 | // Get the TLE from tleFile.  The right TLE is that one with the | 
| 793 | // closest previous date to offRes, that is the date at the time of | 
| 794 | // the first timesync found in the root file. | 
| 795 | // | 
| 796 | // Warning: you must use a tle file obtained by space-track.org | 
| 797 | // querying the database with the RESURS DK-1 id number 29228, | 
| 798 | // selecting the widest timespan, including the satellite name in the | 
| 799 | // results. | 
| 800 | cTle *getTle(TString tleFile, TDatime offRes) | 
| 801 | { | 
| 802 | Float_t tledatefromfile, tledatefromroot; | 
| 803 | fstream tlefile(tleFile.Data(), ios::in); | 
| 804 | vector<cTle*> ctles; | 
| 805 | vector<cTle*>::iterator iter; | 
| 806 |  | 
| 807 |  | 
| 808 | // Build a vector of *cTle | 
| 809 | while(1) { | 
| 810 | cTle *tlef; | 
| 811 | string str1, str2, str3; | 
| 812 |  | 
| 813 | getline(tlefile, str1); | 
| 814 | if(tlefile.eof()) break; | 
| 815 |  | 
| 816 | getline(tlefile, str2); | 
| 817 | if(tlefile.eof()) break; | 
| 818 |  | 
| 819 | getline(tlefile, str3); | 
| 820 | if(tlefile.eof()) break; | 
| 821 |  | 
| 822 | // We now have three good lines for a cTle. | 
| 823 | tlef = new cTle(str1, str2, str3); | 
| 824 | ctles.push_back(tlef); | 
| 825 | } | 
| 826 |  | 
| 827 | // Sort by date | 
| 828 | sort(ctles.begin(), ctles.end(), compTLE); | 
| 829 |  | 
| 830 | tledatefromroot = (offRes.GetYear()-2000)*1e3 + (offRes.Convert() - (TDatime(offRes.GetYear(), 1, 1, 0, 0, 0)).Convert())/ (24.*3600.); | 
| 831 |  | 
| 832 | for(iter = ctles.begin(); iter != ctles.end(); iter++) { | 
| 833 | cTle *tle = *iter; | 
| 834 |  | 
| 835 | tledatefromfile = getTleJulian(tle); | 
| 836 |  | 
| 837 | if(tledatefromroot > tledatefromfile) { | 
| 838 | tlefile.close(); | 
| 839 | cTle *thisTle = tle; | 
| 840 | ctles.clear(); | 
| 841 |  | 
| 842 | return thisTle; | 
| 843 | } | 
| 844 | } | 
| 845 |  | 
| 846 | // File ended withoud founding a TLE with a date after offRes.  We'll use the last aviable date. | 
| 847 | cerr << "Warning: using last available TLE in " << tleFile.Data() << ".  Consider updating your tle file." << endl; | 
| 848 |  | 
| 849 | tlefile.close(); | 
| 850 | cTle *thisTle = ctles[ctles.size()-1]; | 
| 851 | ctles.clear(); | 
| 852 |  | 
| 853 | return thisTle; | 
| 854 | } | 
| 855 |  | 
| 856 |  | 
| 857 | // Return whether the first TLE is older than the second | 
| 858 | bool compTLE (cTle *tle1, cTle *tle2) | 
| 859 | { | 
| 860 | return getTleJulian(tle1) > getTleJulian(tle2); | 
| 861 | } | 
| 862 |  | 
| 863 |  | 
| 864 | // Return the date of the tle using the format (year-2000)*1e3 + | 
| 865 | // julian day.  e.g. 6364.5 is the 31th Dec 2006 12:00:00. | 
| 866 | // It does *not* return a cJulian date. | 
| 867 | float getTleJulian(cTle *tle) { | 
| 868 | return tle->getField(cTle::FLD_EPOCHYEAR)*1e3 + tle->getField(cTle::FLD_EPOCHDAY); | 
| 869 | } | 
| 870 |  | 
| 871 |  | 
| 872 | // Look for a timesync in the TFile rootFile.  Set timesync and | 
| 873 | // obt_timesync.  Returns 1 if timesync is found, 0 otherwise. | 
| 874 | int lookforTimesync(TFile *rootFile, Float_t *timesync, Float_t *obt_timesync) { | 
| 875 | *timesync = -1;  // will be != -1 if found | 
| 876 |  | 
| 877 | ULong64_t             nevents    = 0; | 
| 878 | pamela::McmdRecord     *mcmdrc     = 0; | 
| 879 | pamela::McmdEvent      *mcmdev     = 0; | 
| 880 | TArrayC                *mcmddata; | 
| 881 | TTree *tr = (TTree*) rootFile->Get("Mcmd"); | 
| 882 |  | 
| 883 | tr->SetBranchAddress("Mcmd", &mcmdev); | 
| 884 |  | 
| 885 | nevents = tr->GetEntries(); | 
| 886 |  | 
| 887 | // Looking for a timesync.  We stop at the first one found. | 
| 888 | long int recEntries; | 
| 889 |  | 
| 890 | for(UInt_t i = 0; i < nevents; i++) { | 
| 891 | tr->GetEntry(i); | 
| 892 | recEntries = mcmdev->Records->GetEntries(); | 
| 893 |  | 
| 894 | for(UInt_t j = 0; j < recEntries; j++) { | 
| 895 | mcmdrc = (pamela::McmdRecord*)mcmdev->Records->At(j); | 
| 896 |  | 
| 897 | if ((mcmdrc != 0) && (mcmdrc->ID1 == 0xE0)) //Is it a TimeSync? | 
| 898 | { | 
| 899 | mcmddata = mcmdrc->McmdData; | 
| 900 | *timesync = (((unsigned int)mcmddata->At(0)<<24)&0xFF000000) | 
| 901 | + (((unsigned int)mcmddata->At(1)<<16)&0x00FF0000) | 
| 902 | + (((unsigned int)mcmddata->At(2)<<8)&0x0000FF00) | 
| 903 | + (((unsigned int)mcmddata->At(3))&0x000000FF); | 
| 904 | *obt_timesync = (mcmdrc->MCMD_RECORD_OBT)*(1./1000.); | 
| 905 |  | 
| 906 | goto out;  // a timesync is found | 
| 907 | } | 
| 908 | } | 
| 909 | } | 
| 910 |  | 
| 911 | out: | 
| 912 |  | 
| 913 | if (*timesync == -1) | 
| 914 | return 0; | 
| 915 | else | 
| 916 | return 1; | 
| 917 | } | 
| 918 |  | 
| 919 |  | 
| 920 | // Returns the mean value of the elements stored in the vector v. | 
| 921 | double getMean(vector<Double_t> v) | 
| 922 | { | 
| 923 | double mean = 0; | 
| 924 |  | 
| 925 | for(int i=0; i < v.size(); i++) | 
| 926 | mean += v.at(i); | 
| 927 |  | 
| 928 | return mean/v.size(); | 
| 929 | } | 
| 930 |  | 
| 931 |  | 
| 932 | // Shift all non zero bins by shift. | 
| 933 | TH2F* shiftHist(TH2F* h, Float_t shift) | 
| 934 | { | 
| 935 | // Global bin number. | 
| 936 | Int_t nBins = h->GetBin(h->GetNbinsX(), h->GetNbinsY()); | 
| 937 |  | 
| 938 | for(int i = 0; i < nBins; i++) | 
| 939 | if(h->GetBinContent(i)) h->AddBinContent(i, shift); | 
| 940 |  | 
| 941 | return h; | 
| 942 | } | 
| 943 |  | 
| 944 |  | 
| 945 | // Return a string like YYYY-MM-DD hh:mm:ss, a datetime format. | 
| 946 | string getTleDatetime(cTle *tle) | 
| 947 | { | 
| 948 | int year, mon, day, hh, mm, ss; | 
| 949 | double dom; // day of month (is double!) | 
| 950 | stringstream date; // date in datetime format | 
| 951 |  | 
| 952 | // create a cJulian from the date in tle | 
| 953 | cJulian jdate = cJulian( 2000 + (int) tle->getField(cTle::FLD_EPOCHYEAR), tle->getField(cTle::FLD_EPOCHDAY)); | 
| 954 |  | 
| 955 | // get year, month, day of month | 
| 956 | jdate.getComponent(&year, &mon, &dom); | 
| 957 |  | 
| 958 | // build a datetime YYYY-MM-DD hh:mm:ss | 
| 959 | date.str(""); | 
| 960 | day = (int) floor(dom); | 
| 961 | hh = (int) floor( (dom - day) * 24); | 
| 962 | mm = (int) floor( ((dom - day) * 24 - hh) * 60); | 
| 963 | ss = (int) floor( ((((dom - day) * 24 - hh) * 60 - mm) * 60)); | 
| 964 | //  ms = (int) floor( (((((dom - day) * 24 - hh) * 60 - mm) * 60) - ss) * 1000); | 
| 965 |  | 
| 966 | date << year << "-" << mon << "-" << day << " " << hh << ":" << mm << ":" << ss; | 
| 967 |  | 
| 968 | return date.str(); | 
| 969 | } | 
| 970 |  | 
| 971 | // | 
| 972 | // Solve the overflow for anticoincidence because this counter is | 
| 973 | // stored in 2 bytes so counts from 0 to 65535. | 
| 974 | // | 
| 975 | // counter is the actual value. | 
| 976 | // oldValue is meant to be the previous value of counter. | 
| 977 | // | 
| 978 | // Example: | 
| 979 | // for(...) { | 
| 980 | //   ... | 
| 981 | //   corrected_diff = solve_ac_overflow(oldValueOfTheCounter, actualValue); | 
| 982 | //   ... | 
| 983 | // } | 
| 984 | // | 
| 985 | // | 
| 986 | // Returns the corrected difference between counter and oldValue and | 
| 987 | // set oldValue to the value of counter. | 
| 988 | // Attention: oldValue is a reference. | 
| 989 | Int_t solve_ac_overflow(Int_t& oldValue, Int_t counter) | 
| 990 | { | 
| 991 | Int_t truediff = 0; | 
| 992 |  | 
| 993 | if (counter < oldValue)  // overflow! | 
| 994 | truediff = 0xFFFF - oldValue + counter; | 
| 995 | else | 
| 996 | truediff = counter - oldValue; | 
| 997 |  | 
| 998 | oldValue = counter; | 
| 999 |  | 
| 1000 | return truediff; | 
| 1001 | } |