Exemple #1
0
TGraph* newShiftChi2Graph(const T* const dat1,
                          const Int_t    nd1,
                          const U* const dat2,
                          const Int_t    nd2,
                          const Int_t    minbin=-1,   // -1 => 0
                          const Int_t    maxbin=-1,   // -1 => nd1-1
                          const Bool_t   useSqrtErrs=kFALSE) {
   const Int_t minb = (minbin<0) ?     0 : minbin;
   const Int_t maxb = (maxbin<0) ? nd1-1 : maxbin;
   if ( (maxb<=minb) || (maxb>=nd1) || (maxb>=nd2) ) {
      Fatal("newShiftChi2Graph",
            "Invalid maxb=%d. (minb=%d, nd1=%d, nd2=%d)",
            maxb, minb, nd1, nd2);
   }
   const T* c1 = dat1;
   const U* c2 = dat2;
   Int_t pos, j(0);
   const Int_t ndh = (maxb-minb+1)/2;
   TGraphErrors* gc = new TGraphErrors;
   for (Int_t sh=1-ndh; sh<ndh; ++sh) {
      Double_t x=0, t=0, cmp=0;
      c1 = dat1+minb;
      c2 = dat2+minb-sh;

      for (Int_t i=minb; i<=maxb; ++i, ++c1, ++c2) {
         pos = c2 - dat2;
#ifdef SHIFT_INTO_WINDOW
         if (pos<nd2) {
            if (pos>=0) {
#else
         if (pos<=maxb) {
            if (pos>=minb) {
#endif
               t  = (*c1) - (*c2);
               t *= t;
               if (useSqrtErrs) {
                  t /= TMath::Abs(static_cast<Double_t>(*c2));
               }
               x += t;
               cmp += 1.0;
            }
         } else {
            break;
         }
      }
      if (cmp>1.0) {
         x /= cmp-1.0;

         gc->SetPoint(j, static_cast<Double_t>(sh), x);
         
         ++j;
      }
   }

   return gc;
}



void noAveBounceStdy(const Char_t* rtfn,
                     const Char_t* wvfn,
                     const Char_t* FPNfn,
                     const Char_t* outfn,
                     const Int_t   fitType=0,
                     const Int_t   fitOpt=0,
                     const Char_t* minner="Minuit2",
                     const Char_t* algo="Migrad",
                     const Int_t   shiftminb=-1,
                     const Int_t   shiftmaxb=-1,
                     const Bool_t  applyFilter=kTRUE) {
   // fitType:
   //   0 = fit theta phi with getShiftLL
   //   5 = fit theta phi with getShiftChi2
   //  20 = fit 3 deltaT's; use contraints for other 3
   //
   // fitOpt:
   //   0 = fit (filtered) waveforms
   //  10 = fit envelope of (filtered) waveforms
   //
   //     minner              algo
   //  Minuit /Minuit2        Migrad,Simplex,Combined,Scan  (default is Migrad)
   //  Minuit2                Fumili2
   //  Fumili
   //  GSLMultiMin            ConjugateFR, ConjugatePR, BFGS, 
   //                         BFGS2, SteepestDescent
   //  GSLMultiFit
   //  GSLSimAn
   //  Genetic

   if (mini==0) {
      mini = ROOT::Math::Factory::CreateMinimizer(minner, algo);
      mini->SetMaxFunctionCalls(1000000);
      mini->SetMaxIterations(10000);
      mini->SetTolerance(0.001);
      mini->SetPrintLevel(0);
   }

   nt = new TChain("runtree");
   nt->Add(rtfn);

   const Long64_t nents = nt->GetEntries();
   if (nents==0) {
      Error("noAveBunceStdy","No events in tree from [%s].",rtfn);
      return;
   }

   ns = new TChain("nShifts");
   ns->Add(wvfn);

   if (nents>ns->GetEntries()) {
      Error("bounceStudy","%lld entries in runtree but "
            "%lld entries in shift tree",nents,ns->GetEntries());
      return;
   }
   
   fpnf = TFile::Open(FPNfn);
   if ( (fpnf==0) || (fpnf->IsZombie()) ) {
      Error("bounceStudy","Could not open FPN file [%s]",FPNfn);
      return;
   }
   for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
      gPed[ch]   = dynamic_cast<TGraphErrors*>(
         fpnf->Get(Form("gExlPed_ch%d",ch)));
      gNoise[ch] = dynamic_cast<TGraphErrors*>(
         fpnf->Get(Form("gExlRms_ch%d",ch)));
      if ( (gPed[ch]==0) || (gNoise[ch]==0) ) {
         Error("bounceStudy",
               "Couldn't get FPN/noise graphs from [%s]",FPNfn);
         return;
      }
   }

   // read from tree into...
   Float_t  pedsubs[NSnConstants::kNchans][NSnConstants::kNsamps];
   Float_t  psshift[NSnConstants::kNchans][NSnConstants::kNsamps];
   Float_t  filtered[NSnConstants::kNchans][NSnConstants::kNsamps];
   Float_t  envelope[NSnConstants::kNchans][NSnConstants::kNsamps];
   UShort_t samples[NSnConstants::kNchans][NSnConstants::kNsamps];
   UInt_t   evnum, utime, utimeus, mbchksum;
   
   nt->SetBranchAddress("mbChecksum",&mbchksum);
   nt->SetBranchAddress("EvtNum",&evnum);
   nt->SetBranchAddress("unixTime",&utime);
   nt->SetBranchAddress("unixTimeUS",&utimeus);
   for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
      nt->SetBranchAddress(Form("data%02d",ch), &(samples[ch][0]));
   }

   // shift for stop tree
   Int_t nsent;
   UInt_t nsevn;
   Int_t aveShift(0), aveLen(0);
   Int_t shift[NSnConstants::kNchans];
   Int_t len[NSnConstants::kNchans];
   ns->SetBranchAddress("Ent",&nsent);
   ns->SetBranchAddress("EvtNum",&nsevn);
   for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
      ns->SetBranchAddress(Form("shift%02d",ch),&(shift[ch]));
      ns->SetBranchAddress(Form("len%02d",ch),&(len[ch]));
   }
   ns->BuildIndex("EvtNum");

   // output
   TString hn;
   outf = TFile::Open(outfn,"recreate");

   if (fitType==20) {
      hn = "EvtNum:";
      for (Int_t i=1; i<NSnConstants::kNchans; ++i) {
         hn += Form("dt%d%d:",i,i-1);
      }
      hn += "chi2";
      tChanDTsFit = new TNtuple("tChanDTsFit",
                                "fit of channel dts",
                                hn.Data());
   } else {
      tThetaPhiFit = new TNtuple("tThetaPhiFit","theta phi fit tree",
                                 "EvtNum:theta:phi:chi2");
   }


   for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
      for (Int_t xc=0; xc<ch; ++xc) {
         hn = Form("hFiltCorrCoefShiftVsEvt_ch%02d_ch%02d",ch,xc);
         hFiltCorrCoefShiftVsEvt[ch][xc] = new TH2F(hn.Data(),
              Form("corr coef for offset between ch%d and ch%d of filtered "
                   "wvfms vs event;event;offset (ch%d-ch%d);correlation coef",
                   ch,xc,ch,xc),
                                          nents, -0.5, nents-0.5,
                                          NSnConstants::kNsamps,
                                          1-(NSnConstants::kNsamps/2)-0.5,
                                          (NSnConstants::kNsamps/2)+0.5);
         hFiltCorrCoefShiftVsEvt[ch][xc]->SetDirectory(outf);

         hn = Form("hFiltShiftChi2VsEvt_ch%02d_ch%02d",ch,xc);
         hFiltShiftChi2VsEvt[ch][xc] = new TH2F(hn.Data(),
              Form("#chi^{2} of offset between ch%d and ch%d of filtered "
                   "wvfms vs event;event;offset (ch%d-ch%d);#chi^{2}",
                   ch,xc,ch,xc),
                                          nents, -0.5, nents-0.5,
                                          NSnConstants::kNsamps,
                                          1-(NSnConstants::kNsamps/2)-0.5,
                                          (NSnConstants::kNsamps/2)+0.5);
         hFiltShiftChi2VsEvt[ch][xc]->SetDirectory(outf);
      }
   }

   Long64_t ne(0);
   for (Long64_t ev=0; ev<nents; ++ev) {
   //for (Long64_t ev=0; ev<250; ++ev) {
      if ( (ev%500)==0 ) {
         fprintf(stderr,"Processing %lld / %lld  (%02.2f%%)            \r",
            ev, nents,
            100.*static_cast<Float_t>(ev)/static_cast<Float_t>(nents));
      }
      nt->GetEntry(ev);
      ne = ns->GetEntryNumberWithIndex(evnum);
      if (ne>-1) {
         ns->GetEntry(ne);

         // find the stop shift
         aveShift = aveLen = 0;
         for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
            aveShift += shift[ch];
            aveLen   += len[ch];
         }
         aveShift = TMath::Nint( static_cast<Float_t>(aveShift)/
                                 static_cast<Float_t>(NSnConstants::kNchans) );
         aveLen   = TMath::Nint( static_cast<Float_t>(aveLen)/
                                 static_cast<Float_t>(NSnConstants::kNchans) );
         const Int_t shiftStart = NSnConstants::kNsamps-1 - aveShift - aveLen;
         for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
            // subtract FPN
            const Double_t* pd = gPed[ch]->GetY();
            const UShort_t* sp = &(samples[ch][0]);
            Float_t*        ps = &(pedsubs[ch][0]);
            Float_t*        ph = &(psshift[ch][ shiftStart ]);
            for (Int_t sm=0; sm<NSnConstants::kNsamps;
                                  ++sm, ++pd, ++sp, ++ps, ++ph) {
               *ps = *sp - *pd;
               while ( (ph-&(psshift[ch][0])) >= NSnConstants::kNsamps) {
                  ph -= NSnConstants::kNsamps;
               }
               *ph = *ps;
            }
            
            // apply filter
            memcpy(&(filtered[ch][0]), &(psshift[ch][0]),
                   NSnConstants::kNsamps*sizeof(Float_t));
            if (applyFilter) {
               filterWaveform(&(filtered[ch][0]), NSnConstants::kNsamps);
            }
            // find envelope
            memcpy(&(envelope[ch][0]), &(filtered[ch][0]),
                   NSnConstants::kNsamps*sizeof(Float_t));
            TSnSpectral::EnvelopeReal(&(envelope[ch][0]), NSnConstants::kNsamps);

#ifdef DEBUG_SHIFTS
            TCanvas* cdbgsh = new TCanvas;
            cdbgsh->cd();
            Float_t xsm[NSnConstants::kNsamps], rsmp[NSnConstants::kNsamps];
            for (Int_t i=0; i<NSnConstants::kNsamps; ++i) {
               xsm[i] = i;
               rsmp[i] = samples[ch][i];
            }
            TGraph* gsmp = new TGraph(NSnConstants::kNsamps, xsm, rsmp);
            TGraph* gps  = new TGraph(NSnConstants::kNsamps, xsm, 
                                      &(pedsubs[ch][0]));
            TGraph* gph  = new TGraph(NSnConstants::kNsamps, xsm,
                                      &(psshift[ch][0]));
            TGraph* gfl  = new TGraph(NSnConstants::kNsamps, xsm,
                                      &(filtered[ch][0]));
            TGraph* gen  = new TGraph(NSnConstants::kNsamps, xsm,
                                      &(envelope[ch][0]));
            gsmp->SetMarkerStyle(7);
            gsmp->SetMarkerColor(kBlack);
            gsmp->SetLineColor(kBlack);
            gps->SetMarkerStyle(7);
            gps->SetMarkerColor(kRed);
            gps->SetLineColor(kRed);
            gph->SetMarkerStyle(7);
            gph->SetMarkerColor(kAzure-7);
            gph->SetLineColor(kAzure-7);
            gfl->SetMarkerStyle(7);
            gfl->SetMarkerColor(kGreen+2);
            gfl->SetLineColor(kGreen+2);
            gen->SetMarkerStyle(7);
            gen->SetMarkerColor(kViolet-1);
            gen->SetLineColor(kViolet-1);
            gsmp->SetMinimum(-1500);
            gsmp->SetMaximum(2500);
            Printf("ch%d: shift=%d, len=%d",
                   ch, shift[ch], len[ch]);
            gsmp->Draw("apc");
            gps->Draw("pc");
            gph->Draw("pc");
            gfl->Draw("pc");
            gen->Draw("pc");
            cdbgsh->WaitPrimitive();
            delete gsmp; delete gps; delete gph; delete gfl; delete gen;
            delete cdbgsh;
#endif
         }
         
         if (shiftmaxb!=shiftminb) {
            maxdt = (shiftmaxb - shiftminb) / (2.0*kSmpRate);
         } else {
            maxdt =  NSnConstants::kNsamps  / (2.0*kSmpRate);
         }
         
         const Float_t* chdat(0), * xcdat(0);
         for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
            if (fitOpt==0) {
               chdat = &(filtered[ch][0]);
            } else if (fitOpt==10) {
               chdat = &(envelope[ch][0]);
            } else {
               Fatal("noAveBounceStdy","Unknown fitOpt [%d]",fitOpt);
            }
            for (Int_t xc=0; xc<ch; ++xc) {
               if (fitOpt==0) {
                  xcdat = &(filtered[xc][0]);
               } else if (fitOpt==10) {
                  xcdat = &(envelope[xc][0]);
               } else {
                  Fatal("noAveBounceStdy","Unknown fitOpt [%d]",fitOpt);
               }
               gcor[ch][xc] = newCorrCoefGraph(chdat,
                                               xcdat,
                                               NSnConstants::kNsamps,
                                               shiftminb,
                                               shiftmaxb);
               gspl[ch][xc] = new TSpline3(Form("spl_%d_%d",ch,xc),
                                           gcor[ch][xc]);
               gchi[ch][xc] = newShiftChi2Graph(chdat,
                                                NSnConstants::kNsamps,
                                                xcdat,
                                                NSnConstants::kNsamps,
                                                shiftminb,
                                                shiftmaxb);
               gspc[ch][xc] = new TSpline3(Form("spc_%d_%d",ch,xc),
                                           gchi[ch][xc]);

#ifdef DEBUG_CORRELS
            TCanvas* cdbgcl = new TCanvas("cdbgcl","cdbgcl",800,1000);
            cdbgcl->Divide(1,3);
            cdbgcl->cd(1);
            Float_t xxsm[NSnConstants::kNsamps];
            for (Int_t i=0; i<NSnConstants::kNsamps; ++i) {
               xxsm[i] = i;
            }
            TGraph* gcfl  = new TGraph(NSnConstants::kNsamps, xxsm,
                                       &(filtered[ch][0]));
            TGraph* gxfl  = new TGraph(NSnConstants::kNsamps, xxsm,
                                       &(filtered[xc][0]));
            TGraph* gcen  = new TGraph(NSnConstants::kNsamps, xxsm,
                                       &(envelope[ch][0]));
            TGraph* gxen  = new TGraph(NSnConstants::kNsamps, xxsm,
                                       &(envelope[xc][0]));
            gcfl->SetMarkerStyle(7);
            gcfl->SetMarkerColor(kBlack);
            gcfl->SetLineColor(kBlack);
            gxfl->SetMarkerStyle(7);
            gxfl->SetMarkerColor(kRed);
            gxfl->SetLineColor(kRed);
            gcen->SetMarkerStyle(7);
            gcen->SetMarkerColor(kGray);
            gcen->SetLineColor(kGray);
            gxen->SetMarkerStyle(7);
            gxen->SetMarkerColor(kViolet-1);
            gxen->SetLineColor(kViolet-1);
            gcfl->Draw("apc");
            gxfl->Draw("pc");
            gcen->Draw("pc");
            gxen->Draw("pc");
            cdbgcl->cd(2);
            gspl[ch][xc]->SetMarkerStyle(7);
            gspl[ch][xc]->SetMarkerColor(kAzure-7);
            gspl[ch][xc]->SetLineColor(kAzure-7);
            gspl[ch][xc]->Draw("pc");
            cdbgcl->cd(3);
            gspc[ch][xc]->SetMarkerStyle(7);
            gspc[ch][xc]->SetMarkerColor(kViolet-6);
            gspc[ch][xc]->SetLineColor(kViolet-6);
            gspc[ch][xc]->Draw("pc");
            cdbgcl->cd();
            cdbgcl->Update();
            cdbgcl->WaitPrimitive();
            delete gcfl; delete gxfl; delete cdbgcl;
            delete gcen; delete gxen;
#endif

               const Int_t gn = gcor[ch][xc]->GetN();
               const Double_t* gx = gcor[ch][xc]->GetX(),
                             * gy = gcor[ch][xc]->GetY(),
                             * cx = gchi[ch][xc]->GetX(),
                             * cy = gchi[ch][xc]->GetY();
               for (Int_t k=0; k<gn; ++k, ++gx, ++gy, ++cx, ++cy) {
                  hFiltCorrCoefShiftVsEvt[ch][xc]->Fill(ev, *gx, *gy);
                  hFiltShiftChi2VsEvt[ch][xc]->Fill(ev, *cx, *cy);
               }

            }
         }
         
         if (fitType==20) {
            // fit for the best, consistent time offsets
            mini->Clear();
            ROOT::Math::Functor f(&getDeltaTsLL, NSnConstants::kNchans-1);
            mini->SetFunction(f);
            for (Int_t ch=1; ch<NSnConstants::kNchans; ++ch) {
               if (strcmp(minner,"Genetic")==0) {
                  mini->SetLimitedVariable(ch-1, 
                                           Form("dt%d%d",ch,ch-1), 0, 0.01,
                                           -maxdt, maxdt);
               } else {
                  mini->SetVariable(ch-1, Form("dt%d%d",ch,ch-1), 0, 0.01);
               }
            }
            mini->Minimize();
            const Double_t* result = mini->X();
            const Double_t* rs = result;
            Float_t* tofil = new Float_t[NSnConstants::kNchans+2];
            Float_t* tf = tofil;
            *tf++ = ev;
            for (Int_t ch=1; ch<NSnConstants::kNchans; ++ch, ++tf, ++rs) {
               *tf = *rs;
            }
            *tf = mini->MinValue();
            tChanDTsFit->Fill(tofil);
            delete[] tofil;
#ifdef DEBUG_DTS
            for (Int_t ch=1; ch<NSnConstants::kNchans; ++ch) {
               Printf("result[%d]=%g",ch-1,result[ch-1]);
            }
            TCanvas* cdbgdt = new TCanvas("cdbgdt","cdbgdt",1000,1000);
            cdbgdt->Divide(2,3);
            Float_t xxsm[NSnConstants::kNsamps];
            for (Int_t i=0; i<NSnConstants::kNsamps; ++i) {
               xxsm[i] = i;
            }

            TGraph* gorg[NSnConstants::kNchans];
            TGraph* gocp[NSnConstants::kNchans];
            TGraph* goen[NSnConstants::kNchans];
            TGraph* gshf[NSnConstants::kNchans][NSnConstants::kNchans];
            TGraph* gshe[NSnConstants::kNchans][NSnConstants::kNchans];
            for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
               gorg[ch] = new TGraph(NSnConstants::kNsamps, xxsm,
                                     &(filtered[ch][0]));
               gocp[ch] = new TGraph(NSnConstants::kNsamps, xxsm,
                                     &(filtered[ch][0]));
               goen[ch] = new TGraph(NSnConstants::kNsamps, xxsm,
                                     &(envelope[ch][0]));
               for (Int_t xc=0; xc<ch; ++xc) {
                  Double_t dt=0;
                  for (Int_t i=(ch-xc); i>0; --i) {
                     dt += result[ch-i];
                  }
                  dt *= kSmpRate; // convert to samples
                  Printf("dt[%d][%d]=%g",ch,xc,dt);
                  gshf[ch][xc] = new TGraph(NSnConstants::kNsamps);
                  gshe[ch][xc] = new TGraph(NSnConstants::kNsamps);
                  for (Int_t i=0; i<NSnConstants::kNsamps; ++i) {
                     gshf[ch][xc]->SetPoint(i, xxsm[i]+dt, filtered[xc][i]);
                     gshe[ch][xc]->SetPoint(i, xxsm[i]+dt, envelope[xc][i]);
                  }
                  gshf[ch][xc]->SetMarkerStyle(7);
                  gshf[ch][xc]->SetLineColor(kRed);
                  gshf[ch][xc]->SetMarkerColor(kRed);
                  gshe[ch][xc]->SetMarkerStyle(7);
                  gshe[ch][xc]->SetLineColor(kViolet-1);
                  gshe[ch][xc]->SetMarkerColor(kViolet-1);
               }
               gorg[ch]->SetMarkerStyle(7);
               gorg[ch]->SetLineColor(kBlack);
               gorg[ch]->SetMarkerColor(kBlack);
               goen[ch]->SetMarkerStyle(7);
               goen[ch]->SetLineColor(kGray);
               goen[ch]->SetMarkerColor(kGray);
               gocp[ch]->SetMarkerStyle(7);
               gocp[ch]->SetLineStyle(7);
               gocp[ch]->SetLineColor(kGreen+2);
               gocp[ch]->SetMarkerColor(kGreen+2);
            }
            gStyle->SetOptStat(0);
            Int_t pp=0;
            for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
               for (Int_t xc=0; xc<ch; ++xc) {
                  cdbgdt->cd(++pp);
                  hn = Form("hd_%d_%d",ch,xc);
                  TH2F* hd = new TH2F(hn.Data(),
                                      Form("black=ch%d, red/green=ch%d;"
                                           "sample;ADC",ch,xc),
                                      NSnConstants::kNsamps, -0.5,
                                      NSnConstants::kNsamps-0.5,
                                      200, -900, 900);
                  hd->SetBit(TH1::kCanDelete);
                  hd->Draw();
                  gorg[ch]->Draw("pc");
                  goen[ch]->Draw("pc");
                  gocp[xc]->Draw("pc");
                  gshf[ch][xc]->Draw("pc");
                  gshe[ch][xc]->Draw("pc");
               }
            }
            cdbgdt->cd();
            cdbgdt->Update();
            cdbgdt->WaitPrimitive();
            for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
               delete gorg[ch]; delete gocp[ch]; delete goen[ch];
               for (Int_t xc=0; xc<ch; ++xc) {
                  delete gshf[ch][xc];
                  delete gshe[ch][xc];
               }
            }
            delete cdbgdt;
#endif
         } else {

            Int_t npars(2);
            Double_t (*fitFunction)(const Double_t*) = 0;
            if (fitType==0) {
               fitFunction = &getShiftLL;
            } else if (fitType==5) {
               fitFunction = &getShiftChi2;
            } else {
               Fatal("bounceStudy","Unknown fit type %d",fitType);
            }
            
            mini->Clear();
            ROOT::Math::Functor f(fitFunction, npars);
            mini->SetFunction(f);
            
            if (strcmp(minner,"Genetic")==0) {
               mini->SetLimitedVariable(0, "theta",     3, 0.01,
                                        0, TMath::Pi());
               mini->SetLimitedVariable(1, "phi"  ,   5.5, 0.01,
                                        0, TMath::TwoPi());
            } else {
               //mini->SetVariable(0, "theta",             TMath::Pi(), 0.01);
               //mini->SetVariable(1, "phi"  ,   (gRandom->Rndm()-0.5), 0.01);
               mini->SetVariable(0, "theta",     3, 0.01);
               mini->SetVariable(1, "phi"  ,   5.5, 0.01);
               //mini->SetVariable(0, "theta",     3, 0.05);
               //mini->SetVariable(1, "phi"  ,   5.5, 0.05);
            }
            mini->Minimize();
            const Double_t* result = mini->X();
            tThetaPhiFit->Fill(ev, result[0], result[1], mini->MinValue());


#ifdef DEBUG_THETAPHI
            // regularize the angles
            Double_t theta = TVector2::Phi_mpi_pi(result[0]);
            Double_t phi   = result[1];
            if (theta<0) {
               theta *= -1.0;
               phi   += TMath::Pi();
            }
            phi   = TVector2::Phi_0_2pi(phi);
            Printf("theta=%g, phi=%g (%g, %g)",
                   theta*TMath::RadToDeg(),
                   phi*TMath::RadToDeg(),
               result[0], result[1]);
            TCanvas* cdbgtp = new TCanvas("cdbgtp","cdbgtp",1000,1000);
            cdbgtp->Divide(2,3);
            Float_t xxsm[NSnConstants::kNsamps];
            for (Int_t i=0; i<NSnConstants::kNsamps; ++i) {
               xxsm[i] = i;
            }
            
            TGraph* gorg[NSnConstants::kNchans];
            TGraph* gocp[NSnConstants::kNchans];
            TGraph* gshf[NSnConstants::kNchans][NSnConstants::kNchans];
            for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
               gorg[ch] = new TGraph(NSnConstants::kNsamps, xxsm,
                                     &(filtered[ch][0]));
               gocp[ch] = new TGraph(NSnConstants::kNsamps, xxsm,
                                     &(filtered[ch][0]));
               for (Int_t xc=0; xc<ch; ++xc) {
                  Double_t dtcor=0;
                  for (Int_t i=(ch-xc); i>0; --i) {
                     dtcor += dtCorrs[ch-i];
                  }
                  const TVector3& posCh = getStnPos(ch);
                  const TVector3& posXc = getStnPos(xc);
                  TVector3 norm;
                  norm.SetMagThetaPhi(1.0, result[0], result[1]);
                  //norm.SetMagThetaPhi(1.0, 2.95833, 5.497787);
                  const Double_t  disCh = -(posCh.Dot(norm));
                  const Double_t  disXc = -(posXc.Dot(norm));
                  // !!! check sign of delta(distance) and dtcor!
                  const Double_t  dt = kSmpRate * (
                     ( (disCh-disXc) * kNgTopFern / kC_m_ns )   // from m to ns
                     + dtcor );
                  Printf("dt[%d,%d]=%g (dis[%d]=%g, dis[%d]=%g)",
                         ch,xc,dt, ch,disCh,xc,disXc);
                  gshf[ch][xc] = new TGraph(NSnConstants::kNsamps);
                  for (Int_t i=0; i<NSnConstants::kNsamps; ++i) {
                     gshf[ch][xc]->SetPoint(i, xxsm[i]+dt, filtered[xc][i]);
                  }
                  gshf[ch][xc]->SetMarkerStyle(7);
                  gshf[ch][xc]->SetLineColor(kRed);
                  gshf[ch][xc]->SetMarkerColor(kRed);
               }
               gorg[ch]->SetMarkerStyle(7);
               gorg[ch]->SetLineColor(kBlack);
               gorg[ch]->SetMarkerColor(kBlack);
               gocp[ch]->SetMarkerStyle(7);
               gocp[ch]->SetLineStyle(7);
               gocp[ch]->SetLineColor(kGreen+2);
               gocp[ch]->SetMarkerColor(kGreen+2);
            }
            gStyle->SetOptStat(0);
            Int_t pp=0;
            for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
               for (Int_t xc=0; xc<ch; ++xc) {
                  cdbgtp->cd(++pp);
                  hn = Form("hd_%d_%d",ch,xc);
                  TH2F* hd = new TH2F(hn.Data(),
                                      Form("black=ch%d, red/green=ch%d;"
                                           "sample;ADC",ch,xc),
                                      NSnConstants::kNsamps, -0.5,
                                      NSnConstants::kNsamps-0.5,
                                      200, -900, 900);
                  hd->SetBit(TH1::kCanDelete);
                  hd->Draw();
                  gorg[ch]->Draw("pc");
                  gocp[xc]->Draw("pc");
                  gshf[ch][xc]->Draw("pc");
               }
            }
            cdbgtp->cd();
            cdbgtp->Update();
            cdbgtp->WaitPrimitive();
            for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
               delete gorg[ch]; delete gocp[ch];
               for (Int_t xc=0; xc<ch; ++xc) {
                  delete gshf[ch][xc];
               }
            }
            delete cdbgtp;
#endif

         }

         for (Int_t ch=0; ch<NSnConstants::kNchans; ++ch) {
            for (Int_t xc=0; xc<ch; ++xc) {
               delete gspl[ch][xc];
               delete gcor[ch][xc];
               delete gchi[ch][xc];
               delete gspc[ch][xc];
            }
         }

      }
   } // event loop

   outf->Write();

}