Universita' di GenovaINFN Sezione di Genova  
AIRWATCH / EUSO Genova

EPolygon - source file

// ESAF : Euso Simulation and Analysis Framework
// $Id: EFocalSurfacePainter.cc,v 1.53 2005/11/11 10:37:00 pesce Exp $
// Author A.Thea Jun, 28 2004

/*****************************************************************************
 * ESAF: Euso Simulation and Analysis Framework                              *
 *                                                                           *
 *  Id: FocalSurfacePainter                                                  *
 *  Package: EventViewer                                                     *
 *  Coordinator: Alessandro.Thea                                             *
 *                                                                           *
 *****************************************************************************/

//______________________________________________________________________________
//
//  EFocalSurfacePainter
//
//  A painter to show the development of the signal on the focal surface.
//
//  Setters:
//  
//  ViewNspread
//  MaxColors
//
//
//  TO BE DONE
 
#include "EFocalSurfacePainter.hh"

#include "EEvent.hh"
#include "EDetector.hh"
#include "EElectronics.hh"
#include "EFee.hh"
#include "EAFee.hh"
#include "EMacroCellHit.hh"
#include "EChipTriggPars.hh"

#include "Etypes.hh"
#include "ERunParameters.hh"
#include "ESystemOfUnits.hh"

#include "Riostream.h"
#include "TCanvas.h"
#include "TList.h"
#include "TStyle.h"
#include "TVector3.h"
#include "TH1.h"
#include "TGString.h"

#include <TSystem.h>

using namespace TMath;
using namespace sou;

ClassImp(EFocalSurfacePainter)
ClassImp(EPolygon)

//_____________________________________________________________________________
EFocalSurfacePainter::EFocalSurfacePainter() : fDetector(0), fRunPars(0),
    fH1Hits(0), fHitsStyle(0), fH1SigProfile(0), fH1SigMaxProfile(0), fH1NoiseMaxProfile(0), 
    fH1NoiseMinProfile(0), fH1NoiseMeanProfile(0), fH1HitsMaxProfile(0), fLines(0) {
    //
    // Default constructor
    //
}

//_____________________________________________________________________________
EFocalSurfacePainter::EFocalSurfacePainter( EEvent* ev ) : fH1Hits(0),
    fHitsStyle(0), fH1SigProfile(0), fH1SigMaxProfile(0), fH1NoiseMaxProfile(0), 
    fH1NoiseMinProfile(0), fH1NoiseMeanProfile(0), fH1HitsMaxProfile(0), fLines(0) {
    // 
    //
    //
    
    fDetector = ev->GetDetector();
    fRunPars =  ev->GetRunPars();

    Constructor();
}

//_____________________________________________________________________________
EFocalSurfacePainter::EFocalSurfacePainter( EDetector* det, ERunParameters* runpars) :
    fH1Hits(0), fHitsStyle(0), fH1SigProfile(0), fH1SigMaxProfile(0), fH1NoiseMaxProfile(0),
    fH1NoiseMinProfile(0), fH1NoiseMeanProfile(0), fH1HitsMaxProfile(0), fLines(0) {
    // 
    //
    //

    fDetector = det;
    fRunPars =  runpars;

    Constructor();

}

//______________________________________________________________________________
void EFocalSurfacePainter::Constructor() {
    //
    // Constructor
    //
    
    fLines = new TList;

    fXaxis.SetTitle("X [mm]");
    fXaxis.SetLabelFont(42);
    fXaxis.SetTextFont(52);
    fYaxis.SetTitle("Y [mm]");
    fYaxis.SetLabelFont(42);
    fYaxis.SetTextFont(52);
    fHaxis.SetTitle("Rate");
    fHaxis.SetLabelFont(42);
    fHaxis.SetTextFont(52);
    fHaxis.SetTitleOffset(0.75);

    fGtu               = -1;

    fModified          = kFALSE;

    // graphics options
    fViewRange         = 5.;
    fViewThreshold     = 4;
    fViewBorder        = 0.2;
    fAutoThreshold     = kTRUE;

    fGifCanvasW        = 600;
    fGifCanvasH        = 600;

    fTxtCounter.SetTextAlign(13);
    fTxtCounter.SetTextSize(0.05);
    fTxtCounter.SetTextFont(52);
    fTxtSum.SetTextAlign(13);
    fTxtSum.SetTextSize(0.05);
    fTxtSum.SetTextFont(52);

    fShowAxis          = kTRUE;
    fShowOffPixels     = kFALSE;
    fShowEmptyPixels   = kFALSE;
    fShowGtuCounter    = kTRUE;
    fDrawNightGlow     = kFALSE;
    fIntegral      = kIntNone;
    fAutoRadius        = kTRUE;
    fMoveView          = kFALSE;


    fAlpha = 0;
    fApplyThreshold = kFALSE;
    fAbsoluteThreshold = kFALSE;

    fTriggers.clear();
    fHasTriggersFilled = kFALSE;
    
    fX1                = 0;
    fX2                = 0;
    fY1                = 0;
    fY2                = 0;

    fXmin              = 0;
    fXmax              = 0;
    fYmin              = 0;
    fYmax              = 0;

    fNumColors         = 50;
    fPaletteOffset     = 51;
    fMaxCounts         = 30;

    fStdPalette        = kFALSE;
    fPixelColorOff     = kBlack;
    fPixelColorEmpty   = kWhite;
    fPmtColorEmpty     = 49;
    fPmtColorHit       = 27;

    fCacheCode     = 0;

    fCurrentMapID      = kFeeSignals;
    fCurrentTrigger = 0;

    if ( !fDetector || !fRunPars ) {
        Info("EFocalSurfacePainter","Either Event or RunParameters is not defined. Painter made zombie.");
        MakeZombie(); 
        return;
    }

    Load();
    Modified();
    FindView( kFeeHits );
    fAutoRadius = kFALSE;
    UpdateHist();

}

//_____________________________________________________________________________
EFocalSurfacePainter::~EFocalSurfacePainter() {
    // 
    // Destructor
    // 
    
    Clear();
    SafeDelete(fLines);
    SafeDelete(fH1Hits);
    SafeDelete(fHitsStyle);
    SafeDelete(fH1SigProfile);
    SafeDelete(fH1SigMaxProfile);
    SafeDelete(fH1NoiseMaxProfile);
    SafeDelete(fH1NoiseMinProfile);
    SafeDelete(fH1NoiseMeanProfile);
    SafeDelete(fH1HitsMaxProfile);
}

//_____________________________________________________________________________
void EFocalSurfacePainter::Clear( Option_t *opt ) {
    //
    // Clear all temporay containers
    // 

    TString option(opt);

    ClearPolyLines();

    fPmtsToPaint.clear();
    fCache.clear();

    fPmtLines.clear();
    fPixelLines.clear();

    fFrontEndHits.clear();
    fFrontEndSignals.clear();
    fFrontEndNoises.clear();
    fMacroCellHits.clear();
    fSelFrontEndHits.clear();
    fECHits.clear();

//    fIntegralFrontEndHits.clear();
//    fIntegralFrontEndSignals.clear();
//    fIntegralMacroCellHits.clear();

    if ( fH1Hits ) fH1Hits->Clear();
    if ( fH1SigProfile ) fH1SigProfile->Clear();
    if ( fH1SigMaxProfile ) fH1SigMaxProfile->Clear();
    if ( fH1NoiseMaxProfile ) fH1NoiseMaxProfile->Clear();
    if ( fH1NoiseMinProfile ) fH1NoiseMinProfile->Clear();
    if ( fH1NoiseMeanProfile ) fH1NoiseMeanProfile->Clear();
    if ( fH1HitsMaxProfile ) fH1HitsMaxProfile->Clear();
}

//_____________________________________________________________________________
void EFocalSurfacePainter::Draw( Option_t *opt ) {
    //
    // Build polylines and then append the FSP to pad
    //

    if ( IsZombie() ) return;
    
    TString options(opt);

    // rebuild the lines if needed FIXME
    if ( fPixelLines.empty() ) BuildPolyLines();

    AppendPad(opt);
}

//______________________________________________________________________________
void EFocalSurfacePainter::UpdateHist( Bool_t force ) {
    //
    // 
    //

    if ( !fH1Hits) { 
        fH1Hits = new TH1F("HitsOnScreen","Hits on screen",1,1,10);
        fH1Hits->SetDirectory(0);
        fH1Hits->GetXaxis()->SetTitle("Gtu");
        fH1Hits->GetYaxis()->SetTitle("Signals hits");
    }

    if ( force || (fMaxCounts > 0 || fMaxCounts != (UInt_t)fH1Hits->GetNbinsX()) ) {
        //
        // resize the histogram
        //

        fH1Hits->SetBins( fMaxCounts, -.5, fMaxCounts+.5);
        if ( fHitsStyle ) {
            TStyle *savesty = gStyle;
            gStyle = fHitsStyle;
            fH1Hits->UseCurrentStyle();
            gStyle = savesty;
        }
    }

}

//_____________________________________________________________________________
void EFocalSurfacePainter::Paint( Option_t *opt ) {
    //
    // Options:
    // 
    // ng: paints pmts with a different colors according to the simulated bg
    //     rate
    //
    // hits: paints the electronics hits on the focal surface
    //

    TString options(opt);

    if (  (fGtu < fFirstGtu || fGtu > fLastGtu) && fGtu != -1 ) return;

    // something has changed, find the viewport again
    if ( fModified ) FindView( kFeeHits );

    // calculate frame
    Float_t viewWidth = fViewRange;

    if ( viewWidth < fRunPars->GetPmtData().GetPadSide() ) return;
        
    Float_t padHeight = gPad->GetWh()*gPad->GetHNDC();
    Float_t padWidth  = gPad->GetWw()*gPad->GetWNDC();
    Float_t padMin = TMath::Min(padHeight, padWidth);

    Float_t expand = 1+fViewBorder;

    fXmin = -( viewWidth*padWidth/padMin )+fViewCenter.X();
    fYmin = -( viewWidth*padHeight/padMin )+fViewCenter.Y();
    fXmax =  ( viewWidth*padWidth/padMin )+fViewCenter.X();
    fYmax =  ( viewWidth*padHeight/padMin )+fViewCenter.Y();

    // reset the box size
    fX1 = ( fXmin-fViewCenter.X() )*expand+fViewCenter.X();
    fX2 = ( fXmax-fViewCenter.X() )*expand+fViewCenter.X();
    fY1 = ( fYmin-fViewCenter.Y() )*expand+fViewCenter.Y();
    fY2 = ( fYmax-fViewCenter.Y() )*expand+fViewCenter.Y();

    gPad->Range( fX1, fY1, fX2, fY2);

    
    FindPmtsToPaint( fXmin, fYmin, fXmax, fYmax);
    
    if ( options == "ng" || fDrawNightGlow )
        PaintNightGlowRate();
    else 
        PaintHits();
}

//______________________________________________________________________________
Int_t EFocalSurfacePainter::GetColorPalette( Int_t theColor) const {
    //
    // -1 pixel color empty
    // -2 pixel color off
    // -3 pmt empty
    // -4 pmt hit
    // 0-n palette color
    //

    Int_t ncols;
    if ( fStdPalette ) {
        switch(theColor) {
            case kColorPixelEmpty:
            case kColorPixelOff:
            case kColorPmtEmpty:
            case kColorPmtHit:
                return 0;
            default:
                ncols = gStyle->GetNumberOfColors();
                if ( theColor >= ncols ) theColor = ncols-1;
                return gStyle->GetColorPalette(theColor);
        }            
    } else {
        switch(theColor) {
            case kColorPixelEmpty:
                return fPixelColorEmpty;
            case kColorPixelOff:
                return fPixelColorOff;
            case kColorPmtEmpty:
                return fPmtColorEmpty;
            case kColorPmtHit:
                return fPmtColorHit;
            default:
                ncols = fNumColors;
                if ( theColor >= ncols ) theColor = ncols-1;
                return fPaletteOffset+theColor;
        }
    }

} 

//______________________________________________________________________________
Int_t EFocalSurfacePainter::GetNormColorPalette(Float_t theColor ) const {
    //
    // convert 0-1 to mincol-maxcol
    //
    return GetColorPalette(Nint(theColor*GetPaletteNumColors()));
}
//_____________________________________________________________________________
void EFocalSurfacePainter::PaintHits() {
    //
    // Paint the 
    //

    const Counts_t* pixels = MapToPaint();
    if (!pixels) return; //FIXME or paint "No hits"?

    UInt_t sum(0);
    Int_t  nPmtPads = fRunPars->GetPmtData().GetNumPads();
    fH1Hits->Reset();
    for(UInt_t i(0); i< fPmtsToPaint.size(); i++){

        // check if this pmt is empty
        Bool_t isEmpty = kTRUE;
        Int_t suid = fRunPars->GetPmtGeo( fPmtsToPaint[i] )->GetStartUniqueId();
        for( Int_t k(0); k < nPmtPads; k++) 
            isEmpty &= pixels->count(suid+k) == 0;

        // draw the pmt
        EPolygon *p = GetPmtLine( fPmtsToPaint[i] );
        p->SetFillColor( GetColorPalette( isEmpty ? kColorPmtEmpty : kColorPmtHit ) );
        p->Paint("f");
        p->Paint();


        // paint the pixels
        for( Int_t k(0); k < nPmtPads; k++) {
            Int_t uid = suid+k;
            Color_t c = -1;
            if ( pixels->count(uid) == 0  ) {
                if ( fShowOffPixels )
                    c = GetColorPalette(kColorPixelOff);
            } else {
                Counts_t::const_iterator
                UInt_t counts = it != pixels->end() ? it->second : 0;

                // apply the pixel threshold
                if ( fApplyThreshold ) {
                    Double_t thres = 0;
                    if ( !fAbsoluteThreshold ) {
                        Double_t rate = fRunPars->GetNightGlowRateByUId(uid)/microsecond
                            *fRunPars->GetPmtData().GetGtuLength();
                        thres = rate+fAlpha*Sqrt(rate);
                    } else {
                        thres = fAlpha;
                    }
                    if ( counts > (UInt_t)Nint(Ceil(thres)) )
                        counts -= Nint(Ceil(thres));
                    else counts = 0;
                   
                }

                if ( counts == 0 ) {
                    if ( fShowEmptyPixels || fCurrentMapID == kCellHits )
                        // draw always empty hits in case for macrocells
                        c = GetColorPalette(kColorPixelEmpty);
                } else {
                    sum += counts;

                    fH1Hits->Fill(counts);
                    if ( counts < fMaxCounts ) {

                        c = GetNormColorPalette(0.99*counts/(Float_t)fMaxCounts);
                        //                        c = fPaletteOffset+Nint(0.99*((Float_t)fNumColors/(Float_t)fMaxCounts)*counts);
                    } else {
                        //                        c = fPaletteOffset+fNumColors;
                        c = GetNormColorPalette(1.);
                    }
                }
            }

            if ( c < 0 ) continue;
            p = GetPixelLine( uid );
            p->SetFillColor(c);

            p->Paint("f");
            p->Paint();
        }

    }

    if ( fShowGtuCounter ) {
        if ( fGtu == -1 )
            fTxtCounter.SetText( 0.1*(fXmax-fXmin)+fXmin, fYmax, Form("Gtus %d-%d",fFirstGtu,fLastGtu));
        else
            fTxtCounter.SetText( 0.1*(fXmax-fXmin)+fXmin, fYmax, Form("Gtu %d",fGtu));

        fTxtCounter.Paint();

        fTxtSum.SetText( 0.5*(fXmax-fXmin)+fXmin, fYmax, Form("Hits on screen: %d",sum));
        fTxtSum.Paint();
    }
    
    if ( fShowAxis ) {
        Int_t ndiv = 510;
        Int_t nColors = GetPaletteNumColors();
        Double_t xmin = fXmin;
        Double_t xmax = fXmax;
        fXaxis.PaintAxis(fXmin, fYmin, fXmax, fYmin, xmin, xmax, ndiv);
        fYaxis.PaintAxis(fXmin, fYmin, fXmin, fYmax, xmin, xmax, ndiv);

        Float_t w = (fXmax-fXmin)/25.;
        Float_t h = (fYmax-fYmin)/nColors;
        TPave pave(fXmax-w/2,fYmin,fXmax+w/2,fYmax,0);

        for( Int_t i(0); i < nColors; i++) {
            pave.SetFillColor(GetColorPalette(i)); 
            pave.PaintPave(fXmax-w/2,fYmin+i*h,fXmax+w/2,fYmin+(i+1)*h,0);
        }

        Double_t axMin = 0;
        Double_t axMax = fMaxCounts;
        fHaxis.PaintAxis(fXmax+w/2,fYmin,fXmax+w/2,fYmax,axMin,axMax,ndiv,"+L");
    }
}

//_____________________________________________________________________________
void EFocalSurfacePainter::PaintNightGlowRate() {
    //
    // Paint the elementary cells with color depending on the ng rate.
    //
    
    fDrawNightGlow = kTRUE;
    Double_t rmax = fRunPars->GetMaxNightGlowRate();
    Double_t rmin = fRunPars->GetMinNightGlowRate();
    Int_t ndiv = 10;

    EPolygon *p; 
    for(UInt_t i(0); i< fPmtsToPaint.size(); i++){

        // check if this pmt is empty
        Int_t suid = fRunPars->GetPmtGeo( fPmtsToPaint[i] )->GetStartUniqueId();

        // draw the pmt
        p = GetPmtLine( fPmtsToPaint[i] );

        Int_t chipId = fRunPars->FrontEndChip(suid);
        Double_t rate = fRunPars->GetNightGlowRate(chipId);
        p->SetFillColor( GetNormColorPalette((rate-rmin)/(rmax-rmin)) );

        p->Paint("f");
        p->Paint();

    }

    Int_t nColors = GetPaletteNumColors();
    Float_t w = (fXmax-fXmin)/15.;
    Float_t h = (fYmax-fYmin)/nColors;
    TPave pave(fXmax-w,fYmin,fXmax,fYmax,0);

    for( Int_t i(0); i < nColors; i++) {
       pave.SetFillColor(GetColorPalette(i)); 
       pave.PaintPave(fXmax-w,fYmin+i*h,fXmax,fYmin+(i+1)*h,0);
    }

    fHaxis.PaintAxis(fXmax,fYmin,fXmax,fYmax,rmin,rmax,ndiv,"+L");
}

//______________________________________________________________________________
Int_t EFocalSurfacePainter::DistancetoPrimitive(Int_t px, Int_t py) {
    //
    //
    //
    Int_t pxl, pyl, pxt, pyt;
    Int_t px1 = gPad->XtoAbsPixel(fX1);
    Int_t py1 = gPad->YtoAbsPixel(fY1);
    Int_t px2 = gPad->XtoAbsPixel(fX2);
    Int_t py2 = gPad->YtoAbsPixel(fY2);
    if (px1 < px2) {pxl = px1; pxt = px2;}
    else           {pxl = px2; pxt = px1;}
    if (py1 < py2) {pyl = py1; pyt = py2;}
    else           {pyl = py2; pyt = py1;}

    if ( (px >= pxl && px <= pxt) && (py >= pyl && py <= pyt) ) return 0;
    else return 9999;

}

//______________________________________________________________________________
void EFocalSurfacePainter::ExecuteEvent(Int_t event, Int_t px, Int_t py) {
    //
    // Execute an event when the mouse moves in the display active region
    //

    switch (event) {
        case kMouseMotion:
            break;
        case kButton1Up:
            if ( fMoveView ) {
                SetViewCenter(gPad->AbsPixeltoX(px),gPad->AbsPixeltoY(py));
                gPad->Modified();
                gPad->Update();
                fMoveView  = kFALSE;
            }
            break;
        default:
            break;
    }

}

//______________________________________________________________________________
char* EFocalSurfacePainter::GetObjectInfo(Int_t px, Int_t py) const {
    //   
    //   Redefines TObject::GetObjectInfo.
    //
    if (!gPad) return (char*)"";
    static char info[64];
    Double_t x  = gPad->PadtoX(gPad->AbsPixeltoX(px));//+fViewCenter.X();
    Double_t y  = gPad->PadtoY(gPad->AbsPixeltoY(py));//+fViewCenter.Y();
    Int_t pmtId=-1;
    Int_t pxUID=-1;

    size_t j;
    for (j=0; j<fPmtsToPaint.size(); j++) {
        if ( FindPmtLine(fPmtsToPaint[j])->DistancetoPrimitive(px,py) == 0 ) {
            pmtId = fPmtsToPaint[j];
            break;
        }
    }

    if ( pmtId == -1 ) {
        sprintf(info,"(x=%g, y=%g, no pixel)",x,y);
    } else {
        Int_t  nPmtPads = fRunPars->GetPmtData().GetNumPads();
        // take the first uid in the mapmt
        Int_t suid = fRunPars->GetPmtGeo( pmtId )->GetStartUniqueId();
        for( Int_t k(0); k < nPmtPads; k++) {
            Int_t uid = suid+k;

            if ( fPixelLines.count(uid) == 0 ) break;

            map<Int_t, EPolygon* >::const_iterator it = fPixelLines.find(uid);
            if ( it->second->DistancetoPrimitive(px,py) == 0 ) {
                pxUID = uid;
                break;
            }

        }
        Counts_t* mMap;
        if ( pxUID != -1 && (mMap=(Counts_t*)MapToPaint())) {
            Int_t counts = (*mMap)[pxUID];
            if ( fApplyThreshold ) {
                Double_t thres = 0;
                if (!fAbsoluteThreshold) {
                    Double_t rate = fRunPars->GetNightGlowRateByUId(pxUID)/microsecond
                            *fRunPars->GetPmtData().GetGtuLength();
                    thres = rate+fAlpha*Sqrt(rate);
                } else {
                    thres = fAlpha;
                }
                if ( counts > Nint(Ceil(thres)) )
                    counts -= Nint(Ceil(thres));
                else counts = 0;
            }
            sprintf(info,"(x=%g, y=%g, pmt id=%d, px id=%d, counts=%d)",x,y,pmtId,pxUID,counts);
         } else {
             sprintf(info,"(x=%g, y=%g, pmt id=%d, no pixel)",x,y,pmtId);
         }

    }

    return info;
}

//_____________________________________________________________________________
Bool_t EFocalSurfacePainter::FindView( Int_t id ) {
    //
    // calculates center, spread and orientation of the viewport
    //

    if ( IsZombie() ) return kFALSE;

    Modified( kFALSE );

    // define range
    Int_t nPixelsOn(0);
    TVector3 vSum2(0.,0.,0.);
    fViewCenter.SetXYZ(0.,0.,0.);
    fSpread.SetXYZ(0.,0.,0.);

    Int_t nCountsOverThres(0);

    GtuCounts_t& mViewMap = fFrontEndSignals;

    // find view center and axis
    GtuCounts_t::iterator
    Counts_t::iterator

    Int_t threshold;

    for( threshold = fViewThreshold ; threshold>0; threshold--) {
        // start to chech if the viewport can be defined by pixels over threshold fViewThreshold;
        nCountsOverThres = 0;
        
        for(itGtu = mViewMap.begin(); itGtu !=  mViewMap.end(); itGtu++)
            for( itUId = (itGtu->second).begin(); itUId != (itGtu->second.end()); itUId++){
                if ( itUId->second == 0 ) continue;

                nPixelsOn += itUId->second;

                if ( itUId->second < threshold ) continue;

                // Pmt normals are downward oriented, while Z axis must be upward oriented

                TVector3 dummy = fRunPars->PixelCenter(itUId->first);
                fViewCenter += dummy*itUId->second;

                nCountsOverThres+= itUId->second;
            }
        
        if ( nCountsOverThres || !fAutoThreshold ) break;
    }

    Info("FindView","%d pixels to draw, %d over threshold %d", nPixelsOn, nCountsOverThres, threshold);
    if ( !nCountsOverThres ) {
        Warning("FindView","Not possible to find the center. Try to Lower the threshold");

        const EPmtGeo* pmt = fRunPars->GetPmtGeoByUId(1);
        fViewCenter = pmt->GetCenter();
    } else {
        fViewCenter *= 1./(Float_t)nCountsOverThres;

        // calculate spread along the axis
        for(itGtu = mViewMap.begin(); itGtu !=  mViewMap.end(); itGtu++)
            for( itUId = (itGtu->second).begin(); itUId != (itGtu->second.end()); itUId++){
                if ( itUId->second == 0 ) continue;

                if ( itUId->second < threshold ) continue;

                TVector3 dummy = fRunPars->PixelCenter(itUId->first)-fViewCenter;
                fSpread[0] += TMath::Power((dummy.X()),2)*itUId->second;
                fSpread[1] += TMath::Power((dummy.Y()),2)*itUId->second;
                fSpread[2] += TMath::Power((dummy.Z()),2)*itUId->second;

            }

    }

    for(Int_t i(0); i<3; i++) {
        fSpread[i] = TMath::Sqrt(fSpread[i]/(Float_t)nCountsOverThres);
        fSpread[i] = TMath::Max(fSpread[i],(Double_t)fRunPars->GetPmtData().GetPadSide());
    }

    if ( fAutoRadius ) fViewRange = fSpread.Mag()*5;
    BuildPolyLines();

    return kTRUE;
}

//______________________________________________________________________________
void EFocalSurfacePainter::CenterViewOnPmt( Int_t pmtid){
    //
    //
    //

    fViewCenter = fRunPars->GetPmtGeo(pmtid)->GetCenter();
}
//_____________________________________________________________________________
void EFocalSurfacePainter::BuildPolyLines() {
    // 
    // Creates all the polylines for all the hits in the event
    //
    
    if ( !fDetector ) {
        Error("BuildPolyLines","No Event defined");
        return;
    }

    ClearPolyLines();

    // parse all maps and build all the pixels and the pmts
    GtuCounts_t::iterator
    Counts_t::iterator


    for(itGtu = fFrontEndHits.begin(); itGtu !=  fFrontEndHits.end(); itGtu++)
        for( itUId = itGtu->second.begin(); itUId != itGtu->second.end(); itUId++) {

            Int_t uid = itUId->first;
            GetPixelLine( uid );

            // associated pmt
            Int_t id = fRunPars->Pmt(uid);
            GetPmtLine( id );

        }

}

//______________________________________________________________________________
void EFocalSurfacePainter::ClearPolyLines() {
    //
    // remove all the polylines stored in memory
    //

    fLines->Clear();
    fPmtLines.clear();
    fPixelLines.clear();
}

//_____________________________________________________________________________
Bool_t EFocalSurfacePainter::Load() {
    // 
    // Load data and fills GtuCounts from the event and the runparameters
    //
    
    Clear();

    fFirstGtu = kMaxInt;
    fLastGtu = -kMaxInt;

    if ( !fDetector->GetNumFee() ) {
        Info("Load","No EFee in EDetector object. Painter made zombie.");
        MakeZombie();
        return kFALSE;
    }
    
    FillChipTriggers();
    
    map<Int_t,Bool_t> microcells; // id of microcells with at least a signal
    // read EFee from event
    for(Int_t i(0); i<fDetector->GetNumFee(); i++) {
        EFee *dfee = fDetector->GetFee(i);
        Int_t uid =  dfee->GetChUId();
        Int_t gtu =  dfee->GetGtu();
        Int_t fee_id = fRunPars->FrontEndChip(uid);  

        if ( fFrontEndHits[gtu].count( uid ) == 0 ) 
            fFrontEndHits[gtu][uid] = 0;
        
        fFrontEndHits[gtu][uid] += dfee->GetNumHits();

        if ( fFrontEndSignals.count( uid ) == 0 ) 
            fFrontEndSignals[gtu][uid] = 0;

        fFrontEndSignals[gtu][uid] += dfee->GetNumSignals();
        if ( dfee->GetNumSignals()>0 ) {
            microcells[fee_id] = kTRUE;
            if ( fSelFrontEndHits[gtu].count( uid ) == 0 )
                fSelFrontEndHits[gtu][uid] = 0;
            fSelFrontEndHits[gtu][uid] += dfee->GetNumHits();
        }

        if ( fECHits[gtu].count( fee_id ) == 0 ) 
            fECHits[gtu][fee_id] = 0;
        
        fECHits[gtu][fee_id] += dfee->GetNumHits();

        // look for first and last gtu
        if ( gtu < fFirstGtu ) fFirstGtu = gtu;
        if ( gtu > fLastGtu )  fLastGtu = gtu;
    }

    //read the front end (background) hits in the elementary cells with at least a signal
    for(Int_t i(0); i<fDetector->GetNumFee(); i++) {
        EFee *dfee = fDetector->GetFee(i);
        Int_t uid =  dfee->GetChUId();
        Int_t gtu =  dfee->GetGtu();
        Int_t fee_id = fRunPars->FrontEndChip(uid);
        
        if ( microcells.count(fee_id)==0 ) continue;
        
        if ( fFrontEndNoises[gtu].count( uid) == 0 )
            fFrontEndNoises[gtu][uid] = 0;

        fFrontEndNoises[gtu][uid] += ( dfee->GetNumHits() - dfee->GetNumSignals() );
    }

    // read CellHits from event
    for(Int_t i(0); i<fDetector->GetNumCellHits(); i++) {
        EMacroCellHit* mchit = fDetector->GetMacroCellHit(i);
        Int_t uid =  mchit->GetChUId();
        Int_t gtu =  mchit->GetGtu();

        if ( fMacroCellHits[gtu].count( uid ) == 0 ) 
            fMacroCellHits[gtu][uid] = 0;

        fMacroCellHits[gtu][uid] += mchit->GetCounts();

        // look for first and last gtu
        if ( gtu < fFirstGtu ) fFirstGtu = gtu;
        if ( gtu > fLastGtu )  fLastGtu = gtu;
    }

    Bool_t adddir = TH1::AddDirectoryStatus();
    TH1::AddDirectory(kFALSE);
        
    fH1SigProfile = new TH1F("SignalTimeProfile","Signal Hits",
                             fLastGtu-fFirstGtu+1,fFirstGtu-0.5,fLastGtu+0.5);
    fH1SigProfile->SetXTitle("Gtu");
    fH1SigProfile->SetYTitle("N_{hits}");

    fH1SigMaxProfile = new TH1F("SignalMaxTimeProfile","Maximum of signal hits per pixel",
                                fLastGtu-fFirstGtu+1,fFirstGtu-0.5,fLastGtu+0.5);
    fH1SigMaxProfile->SetXTitle("Gtu");
    fH1SigMaxProfile->SetYTitle("N_{hits}");
    fH1SigMaxProfile->SetMinimum(0);

    fH1NoiseMaxProfile = new TH1F("NoiseMaxTimeProfile","Maximum of background hits per pixel",
                                fLastGtu-fFirstGtu+1,fFirstGtu-0.5,fLastGtu+0.5);
    fH1NoiseMaxProfile->SetXTitle("Gtu");
    fH1NoiseMaxProfile->SetYTitle("N_{hits}");
    fH1NoiseMaxProfile->SetMinimum(0);

    fH1NoiseMinProfile = new TH1F("NoiseMinTimeProfile","Minimum of background hits per pixel",
                                fLastGtu-fFirstGtu+1,fFirstGtu-0.5,fLastGtu+0.5);
    fH1NoiseMinProfile->SetXTitle("Gtu");
    fH1NoiseMinProfile->SetYTitle("N_{hits}");
    fH1NoiseMinProfile->SetMinimum(0);

    fH1NoiseMeanProfile = new TH1F("NoiseMeanTimeProfile","Mean background hits per pixel",
                                fLastGtu-fFirstGtu+1,fFirstGtu-0.5,fLastGtu+0.5);
    fH1NoiseMeanProfile->SetXTitle("Gtu");
    fH1NoiseMeanProfile->SetYTitle("N_{hits}");
    fH1NoiseMeanProfile->SetMinimum(0);

    fH1HitsMaxProfile = new TH1F("HitsMaxTimeProfile","Maximum of hits per pixel",
                                fLastGtu-fFirstGtu+1,fFirstGtu-0.5,fLastGtu+0.5);
    fH1HitsMaxProfile->SetXTitle("Gtu");
    fH1HitsMaxProfile->SetYTitle("N_{hits}");
    fH1HitsMaxProfile->SetMinimum(0);

    TH1::AddDirectory(adddir);

    GtuCounts_t::const_iterator
    Counts_t::const_iterator

    for(itGtu = fFrontEndSignals.begin(); itGtu!=fFrontEndSignals.end(); itGtu++) {
        Int_t sigMax = 0;
        for(itPx = itGtu->second.begin(); itPx!=itGtu->second.end(); itPx++) {
            fH1SigProfile->Fill(itGtu->first,itPx->second);
            sigMax = Max(sigMax,itPx->second);
        }
        fH1SigMaxProfile->Fill(itGtu->first,sigMax);
    }

    for(itGtu = fFrontEndNoises.begin(); itGtu!=fFrontEndNoises.end(); itGtu++) {
        Int_t noiseMax = 0;
        Int_t noiseMin = 9999;
        for(itPx = itGtu->second.begin(); itPx!=itGtu->second.end(); itPx++) {
            noiseMax = Max(noiseMax,itPx->second);
            noiseMin = Min(noiseMin,itPx->second);
        }
        fH1NoiseMaxProfile->Fill(itGtu->first,noiseMax);
        fH1NoiseMinProfile->Fill(itGtu->first,noiseMin);
    }

    for(itGtu = fECHits.begin(); itGtu!=fECHits.end(); itGtu++) {
        Int_t hitsMax = 0;
        Int_t ECMaxId = -1;
        for(itPx = itGtu->second.begin(); itPx!=itGtu->second.end(); itPx++) {
            hitsMax = Max(hitsMax,itPx->second);
            ECMaxId = itPx->first;
        }
        Float_t mean = (fRunPars->GetNightGlowRate(ECMaxId))*(fRunPars->GetPmtData().GetGtuLength())/microsecond;
        fH1NoiseMeanProfile->Fill(itGtu->first,Ceil(mean));
    }
    
    for(itGtu = fSelFrontEndHits.begin(); itGtu!=fSelFrontEndHits.end(); itGtu++) {
        Int_t hitsMax = 0;
        for(itPx = itGtu->second.begin(); itPx!=itGtu->second.end(); itPx++) {
            hitsMax = Max(hitsMax,itPx->second);
        }
        fH1HitsMaxProfile->Fill(itGtu->first,hitsMax);
    }

    return kTRUE;
}

//_____________________________________________________________________________
void EFocalSurfacePainter::ApplyTriggerThreshold( ETriggerTypeIdentifier id ) {
    //
    // Apply a threshold on the pixels according to the trigger threshold
    //
    
    if (!fHasTriggersFilled) FillChipTriggers(); 
    if ( id==(ETriggerTypeIdentifier)0 ) {
        fAlpha = 0;
        fApplyThreshold = kFALSE;
        fAbsoluteThreshold = kTRUE;
        fCurrentTrigger = 0;
    } else {
        if ( !(fTriggers.count(id)) ) {
            Info("ApplyTriggerThreshold","Trigger not found in event.");
            return;
        }
        fApplyThreshold = kTRUE;
        fAlpha = Abs(fTriggers[id]);
        if ( fTriggers[id]<0 ) fAbsoluteThreshold = kTRUE;
        else fAbsoluteThreshold = kFALSE;
        fCurrentTrigger = id;
    }
    PaintHits();
}

//_____________________________________________________________________________
void EFocalSurfacePainter::FillChipTriggers() {
    //
    // Fill the map with the chip tracking trigger thresholds
    //
    
    // search for the various type of chip tracking trigger
    // if there is a trigger engine active fill fTriggers with his own fAlpha
    // if the threshold is absolute put a - sign
    EChipTriggPars *fTriggPars = 0;
    if ( fRunPars->GetTriggPars(kChipTrackingTrigger) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kChipTrackingTrigger);
        fTriggers[kChipTrackingTrigger] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kChipTrackingTrigger] *= -1;
    }
    if ( fRunPars->GetTriggPars(kChipTrackingTrigger0) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kChipTrackingTrigger0);
        fTriggers[kChipTrackingTrigger0] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kChipTrackingTrigger0] *= -1;
    }
    if ( fRunPars->GetTriggPars(kChipTrackingTrigger1) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kChipTrackingTrigger1);
        fTriggers[kChipTrackingTrigger1] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kChipTrackingTrigger1] *= -1;
    }
    if ( fRunPars->GetTriggPars(kChipTrackingTrigger2) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kChipTrackingTrigger2);
        fTriggers[kChipTrackingTrigger2] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kChipTrackingTrigger2] *= -1;
    }
    if ( fRunPars->GetTriggPars(kChipTrackingTrigger3) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kChipTrackingTrigger3);
        fTriggers[kChipTrackingTrigger3] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kChipTrackingTrigger3] *= -1;
    }
    if ( fRunPars->GetTriggPars(kChipTrackingTrigger4) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kChipTrackingTrigger4);
        fTriggers[kChipTrackingTrigger4] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kChipTrackingTrigger4] *= -1;
    }
    if ( fRunPars->GetTriggPars(kSignalChipTrackingTrigger) ) {
        fTriggPars = (EChipTriggPars*)fRunPars->GetTriggPars(kSignalChipTrackingTrigger);
        fTriggers[kSignalChipTrackingTrigger] = fTriggPars->GetThresholdNumber();
        if ( !fTriggPars->HasRelativeThreshold() ) fTriggers[kSignalChipTrackingTrigger] *= -1;
    }

    fHasTriggersFilled = kTRUE;
}

//_____________________________________________________________________________
Bool_t EFocalSurfacePainter::IsTriggerEnabled( ETriggerTypeIdentifier id ) {
    //
    // Check if a given trigger is enabled
    //
    
    if (!fHasTriggersFilled) FillChipTriggers();
    return (fTriggers.count(id)!=0);
}

//_____________________________________________________________________________
EPolygon* EFocalSurfacePainter::GetPixelLine( Int_t uid ) {
    // 
    // Returns a EPolygon corresponding to uid if doesn't exist.
    // If doesn't exists yet in fPixelLines creates a new one. 
    //

    if ( fPixelLines.count(uid) != 0 )
        return fPixelLines[uid];
    
    // projections of the axis of the geometry

    Float_t x[5], y[5];
    for(Int_t iCorner(0); iCorner<4; iCorner++){
        TVector3 dummy = fRunPars->PixelCorner(uid,iCorner);//-fViewCenter;
        x[iCorner] = dummy.X();//*fXaxis;
        y[iCorner] = dummy.Y();//*fYaxis;
    }
    x[4] = x[0];
    y[4] = y[0];

    EPolygon *p = new EPolygon(5,x,y); 
    fPixelLines[uid] = p;
    fLines->Add(p);

    fPixelLines[uid] = p;
    fLines->Add(p);

    return p;
}

//_____________________________________________________________________________
EPolygon* EFocalSurfacePainter::FindPmtLine( Int_t id ) const {
    //
    // Lookf for EPolygon corresponding to id among the ones already created
    //
    EPolygon *pol = 0;
    
    if ( fPmtLines.count( id ) != 0 ) pol = fPmtLines.find(id)->second;
    return pol;
    
}

//_____________________________________________________________________________
EPolygon* EFocalSurfacePainter::GetPmtLine( Int_t id ) {
    //
    // Returns a EPolygon corresponding to id if doesn't exist.
    // If doesn't exists yet in fPmtLines creates a new one. 
    //

    if ( fPmtLines.count( id ) != 0 )
        return fPmtLines[id];

    // this pmt doesn't exists. make new polyline

    Float_t x[5], y[5];
    for(Int_t iCorner(0); iCorner<4; iCorner++){
        TVector3 dummy = fRunPars->PmtCorner(id, iCorner);
        x[iCorner] = dummy.X();
        y[iCorner] = dummy.Y();
    }
    x[4] = x[0];
    y[4] = y[0];

    EPolygon *p = new EPolygon(5,x,y); 
    fPmtLines[id] = p;
    
    fLines->Add(p);
    return p;
}

//_____________________________________________________________________________
void EFocalSurfacePainter::FindPmtsToPaint( Float_t xmin, Float_t ymin, Float_t xmax, Float_t ymax ) {
    // 
    // Looks for Pmts which centers are in the viewport. 
    // Fills fPmtsToPaint and fPixelsToPaint
    //
    
    fPmtsToPaint.clear();

    for( Int_t i(1); i <= fRunPars->GetNumPmts(); i++) {
        TVector3 dummy = fRunPars->GetPmtGeo(i)->GetCenter();
        if ( dummy.X() < xmin || dummy.X() > xmax ||
             dummy.Y() < ymin || dummy.Y() > ymax )
            continue;

        // add the polyline to the list
        GetPmtLine(i);
        fPmtsToPaint.push_back(i);
    }

}


//_____________________________________________________________________________
void EFocalSurfacePainter::Play( Option_t *opt ) {
    // 
    // Start the movie
    //

    if ( gPad ) gPad->Clear();

    TString option(opt);

    Draw( option );

    fTimer->Connect("Timeout()","EFocalSurfacePainter", this, "Animate()" );
    Rewind(); 

    Info("Play","Animation started");
    fTimer->TurnOn();
}

//_____________________________________________________________________________
void EFocalSurfacePainter::Animate() {
    //
    // Move to next animation step and increase the counter
    //
   
    if ( IsEnded() ) {
        // leave the last frame to be painted
        fGtu = fLastGtu;
        Stop();
        return;
    } 

    NextFrame();

    if ( gPad ) {
        gPad->Modified();
        gPad->Update();
    }

}

//_____________________________________________________________________________
void EFocalSurfacePainter::NextFrame() {
    //
    // Move the internal counter to the next frame
    //
    
    if ( fGtu < fLastGtu ) fGtu++;
}

//_____________________________________________________________________________
void EFocalSurfacePainter::MakeGifSequence(const char *option, const char *path) {
    //
    // Build a sequence of gifs inside a dedicated canvas.
    // Gifs are created with opt options 
    //


    TString opt(option);

    TCanvas *display = new TCanvas("MakeGifDisplay","MakeGifDisplay",
                                   fGifCanvasW, fGifCanvasH);

    fGtu = -1;

    display->GetListOfPrimitives()->Add(this,opt);
    display->Modified(kTRUE);

    display->SaveAs("AnimHead.gif");

    for( fGtu = fFirstGtu; fGtu <= fLastGtu; fGtu++) {
        display->Modified();
        display->Update();
        display->SaveAs(Form("%s%.3d.gif",path,fGtu));
    }

    fGtu = -1;
    display->Modified();
    display->SaveAs("AnimTail.gif");

    delete display;

}
//_____________________________________________________________________________
const Counts_t* EFocalSurfacePainter::MapToPaint() const {

    Counts_t* m;

    const GtuCounts_t *pMap = GtuCountsToPaint();
    if (!pMap) return 0;

    GtuCounts_t::const_iterator
    if (fGtu == -1 ) {
        // paint all hits superimposed

        fCountsSum.clear();
        for( itGtu = pMap->begin(); itGtu != pMap->end(); itGtu++)
            switch (fIntegral) {
                case kIntMax:
                    fCountsSum |= (itGtu->second);
                    break;
                case kIntSum:
                default:
                    fCountsSum += (itGtu->second);
            }
                    

        m = &fCountsSum;
        
    } else if ( fIntegral != kIntNone ) {
        // draw superposition of all hits from first gtu to the current one.


        // check cache content
        if ( fCacheCode != CurrentCode() ) CacheIntegral();

        // look for the right entry
        if ( (itGtu = fCache.find(fGtu)) != fCache.end() ) 
            m = (Counts_t*)&(itGtu->second);
        
    } else {
        // draw just a gtu
        itGtu = pMap->find(fGtu);
        if ( itGtu != pMap->end() ) m = (Counts_t*)&(itGtu->second);

    }

    return m;

}

//_____________________________________________________________________________
const GtuCounts_t* EFocalSurfacePainter::GtuCountsToPaint() const {
   
    switch( fCurrentMapID ) {
        case kFeeHits:
            return &fFrontEndHits;
        case kFeeSignals:
            return &fFrontEndSignals;
        case kCellHits:
            return &fMacroCellHits;
        default:
            Error("MapToPaint","bad id in fCurrentMapID, returning 0");
    }
     return 0;
}

//_____________________________________________________________________________
void EFocalSurfacePainter::CacheIntegral() const {
    // cache data to speed-up animation
    
    Counts_t dummy;
    const GtuCounts_t *map = GtuCountsToPaint();
    if ( !map ) return;

    fCache.clear();

    GtuCounts_t::const_iterator
    for( Int_t gtu = fFirstGtu; gtu <= fLastGtu; gtu++ ) {
        if ( (itGtu = map->find(gtu)) != map->end())
            switch( fIntegral ) {
                case kIntMax:
                    dummy |= (itGtu->second); 
                    break;
                case kIntSum:
                default:
                    dummy += (itGtu->second); 
            }
        fCache[gtu] = dummy;
    }

    fCacheCode = CurrentCode();
    
}

//______________________________________________________________________________
const Counts_t operator+(const Counts_t& a, const Counts_t& b){
    Counts_t::iterator
    Counts_t::const_iterator
    Counts_t tmp = a;

    for( itB = b.begin(); itB != b.end(); itB++) {
        if ( (itA = tmp.find(itB->first) ) == tmp.end() )
            tmp[itB->first] = itB->second;
        else
            itA->second += itB->second;

    }
    return tmp;
}

//______________________________________________________________________________
Counts_t& operator+=( Counts_t& a, const Counts_t& b){
    Counts_t::iterator
    Counts_t::const_iterator

    for( itB = b.begin(); itB != b.end(); itB++) {
        if ( (itA = a.find(itB->first) ) == a.end() )
            a[itB->first] = itB->second;
        else
            itA->second += itB->second;
    }
    return a;
}

//______________________________________________________________________________
const Counts_t operator|(const Counts_t& a, const Counts_t& b){
    Counts_t::iterator
    Counts_t::const_iterator
    Counts_t tmp = a;

    for( itB = b.begin(); itB != b.end(); itB++) {
        if ( (itA = tmp.find(itB->first) ) == tmp.end() )
            tmp[itB->first] = itB->second;
        else
            itA->second = Max(itA->second,itB->second);

    }
    return tmp;
}

//______________________________________________________________________________
Counts_t& operator|=( Counts_t& a, const Counts_t& b){
    Counts_t::iterator
    Counts_t::const_iterator

    for( itB = b.begin(); itB != b.end(); itB++) {
        if ( (itA = a.find(itB->first) ) == a.end() )
            a[itB->first] = itB->second;
        else
            itA->second = Max(itA->second, itB->second);

    }
    return a;
}



//______________________________________________________________________________
 EPolygon::EPolygon( Int_t n, Float_t *x, Float_t *y ) : TPolyLine( n, x, y ) {
    //
    // Constructor
    //
}


//______________________________________________________________________________
 EPolygon::~EPolygon() {
    //
    // Destructor
    //

}


//______________________________________________________________________________
 void EPolygon::ExecuteEvent(Int_t event, Int_t px, Int_t py) {


    TPolyLine::ExecuteEvent(event, px, py);
}


//______________________________________________________________________________
 Int_t EPolygon::DistancetoPrimitive(Int_t px, Int_t py) {

    Int_t distance= 999999;
    if (TMath::IsInside(gPad->AbsPixeltoX(px),gPad->AbsPixeltoY(py),fLastPoint+1,fX,fY)) distance = 0;

    return distance;
}


About Us | EUSO Official Website | Web pages created by Roberto Pesce and Alessandro Thea - Last Update Wed Nov 16 16:57:39 2005 Wed Nov 16 16:29:22 2005