// Do the extraction of the actual constants
void ExtractTimeOffsetsAndCEff(int run = 2931, TString filename = "hd_root.root") {

    // Open our input and output file
    thisFile = TFile::Open(filename);
    TFile *outputFile = TFile::Open("BCALTimeOffsetAndCEff_Results.root", "RECREATE");
    outputFile->mkdir("Fits");
    outputFile->mkdir("ResultOverview");

    // Check to make sure it is open
    if (thisFile == 0) {
        cout << "Unable to open file " << fileName.Data() << "...Exiting" << endl;
        return;
    }

    // We need to have the value of C_effective used for the position determination to get the time offsets
    double C_eff = 16.75; // cm/ns

    // Since we are updating existing constants we will need their current values. We can pipe them in from the CCDB...
    // We need a place to store them...
    double tdc_offsets[1152];
    double adc_offsets[1536];

    //Pipe the current constants into this macro
    //NOTE: This dumps the "LATEST" values. If you need something else, modify this script.
    char command[100];
    sprintf(command, "ccdb dump /BCAL/TDC_offsets:%i:default", run);
    FILE* locInputFile = gSystem->OpenPipe(command, "r");
    if(locInputFile == NULL)
        return 0;
    //get the first (comment) line
    char buff[1024];
    if(fgets(buff, sizeof(buff), locInputFile) == NULL)
        return 0;
    //get the remaining lines
    double time;
    int counter = 0;
    while(fgets(buff, sizeof(buff), locInputFile) != NULL) {
        istringstream locConstantsStream(buff);
        locConstantsStream >> time;
        cout << "TDC Time Offset = " << time << endl;
        tdc_offsets[counter] = time;
        counter++;
    }
    if (counter != 1152) cout << "Wrong number of TDC entries (" << counter << " != 1152)?" << endl;
    //Close the pipe
    gSystem->ClosePipe(locInputFile);

    sprintf(command, "ccdb dump /BCAL/ADC_timing_offsets:%i:default", run);
    locInputFile = gSystem->OpenPipe(command, "r");
    if(locInputFile == NULL)
        return 0;
    //get the first (comment) line
    char buff[1024];
    if(fgets(buff, sizeof(buff), locInputFile) == NULL)
        return 0;
    //get the remaining lines
    counter = 0;
    while(fgets(buff, sizeof(buff), locInputFile) != NULL) {
        istringstream locConstantsStream(buff);
        locConstantsStream >> time;
        cout << "ADC Time Offset = " << time << endl;
        adc_offsets[counter] = time;
        counter++;
    }
    if (counter != 1536) cout << "Wrong number of ADC entries (" << counter << " != 1536)?" << endl;
    //Close the pipe
    gSystem->ClosePipe(locInputFile);

    // This stream will be for outputting the results in a format suitable for the CCDB
    // Will wait to open until needed
    ofstream adcOffsetFile, tdcOffsetFile;
    adcOffsetFile.open("ADCOffsetsBCAL.txt");
    tdcOffsetFile.open("TDCOffsetsBCAL.txt");

    // Declaration of the fit funtion
    TF1 *f1 = new TF1("f1", "[0]+[1]*x", -200, 200);
    f1->SetParLimits(0, -20.0, 20.0);
    f1->SetParLimits(1, 0.85, 1.15);
    outputFile->cd("ResultOverview");
    // Make some histograms to get the distributions of the fit parameters
    TH1I *h1_c0 = new TH1I("h1_c0", "Distribution of parameter c_{0}", 100, -15, 15);
    TH1I *h1_c1 = new TH1I("h1_c1", "Distribution of parameter c_{1}", 100, 0.85, 1.15);
    TH1F *h1_c0_all = new TH1F ("h1_c0_all", "Value of c0; CCDB Index; c0 [cm]", 768, 0.5, 768.5);
    TH1F *h1_c1_all = new TH1F ("h1_c1_all", "Value of c1; CCDB Index; c1 [cm]", 768, 0.5, 768.5);
    TH2I *h2_c0_c1 = new TH2I("h2_c0_c1", "c_{1} Vs. c_{0}; c_{0}; c_{1}", 100, -15, 15, 100, 0.85, 1.15);

    // Fit the global offset histogram to get the per channel global offset
    double globalOffset[768];
    TH1D * selectedBCALOffset = new TH1D("selectedBCALOffset", "Selected Global BCAL Offset; CCDB Index; Offset [ns]", 768, 0.5, 768 + 0.5);
    TH1I * BCALOffsetDistribution = new TH1I("BCALOffsetDistribution", "Global BCAL Offset; Global Offset [ns]; Entries", 100, -10, 10);

    thisHist = Get2DHistogram("BCAL_Global_Offsets", "Target Time", "Target Time Minus RF Time Vs. Cell Number");
    if(thisHist != NULL) {
        int nBinsX = thisHist->GetNbinsX();
        int nBinsY = thisHist->GetNbinsY();
        for (int i = 1 ; i <= nBinsX; i++) {
            TH1D *projY = thisHist->ProjectionY("temp", i, i);
            // Scan over the histogram
            float nsPerBin = (projY->GetBinCenter(projY->GetNbinsX()) - projY->GetBinCenter(1)) / projY->GetNbinsX();
            float timeWindow = 0.5; //ns (Full Width)
            int binWindow = int(timeWindow / nsPerBin);
            double maxEntries = 0;
            double maxMean = 0;
            for (int j = 1 ; j <= projY->GetNbinsX(); j++) {
                int minBin = j;
                int maxBin = (j + binWindow) <= projY->GetNbinsX() ? (j + binWindow) : projY->GetNbinsX();
                double sum = 0, nEntries = 0;
                for (int bin = minBin; bin <= maxBin; bin++) {
                    sum += projY->GetBinContent(bin) * projY->GetBinCenter(bin);
                    nEntries += projY->GetBinContent(bin);
                    if (bin == maxBin) {
                        if (nEntries > maxEntries) {
                            maxMean = sum / nEntries;
                            maxEntries = nEntries;
                        }
                    }
                }
            }
            globalOffset[i-1] = maxMean;
            selectedBCALOffset->SetBinContent(i, maxMean);
            BCALOffsetDistribution->Fill(maxMean);
        }
    }

    outputFile->cd("Fits");
    // Now we want to loop through all available module/layer/sector and try to make a fit of each one
    for (unsigned int iModule = 1; iModule <=48; iModule++) {
        for (unsigned int iLayer = 1; iLayer <= 4; iLayer++) { // Only 3 layers with TDCs
            for (unsigned int iSector = 1; iSector <= 4; iSector++) {
                int the_cell = (iModule - 1) * 16 + (iLayer - 1) * 4 + iSector;
                int the_tdc_cell = (iModule - 1) * 12 + (iLayer - 1) * 4 + iSector; // One less layer of TDCs
                // Format the string to lookup the histogram by name
                char name[200];
                sprintf(name, "Module %.2i Layer %.2i Sector %.2i", iModule, iLayer, iSector);

                // These histograms are created on the fly in the plugin, so there is a chance that they do not exist, in which case the pointer will be NULL

                TH2I *h_offsets   = Get2DHistogram ("BCAL_TDC_Offsets", "Z Position", name);

                // Use FitSlicesY routine to extract the mean of each x bin
                TObjArray ySlices;

                if (h_offsets != NULL) {
                    h_offsets->RebinX(5);
                    TProfile *profile = h_offsets->ProfileX();
                    f1->SetParameters(0, 1); // Just out initial guess
                    TFitResultPtr fr = profile->Fit(f1, "SQR");
                    Int_t fitStatus = fr;
                    if (fitStatus == 0) {
                        double c0 = fr->Parameter(0);
                        double c0_err = fr->ParError(0);
                        double c1 = fr->Parameter(1);
                        double c1_err = fr->ParError(1);
                        if (c0 == 10.0 || c0 == -10.0 || c1 == 0.9 || c1 == 1.1) {
                            cout << "WARNING: Parameter hit limit " << name << endl;
                        }
                        h1_c0->Fill(c0);
                        h1_c1->Fill(c1);
                        h2_c0_c1->Fill(c0,c1);
                        h1_c0_all->SetBinContent(the_cell, c0);
                        h1_c0_all->SetBinError(the_cell, c0_err);
                        h1_c1_all->SetBinContent(the_cell, c1);
                        h1_c1_all->SetBinError(the_cell, c1_err);
                        adcOffsetFile << adc_offsets[(the_cell - 1) * 2] + 0.5 * c0 / C_eff + globalOffset[the_cell] << endl;
                        adcOffsetFile << adc_offsets[ the_cell*2 - 1] - 0.5 * c0 / C_eff + globalOffset[the_cell] << endl;
                        if (iLayer != 4) {
                            tdcOffsetFile << tdc_offsets[(the_tdc_cell - 1) * 2] + 0.5 * c0 / C_eff + globalOffset[the_cell] << endl;
                            tdcOffsetFile << tdc_offsets[the_tdc_cell*2 - 1] - 0.5 * c0 / C_eff + globalOffset[the_cell] << endl;
                        }
                    }
                    else {
                        cout << "WARNING: Fit Status "<< fitStatus << " for Upstream " << name << endl;
                        adcOffsetFile << adc_offsets[(the_cell - 1) * 2] + globalOffset[the_cell] << endl;
                        adcOffsetFile << adc_offsets[the_cell*2 - 1] + globalOffset[the_cell] << endl;
                        if (iLayer != 4) {
                            tdcOffsetFile << tdc_offsets[(the_tdc_cell - 1) * 2] + globalOffset[the_cell] << endl;
                            tdcOffsetFile << tdc_offsets[the_tdc_cell*2 - 1] + globalOffset[the_cell] << endl;
                        }
                    }
                }
                else {
                    adcOffsetFile << adc_offsets[ (the_cell-1) * 2] + globalOffset[the_cell] << endl;
                    adcOffsetFile << adc_offsets[  the_cell*2  - 1] + globalOffset[the_cell] << endl;
                    if (iLayer != 4) {
                        tdcOffsetFile << tdc_offsets[(the_tdc_cell -1) * 2] + globalOffset[the_cell] << endl;
                        tdcOffsetFile << tdc_offsets[ the_tdc_cell*2 - 1] + globalOffset[the_cell] << endl;
                    }
                }
            }
        }
    }
    adcOffsetFile.close();
    tdcOffsetFile.close();
    outputFile->Write();
    thisFile->Close();
    return;
}
void ExtractTrackBasedTiming(int runNumber){

    TString fileName = Form ("Run%i/TrackBasedTiming.root", runNumber);
    TString prefix = Form ("Run%i/constants/TrackBasedTiming/",runNumber);
    TString inputPrefix = Form ("Run%i/constants/TDCADCTiming/",runNumber);

    thisFile = TFile::Open( fileName , "UPDATE");
    if (thisFile == 0) {
        cout << "Unable to open file " << fileName.Data() << "...Exiting" << endl;
        return;
    }

    //We need the existing constants, The best we can do here is just read them from the file.
    vector<double> sc_tdc_time_offsets;
    vector<double> sc_fadc_time_offsets;
    vector<double> tof_tdc_time_offsets;
    vector<double> tof_fadc_time_offsets;
    vector<double> tagm_tdc_time_offsets;
    vector<double> tagm_fadc_time_offsets;
    vector<double> tagh_tdc_time_offsets;
    vector<double> tagh_fadc_time_offsets;

    double sc_t_base_fadc;
    double sc_t_base_tdc;
    double tof_t_base_fadc;
    double tof_t_base_tdc;
    double bcal_t_base_fadc;
    double bcal_t_base_tdc;
    double tagm_t_base_fadc;
    double tagm_t_base_tdc;
    double tagh_t_base_fadc;
    double tagh_t_base_tdc;
    double fcal_t_base;
    double cdc_t_base;

    ifstream inFile;
    inFile.open(inputPrefix + "sc_tdc_timing_offsets.txt");
    string line;
    if (inFile.is_open()){
        while (getline (inFile, line)){
            sc_tdc_time_offsets.push_back(atof(line.data()));
        }
    }
    inFile.close();

    ifstream inFile;
    inFile.open(inputPrefix + "sc_adc_timing_offsets.txt");
    string line;
    if (inFile.is_open()){
        while (getline (inFile, line)){
            sc_fadc_time_offsets.push_back(atof(line.data()));
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tof_tdc_timing_offsets.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            tof_tdc_time_offsets.push_back(atof(line.data()));
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tof_adc_timing_offsets.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            tof_fadc_time_offsets.push_back(atof(line.data()));
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tagm_tdc_timing_offsets.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double r, c, offset;
            while (iss>>r>>c>>offset){
                //if (row != 0) continue;
                tagm_tdc_time_offsets.push_back(offset);
            }
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tagm_adc_timing_offsets.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double r, c, offset;
            while (iss>>r>>c>>offset){
                //if (row != 0) continue;
                tagm_fadc_time_offsets.push_back(offset);
            }
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tagh_tdc_timing_offsets.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double counter, offset;
            while (iss>>counter>>offset){
                tagh_tdc_time_offsets.push_back(offset);
            }
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tagh_adc_timing_offsets.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double counter, offset;
            while (iss>>counter>>offset){
                tagh_fadc_time_offsets.push_back(offset);
            }
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tof_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            iss>>tof_t_base_fadc>>tof_t_base_tdc;
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "sc_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            iss>>sc_t_base_fadc>>sc_t_base_tdc;
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "bcal_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double adc_offset, tdc_offset;
            iss>>adc_offset>>tdc_offset; // TDC not used currently
            bcal_t_base_fadc = adc_offset;
            bcal_t_base_tdc = tdc_offset;
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "tagm_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double adc_offset, tdc_offset;
            iss>>adc_offset>>tdc_offset; // TDC not used currently
            tagm_t_base_fadc = adc_offset;
            tagm_t_base_tdc = tdc_offset;
        }
    }

    inFile.close();
    inFile.open(inputPrefix + "tagh_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            double adc_offset, tdc_offset;
            iss>>adc_offset>>tdc_offset; // TDC not used currently
            tagh_t_base_fadc = adc_offset;
            tagh_t_base_tdc = tdc_offset;
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "fcal_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            iss>>fcal_t_base; 
        }
    }
    inFile.close();

    inFile.open(inputPrefix + "cdc_base_time.txt");
    if (inFile.is_open()){
        while (getline (inFile, line)){
            istringstream iss(line);
            iss>>cdc_t_base; 
        }
    }
    inFile.close();


    // Do our final step in the timing alignment with tracking

    //When the RF is present we can try to simply pick out the correct beam bucket for each of the runs
    //First just a simple check to see if we have the appropriate data
    bool useRF = false;
    double RF_Period = 4.0080161;
    TH1I *testHist = Get1DHistogram("HLDetectorTiming", "TAGH_TDC_RF_Compare","Counter ID 001");
    if (testHist != NULL){ // Not great since we rely on channel 1 working, but can be craftier later.
        useRF = true;
    }
    ofstream outFile;
    TH2I *thisHist; 
    thisHist = Get2DHistogram("HLDetectorTiming", "TRACKING", "TAGM - SC Target Time");
    if (useRF) thisHist = Get2DHistogram("HLDetectorTiming", "TRACKING", "TAGM - RFBunch Time");
    if (thisHist != NULL){
        //Statistics on these histograms are really quite low we will have to rebin and do some interpolation
        outFile.open(prefix + "tagm_tdc_timing_offsets.txt", ios::out | ios::trunc);
        outFile.close(); // clear file
        outFile.open(prefix + "tagm_adc_timing_offsets.txt", ios::out | ios::trunc);
        outFile.close(); // clear file
        int nBinsX = thisHist->GetNbinsX();
        int nBinsY = thisHist->GetNbinsY();
        TH1D * selectedTAGMOffset = new TH1D("selectedTAGMOffset", "Selected TAGM Offset; Column; Offset [ns]", nBinsX, 0.5, nBinsX + 0.5);
        TH1I * TAGMOffsetDistribution = new TH1I("TAGMOffsetDistribution", "TAGM Offset; TAGM Offset [ns]; Entries", 500, -250, 250);
        for (int i = 1 ; i <= nBinsX; i++){ 
            TH1D *projY = thisHist->ProjectionY("temp", i, i);
            // Scan over the histogram
            //chose the correct number of bins based on the histogram
            float nsPerBin = (projY->GetBinCenter(projY->GetNbinsX()) - projY->GetBinCenter(1)) / projY->GetNbinsX();
            float timeWindow = 3; //ns (Full Width)
            int binWindow = int(timeWindow / nsPerBin);
            double maxEntries = 0;
            double maxMean = 0;
            for (int j = 1 ; j <= projY->GetNbinsX();j++){
                int minBin = j;
                int maxBin = (j + binWindow) <= projY->GetNbinsX() ? (j + binWindow) : projY->GetNbinsX();
                double sum = 0, nEntries = 0;
                for (int bin = minBin; bin <= maxBin; bin++){
                    sum += projY->GetBinContent(bin) * projY->GetBinCenter(bin);
                    nEntries += projY->GetBinContent(bin);
                    if (bin == maxBin){
                        if (nEntries > maxEntries) {
                            maxMean = sum / nEntries;
                            maxEntries = nEntries;
                        }
                    } 
                }
            }
            //In the case there is RF, our job is to pick just the number of the correct beam bunch, so that's really all we need.
            if(useRF) {
                int beamBucket = int((maxMean / RF_Period) + 0.5); // +0.5 to handle rounding correctly
                selectedTAGMOffset->SetBinContent(i, beamBucket);
                TAGMOffsetDistribution->Fill(beamBucket);
            }
            else{
                selectedTAGMOffset->SetBinContent(i, maxMean);
                TAGMOffsetDistribution->Fill(maxMean);
            }
        }
        /*
        if (!useRF){
            //TFitResultPtr fr1 = selectedTAGMOffset->Fit("pol1", "SQ", "", 0.5, nBinsX + 0.5);
            TFitResultPtr fr1 = selectedTAGMOffset->Fit("pol1", "SQ", "", 5, 50);

            for (int i = 1 ; i <= nBinsX; i++){
                double x0 = fr1->Parameter(0);
                double x1 = fr1->Parameter(1);
                //double x2 = fr1->Parameter(2);
                //double fitResult = x0 + i*x1 + i*i*x2;
                double fitResult = x0 + i*x1;

                double outlierCut = 20;
                double valueToUse = selectedTAGMOffset->GetBinContent(i);
                if (fabs(selectedTAGMOffset->GetBinContent(i) - fitResult) > outlierCut && valueToUse != 0.0){
                    valueToUse = fitResult;
                }

                selectedTAGMOffset->SetBinContent(i, valueToUse);
                if (valueToUse != 0 ) TAGMOffsetDistribution->Fill(valueToUse);
            }
        }
*/
        double meanOffset = TAGMOffsetDistribution->GetMean();
        // This might be in units of beam bunches, so we need to convert
        if (useRF) meanOffset *= RF_Period;
        /*
           for (int i = 1 ; i <= nBinsX; i++){
           double valueToUse = selectedTAGMOffset->GetBinContent(i);
           if (useRF) valueToUse *= RF_Period;
           if (valueToUse == 0) valueToUse = meanOffset;
           outFile.open(prefix + "tagm_tdc_timing_offsets.txt", ios::out | ios::app);
           outFile << "0 " << i << " " << valueToUse + tagm_tdc_time_offsets[i-1] - meanOffset<< endl;
           if (i == 7 || i == 25 || i == 79 || i == 97){
           for(int j = 1; j <= 5; j++){
           outFile << j << " " << i << " " << valueToUse + tagm_tdc_time_offsets[i-1] - meanOffset<< endl;
           }
           }
           outFile.close();
        // Apply the same shift to the adc offsets
        outFile.open(prefix + "tagm_adc_timing_offsets.txt", ios::out | ios::app);
        outFile << "0 " << i << " " << valueToUse + tagm_fadc_time_offsets[i-1] - meanOffset<< endl;
        if (i == 7 || i == 25 || i == 79 || i == 97){
        for(int j = 1; j <= 5; j++){
        outFile << j << " " << i << " " << valueToUse + tagm_fadc_time_offsets[i-1] - meanOffset<< endl;
        }
        }
        outFile.close();
        }
        */

        outFile.open(prefix + "tagm_adc_timing_offsets.txt", ios::out);
        //for (int i = 1 ; i <= nBinsX; i++){
        // Loop over rows
        for (unsigned int column = 1; column <= 102; column++){
            int index = GetCCDBIndexTAGM(column, 0);
            double valueToUse = selectedTAGMOffset->GetBinContent(index);
            if (useRF) valueToUse *= RF_Period;
            if (valueToUse == 0) valueToUse = meanOffset;
            outFile << "0 " << column << " " << valueToUse + tagm_fadc_time_offsets[index-1] - meanOffset<< endl;
            if (column == 9 || column == 27 || column == 81 || column == 99){
                for (unsigned int row = 1; row <= 5; row++){
                    index = GetCCDBIndexTAGM(column, row);
                    valueToUse = selectedTAGMOffset->GetBinContent(index);
                    if (useRF) valueToUse *= RF_Period;
                    if (valueToUse == 0) valueToUse = meanOffset;
                    outFile << row << " " << column << " " << valueToUse + tagm_fadc_time_offsets[index-1] - meanOffset<< endl;
                }
            }
        }
        outFile.close();

        outFile.open(prefix + "tagm_tdc_timing_offsets.txt", ios::out);
        //for (int i = 1 ; i <= nBinsX; i++){
        // Loop over rows
        for (unsigned int column = 1; column <= 102; column++){
            int index = GetCCDBIndexTAGM(column, 0);
            double valueToUse = selectedTAGMOffset->GetBinContent(index);
            if (useRF) valueToUse *= RF_Period;
            if (valueToUse == 0) valueToUse = meanOffset;
            outFile << "0 " << column << " " << valueToUse + tagm_tdc_time_offsets[index-1] - meanOffset << endl;
            if (column == 9 || column == 27 || column == 81 || column == 99){
                for (unsigned int row = 1; row <= 5; row++){
                    index = GetCCDBIndexTAGM(column, row);
                    valueToUse = selectedTAGMOffset->GetBinContent(index);
                    if (useRF) valueToUse *= RF_Period;
                    if (valueToUse == 0) valueToUse = meanOffset;
                    outFile << row << " " << column << " " << valueToUse + tagm_tdc_time_offsets[index-1] - meanOffset << endl;
                }
            }
        }
        outFile.close();
        outFile.open(prefix + "tagm_base_time.txt", ios::out);
        outFile << tagm_t_base_fadc - meanOffset << " " << tagm_t_base_tdc - meanOffset << endl;
        outFile.close();

    }

    thisHist = Get2DHistogram("HLDetectorTiming", "TRACKING", "TAGH - SC Target Time");
    if (useRF) thisHist = Get2DHistogram("HLDetectorTiming", "TRACKING", "TAGH - RFBunch Time");
    if(thisHist != NULL){
        outFile.open(prefix + "tagh_tdc_timing_offsets.txt", ios::out | ios::trunc);
        outFile.close(); // clear file
        outFile.open(prefix + "tagh_adc_timing_offsets.txt", ios::out | ios::trunc);
        outFile.close(); // clear file

        int nBinsX = thisHist->GetNbinsX();
        int nBinsY = thisHist->GetNbinsY();
        TH1D * selectedTAGHOffset = new TH1D("selectedTAGHOffset", "Selected TAGH Offset; ID; Offset [ns]", nBinsX, 0.5, nBinsX + 0.5);
        TH1I * TAGHOffsetDistribution = new TH1I("TAGHOffsetDistribution", "TAGH Offset; TAGH Offset [ns]; Entries", 500, -250, 250);
        for (int i = 1 ; i <= nBinsX; i++){
            TH1D *projY = thisHist->ProjectionY("temp", i, i);
            // Scan over the histogram
            //chose the correct number of bins based on the histogram
            float nsPerBin = (projY->GetBinCenter(projY->GetNbinsX()) - projY->GetBinCenter(1)) / projY->GetNbinsX();
            float timeWindow = 2; //ns (Full Width)
            int binWindow = int(timeWindow / nsPerBin);

            double maxEntries = 0;
            double maxMean = 0;
            for (int j = 1 ; j <= projY->GetNbinsX();j++){
                int minBin = j;
                int maxBin = (j + binWindow) <= projY->GetNbinsX() ? (j + binWindow) : projY->GetNbinsX();
                double sum = 0; 
                double nEntries = 0;
                for (int bin = minBin; bin <= maxBin; bin++){
                    sum += projY->GetBinContent(bin) * projY->GetBinCenter(bin);
                    nEntries += projY->GetBinContent(bin);
                    if (bin == maxBin){
                        if (nEntries > maxEntries){
                            maxMean = sum / nEntries;
                            maxEntries = nEntries;
                        }
                    }
                }
            }

            if(useRF) {
                int beamBucket = int((maxMean / RF_Period) + 0.5); // +0.5 to handle rounding correctly
                selectedTAGHOffset->SetBinContent(i, beamBucket);
                TAGHOffsetDistribution->Fill(beamBucket);
            }
            else{
                selectedTAGHOffset->SetBinContent(i, maxMean);
            }
            /*
               outFile.open("tagh_tdc_timing_offsets.txt", ios::out | ios::app);
               outFile << i << " " << maxMean + tagh_tdc_time_offsets[i] << endl;
               outFile.close();
               outFile.open("tagh_adc_timing_offsets.txt", ios::out | ios::app);
               outFile << i << " " << maxMean + tagh_fadc_time_offsets[i] << endl;
               outFile.close();
               */
        }

        // Fit 1D histogram. If value is far from the fit use the fitted value
        // Two behaviors above and below microscope
        // This isn't working well, so removing...
        /*
           TFitResultPtr fr1 = selectedTAGHOffset->Fit("pol2", "SQ", "", 0.5, 131.5);
           TFitResultPtr fr2 = selectedTAGHOffset->Fit("pol2", "SQ", "", 182.5, 274.5);        

           for (int i = 1 ; i <= nBinsX; i++){
           double fitResult = 0.0;
           if (i < 150){
           double x0 = fr1->Parameter(0);
           double x1 = fr1->Parameter(1);
           double x2 = fr1->Parameter(2);
           fitResult = x0 + i*x1 + i*i*x2;
           }
           else{
           double x0 = fr2->Parameter(0);
           double x1 = fr2->Parameter(1);
           double x2 = fr2->Parameter(2);
           fitResult = x0 + i*x1 + i*i*x2;
           }

           double outlierCut = 7;
           double valueToUse = selectedTAGHOffset->GetBinContent(i);
           if (fabs(selectedTAGHOffset->GetBinContent(i) - fitResult) > outlierCut && valueToUse != 0.0){
           valueToUse = fitResult;
           }

           selectedTAGHOffset->SetBinContent(i, valueToUse);
           if(valueToUse != 0) TAGHOffsetDistribution->Fill(valueToUse);
           }
           */
        double meanOffset = TAGHOffsetDistribution->GetMean();
        if (useRF) meanOffset *= RF_Period;
        for (int i = 1 ; i <= nBinsX; i++){
            valueToUse = selectedTAGHOffset->GetBinContent(i);
            if (useRF) valueToUse *= RF_Period;
            if (valueToUse == 0) valueToUse = meanOffset;
            outFile.open(prefix + "tagh_tdc_timing_offsets.txt", ios::out | ios::app);
            outFile << i << " " << valueToUse + tagh_tdc_time_offsets[i-1] - meanOffset << endl;
            outFile.close();
            outFile.open(prefix + "tagh_adc_timing_offsets.txt", ios::out | ios::app);
            outFile << i << " " << valueToUse + tagh_fadc_time_offsets[i-1] - meanOffset << endl;
            outFile.close();
        }

        outFile.open(prefix + "tagh_base_time.txt", ios::out);
        outFile << tagh_t_base_fadc - meanOffset << " " << tagh_t_base_tdc - meanOffset << endl;
        outFile.close();
    }

    // We can use the RF time to calibrate the SC time (Experimental for now)
    double meanSCOffset = 0.0; // In case we change the time of the SC, we need this in this scope
    if(useRF){
        TH1F * selectedSCSectorOffset = new TH1F("selectedSCSectorOffset", "Selected TDC-RF offset;Sector; Time", 30, 0.5, 30.5);
        TH1F * selectedSCSectorOffsetDistribution = new TH1F("selectedSCSectorOffsetDistribution", "Selected TDC-RF offset;Time;Entries", 100, -3.0, 3.0);
        TF1* f = new TF1("f","pol0(0)+gaus(1)", -3.0, 3.0);
        for (int sector = 1; sector <= 30; sector++){
            TH1I *scRFHist = Get1DHistogram("HLDetectorTiming", "SC_Target_RF_Compare", Form("Sector %.2i", sector));
            if (scRFHist == NULL) continue;
            //Do the fit
            TFitResultPtr fr = scRFHist->Fit("pol0", "SQ", "", -2, 2);
            double p0 = fr->Parameter(0);

            f->FixParameter(0,p0);
            f->SetParLimits(2, -2, 2);
            f->SetParLimits(3, 0, 2);
            f->SetParameter(1, 10);
            f->SetParameter(2, scRFHist->GetBinCenter(scRFHist->GetMaximumBin()));
            f->SetParameter(3, 0);

            fr = scRFHist->Fit(f, "SQ", "", -2, 2);
            double SCOffset = fr->Parameter(2);
            selectedSCSectorOffset->SetBinContent(sector, SCOffset);
            selectedSCSectorOffsetDistribution->Fill(SCOffset);
        }
        // Now write out the offsets
        meanSCOffset = selectedSCSectorOffsetDistribution->GetMean();
        outFile.open(prefix + "sc_tdc_timing_offsets.txt");
        for (int sector = 1; sector <= 30; sector++){
            outFile << sc_tdc_time_offsets[sector-1] + selectedSCSectorOffset->GetBinContent(sector) - meanSCOffset << endl;
        }
        outFile.close();
        outFile.open(prefix + "sc_adc_timing_offsets.txt");
        for (int sector = 1; sector <= 30; sector++){
            outFile << sc_fadc_time_offsets[sector-1] + selectedSCSectorOffset->GetBinContent(sector) - meanSCOffset << endl;
        }
        outFile.close();
        
        outFile.open(prefix + "sc_base_time.txt");
        outFile << sc_t_base_fadc - meanSCOffset << " " << sc_t_base_tdc - meanSCOffset << endl;
        outFile.close();
    }

    TH1I *this1DHist = Get1DHistogram("HLDetectorTiming", "TRACKING", "TOF - SC Target Time");
    if(this1DHist != NULL){
        //Gaussian
        Double_t maximum = this1DHist->GetBinCenter(this1DHist->GetMaximumBin());
        TFitResultPtr fr = this1DHist->Fit("gaus", "S", "", maximum - 1.5, maximum + 1.5);
        float mean = fr->Parameter(1);
        outFile.open(prefix + "tof_base_time.txt");
        outFile << tof_t_base_fadc - mean - meanSCOffset<< " " << tof_t_base_tdc - mean - meanSCOffset<< endl;
        outFile.close();
    }

    this1DHist = Get1DHistogram("HLDetectorTiming", "TRACKING", "BCAL - SC Target Time");
    if(this1DHist != NULL){
        //Gaussian
        Double_t maximum = this1DHist->GetBinCenter(this1DHist->GetMaximumBin());
        TFitResultPtr fr = this1DHist->Fit("gaus", "S", "", maximum - 5, maximum + 5);
        float mean = fr->Parameter(1);
        outFile.open(prefix + "bcal_base_time.txt");
        outFile << bcal_t_base_fadc - mean - meanSCOffset << " " << bcal_t_base_tdc - mean - meanSCOffset << endl; // TDC info not used
        outFile.close();
    }

    this1DHist = Get1DHistogram("HLDetectorTiming", "TRACKING", "FCAL - SC Target Time");
    if(this1DHist != NULL){
        //Gaussian
        Double_t maximum = this1DHist->GetBinCenter(this1DHist->GetMaximumBin());
        TFitResultPtr fr = this1DHist->Fit("gaus", "S", "", maximum - 5, maximum + 5);
        float mean = fr->Parameter(1);
        outFile.open(prefix + "fcal_base_time.txt");
        outFile << fcal_t_base - mean - meanSCOffset<< endl; 
        outFile.close();
    }

    this1DHist = Get1DHistogram("HLDetectorTiming", "TRACKING", "Earliest CDC Time Minus Matched SC Time");
    if(this1DHist != NULL){
        //Gaussian
        Double_t maximum = this1DHist->GetBinCenter(this1DHist->GetMaximumBin());
        TFitResultPtr fr = this1DHist->Fit("gaus", "S", "", maximum - 15, maximum + 10);
        float mean = fr->Parameter(1);
        outFile.open(prefix + "cdc_base_time.txt");
        outFile << cdc_t_base - mean - meanSCOffset << endl;
        outFile.close();
    }
    thisFile->Write();
    return;
    }
// Do the extraction of the actual constants
void ExtractCDCDeformation(TString filename = "hd_root.root"){

    // Open our input and output file
    thisFile = TFile::Open(filename);
    TFile *outputFile = TFile::Open("CDCDeformation_Results.root", "RECREATE");

    // Check to make sure it is open
    if (thisFile == 0) {
        cout << "Unable to open file " << filename.Data() << "...Exiting" << endl;
        return;
    }

    // This stream will be for outputting the results in a format suitable for the CCDB
    // Will wait to open until needed
    ofstream textFile;
    textFile.open("CDC_Deformation.txt");

    // We want to display the direction of the shift as well as the magnitude in the "CDC view"
    // Let's make it happen
    int straw_offset[29] = {0,0,42,84,138,192,258,324,404,484,577,670,776,882,1005,1128,1263,1398,1544,1690,1848,2006,2176,2346,2528,2710,2907,3104,3313};
    int Nstraws[28] = {42, 42, 54, 54, 66, 66, 80, 80, 93, 93, 106, 106, 123, 123, 135, 135, 146, 146, 158, 158, 170, 170, 182, 182, 197, 197, 209, 209};
    double radius[28] = {10.72134, 12.08024, 13.7795, 15.14602, 18.71726, 20.2438, 22.01672, 23.50008, 25.15616, 26.61158, 28.33624, 29.77388, 31.3817, 32.75838, 34.43478, 35.81146, 38.28542, 39.7002, 41.31564, 42.73042, 44.34078, 45.75302, 47.36084, 48.77054, 50.37582, 51.76012, 53.36286, 54.74716};
    double phi[28] = {0, 0.074707844, 0.038166294, 0.096247609, 0.05966371, 0.012001551, 0.040721951, 0.001334527, 0.014963808, 0.048683644, 0.002092645, 0.031681749, 0.040719354, 0.015197341, 0.006786058, 0.030005892, 0.019704045, -0.001782064, -0.001306618, 0.018592421, 0.003686784, 0.022132975, 0.019600866, 0.002343723, 0.021301449, 0.005348855, 0.005997358, 0.021018761};

    TH2D * Amplitude_view[29];
    TH2D * Direction_view[29];
    TH2D * Vertical_view[29];
    TH2D * Horizontal_view[29];

    outputFile->mkdir("PerRing");
    outputFile->cd("PerRing");
    for(unsigned int iring=0; iring<28; iring++){
        double r_start = radius[iring] - 0.8;
        double r_end = radius[iring] + 0.8;
        double phi_start = phi[iring]; 
        double phi_end = phi_start + TMath::TwoPi();

        char hname[256];
        sprintf(hname, "Amplitude_view_ring[%d]", iring+1);
        Amplitude_view[iring+1] = new TH2D(hname, "", Nstraws[iring], phi_start, phi_end, 1, r_start, r_end);
        sprintf(hname, "Direction_view_ring[%d]", iring+1);
        Direction_view[iring+1] = new TH2D(hname, "", Nstraws[iring], phi_start, phi_end, 1, r_start, r_end);
        sprintf(hname, "Vertical_view_ring[%d]", iring+1);
        Vertical_view[iring+1] = new TH2D(hname, "", Nstraws[iring], phi_start, phi_end, 1, r_start, r_end);
        sprintf(hname, "Horizontal_view_ring[%d]", iring+1);
        Horizontal_view[iring+1] = new TH2D(hname, "", Nstraws[iring], phi_start, phi_end, 1, r_start, r_end);
    }

    //Fit function for 
    TF1 *f1 = new TF1("f1", "[0] + [1] * TMath::Cos(x + [2])", -3.14, 3.14);
    f1->SetParLimits(0, 0.5, 1.0);
    f1->SetParLimits(1, 0.0, 0.35);
    //f1->SetParLimits(2, -3.14, 3.14);
    f1->SetParameters(0.78, 0.0, 0.0);

    outputFile->cd();
    outputFile->mkdir("FitParameters");
    outputFile->cd("FitParameters");

    // Make some histograms to get the distributions of the fit parameters
    TH1I *h1_c0 = new TH1I("h1_c0", "Distribution of Constant", 100, 0.5, 1.0);
    TH1I *h1_c1 = new TH1I("h1_c1", "Distribution of Amplitude", 100, 0.0, 0.35);
    TH1I *h1_c2 = new TH1I("h1_c2", "Direction of Longest Drift Time", 100, -3.14, 3.14);
    TH1F *h1_c2_weighted = new TH1F("h1_c2_weighted", "Distribution of Direction weighted by amplitude", 100, -3.14, 3.14);
    TH2I *h2_c0_c1 = new TH2I("h2_c0_c1", "c_{1} Vs. c_{0}; c_{0}; c_{1}", 100, 0.5, 1.0, 100, 0, 0.35);
    TH2I *h2_c0_c2 = new TH2I("h2_c0_c2", "c_{2} Vs. c_{0}; c_{0}; c_{2}", 100, 0.5, 1.0, 100, -10, 10);
    TH2I *h2_c1_c2 = new TH2I("h2_c1_c2", "c_{2} Vs. c_{1}; c_{1}; c_{2}", 100, 0.0, 0.35, 100, -10, 10);

    outputFile->cd();
    outputFile->mkdir("Fits");
    outputFile->cd("Fits");

    // Now we want to loop through all available module/layer/sector and try to make a fit of each one
    int ring = 1, straw = 1;
    while (ring <= 28){
        cout << "Entering Fit " << endl;
        char folder[100];
        sprintf(folder, "Ring %.2i", ring);
        char strawname[100];
        sprintf(strawname,"Straw %.3i Predicted Drift Distance Vs phi_DOCA", straw);
        TH2I *thisStrawHistogram = Get2DHistogram("CDC_Cosmic_Per_Straw",folder,strawname);

        if (thisStrawHistogram != NULL) {

            // Now to do our fits. This time we know there are 16 bins.
            double percentile95[16], percentile97[16], percentile99[16]; // Location of 95, 97,and 99th percentile bins
            double binCenter[16];
            char name[100];
            sprintf(name,"Ring %.2i Straw %.3i", ring, straw);
            TH1D *extractedPoints = new TH1D(name, name, 16, -3.14, 3.14);
            for (int i = 1; i <= thisStrawHistogram->GetNbinsX() ; i++){
                TH1D *projY = thisStrawHistogram->ProjectionY(" ", i, i);
                binCenter[i-1] = thisStrawHistogram->GetXaxis()->GetBinCenter(i);
                int nbins = projY->GetNbinsX();
                //Get the total nubmer of entries
                int nEntries = projY->GetEntries();
                if (nEntries == 0) continue;
                double errorFraction = TMath::Sqrt(nEntries) / nEntries;
                double perc95 = 0.95*nEntries, perc97 = 0.97 * nEntries, perc99 = 0.99 * nEntries;
                //Accumulate from the beginning to get total, mark 95, 97, 99% location
                int total = 0;
                for (int j = 0; j <= nbins; j++){
                    total += projY->GetBinContent(j);
                    if (total > perc99) percentile99[i-1] = projY->GetBinCenter(j);
                    else if (total > perc97) {
                        percentile97[i-1] = projY->GetBinCenter(j);
                        extractedPoints->SetBinContent(i, projY->GetBinCenter(j));
                        extractedPoints->SetBinError(i, errorFraction * projY->GetBinCenter(j));
                    }
                    else if (total > perc95) percentile95[i-1] = projY->GetBinCenter(j);
                }
            }
            f1->SetParameters(0.78, 0.0, 0.0);
            TFitResultPtr fr = extractedPoints->Fit(f1, "SR");
            Int_t fitStatus = fr;
            if (fitStatus == 0){
                double c0 = fr->Parameter(0);
                double c1 = fr->Parameter(1);
                double c2 = fr->Parameter(2);
                // Move c2 to fit on our range
                while (c2 > TMath::Pi()) c2 -= 2 * TMath::Pi();
                while (c2 < -1* TMath::Pi()) c2 += 2 * TMath::Pi();
                h1_c0->Fill(c0); h1_c1->Fill(c1); h1_c2->Fill(-1*c2); h1_c2_weighted->Fill(-1*c2,c1);
                h2_c0_c1->Fill(c0,c1); h2_c0_c2->Fill(c0,c2); h2_c1_c2->Fill(c1,c2);
                Amplitude_view[ring]->SetBinContent(straw,1,c1);
                Direction_view[ring]->SetBinContent(straw,1,-1*c2);
                Vertical_view[ring]->SetBinContent(straw,1,c1*TMath::Sin(-1*c2));
                Horizontal_view[ring]->SetBinContent(straw,1,c1*TMath::Cos(-1*c2));
                textFile << c1 << " " << c2 << endl;
            }
            else {
                cout << "WARNING: Fit Status "<< fitStatus << " for ring " << ring << " straw " << straw << endl;
                textFile << "0.0 0.0" << endl;
            }

        }
        else{
            textFile << "0.0 0.0" << endl;
        }

        // On to the next one
        straw++;
        if(straw > Nstraws[ring-1]){
            straw = 1;
            ring++;
        } 
    }

    outputFile->cd();
    outputFile->mkdir("2D");
    outputFile->cd("2D");

    TCanvas *c_Amplitude  = Plot2DCDC(Amplitude_view,"c_Amplitude", "Amplitude of Sinusoid", 0.0, 0.3);
    TCanvas *c_Direction  = Plot2DCDC(Direction_view,"c_Direction", "Direction of #delta", -3.14, 3.14);
    TCanvas *c_Vertical   = Plot2DCDC(Vertical_view,"c_Vertical", "Vertical Projection of Delta", -0.3, 0.3);
    TCanvas *c_Horizontal = Plot2DCDC(Horizontal_view,"c_Horizontal", "Horizontal Projection of Delta", -0.3, 0.3);

    c_Amplitude->Write();
    c_Direction->Write();
    c_Horizontal->Write();
    c_Vertical->Write();

    cout << "Closing Files..." << endl;
    outputFile->Write();
    thisFile->Close();
    textFile.close();
    return;
}