Commit 6aa4388f authored by Stezowski Olivier's avatar Stezowski Olivier
Browse files

Merge branch 'CompressedCrystalFrame' into 'preprod'

Compressed crystal frame

See merge request !68
parents 39088d9f dc1e3071
Pipeline #144268 passed with stages
in 12 minutes and 15 seconds
......@@ -82,21 +82,19 @@ SharedFP *AgataFrameFactory::DoNew(Key *key, const FactoryItem & which_frame)
// data frames
// CRYSTAL --------------------------------------------------------------------------- //
if ( which_frame.GetItemName() == "data:crystal" ) {
if ( which_frame.GetVersion() == Version(0,0) )
frame = new CrystalFrame_0(key);
}
if ( which_frame.GetItemName() == "data:ccrystal" ) {
if ( which_frame.GetVersion() == Version(0,0) )
frame = new CrystalFrame_1(key);
// compressed raw traces
if ( which_frame.GetItemName() == "data:crystal" ) {
if ( which_frame.GetVersion() == Version(0,0) )
frame = new CrystalFrame_0_0(key);
}
// uncompressed raw and calibrated traces
if ( which_frame.GetItemName() == "data:crystal" ) {
if ( which_frame.GetVersion() == Version(65000,0) )
frame = new CrystalFrame_0(key);
if ( which_frame.GetVersion() == Version(65000,0) )
frame = new CrystalFrame_65000_0(key);
}
if ( which_frame.GetItemName() == "data:ccrystal" ) {
if ( which_frame.GetVersion() == Version(65000,0) )
frame = new CrystalFrame_1(key);
frame = new CrystalFrame_65000_1(key);
}
// PSA --------------------------------------------------------------------------- //
if ( which_frame.GetItemName() == "data:psa" ) {
......
#include "CrystalFrame.h"
namespace ADF
{
class CrystalFrame_ : public ACrystalFrame
{
friend class AgataFrameFactory;
{
friend class AgataFrameFactory;
protected:
NamedItem<UShort_t> *fUID;
NamedItem<UShort_t> *fStatus;
protected:
PtrStack<GeCore> fCore;
PtrStack<GeSegment> fSegment;
protected:
UInt_t fMaxFrameSize;
NamedItem<UShort_t> *fUID;
NamedItem<UShort_t> *fStatus;
protected:
PtrStack<GeCore> fCore;
PtrStack<GeSegment> fSegment;
protected:
UInt_t fMaxFrameSize;
protected:
CrystalFrame_(Key *akey, const char *sig_type);
virtual UInt_t ReadImp() ;
virtual UInt_t WriteImp() ;
CrystalFrame_(Key *akey, const char *sig_type);
virtual UInt_t ReadImp() ;
virtual UInt_t WriteImp() ;
public:
virtual ~CrystalFrame_()
{;}
//! to get the crystal ID
virtual Int_t GetUID() const
{ return fUID->Get(); }
//! to set the crystal ID
virtual void SetUID(Int_t id)
{ fUID->Set(id); }
virtual GeSegment *GetSegment(UShort_t which)
{ return fSegment.At(which); }
virtual ~CrystalFrame_() {;}
//! to get the crystal ID
virtual Int_t GetUID() const
{ return fUID->Get(); }
//! to set the crystal ID
virtual void SetUID(Int_t id)
{ fUID->Set(id); }
virtual GeSegment *GetSegment(UShort_t which)
{ return fSegment.At(which); }
virtual GeCore *GetCore(UShort_t which)
{ return fCore.At(which); }
virtual void DataReset();
virtual void DataReset();
};
CrystalFrame_::CrystalFrame_(Key *akey, const Char_t *sig_type) :
ACrystalFrame(akey), fUID(0x0), fStatus(0x0), fCore(kNbCores), fSegment(kNbSegments), fMaxFrameSize(ADF::aMByte)
CrystalFrame_::CrystalFrame_(Key *akey, const Char_t *sig_type) :
ACrystalFrame(akey), fUID(0x0), fStatus(0x0), fCore(kNbCores), fSegment(kNbSegments), fMaxFrameSize(ADF::aMByte)
{
for (UShort_t i = 0u; i < kNbCores; i++ )
{ fCore.Add( new GeCore(kDefaultLength,sig_type) ); }
for (UShort_t i = 0u; i < kNbSegments; i++ )
{ fSegment.Add( new GeSegment(kDefaultLength,sig_type) ); }
Global()->AddItem( fUID = new NamedItem<UShort_t>("CrystalID",0u) );
Global()->AddItem( fStatus = new NamedItem<UShort_t>("CrystalStatus",0u) );
for (UShort_t i = 0u; i < kNbCores; i++ )
{ fCore.Add( new GeCore(kDefaultLength,sig_type) ); }
for (UShort_t i = 0u; i < kNbSegments; i++ )
{ fSegment.Add( new GeSegment(kDefaultLength,sig_type) ); }
Global()->AddItem( fUID = new NamedItem<UShort_t>("CrystalID",0u) );
Global()->AddItem( fStatus = new NamedItem<UShort_t>("CrystalStatus",0u) );
}
void CrystalFrame_::DataReset()
void CrystalFrame_::DataReset()
{
// set check level to 0 to fully reset the signals .. in principle
// not needed since the user should fill them completely
if ( GetCheckLevel() > 0 ) {
DataInterface::ResetGlobal();
for (UShort_t i = 0u; i < kNbCores; i++ )
{ fCore.At(i)->Reset(); }
for (UShort_t i = 0u; i < kNbSegments; i++ )
{ fSegment.At(i)->Reset(); }
}
// set check level to 0 to fully reset the signals .. in principle
// not needed since the user should fill them completely
if ( GetCheckLevel() > 0 ) {
DataInterface::ResetGlobal();
for (UShort_t i = 0u; i < kNbCores; i++ )
{ fCore.At(i)->Reset(); }
for (UShort_t i = 0u; i < kNbSegments; i++ )
{ fSegment.At(i)->Reset(); }
}
}
UInt_t CrystalFrame_::ReadImp()
{
// local variables used to decode the in buffer objects
Int_t length;
Float_t energy;
Float_t t;
UShort_t status, id;
// read the global part first
Global()->GetItems((*fBuffer));
for (UShort_t i = 0u; i < kNbSegments; i++ ) {
GeSegment *seg = fSegment.At(i); (*fBuffer) >> length >> status >> id >> energy;
seg->SetStatus(status);
seg->SetID(id);
seg->SetE(energy);
// the trace
if ( GetCheckLevel() == -1 ) {
seg->GetSignal()->SetAddress( fBuffer->CurrentAddress() , length ) ;
fBuffer->SetOffset(fBuffer->Offset()+seg->GetSignal()->SizeOf());
}
else {
seg->GetSignal()->Resize(length,'n');
// seg->GetSignal()->Resize(length,'0');
UInt_t CrystalFrame_::ReadImp()
{
// local variables used to decode the in buffer objects
Int_t length;
Float_t energy;
Float_t t;
UShort_t status, id;
// read the global part first
Global()->GetItems((*fBuffer));
for (UShort_t i = 0u; i < kNbSegments; i++ ) {
GeSegment *seg = fSegment.At(i); (*fBuffer) >> length >> status >> id >> energy;
seg->SetStatus(status);
seg->SetID(id);
seg->SetE(energy);
// the trace
if ( GetCheckLevel() == -1 ) {
seg->GetSignal()->SetAddress( fBuffer->CurrentAddress() , length ) ;
fBuffer->SetOffset(fBuffer->Offset()+seg->GetSignal()->SizeOf());
}
else {
seg->GetSignal()->Resize(length,'n');
// seg->GetSignal()->Resize(length,'0');
seg->GetSignal()->Import(fBuffer);
}
}
for (UShort_t i = 0u; i < kNbCores; i++ ) {
GeCore *core = fCore.At(i); (*fBuffer) >> length >> status >> id >> energy >> t;
core->SetStatus(status);
core->SetID(id);
core->SetE(energy);
core->SetT(t);
// the trace
if ( GetCheckLevel() == -1 ) {
core->GetSignal()->SetAddress( fBuffer->CurrentAddress() , length ) ;
fBuffer->SetOffset(fBuffer->Offset()+core->GetSignal()->SizeOf());
}
else {
core->GetSignal()->Resize(length,'n');
//core->GetSignal()->Resize(length,'0');
}
}
for (UShort_t i = 0u; i < kNbCores; i++ ) {
GeCore *core = fCore.At(i); (*fBuffer) >> length >> status >> id >> energy >> t;
core->SetStatus(status);
core->SetID(id);
core->SetE(energy);
core->SetT(t);
// the trace
if ( GetCheckLevel() == -1 ) {
core->GetSignal()->SetAddress( fBuffer->CurrentAddress() , length ) ;
fBuffer->SetOffset(fBuffer->Offset()+core->GetSignal()->SizeOf());
}
else {
core->GetSignal()->Resize(length,'n');
//core->GetSignal()->Resize(length,'0');
core->GetSignal()->Import(fBuffer);
}
}
return fBuffer->Offset();
}
return fBuffer->Offset();
}
UInt_t CrystalFrame_::WriteImp()
{
// local variables used to encode the in memory objects
Int_t length;
Float_t energy;
Float_t t;
UShort_t dummy=0;
if ( !fBuffer->Reserve(fMaxFrameSize) )
return 0u;
// start writting data in the buffer
Global()->SetItems((*fBuffer));
for (UShort_t i = 0u; i < kNbSegments; i++ ) {
// the segment to be filled
GeSegment *seg = fSegment.At(i);
energy = (Float_t)seg->GetE();
length = seg->GetSignal()->GetLength();
(*fBuffer) << length << seg->GetStatus() << seg->GetID() << energy;
// the trace, without the length writting in the buffer
seg->GetSignal()->Export(fBuffer);
}
for (UShort_t i = 0u; i < kNbCores; i++ ) {
GeCore *core = fCore.At(i);
energy = (Float_t)core->GetE();
t = (Float_t)core->GetT();
length = core->GetSignal()->GetLength();
(*fBuffer) << length << core->GetStatus() << core->GetID() << energy << t;
// the trace, without the length writting in the buffer
core->GetSignal()->Export(fBuffer);
}
return fBuffer->Offset();
}
class CompressedCrystalFrame_ : public CrystalFrame_
{
friend class AgataFrameFactory;
protected:
Signal *fCompressedSignal = nullptr;
const int MIN_1x6 = -32;
const int TOK_BINSIZE = 32;
public:
CompressedCrystalFrame_(Key *akey, const char *sig_type);
public:
virtual ~CompressedCrystalFrame_() {
delete fCompressedSignal;
}
protected:
virtual UInt_t ReadImp() ;
virtual UInt_t WriteImp() ;
//! Alexander Buerger's compression/uncompression June 2010
unsigned int compress_trace(unsigned short* trace, unsigned char* compressed);
unsigned int uncompress_trace(unsigned char* compr, unsigned int csize, unsigned short* trace);
};
CompressedCrystalFrame_::CompressedCrystalFrame_(Key *akey, const Char_t *sig_type) : CrystalFrame_(akey, sig_type)
{
fCompressedSignal = Signal::New(CrystalInterface::kDefaultLength,"US");
}
UInt_t CompressedCrystalFrame_::ReadImp()
{
// local variables used to decode the in buffer objects
Int_t length;
Float_t energy;
Float_t t;
UShort_t status, id;
UShort_t dummy=0;
// read the global part first
Global()->GetItems((*fBuffer));
for (UShort_t i = 0u; i < kNbSegments; i++ ) {
GeSegment *seg = fSegment.At(i); (*fBuffer) >> length >> status >> id >> energy;
seg->SetStatus(status);
seg->SetID(id);
seg->SetE(energy);
// the trace
// uncompress the trace
fCompressedSignal->Resize(length,'n');
fCompressedSignal->Import(fBuffer);
unsigned char* CompTrace = ( unsigned char*)fCompressedSignal->Address(&dummy);
unsigned int nsamp = uncompress_trace(CompTrace,length*2,seg->GetSignal()->Address(&dummy));
seg->GetSignal()->Resize(nsamp,'n');
if(nsamp != CrystalInterface::kDefaultLength) {
std::cout<<"Error in CrystalFrame.icpp => CrystalInterface::kDefaultLength differ from the uncompressed trace length" << std::endl;
std::cout<<"CrystalInterface::kDefaultLength = " << CrystalInterface::kDefaultLength << " ; uncompressed trace length: " << nsamp << std::endl;
seg->GetSignal()->Reset();
}
}
for (UShort_t i = 0u; i < kNbCores; i++ ) {
GeCore *core = fCore.At(i); (*fBuffer) >> length >> status >> id >> energy >> t;
core->SetStatus(status);
core->SetID(id);
core->SetE(energy);
core->SetT(t);
// the trace
// uncompress the trace
fCompressedSignal->Resize(length,'n');
fCompressedSignal->Import(fBuffer);
unsigned char* CompTrace = ( unsigned char*)fCompressedSignal->Address(&dummy);
unsigned int nsamp = uncompress_trace(CompTrace,length*2,core->GetSignal()->Address(&dummy));
core->GetSignal()->Resize(nsamp,'n');
if(nsamp != CrystalInterface::kDefaultLength) {
std::cout<<"Error in CrystalFrame.icpp => CrystalInterface::kDefaultLength differ from the uncompressed trace length" << std::endl;
std::cout<<"CrystalInterface::kDefaultLength = " << CrystalInterface::kDefaultLength << " ; uncompressed trace length: " << nsamp << std::endl;
core->GetSignal()->Reset();
}
}
return fBuffer->Offset();
}
UInt_t CompressedCrystalFrame_::WriteImp()
{
// local variables used to encode the in memory objects
Int_t length;
Float_t energy;
Float_t t;
UShort_t dummy=0;
if ( !fBuffer->Reserve(fMaxFrameSize) )
return 0u;
// start writting data in the buffer
Global()->SetItems((*fBuffer));
for (UShort_t i = 0u; i < kNbSegments; i++ ) {
// the segment to be filled
GeSegment *seg = fSegment.At(i);
energy = (Float_t)seg->GetE();
unsigned char* fCompTrace = ( unsigned char*)fCompressedSignal->Address(&dummy);
// as we don't know the compressed size, make sure to have enough space
fCompressedSignal->Resize(CrystalInterface::kDefaultLength,'-');
length = compress_trace(seg->GetSignal()->Address(&dummy),fCompTrace);
// To allow a simplified inspection of the compressed data each trace is aligned to an an even number of bytes
// The possible extra byte has been zeroed by the compression routine;
// The decompression is not influenced by the possible extra byte.
length = (length+1)/2;
fCompressedSignal->Resize(length,'-');
(*fBuffer) << length << seg->GetStatus() << seg->GetID() << energy;
// the trace, without the length writting in the buffer
fCompressedSignal->Export(fBuffer);
}
for (UShort_t i = 0u; i < kNbCores; i++ ) {
GeCore *core = fCore.At(i);
energy = (Float_t)core->GetE();
t = (Float_t)core->GetT();
unsigned char* fCompTrace = ( unsigned char*)fCompressedSignal->Address(&dummy);
// as we don't know the compressed size, make sure to have enough space
fCompressedSignal->Resize(CrystalInterface::kDefaultLength,'-');
length = compress_trace(core->GetSignal()->Address(&dummy),fCompTrace);
// To allow a simplified inspection of the compressed data each trace is aligned to an an even number of bytes
// The possible extra byte has been zeroed by the compression routine;
// The decompression is not influenced by the possible extra byte.
length = (length+1)/2;
fCompressedSignal->Resize(length,'-');
(*fBuffer) << length << core->GetStatus() << core->GetID() << energy << t;
// the trace, without the length writting in the buffer
fCompressedSignal->Export(fBuffer);
}
return fBuffer->Offset();
}
// Save first sample and try to pack 3 differentiated samples into 16 bits
// Algorithm and original version of the next 2 methods have been written by
// Alexander Buerger during the 2010_week21 experiment (which wrote about 20 TB of data)
// Size of the compressed mezzanines is ~42% of the original size
//(~49% if the 4 garbaged channels in the mezzanine of the core are not zeroed)
// Knowing that the data is from a 14 bit ADC spanning -8192...8191
// -- compress_single_trace_AB extracts it as (samp&0x3FFF)^0x2000 (==> 0...16383)
// -- uncompress_single_trace_AB returns it as val^0x2000to (so as to go back to the original coding)
// The bit flipping could be avoided at the expenses of a (very) small loss of compression
unsigned int CompressedCrystalFrame_::compress_trace(unsigned short* trace, unsigned char* compr)
{
unsigned char* compressed = compr;
// always copy first trace point verbatim (little endian)
unsigned short ref = (trace[0]&0x3FFF)^0x2000;
*compressed++ = ref&0xFF;
*compressed++ = ref>>8;
// loop over remaining trace points
for(uint tp=1; tp<CrystalInterface::kDefaultLength; ++tp) {
const unsigned short val = (trace[tp]&0x3FFF)^0x2000;
const int diff = val - ref;
// try to put 3*5 bits in 2 bytes; highest bit is 0
if( diff>=-15 && diff<=16 && tp<CrystalInterface::kDefaultLength-2 ) {
const unsigned short val2 = (trace[tp+1]&0x3FFF)^0x2000;
const int diff2 = val2 - val;
if( diff2>=-15 && diff2<=16 ) {
const unsigned short val3 = (trace[tp+2]&0x3FFF)^0x2000;
const int diff3 = val3 - val2;
if( diff3>=-15 && diff3<=16 ) {
const unsigned short packed = ((diff+15) << 10) | ((diff2+15)<<5) | (diff3+15);
*compressed++ = packed>>8;
*compressed++ = packed&0xFF;
tp += 2; // we read three trace points
ref = val3;
continue;
}
}
} // no else here
if( diff>MIN_1x6 && diff<(MIN_1x6+64) ) {
// store the difference to the previous point in 6 bit; highest bits are "10"
const unsigned char packed = 0x80 | (diff-MIN_1x6);
*compressed++ = packed;
} else {
// store the trace point in 14 bit; highest bits are "11"
//if( val & 0xC000 ) // this is already taken care by samp&0x3FFF
// return 0xFFFFFFFF;
const unsigned short copy = 0xC000 | val;
*compressed++ = copy>>8;
*compressed++ = copy&0xFF;
}
ref = val;
}
// zeroing the last+1 byte allows the caller to round to 2-bytes boundary in a consistent way // DB
*compressed = 0;
return (unsigned int)(compressed-compr);
}
unsigned int CompressedCrystalFrame_::uncompress_trace(unsigned char* compr, unsigned int csize, unsigned short* trace)
{
unsigned char* compressed = compr;
unsigned char* c_end = compr + csize;
// first trace point is verbatim (little endian)
unsigned char p1 = *compressed++, p2 = *compressed++;
unsigned short ref = p2<<8 | p1;
trace[0] = ref^0x2000;
int midx;
for(midx=1; compressed<c_end && midx<CrystalInterface::kDefaultLength; ++midx) {
const unsigned char packed = *compressed++;
if( (packed & 0x80) == 0 ) {
// three trace points as two differences
const unsigned char p2 = *compressed++;
const unsigned short packed2 = packed<<8 | p2;
const int diff1 = ((packed2>>10) & 0x1F) - 15;
const int diff2 = ((packed2>> 5) & 0x1F) - 15;
const int diff3 = ( packed2 & 0x1F) - 15;
ref += diff1;
trace[midx++] = ref^0x2000;
ref += diff2;
trace[midx++] = ref^0x2000;
ref += diff3;
} else if( (packed & 0xC0) == 0xC0 ) {
if( compressed>=c_end )
return false;
// one trace point as copy
ref = (packed&0x3F)<<8 | *compressed++;
} else {
// one trace point as difference to previous
const int diff1 = (packed & 0x3F) + MIN_1x6;
ref += diff1;
}
trace[midx] = ref^0x2000;
}
return midx;
}
UInt_t CrystalFrame_::WriteImp()
{
// local variables used to encode the in memory objects
Int_t length;
Float_t energy;
Float_t t;
if ( !fBuffer->Reserve(fMaxFrameSize) )
return 0u;
// start writting data in the buffer
Global()->SetItems((*fBuffer));
for (UShort_t i = 0u; i < kNbSegments; i++ ) {
// the segment to be filled
GeSegment *seg = fSegment.At(i);
length = seg->GetSignal()->GetLength();
energy = (Float_t)seg->GetE();
(*fBuffer) << length << seg->GetStatus() << seg->GetID() << energy;
// the trace, without the length writting in the buffer
seg->GetSignal()->Export(fBuffer);
}
for (UShort_t i = 0u; i < kNbCores; i++ ) {
GeCore *core = fCore.At(i);
length = core->GetSignal()->GetLength();
energy = (Float_t)core->GetE();
t = (Float_t)core->GetT();
(*fBuffer) << length << core->GetStatus() << core->GetID() << energy << t;
// the trace, without the length writting in the buffer
core->GetSignal()->Export(fBuffer);
}
return fBuffer->Offset();
}
//! CrystalFrame with signals as UShort_t
/*!
*/
class CrystalFrame_0 : public CrystalFrame_
class CrystalFrame_65000_0 : public CrystalFrame_
{
friend class AgataFrameFactory;
friend class AgataFrameFactory;
protected:
CrystalFrame_0(Key *akey) : CrystalFrame_(akey,"US") {;}
CrystalFrame_65000_0(Key *akey) : CrystalFrame_(akey,"US") {;}
public:
virtual ~CrystalFrame_0()
{;}
virtual ~CrystalFrame_65000_0()
{;}
};
//! CrystalFrame with signals as Float_t
/*!
*/
class CrystalFrame_1 : public CrystalFrame_
class CrystalFrame_65000_1 : public CrystalFrame_
{
friend class AgataFrameFactory;
friend class AgataFrameFactory;
protected:
CrystalFrame_65000_1(Key *akey) : CrystalFrame_(akey,"F") {;}
public:
virtual ~CrystalFrame_65000_1()
{;}
};
//! Compressed CrystalFrame with signals as UShort_t
/*!
*/
class CrystalFrame_0_0 : public CompressedCrystalFrame_
{
friend class AgataFrameFactory;