// ESAF : Euso Simulation and Analysis Framework
// $Id: EusoElectronics.cc,v 1.75 2005/05/15 13:19:31 thea 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 <iostream>
#include <math.h>
#include "euso.hh"
#include "EusoElectronics.hh"
#include "ElectronicsFactory.hh"
#include "OpticsFactory.hh"
#include "MacroCell.hh"
#include "Photomultiplier.hh"
#include "Telemetry.hh"
#include "MacroCellData.hh"
#include "PmtGeometry.hh"
#include "EsafRandom.hh"
#include "FrontEndChip.hh"
#include "AnalogFrontEnd.hh"
#include "ElementaryCell.hh"
#include "FocalSurfaceFileParser.hh"
#include "MacroCellGeometry.hh"
#include "EEventTelemetryAdder.hh"
ClassImp(EusoElectronics)
//______________________________________________________________________________
EusoElectronics::EusoElectronics() : EsafConfigurable(), EsafMsgSource(),
fSimulateElectronics(kTRUE), 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 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();
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 *= geo->PadSide()*geo->PadSide()*Abs(norm.CosTheta());
ngr *= pmt->GetQuantum();
}
}
return ngr;
}
//______________________________________________________________________________
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");
// 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] );
// set night glow parameter for pChip
if ( fNightGlow != "none" )
pChip->SetNightGlowRate( NightGlowRate( pP[0] ) );
}
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] );
// set night glow parameter for pChip
if ( fNightGlow != "none" )
pChip->SetNightGlowRate( NightGlowRate( pP[0] ) );
}
// complete last elementary cell
if ( pEC ) {
pEC->AssociatePmts( pP[0], pP[1], pP[2], pP[3] );
pCell->Add( pEC, RowOffset, ColOffset );
}
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;
}
// 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 ) {
if ( t3 > s->Time() ) t3 = s->Time();
if ( t4 < s->Time() ) t4 = s->Time();
}
}
}
}
}
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();
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
TRandom* rndm = EsafRandom::Get();
Double_t 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;
}
}