Universita' di GenovaINFN Sezione di Genova  
AIRWATCH / EUSO Genova

EusoElectronics - source file

// ESAF : Euso Simulation and Analysis Framework
// $Id: EusoElectronics.cc,v 1.82 2005/10/31 16:01:05 pesce Exp $
// M. Pallavicini - created
// implementation for EusoElectronics object

//_____________________________________________________________________________
//  
//   Euso Electronics
//   ================
//
//   Electronics description of the focal surface. It is the core of the
//   detector simulation
//
//   fFrontEndSize : Number of channels in a front end chip. Do not change it
//
//   fPmtSide : Number of channels in a pmt side. Do not change it.
//
//   fEnable [bool] : Enable / disable electronics simulation 
//
//   fFocalSurfaceFile : Focal surface layout file
//
//   fNightGlow [bool] : Choose night glow background implementation
//   Valid options: 
//      - none:    no background at all
//      - yes:     background added according to NightGlowCode variable

#include "EusoElectronics.hh"

#include <iostream>
#include <string>
#include <math.h>

#include "AnalogFrontEnd.hh"
#include "EEventTelemetryAdder.hh"
#include "ElectronicsFactory.hh"
#include "ElementaryCell.hh"
#include "EsafRandom.hh"
#include "euso.hh"
#include "FocalSurfaceFileParser.hh"
#include "FrontEndChip.hh"
#include "MacroCellData.hh"
#include "MacroCellGeometry.hh"
#include "MacroCell.hh"
#include "OpticsFactory.hh"
#include "Photomultiplier.hh"
#include "PmtGeometry.hh"
#include "Telemetry.hh"
#include "TMath.h"

using namespace sou;

ClassImp(EusoElectronics)

//______________________________________________________________________________
 EusoElectronics::EusoElectronics() : EsafConfigurable(), EsafMsgSource(),
    fSimulateElectronics(kTRUE), fDetectorScaleFactor(1.), fNightGlowDist(0) {
    //
    // Constructor
    //

    fTelemetry = 0;
}

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

    if ( fTelemetry )
        delete fTelemetry;
    
    // delete all ECs and Front End chips
    vector<ElementaryCell*>::const_iterator it2;
    for(it2=fElementaryCells.begin(); it2 != fElementaryCells.end(); it2++) {
        ElementaryCell *ec = *it2;
        FrontEndChip *fe = ec->FrontEnd();
        delete ec;
        delete fe;
    }
    
    // delete all pmts
    vector<Photomultiplier*>::const_iterator it;
    for(it=fPmts.begin(); it != fPmts.end(); it++) {
        Photomultiplier *pmt = *it;
        delete pmt;
    }

    SafeDelete(fNightGlowDist);
}
//______________________________________________________________________________
 Double_t EusoElectronics::NightGlowRate( const TVector3& pos, const TVector3& norm,
         Double_t pxsize, Double_t pde ) const {
    //
    // Nightglow rate as function of the location on the FS
    // (number of hits per microseconds)

    Double_t ngr(0);
    if ( fNightGlow == "byRate" ) {
        if ( fNightGlowShape == "Flat" ) 
            ngr = fNightGlowRateOnAxis; 
        else if ( fNightGlowShape == "CosTheta" ) {
            Double_t fsPosZ = 2200*mm;

            Double_t tg2th = pos.Perp2();//(pos.x()*pos.x() + pos.y()*pos.y());
            tg2th /= ( (fsPosZ+pos.z()) * (fsPosZ+pos.z()));
            Double_t cth = 1. / TMath::Sqrt((1. + tg2th));
            ngr = fNightGlowRateOnAxis*cth;
        } else 
            FatalError("Unknown night glow shape:"+fNightGlowShape);
    } else if ( fNightGlow == "byRadiance" ) {
        Double_t r = pos.Perp();

        if ( r > fNightGlowDist->GetXmax() ) {
            ngr = 0;
        } else {
            ngr = fNightGlowDist->GetValue( r )*fNightGlowRadiance;

            // apply quantum efficiency and pmt orientation
            ngr *= pxsize*pxsize*Abs(norm.CosTheta());
            ngr *= pde;
            ngr *= fDetectorScaleFactor*fDetectorScaleFactor;

        }

    }

    return ngr;
}

//______________________________________________________________________________
 Double_t EusoElectronics::NightGlowRate( const Photomultiplier* pmt ) const {
    //
    // Nightglow rate as function of the location on the FS
    //


    const PmtGeometry* geo = pmt->Geometry();
    const TVector3& pos  = geo->Position();
    const TVector3& norm = geo->Normal();

    return NightGlowRate(pos, norm, geo->Side(), pmt->GetQuantum());
}


//______________________________________________________________________________
 Double_t EusoElectronics::NightGlowRate( const FrontEndChip* fe ) const {
    //
    // Nightglow rate as function of the front end chip
    //

    Int_t n = fe->GetNumPmts();
    const PmtGeometry* geo = fe->Pmt()->Geometry();
    const TVector3& norm = geo->Normal();
    TVector3 pos;

    for(Int_t i(0); i<n; i++) 
        pos += fe->Pmt(i)->Geometry()->Position(); 

    pos *= (1/(Double_t)n);
    return NightGlowRate(pos, norm, geo->PadSide(), fe->Pmt()->GetQuantum());
}

//______________________________________________________________________________
 void EusoElectronics::BuildBackgroundChipDist() {
    //
    // Nightglow rate as function of the location on the FS
    //

    if ( fNightGlow == "none" ) return;

    vector<ElementaryCell*>::const_iterator it;
    for(it=fElementaryCells.begin(); it != fElementaryCells.end(); it++) {
        ElementaryCell *ec = *it;
        FrontEndChip *fe = ec->FrontEnd();
        Double_t rate = NightGlowRate( fe )+fe->Pmt()->GetDarkNoiseRate();
        fe->SetNightGlowRate( rate );
    }

}

//______________________________________________________________________________
 Bool_t EusoElectronics::Build() {
    //
    // New building strategy 
    //

    Msg(EsafMsg::Info) << "Start Building" << MsgDispatch;

    Int_t pm=0;
    // Channels Ids must start from 1
    ChannelUniqueId UniqueId = 1; 
    fNumOfChannelUniqueId = 0;

    // enable/disable electronics simulation
    fSimulateElectronics = (Int_t)Conf()->GetBool("EusoElectronics.fEnable");

    // get the number of channels for each Front End Chip
    Int_t chip_size = (Int_t)Conf()->GetNum("EusoElectronics.fFrontEndSize");

    // get the number of pads in each Pmt
    Int_t pmt_size = (Int_t)Conf()->GetNum("EusoElectronics.fPmtSide");
    pmt_size *= pmt_size;

    // get the factory
    ElectronicsFactory* factory = ElectronicsFactory::Get();

    // get eusoelectronics file name
    string fileName = Conf()->GetStr("EusoElectronics.fFocalSurfaceFile");

    // add a random phase to the gtu
    fAddRandomGtuPhase = Conf()->GetBool("EusoElectronics.fAddRandomGtuPhase");
    
    // get NightGlow type
    fNightGlow = Conf()->GetStr("EusoElectronics.fNightGlow");
    fNightGlowCode = 0;
    fNightGlowRateOnAxis = 0.;
    if ( fNightGlow == "byRate" || fNightGlow == "byRadiance" ) {
        fNightGlowRateOnAxis = Conf()->GetNum("EusoElectronics.fNightGlowRateOnAxis")/microsecond;
        fNightGlowRadiance   = Conf()->GetNum("EusoElectronics.fNightGlowRadiance")/(ns*sr*m2);
        fNightGlowShape      = Conf()->GetStr("EusoElectronics.fNightGlowShape");
        fNightGlowCode       = (Int_t)Conf()->GetNum("EusoElectronics.fNightGlowCode");

        if ( fNightGlow == "byRadiance" ) {
            // FIXME improve path resolution
            string path = Conf()->GetCfgDir()+'/'+
                ClassType()+'/'+
                ClassName()+'/';
            fNightGlowDist = new Interpolate(path+"NightGlow."+fNightGlowShape+".dat");
            // set unit, (meter^2*steradiant)/mm^2
            fNightGlowDist->SetUnit(m2*ns*sr/mm2);
           
            /*
            cout << "Unit " << (m2*sr/mm2)  << endl;
            cout << fNightGlowDist->GetUnit()  << endl;
            cout << path+fNightGlowShape+".dat" << endl;
            cout << "Radiance   " << Conf()->GetNum("EusoElectronics.fNightGlowRadiance") << endl;
            cout << "Radiance with unit   " << fNightGlowRadiance << endl;
            cout << path+fNightGlowShape+".dat" << endl;
            cout << fNightGlowDist->GetValue(100.) << endl;
            cout << fNightGlowDist->GetValue(1000.) << endl;
            exit(0);
            */
        }
           
    } else if ( fNightGlow != "none" )
        FatalError("Unknown option for fNightGlow "+fNightGlow);

    FrontEndChip *pChip = 0;
    Photomultiplier *pPmt = 0;
    MacroCell *pCell = 0;
    ElementaryCell *pEC = 0;
    Photomultiplier *pP[9];
    Int_t RowOffset = 0;
    Int_t ColOffset = 0;

    FocalSurfaceFileParser fs( fileName );

    while ( Int_t PmtId = fs.NewPmtId() ) {

        // front end chip and its analog front end simulation
        if ( fs.NewFrontEndChip() ) {
            if ( pChip ) {
                // fill the chip up
                pChip->AssociatePmts( pP[0], pP[1], pP[2], pP[3] );
                
            }
        

            pChip = factory->MakeFrontEndChip( chip_size );
            AnalogFrontEnd* afee = factory->MakeAFEE( pChip, chip_size );
            pChip->SetAfee( afee );
            pm = 0;		

        }

        if ( fs.NewElementaryCell() ) {
            if ( pEC ) {
                pEC->AssociatePmts( pP[0], pP[1], pP[2], pP[3] );
                pCell->Add( pEC, RowOffset, ColOffset);
            }
            pEC = factory->MakeElementaryCell();
            fElementaryCells.push_back( pEC );
        }

        if ( fs.NewMacroCell() ) {
            // build new MacroCell
            pCell = factory->MakeMacroCell();
            // set geometry 
            MacroCellGeometry *pMg = factory->MakeMacroCellGeometry( pCell );
            pCell->SetGeometry( pMg );
            fMacrocells.push_back( pCell );
        }

        //if ( Int_t PDMId = fs.NewPhotoDetModule() ) {
        //}

        // pmt geometry
        PmtGeometry *g = factory->MakePmtGeometry( fs.Pos(), fs.Norm(), fs.Dir() );

        // it's optical adaptor
        OpticalAdaptor *oa = OpticsFactory::Get()->GetOA();
        g->InsertOA(oa);

        // build the pmt and attach the front end chip
        //        Int_t first = pm * pmt_size;
        pPmt = factory->MakePmt( PmtId, g);
        pP[pm++] = pPmt; // keep pointers for the EC

        // associate the macrocell to the pmt
        pPmt->SetCell( pCell );

        // associate pmt to front end

        // add this pmt to the list
        fPmts.push_back( pPmt );

        // associate unique id to objects
        // UniqueId = (pmt_id-1)*nchan+chId
        // pmt_id=[1,nPmt], nchan=PmtSide^2, chId=[0,nchan-1]
        pPmt->SetStartUniqueId( UniqueId );
        for(Int_t ii = pPmt->GetStartUniqueId(); ii <= pPmt->GetLastUniqueId(); ii++) {
            fMap[ii] = pPmt;
        }
        UniqueId += ( pPmt->GetLastUniqueId() - pPmt->GetStartUniqueId() + 1 );

        // save offsets for elementarycell association
        RowOffset = fs.GetRowOffset();
        ColOffset = fs.GetColOffset();

    }

    // complete the last frontend chip
    if ( pChip ) {
        pChip->AssociatePmts( pP[0], pP[1], pP[2], pP[3] );

    }

    // complete last elementary cell
    if ( pEC ) {
        pEC->AssociatePmts( pP[0], pP[1], pP[2], pP[3] );
        pCell->Add( pEC, RowOffset, ColOffset );
    }

    BuildBackgroundChipDist();

    Msg(EsafMsg::Debug) << NumPmt() << " Photomultipliers read" << MsgDispatch;  
    Msg(EsafMsg::Debug) << NumElemCell() << " ElementaryCells created" << MsgDispatch;
    Msg(EsafMsg::Debug) << NumCell() << " MacroCells assembled" << MsgDispatch;

    Msg(EsafMsg::Info) << "Night Glow background will be added in ";
    if ( fNightGlowCode > 0 )
        Msg(EsafMsg::Info) << "macrocell " << fNightGlowCode << " only" << MsgDispatch;
    else if ( fNightGlowCode == -1 )
        Msg(EsafMsg::Info) << "all macrocells with at least one signal photon" << MsgDispatch;
    else if ( fNightGlowCode == -2 )
        Msg(EsafMsg::Info) << "all macrocells" << MsgDispatch;
    else if ( fNightGlowCode == 0 || fNightGlow == "none")
        Msg(EsafMsg::Info) << "0 macrocells" << MsgDispatch;
    // save the number of channels
    fNumOfChannelUniqueId=UniqueId-1;

    // get telemetry object
    fTelemetry = factory->MakeTelemetry();

    Msg(EsafMsg::Info) << "Build Complete." << MsgDispatch;
    return true;
}

//______________________________________________________________________________
 Bool_t EusoElectronics::Destroy() {
    //
    // Destroy the whole electronics tree 
    //
    // to be done

    return true;
}

//______________________________________________________________________________
 MacroCell* EusoElectronics::Cell( UInt_t index ) {
    // 
    // Mapping functions.
    // Returns macrocell from index
    //

    if ( index >= fMacrocells.size() ) {
        Msg(EsafMsg::Warning) << "Cell()    Macrocell " 
		 << index << " does not exist." << MsgDispatch;
        return 0;
    }
    return fMacrocells[index];
}
  
  
//______________________________________________________________________________
 MacroCell* EusoElectronics::CellId( const ChannelUniqueId& chid ) {
    // 
    // Returns macrocell from channel unique id
    //

    Photomultiplier *pPmt = fMap[chid];
    if ( pPmt )
        return pPmt->Cell();
 
    return 0;
}

//______________________________________________________________________________
 ElementaryCell* EusoElectronics::ElemCell( UInt_t index ) {
    //
    //
    //
    
    if ( index >= fElementaryCells.size() ) {
        Msg(EsafMsg::Warning) << "ElemCell()    Macrocell " 
		 << index << " does not exist." << MsgDispatch;
        return 0;
    }
    return fElementaryCells[index];
}

//______________________________________________________________________________
 Photomultiplier* EusoElectronics::Pmt( UInt_t index ) {
    //
    // Returns photomultiplier from id
    //

    if ( index >= fPmts.size() ) {
        Msg(EsafMsg::Warning) << "Pmt()    Pmt " 
		 << index << " does not exist." << MsgDispatch;
        return 0;
    }
    return fPmts[index];
}
  
//______________________________________________________________________________
 Photomultiplier* EusoElectronics::PmtId(ChannelUniqueId chid) {
    //
    // Returns photomultiplier from channel_unique_id
    //

    return fMap[chid];
}
  
//______________________________________________________________________________
 void EusoElectronics::ElectronicsMap( MacroCell** cell, Photomultiplier** pmt, 
                                      Int_t& pmtchan, ChannelUniqueId chid ) {
    //
    // Returns all mapping from ChannelUniqueId
    //

    *cell = CellId(chid);
    *pmt = PmtId(chid);
    pmtchan = PmtId(chid)->GetChannel(chid);
    return;
}

//______________________________________________________________________________
 Bool_t EusoElectronics::Simulate( Double_t tBegin, Double_t tEnd) {
    // 
    // Simulate the whole electronics behaviour for this event
    //

    if ( !fSimulateElectronics ) {
        Msg(EsafMsg::Info) << "EusoElectronics: Simulation disabled" << MsgDispatch;
        return kTRUE;
    }

    fNumPmtSignals = 0;

    // consistency checks 
    Double_t t1=1.e20;
    Double_t t2=-1.e20;
    Double_t t3=1.e20;
    Double_t t4=-1.e20;
    for(UInt_t i=0; i<fPmts.size(); i++) {
        Photomultiplier *pPmt=fPmts[i];
        if ( t1 > pPmt->GetStartTime() && !pPmt->IsEmpty() )
            t1 = pPmt->GetStartTime();
        if ( t2 < pPmt->GetEndTime() && !pPmt->IsEmpty() )
            t2 = pPmt->GetEndTime();
        for ( Int_t ch=0; ch < pPmt->NumChan(); ch++ ) {
            vector<PmtSignal*>* sigs = &(pPmt->Signals(ch));
            if ( sigs ) {
                for(UInt_t iSig=0; iSig < sigs->size(); iSig++) {
                    PmtSignal *s = (*sigs)[iSig];
                    if ( s ) {
                        fNumPmtSignals++;
                        if ( t3 > s->Time() ) t3 = s->Time();
                        if ( t4 < s->Time() ) t4 = s->Time();
                    }
                }
            }
        }
    }

    // 
    // calculate the threshold on pmtsignals for simulating a macrocell
    // 
    
    string thrStr = Conf()->GetStr("EusoElectronics.fSimulateLowSignalMacroCells");
    Double_t thrVal = Conf()->GetNum("EusoElectronics.fLowSignalMacrocellThreshold");

    if ( thrStr =="absolute") {
        fLowSignalCellThreshold = Nint(thrVal);
    } else if ( thrStr =="relative") {
        fLowSignalCellThreshold = Nint(Ceil(thrVal*fNumPmtSignals/100.));
    } else if ( thrStr == "all" ) {
        fLowSignalCellThreshold = 0;
    } else {
        FatalError("Wrong config value in EusoElectronics.fSimulateLowSignalMacroCells");
    }

    MsgForm(EsafMsg::Info,"Pmt Time Interval (ns)   :t\tSTART=%ld  END=%ld",(Long_t)t1,(Long_t)t2);
    MsgForm(EsafMsg::Info,"Signal Time Interval (ns):t\tSTART=%ld  END=%ld",(Long_t)t3,(Long_t)t4);

    MacroCell* pCell;

    // get the time of the first photon added ( ns )
    Double_t start = HUGE;
    for( size_t iCell=0; iCell<fMacrocells.size(); iCell++ ) {
        pCell = fMacrocells[ iCell ];
        if ( pCell ) {
            pCell->CheckPmtState();
            pCell->SetLowSignalThreshold(fLowSignalCellThreshold);
            Double_t tt = pCell->FirstHitTime();
            if ( start > tt )
                start = tt;
        } else {
            FatalError("Error in Simulate(); Bad macrocell map");
        } 
    }

    // generate a random phase with respect to the GTU cycle
    Double_t phase(0);
    if (fAddRandomGtuPhase) {
        TRandom* rndm = EsafRandom::Get();
        phase = rndm->Rndm();
        phase *= Config::Get()->GetCF("Electronics","MacroCell")->GetNum("MacroCell.fGtuTimeLength");
    }
    start -= phase;

    MsgForm(EsafMsg::Info,"GTU Phase (ns)           :t\tSTART=%ld   PHASE=%ld",(Long_t)start,(Long_t)phase);

    // simulate all macrocells 
    for(UInt_t iCell=0; iCell < fMacrocells.size(); iCell++) {
        pCell = fMacrocells[ iCell ];
        pCell->SetGtuBegin( start );

        // simulate macrocell electronics and trigger
        MacroCellData* pData = pCell->Simulate( fNightGlowCode );

        if ( pData ) {
            // if there was activity, add data to telemetry object
            if ( !pData->IsEmpty()) {
                MsgForm(EsafMsg::Info,"Adding into telemetry Macrocell %d",pData->Cell()->Id());
                fTelemetry->Add( pData );
            } 
            else {
                delete pData;
            }
            pCell->Reset();
        }
        else {
            Msg(EsafMsg::Panic) << "Error while simulating Macro Cell = " << pCell->Id() << MsgDispatch;
            FatalError("Bad pData from MacroCell::Simulate");
        }
    }

    // third level triggering and on-board data processing simulation
    fTelemetry->SimulateTCU();

    // add telemetry data to root event
    if ( EEvent::GetCurrent() ){
        EEventTelemetryAdder adder(fTelemetry);
        EEvent::GetCurrent()->Fill( adder );
    }

    return true;
}

//______________________________________________________________________________
 void EusoElectronics::Reset() {
    //
    // Reset the electronics and get ready for next event
    //

   for( size_t iCell=0; iCell<fMacrocells.size(); iCell++ ) {
      MacroCell* pCell = fMacrocells[ iCell ];
      if ( pCell )
         pCell->Reset();
      else {
          Msg(EsafMsg::Panic) << "EusoElectronics: Error in Reset(). Bad map."<< MsgDispatch;
          exit(2);
      }
   }

   fTelemetry->Clear();
}

//______________________________________________________________________________
 void EusoElectronics::Dump(ostream& os) {
    //
    // Dump information about the electronics (for debugging)
    //

    os << "This is EusoElectronics" << endl;
    os << "Number of Macro Cells " << fMacrocells.size() << endl;
    for(UInt_t i=0; i<fMacrocells.size(); i+=20 ) {
        os << "MacroCell " << fMacrocells[i]->Id() << " has " <<
            fMacrocells[i]->GetRows() << " rows and " << fMacrocells[i]->GetColumns() <<
            " columns " << endl;
    }
}
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