Exemple #1
0
bool videoFormatToGL(const VideoFormat& fmt, GLint* internal_format, GLenum* data_format, GLenum* data_type, QMatrix4x4* mat)
{
    typedef struct fmt_entry {
        VideoFormat::PixelFormat pixfmt;
        GLint internal_format;
        GLenum format;
        GLenum type;
    } fmt_entry;
    static const fmt_entry pixfmt_to_gles[] = {
        {VideoFormat::Format_BGRA32, GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE }, //tested for angle
        {VideoFormat::Format_RGB32,  GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE },
        {VideoFormat::Format_Invalid, 0, 0, 0}
    };
    Q_UNUSED(pixfmt_to_gles);
    static const fmt_entry pixfmt_to_desktop[] = {
        {VideoFormat::Format_BGRA32, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE }, //bgra bgra works on win but not osx
        {VideoFormat::Format_RGB32,  GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE }, //FIXMEL endian check
        //{VideoFormat::Format_BGRA32,  GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, //{2,1,0,3}
        //{VideoFormat::Format_BGR24,   GL_RGB,  GL_BGR,  GL_UNSIGNED_BYTE }, //{0,1,2,3}
    #ifdef GL_UNSIGNED_SHORT_5_6_5_REV
        {VideoFormat::Format_BGR565, GL_RGB,  GL_RGB,  GL_UNSIGNED_SHORT_5_6_5_REV}, // es error, use channel map
    #endif
    #ifdef GL_UNSIGNED_SHORT_1_5_5_5_REV
        {VideoFormat::Format_RGB555, GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
    #endif
    #ifdef GL_UNSIGNED_SHORT_1_5_5_5_REV
        {VideoFormat::Format_BGR555, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
    #endif
        // TODO: BE formats not implemeted
        {VideoFormat::Format_RGB48, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT }, //TODO: they are not work for ANGLE, and rgb16 works on desktop gl, so remove these lines to use rgb16?
        {VideoFormat::Format_RGB48LE, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_RGB48BE, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_BGR48, GL_RGB, GL_BGR, GL_UNSIGNED_SHORT }, //RGB16?
        {VideoFormat::Format_BGR48LE, GL_RGB, GL_BGR, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_BGR48BE, GL_RGB, GL_BGR, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_RGBA64LE, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_RGBA64BE, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_BGRA64LE, GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_BGRA64BE, GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT },
        {VideoFormat::Format_Invalid, 0, 0, 0}
    };
    Q_UNUSED(pixfmt_to_desktop);
    const fmt_entry *pixfmt_gl_entry = pixfmt_to_desktop;
    if (OpenGLHelper::isOpenGLES())
        pixfmt_gl_entry = pixfmt_to_gles;
    // Very special formats, for which OpenGL happens to have direct support
    static const fmt_entry pixfmt_gl_base[] = {
        {VideoFormat::Format_RGBA32, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // only tested for osx, win, angle
        {VideoFormat::Format_RGB24,  GL_RGB,  GL_RGB,  GL_UNSIGNED_BYTE },
        {VideoFormat::Format_RGB565, GL_RGB,  GL_RGB,  GL_UNSIGNED_SHORT_5_6_5},
        {VideoFormat::Format_BGR32,  GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE }, //rgba(tested) or abgr, depending on endian
    };
    const VideoFormat::PixelFormat pixfmt = fmt.pixelFormat();
    // can not use array size because pixfmt_gl_entry is set on runtime
    for (const fmt_entry* e = pixfmt_gl_entry; e->pixfmt != VideoFormat::Format_Invalid; ++e) {
        if (e->pixfmt == pixfmt) {
            *internal_format = e->internal_format;
            *data_format = e->format;
            *data_type = e->type;
            if (mat)
                *mat = QMatrix4x4();
            return true;
        }
    }
    for (size_t i = 0; i < ARRAY_SIZE(pixfmt_gl_base); ++i) {
        const fmt_entry& e = pixfmt_gl_base[i];
        if (e.pixfmt == pixfmt) {
            *internal_format = e.internal_format;
            *data_format = e.format;
            *data_type = e.type;
            if (mat)
                *mat = QMatrix4x4();
            return true;
        }
    }
    static const fmt_entry pixfmt_to_gl_swizzele[] = {
        {VideoFormat::Format_UYVY, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
        {VideoFormat::Format_YUYV, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
        {VideoFormat::Format_VYUY, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
        {VideoFormat::Format_YVYU, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
        {VideoFormat::Format_BGR565, GL_RGB,  GL_RGB,  GL_UNSIGNED_SHORT_5_6_5}, //swizzle
        {VideoFormat::Format_RGB555, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, //not working
        {VideoFormat::Format_BGR555, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, //not working
    };
    for (size_t i = 0; i < ARRAY_SIZE(pixfmt_to_gl_swizzele); ++i) {
        const fmt_entry& e = pixfmt_to_gl_swizzele[i];
        if (e.pixfmt == pixfmt) {
            *internal_format = e.internal_format;
            *data_format = e.format;
            *data_type = e.type;
            if (mat)
                *mat = channelMap(fmt);
            return true;
        }
    }
    GLint *i_f = internal_format;
    GLenum *d_f = data_format;
    GLenum *d_t = data_type;
    gl_param_t* gp = (gl_param_t*)get_gl_param();
    if (gp == gl_param_desktop && (
                fmt.planeCount() == 2 // nv12 UV plane is 16bit, but we use rg
                || (OpenGLHelper::depth16BitTexture() == 16 && OpenGLHelper::has16BitTexture() && fmt.isBigEndian() && fmt.bitsPerComponent() > 8) // 16bit texture does not support be channel now
                )) {
        gp = (gl_param_t*)gl_param_desktop_fallback;
        qDebug("desktop_fallback for %s", fmt.planeCount() == 2 ? "bi-plane format" : "16bit big endian channel");
    }
    for (int p = 0; p < fmt.planeCount(); ++p) {
        // for packed rgb(swizzle required) and planar formats
        const int c = (fmt.channels(p)-1) + 4*((fmt.bitsPerComponent() + 7)/8 - 1);
        if (gp[c].format == 0)
            return false;
        const gl_param_t& f = gp[c];
        *(i_f++) = f.internal_format;
        *(d_f++) = f.format;
        *(d_t++) = f.type;
    }
    if (mat)
        *mat = channelMap(fmt);
    return true;
}
void plotPedestalAnalysis(string inputFileName, string outputDIR, bool testDoubleGaussianChannels){

  system(("mkdir -p "+outputDIR).c_str());

  setTDRStyle();
  gROOT->SetBatch(kTRUE);

  TFile* inputFile = TFile::Open(inputFileName.c_str(),"READ");
  inputFile->cd();
  TTree* tree = (TTree*) inputFile->Get("pedestalFullNoise");

  uint32_t detid,fedKey;
  uint16_t fecCrate,fecSlot, fecRing, ccuAdd, ccuChan, lldChannel, fedId, fedCh, apvId, stripId;
  float    fitChi2Probab, kSProbab, jBProbab, aDProbab, fitChi2;
  float    noiseSkewness, noiseKurtosis;
  float    fitGausMean, fitGausSigma, fitGausNormalization;
  float    fitGausMeanError, fitGausSigmaError, fitGausNormalizationError;
  vector<float>* noiseDistribution = 0;
  vector<float>* noiseDistributionError = 0;
  float    nBin, xMin, xMax;

  tree->SetBranchStatus("*",kFALSE);
  tree->SetBranchStatus("detid",kTRUE);
  tree->SetBranchStatus("fedKey",kTRUE);
  tree->SetBranchStatus("fecCrate",kTRUE);
  tree->SetBranchStatus("fecSlot",kTRUE);
  tree->SetBranchStatus("fecRing",kTRUE);
  tree->SetBranchStatus("ccuAdd",kTRUE);
  tree->SetBranchStatus("ccuChan",kTRUE);
  tree->SetBranchStatus("lldChannel",kTRUE);
  tree->SetBranchStatus("fedId",kTRUE);
  tree->SetBranchStatus("fedCh",kTRUE);
  tree->SetBranchStatus("apvId",kTRUE);
  tree->SetBranchStatus("stripId",kTRUE);
  tree->SetBranchStatus("fitChi2",kTRUE);
  tree->SetBranchStatus("fitChi2Probab",kTRUE);
  tree->SetBranchStatus("kSProbab",kTRUE);
  tree->SetBranchStatus("jBProbab",kTRUE);
  tree->SetBranchStatus("aDProbab",kTRUE);
  tree->SetBranchStatus("fitGausNormalization",kTRUE);
  tree->SetBranchStatus("fitGausMean",kTRUE);
  tree->SetBranchStatus("fitGausSigma",kTRUE);
  tree->SetBranchStatus("fitGausNormalizationError",kTRUE);
  tree->SetBranchStatus("fitGausMeanError",kTRUE);
  tree->SetBranchStatus("fitGausSigmaError",kTRUE);
  tree->SetBranchStatus("noiseSkewness",kTRUE);
  tree->SetBranchStatus("noiseKurtosis",kTRUE);
  tree->SetBranchStatus("noiseDistribution",kTRUE);
  tree->SetBranchStatus("noiseDistributionError",kTRUE);
  tree->SetBranchStatus("nBin",kTRUE);
  tree->SetBranchStatus("xMin",kTRUE);
  tree->SetBranchStatus("xMax",kTRUE);

  tree->SetBranchAddress("detid",&detid);
  tree->SetBranchAddress("fedKey",&fedKey);
  tree->SetBranchAddress("fecCrate",&fecCrate);
  tree->SetBranchAddress("fecSlot",&fecSlot);
  tree->SetBranchAddress("fecRing",&fecRing);
  tree->SetBranchAddress("ccuAdd",&ccuAdd);
  tree->SetBranchAddress("ccuChan",&ccuChan);
  tree->SetBranchAddress("lldChannel",&lldChannel);
  tree->SetBranchAddress("fedId",&fedId);
  tree->SetBranchAddress("fedCh",&fedCh);
  tree->SetBranchAddress("apvId",&apvId);
  tree->SetBranchAddress("stripId",&stripId);
  tree->SetBranchAddress("fitGausNormalization",&fitGausNormalization);
  tree->SetBranchAddress("fitGausMean",&fitGausMean);
  tree->SetBranchAddress("fitGausSigma",&fitGausSigma);
  tree->SetBranchAddress("fitGausNormalizationError",&fitGausNormalizationError);
  tree->SetBranchAddress("fitGausMeanError",&fitGausMeanError);
  tree->SetBranchAddress("fitGausSigmaError",&fitGausSigmaError);
  tree->SetBranchAddress("fitChi2",&fitChi2);
  tree->SetBranchAddress("fitChi2Probab",&fitChi2Probab);
  tree->SetBranchAddress("noiseSkewness",&noiseSkewness);
  tree->SetBranchAddress("noiseKurtosis",&noiseKurtosis);
  tree->SetBranchAddress("kSProbab",&kSProbab);
  tree->SetBranchAddress("aDProbab",&aDProbab);
  tree->SetBranchAddress("jBProbab",&jBProbab);
  tree->SetBranchAddress("noiseDistribution",&noiseDistribution);
  tree->SetBranchAddress("noiseDistributionError",&noiseDistributionError);
  tree->SetBranchAddress("nBin",&nBin);
  tree->SetBranchAddress("xMin",&xMin);
  tree->SetBranchAddress("xMax",&xMax);

  TFile* badStripsNFilledBins = new TFile((outputDIR+"/badStripsNFilledBins.root").c_str(),"RECREATE");
  TFile* badKsTest = new TFile((outputDIR+"/badStripsKsTest.root").c_str(),"RECREATE");
  TFile* badjBTest = new TFile((outputDIR+"/badStripsjBTest.root").c_str(),"RECREATE");
  TFile* badChi2Test = new TFile((outputDIR+"/badStripsChi2Test.root").c_str(),"RECREATE");
  TFile* badaDTest = new TFile((outputDIR+"/badStripsaDTest.root").c_str(),"RECREATE");
  TFile* badCombinedTest = new TFile((outputDIR+"/badStripsCombined.root").c_str(),"RECREATE");
  TFile* badJBNotKSTest = new TFile((outputDIR+"/badStripsjBNotKS.root").c_str(),"RECREATE");
  TFile* badaDNotKSandjBTest = new TFile((outputDIR+"/badStripaDNotKSNotjB.root").c_str(),"RECREATE");
  TFile* badChi2NotKSandjBandaDTest = new TFile((outputDIR+"/badStripsChi2NotKsandjBandaD.root").c_str(),"RECREATE");

  long int nbadNFilledBins = 0;
  long int nbadKsTest = 0;
  long int nbadjBTest = 0;
  long int nbadaDTest = 0;
  long int nbadChi2Test = 0;
  long int nbadCombinedTest = 0;
  long int nbadJBNotKSTest = 0;
  long int nbadaDNotKSandjBTest = 0;
  long int nbadChi2NotKSandjBandaDTest = 0;

  long int nbadDoublePeakDistance = 0;
  long int nbadDoublePeakAshman = 0;
  long int nbadDoublePeakChi2 = 0;
  long int nbadDoublePeakAmplitude = 0;
  long int nbadDoublePeakBimodality = 0;
  long int nbadDoublePeakCombined = 0;

  TCanvas* canvas = new TCanvas("canvas","canvas",600,650);

  map<uint32_t,uint32_t> moduleDenominator;
  map<uint32_t,uint32_t> moduleNumerator;
  //  map<uint32_t,uint32_t> moduleNonEdgeNumerator;
  //  map<uint32_t,uint32_t> moduleAPVEdgeNumerator;

  map<uint32_t,uint32_t> moduleNumeratorFilledBins;
  map<uint32_t,uint32_t> moduleNumeratorKS;
  map<uint32_t,uint32_t> moduleNumeratorJB;
  map<uint32_t,uint32_t> moduleNumeratorDoublePeak;

  vector<TrackerStrip> badStrip;

  TH1F* noiseHist = NULL;
  TF1*  noiseFit  = NULL;
  TF1*  noiseFit2Gaus  = NULL;
  TFitResultPtr result;

  TH1F* chi2Distance       = new TH1F("chi2Distance","",100,0,1);
  chi2Distance->Sumw2();
  TH1F* peakDistance    = new TH1F("peakDistance","",100,0,3);
  peakDistance->Sumw2();
  TH1F* ashmanDistance  = new TH1F("ashmanDistance","",100,0,5);
  ashmanDistance->Sumw2();
  TH1F* bimodalityDistance = new TH1F("bimodalityDistance","",100,0,1);
  bimodalityDistance->Sumw2();
  TH1F* amplitudeRatioDistance = new TH1F("amplitudeRatioDistance","",100,0,3);
  amplitudeRatioDistance->Sumw2();

  TFile* multiPeakChannelsChi2       = new TFile((outputDIR+"/multiPeakChannelsChi2.root").c_str(),"RECREATE");
  TFile* multiPeakChannelsDistance   = new TFile((outputDIR+"/multiPeakChannelsDistance.root").c_str(),"RECREATE");
  TFile* multiPeakChannelsAshman     = new TFile((outputDIR+"/multiPeakChannelsAshman.root").c_str(),"RECREATE");
  TFile* multiPeakChannelsAmplitude  = new TFile((outputDIR+"/multiPeakChannelsAmplitude.root").c_str(),"RECREATE");
  TFile* multiPeakChannelsBimodality = new TFile((outputDIR+"/multiPeakChannelsBimodality.root").c_str(),"RECREATE");
  TFile* multiPeakChannelsCombined   = new TFile((outputDIR+"/multiPeakChannelsCombined.root").c_str(),"RECREATE");

  int nonNullBins = 0;
  float chi2Ratio = 0;
  float distance  = 0;
  float ashman    = 0;
  float bimodality = 0;
  float amplitudeRatio = 0;

  bool isfound = false;
  string fedKeyStr ;
  TString name ;
  std::map<string,string> fitParam;
 
  for(long int iChannel = 0; iChannel < tree->GetEntries(); iChannel++){
    tree->GetEntry(iChannel);
    cout.flush();
    if(iChannel %10000 == 0) cout<<"\r"<<"iChannel "<<100*double(iChannel)/(tree->GetEntries()/reductionFactor)<<" % ";
    if(iChannel > double(tree->GetEntries())/reductionFactor) break;

    // skip problematic fed id
    isfound = false;
    for(auto skipfed : skipFEDid){
      if(fedId == skipfed) isfound = true;
    }
    if(isfound) continue;

    // make selections to identify bad noisy channels (not gaussian ones)
    std::stringstream stream;
    stream << std::hex << fedKey;
    fedKeyStr = stream.str();
    if(fedKeyStr.size() == 4)
      name = Form("fecCrate%d_fecSlot%d_fecRing%d_ccuAdd%d_ccuCh%d_fedKey0x0000%s_lldCh%d_apv%d_strip%d",fecCrate,fecSlot,fecRing,ccuAdd,ccuChan,fedKeyStr.c_str(),lldChannel,apvId,stripId);
    else if(fedKeyStr.size() == 5)
      name = Form("fecCrate%d_fecSlot%d_fecRing%d_ccuAdd%d_ccuCh%d_fedKey0x000%s_lldCh%d_apv%d_strip%d",fecCrate,fecSlot,fecRing,ccuAdd,ccuChan,fedKeyStr.c_str(),lldChannel,apvId,stripId);
  
    fitParam.clear();
    stringstream sMean;
    sMean << std::scientific << fitGausMean;
    fitParam["fitGausMean"]   = sMean.str();
    stringstream sSigma;
    sSigma << std::scientific << fitGausSigma;
    fitParam["fitGausSigma"]  = sSigma.str();
    stringstream sSkew;
    sSkew << std::scientific << noiseSkewness;
    fitParam["noiseSkewness"] = sSkew.str();
    stringstream sKurt;
    sKurt << std::scientific << noiseKurtosis;
    fitParam["noiseKurtosis"] = sKurt.str();
    stringstream sKS;
    sKS << std::scientific << kSProbab;
    fitParam["kSProbab"] = sKS.str();
    stringstream sJB;
    sJB << std::scientific << jBProbab;
    fitParam["jBProbab"] = sJB.str();
    stringstream sChi2;
    sChi2 << std::scientific << fitChi2Probab;
    fitParam["fitChi2Probab"] = sChi2.str();
    stringstream sAD;
    sAD << std::scientific << aDProbab;
    fitParam["aDProbab"] = sAD.str();

    moduleDenominator[detid] = moduleDenominator[detid]+1;
    if(noiseHist == NULL){
      noiseHist = new TH1F ("noiseHist","",nBin,xMin,xMax);
      noiseHist->Sumw2();
    }
    noiseHist->Reset();
    
    for(int iBin = 0; iBin < noiseDistribution->size(); iBin++){
      noiseHist->SetBinContent(iBin+1,noiseDistribution->at(iBin));
      noiseHist->SetBinError(iBin+1,noiseDistributionError->at(iBin));
    }

    if(noiseFit == NULL)
      noiseFit = new TF1 ("noiseFist","gaus(0)",xMin,xMax);
    
    noiseFit->SetRange(xMin,xMax);
    noiseFit->SetParameters(fitGausNormalization,fitGausMean,fitGausSigma);
    noiseFit->SetParError(0,fitGausNormalizationError);
    noiseFit->SetParError(1,fitGausMeanError);
    noiseFit->SetParError(2,fitGausSigmaError);

    nonNullBins = 0;
    for(int iBin = 0; iBin < noiseHist->GetNbinsX(); iBin++){
      if(noiseHist->GetBinContent(iBin+1) != 0) nonNullBins++;
    }

    if(nonNullBins < nFilledBinSelection or noiseHist->GetRMS() < minimumRMS){
      badStripsNFilledBins->cd();
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);
      nbadNFilledBins++;
      moduleNumeratorFilledBins[detid] +=1;
      continue;
    }


    if(kSProbab < quantile3sigma){
      badKsTest->cd();
      nbadKsTest++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
      moduleNumeratorKS[detid] += 1;
    }
    
    if(jBProbab < quantile5sigma){
      badjBTest->cd();
      nbadjBTest++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
    }

    if(fitChi2Probab < quantile4sigma){
      badChi2Test->cd();
      nbadChi2Test++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
    }

    if(aDProbab < quantile3sigma){
      badaDTest->cd();
      nbadaDTest++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);
    }
    if(jBProbab < quantile5sigma and kSProbab > quantile3sigma and kSProbab < quantile){
      badJBNotKSTest->cd();
      nbadJBNotKSTest++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
      moduleNumeratorJB[detid] += 1;
    }

    if(aDProbab < quantile3sigma and jBProbab > quantile5sigma and kSProbab > quantile3sigma and kSProbab < quantile){
      badaDNotKSandjBTest->cd();
      nbadaDNotKSandjBTest++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
    }


    if(fitChi2Probab < quantile4sigma and jBProbab > quantile5sigma and kSProbab > quantile3sigma and kSProbab < quantile and aDProbab > quantile3sigma){
      badChi2NotKSandjBandaDTest->cd();
      nbadChi2NotKSandjBandaDTest++;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
    }

    if(kSProbab < quantile3sigma or (kSProbab > quantile3sigma and kSProbab < quantile and jBProbab < quantile5sigma) or (kSProbab > quantile3sigma and kSProbab < quantile and jBProbab > quantile5sigma and aDProbab < quantile3sigma)  or (kSProbab > quantile3sigma and kSProbab < quantile and jBProbab > quantile5sigma and aDProbab > quantile3sigma and fitChi2Probab < quantile4sigma)){
      badCombinedTest->cd();
      nbadCombinedTest++;
      moduleNumerator[detid] = moduleNumerator[detid]+1;
      //if(stripId == 1 or stripId == 128)
      //  moduleAPVEdgeNumerator[detid] = moduleAPVEdgeNumerator[detid]+1;
      //else
      //  moduleNonEdgeNumerator[detid] = moduleNonEdgeNumerator[detid]+1;
      storeOutputCanvas(canvas,noiseHist,noiseFit,name,fitParam);      
      name = Form("fecCrate%d_fecSlot%d_fecRing%d_ccuAdd%d_ccuCh%d_fedKey0x0000%s_lldCh%d_apv%d_strip%d",fecCrate,fecSlot,fecRing,ccuAdd,ccuChan,fedKeyStr.c_str(),lldChannel,apvId,stripId);      
      badStrip.push_back(TrackerStrip(fecCrate,fecSlot,fecRing,ccuAdd,ccuChan,uint32_t(atoi(fedKeyStr.c_str())),lldChannel,apvId,stripId));

      //try to identify double peaked channels
      if(testDoubleGaussianChannels){
	if(noiseFit2Gaus == NULL)
	  // double gaussian in which the sigma is constrained to be the same --> identifing clear two peak channels
	  noiseFit2Gaus = new TF1("dgaus","[0]*exp(-((x-[1])*(x-[1]))/(2*[2]*[2]))+[3]*exp(-((x-[4])*(x-[4]))/(2*[5]*[5]))",xMin,xMax);

	noiseFit2Gaus->SetRange(xMin,xMax);
	noiseFit2Gaus->SetParameter(0,fitGausNormalization/2);
	noiseFit2Gaus->SetParameter(3,fitGausNormalization/2);
	noiseFit2Gaus->SetParameter(1,1.);
	noiseFit2Gaus->SetParameter(4,-1.);
	noiseFit2Gaus->SetParameter(2,fitGausSigma);
	noiseFit2Gaus->SetParameter(5,fitGausSigma);
	noiseFit2Gaus->SetParLimits(1,0.,xMax);
	noiseFit2Gaus->SetParLimits(4,xMin,0);
	result = noiseHist->Fit(noiseFit2Gaus,"QSR");

	chi2Ratio = 0;
	distance  = 0;
	ashman    = 0;
	bimodality = 0;
	amplitudeRatio = 0;
	if(result.Get() or noiseHist->Integral() == 0){

	  //compute the chi2 ratio
	  chi2Ratio = 0.5*ROOT::Math::chisquared_cdf_c((fitChi2/(result->Ndf()+3))/(result->Chi2()/result->Ndf()),1);
	  chi2Distance->Fill(chi2Ratio);			
	  distance = fabs(noiseFit2Gaus->GetParameter(1)-noiseFit2Gaus->GetParameter(4))/(2*sqrt(noiseFit2Gaus->GetParameter(2)*noiseFit2Gaus->GetParameter(5)));
	  peakDistance->Fill(distance);
	  ashman   = TMath::Power(2,0.5)*abs(noiseFit2Gaus->GetParameter(1)-noiseFit2Gaus->GetParameter(4))/(sqrt(pow(noiseFit2Gaus->GetParameter(2),2)+pow(noiseFit2Gaus->GetParameter(5),2)));
	  ashmanDistance->Fill(ashman);	 
	  if(nonNullBins > 3)
	    bimodality = (noiseHist->GetSkewness()*noiseHist->GetSkewness()+1)/(noiseHist->GetKurtosis()+3*(nonNullBins-1)*(nonNullBins-1)/((nonNullBins-2)*(nonNullBins-3)));
	  else
	    bimodality = (noiseHist->GetSkewness()*noiseHist->GetSkewness()+1)/(noiseHist->GetKurtosis());
	  bimodalityDistance->Fill(bimodality);	  
	  amplitudeRatio = std::min(noiseFit2Gaus->GetParameter(0),noiseFit2Gaus->GetParameter(3))/std::max(noiseFit2Gaus->GetParameter(0),noiseFit2Gaus->GetParameter(3));
	  amplitudeRatioDistance->Fill(amplitudeRatio);	
	  
	  if(distance > 1){
	    multiPeakChannelsDistance->cd();
	    storeOutputCanvas(canvas,noiseHist,noiseFit,noiseFit2Gaus,name);
	    nbadDoublePeakDistance++;
	}
	  
	  if(ashman > 2){
	    multiPeakChannelsAshman->cd();
	    storeOutputCanvas(canvas,noiseHist,noiseFit,noiseFit2Gaus,name);
	    nbadDoublePeakAshman++;
	  }
	  
	  if(chi2Ratio < 0.05){
	    multiPeakChannelsChi2->cd();
	    storeOutputCanvas(canvas,noiseHist,noiseFit,noiseFit2Gaus,name);
	    nbadDoublePeakChi2++;
	  }
	  
	  if(amplitudeRatio > 0.85){
	    multiPeakChannelsAmplitude->cd();
	    storeOutputCanvas(canvas,noiseHist,noiseFit,noiseFit2Gaus,name);
	    nbadDoublePeakAmplitude++;
	}
	  
	  if(bimodality > 0.55){
	    multiPeakChannelsBimodality->cd();
	    storeOutputCanvas(canvas,noiseHist,noiseFit,noiseFit2Gaus,name);
	    nbadDoublePeakBimodality++;
	  }
	  
	  if(ashman > 2 && amplitudeRatio > 0.85){
	    multiPeakChannelsCombined->cd();
	    storeOutputCanvas(canvas,noiseHist,noiseFit,noiseFit2Gaus,name);
	    nbadDoublePeakCombined++;
	    moduleNumeratorDoublePeak[detid]++;
	  }
	}
      }
    }
  }

  // plot the chi2 and peak distance
  if(testDoubleGaussianChannels){
    storeOutputCanvas(canvas,chi2Distance,"chi2TestStatistics",outputDIR);
    storeOutputCanvas(canvas,peakDistance,"peakDistanceTestStatistics",outputDIR);
    storeOutputCanvas(canvas,ashmanDistance,"ashmanTestStatistics",outputDIR);
    storeOutputCanvas(canvas,amplitudeRatioDistance,"amplitudeRatioDistance",outputDIR);
    storeOutputCanvas(canvas,bimodalityDistance,"bimodalityDistance",outputDIR);
  }
  
  std::cout<<std::endl;
  badStripsNFilledBins->Close();
  badKsTest->Close();
  badaDTest->Close();
  badjBTest->Close();
  badChi2Test->Close();
  badCombinedTest->Close();
  badJBNotKSTest->Close();
  badaDNotKSandjBTest->Close();
  badChi2NotKSandjBandaDTest->Close();
  multiPeakChannelsCombined->Close();
  //////
  multiPeakChannelsChi2->Close();
  multiPeakChannelsDistance->Close();
  multiPeakChannelsAshman->Close();
  multiPeakChannelsAmplitude->Close();
  multiPeakChannelsBimodality->Close();

  cout<<"#### Bad Nfilled bins "<<nbadNFilledBins<<" --> "<<double(nbadNFilledBins)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad KS Test Channels "<<nbadKsTest<<" ---> "<<double(nbadKsTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad JB Test Channels "<<nbadjBTest<<" ---> "<<double(nbadjBTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad AD Test Channels "<<nbadaDTest<<" ---> "<<double(nbadaDTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad Chi2 Test Channels "<<nbadChi2Test<<" ---> "<<double(nbadChi2Test)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad JB but not KS Test Channels "<<nbadJBNotKSTest<<" ---> "<<double(nbadJBNotKSTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad AD but not KS and not JB Test Channels "<<nbadaDNotKSandjBTest<<" ---> "<<double(nbadaDNotKSandjBTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad Chi2 but not KS and JB and AD Test Channels "<<nbadChi2NotKSandjBandaDTest<<" ---> "<<double(nbadChi2NotKSandjBandaDTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  cout<<"#### Bad Combined Test Channels "<<nbadCombinedTest<<" ---> "<<double(nbadCombinedTest)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;

  if(testDoubleGaussianChannels){
    cout<<"###############################"<<endl;
    cout<<"#### Multiple peak finder ####"<<endl;
    cout<<"##############################"<<endl;
    cout<<"Two peak by Chi2 "<<nbadDoublePeakChi2<<" --> "<<double(nbadDoublePeakChi2)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
    cout<<"Two peak by Distance "<<nbadDoublePeakDistance<<" --> "<<double(nbadDoublePeakDistance)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
    cout<<"Two peak by Ashman "<<nbadDoublePeakAshman<<" --> "<<double(nbadDoublePeakAshman)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
    cout<<"Two peak by Amplitude "<<nbadDoublePeakAmplitude<<" --> "<<double(nbadDoublePeakAmplitude)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
    cout<<"Two peak by Bimodality "<<nbadDoublePeakBimodality<<" --> "<<double(nbadDoublePeakBimodality)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
    cout<<"Two peak by Combibed "<<nbadDoublePeakCombined<<" ---> "<<double(nbadDoublePeakCombined)/(tree->GetEntries()/reductionFactor)<<" % "<<endl;
  }

  /// -------> 
  ofstream channelMap ((outputDIR+"/fractionOfGoodChannels.txt").c_str());
  for(auto module : moduleDenominator)
    channelMap << module.first <<"  "<< 1. - double(moduleNumerator[module.first])/double(moduleDenominator[module.first]) << "\n";
  channelMap.close();

  /// -------> 
  ofstream nchannelMapFilledBins ((outputDIR+"/numberBadChannelsFilledBins.txt").c_str());
  for(auto module : moduleNumeratorFilledBins)
    nchannelMapFilledBins << module.first <<"  "<< moduleNumeratorFilledBins[module.first] << "\n";
  nchannelMapFilledBins.close();

  /// -------> 
  ofstream nchannelMap ((outputDIR+"/numberBadChannels.txt").c_str());
  for(auto module : moduleNumerator)
    nchannelMap << module.first <<"  "<< moduleNumerator[module.first] << "\n";
  nchannelMap.close();

  /// -------> 
  //  ofstream nNonEdgechannelMap ((outputDIR+"/numberBadChannelsNonEdge.txt").c_str());
  //  for(auto module : moduleNonEdgeNumerator)
  //    nNonEdgechannelMap << module.first <<"  "<< moduleNonEdgeNumerator[module.first] << "\n";
  //  nNonEdgechannelMap.close();

  /// -------> 
  //  ofstream nAPVEdgechannelMap ((outputDIR+"/numberBadChannelsAPVEdge.txt").c_str());
  //  for(auto module : moduleAPVEdgeNumerator)
  //    nAPVEdgechannelMap << module.first <<"  "<< moduleAPVEdgeNumerator[module.first] << "\n";
  //  nAPVEdgechannelMap.close();

  /// -------> 
  ofstream nchannelMapKS ((outputDIR+"/numberBadChannelsKS.txt").c_str());
  for(auto module : moduleNumeratorKS)
    nchannelMapKS << module.first <<"  "<< moduleNumeratorKS[module.first] << "\n";
  nchannelMapKS.close();

  /// -------> 
  ofstream nchannelMapJB ((outputDIR+"/numberBadChannelsJB.txt").c_str());
  for(auto module : moduleNumeratorJB)
    nchannelMapJB << module.first <<"  "<< moduleNumeratorKS[module.first] << "\n";
  nchannelMapJB.close();

  /// -------> 
  ofstream nchannelMapDoublePeak ((outputDIR+"/numberBadChannelsDoublePeak.txt").c_str());
  for(auto module : moduleNumeratorDoublePeak)
    nchannelMapDoublePeak << module.first <<"  "<< moduleNumeratorDoublePeak[module.first] << "\n";
  nchannelMapDoublePeak.close();
  
  // ------> detailed info of bad strips
  ofstream badStripDump ((outputDIR+"/badStripDump.txt").c_str());
  for(auto badstrip : badStrip){
    badStripDump<< badstrip.fecCrate_<<" "<<badstrip.fecSlot_<<" "<<badstrip.fecRing_<<" "<<badstrip.ccuAdd_<<" "<<badstrip.ccuCh_<<" "<<badstrip.fedKey_<<" "<<badstrip.lldCh_<<" "<<badstrip.apvid_<<" "<<badstrip.stripid_<<" \n";
  }
  badStripDump.close();

}