Commit 166cdae7 authored by dino's avatar dino
Browse files

Timing of ge-ancillary in TrackingFilter improved by using the LocalTrigger of...

Timing of ge-ancillary in TrackingFilter improved by using the LocalTrigger of the AGAVA as taken in a TDC of the VME electronics. After calibration of the TDCs in the AncillaryFilterVME the "10 ns" is added to all TDC channels. The reference channels of the "10 ns" is given in AncillaryFilter.conf by the keyword ReferenceTDC.

PSAFilterGridSearch has been improved for multiple segment events by analyzing the sub-events in energy-decreasing order and removing from the data-traces the result of the previous (higer-energy) interactions.

git-svn-id: svn://gal-serv.lnl.infn.it/agata/trunk/narval_emulator@862 170316e4-aea8-4b27-aad4-0380ec0519c9
parent 9d39cb62
......@@ -14,7 +14,7 @@
#define WCT_BUFSIZE (10*1024*1024) // size (bytes) of the data buffers connecting the actors
//#define WCT_BUFSIZE_AP ( 2*1024*1024) // for the Ancillary producer (must be < WCT_BUFSIZE)
#define WCT_BUFSIZE_AP ( 512*1024) // for the Ancillary producer (must be < WCT_BUFSIZE)
#define WCT_BUFSIZE_AP ( 30*1024) // for the Ancillary producer (must be < WCT_BUFSIZE)
//#define WCT_THREADED // to run the various chains in parallel on a many-core system
......
......@@ -101,7 +101,7 @@ const int defTriggerSample = 10; // 60-10 useful samples passed to the PS
//////// CrystalProducerATCA ////////
/////////////////////////////////////
#define PCI_EXPRESS // reading from the AGATA ATCA carriers via PCI express
//#define PCI_EXPRESS // reading from the AGATA ATCA carriers via PCI express
#define CP_NO_ADF // CrystalProducerATCA does not use ADF to format the output buffer
/////////////////////////////////////
......@@ -115,14 +115,9 @@ const int defTriggerSample = 10; // 60-10 useful samples passed to the PS
//////// PSAFilter ////////
///////////////////////////
#define TCOUNT 3 // number of threads to use to decompose signals
#define TMODULO 100 // how many events are distributed to each thread
//#define WRITE_PSA_HITS // to write input hits in Francesco's imaging format
//#define USENETCHARGES // to use the net charge signals in the grid search
//#define USECORETRACE // to use also the core signal in the grid search
#define USEADAPTIVE // to use adaptive search
//#define TCOUNT 3 // number of threads to use to decompose signals
#define TMODULO 100 // how many events are distributed to each thread
#define USEADAPTIVE // to use the coarse-fine grid searh
// don't have yet the boost library on WIN64
#ifdef WIN64
......@@ -136,7 +131,8 @@ const int defTriggerSample = 10; // 60-10 useful samples passed to the PS
/////////////////////////////////
//#define AF_PRISMA // processing of PRISMA
#define AF_DANTE // processing of DANTE ==> still to be adjusted
//#define AF_DANTE // processing of DANTE ==> still to be adjusted
#define AF_HELENA // processing of the Helena detectors for the neutron test
//#define AF_ROOTTREE
////////////////////////////
......
......@@ -39,6 +39,9 @@ fTrigger("data:ranc0")
fDanteChXcal0 = fDanteChYcal0 = 0; // offsets
fDanteChXcal1 = fDanteChYcal1 = 1.f; // gains
fRefTDCModule = fRefTDCIndex = fRefTDCOffset = 0;
fRefTDC = false;
rawBufLen = 0;
rawBuf = NULL;
......@@ -212,6 +215,10 @@ void AncillaryFilter::GetParameters(UInt_t *error_code)
else if( stringEq(keyw, "DanteCalY") ) {
ok = 2 == sscanf(data.c_str(), "%f %f", &fDanteChYcal0, &fDanteChYcal1);
}
else if( stringEq(keyw, "ReferenceTDC") ) {
ok = 3 == sscanf(data.c_str(), "%d %d %d", &fRefTDCModule, &fRefTDCIndex, &fRefTDCOffset);
if(ok) fRefTDC = true;
}
else if( stringEq(keyw, "Verbose") ) {
fVerbose = true;
ok = true;
......@@ -263,7 +270,7 @@ bool AncillaryFilter::Decodesetup()
cout << " ADC crate slot channels" << endl;
cout << " TDC crate slot channels" << endl;
cout << " SCALER crate slot channels" << endl;
cout << " cal index chan offset gain" << endl;
cout << " cal index chan threshold offset gain" << endl;
cout << endl;
string line, name, data;
......@@ -501,7 +508,7 @@ Int_t AncillaryFilter::SetInput()
ii++; // the next channel
indChan = (rawBuf[ii] & 0x1F0000) >> 16;
Int_t value = rawBuf[ii] & 0xFFF;
Converter[indMod].SetValue(indChan, (Float_t)value);
Converter[indMod].SetValue(indChan, value+fRAND());
}
ii++; // skip the End Of Block word (not present in SCALER)
break;
......
......@@ -82,6 +82,9 @@ protected:
Float_t fDanteChXcal0, fDanteChXcal1; // calibration coefficients
Float_t fDanteChYcal0, fDanteChYcal1; // calibration coefficients
UInt_t fRefTDCModule, fRefTDCIndex, fRefTDCOffset;
Bool_t fRefTDC;
public:
// next three methods can be overloaded in the daughter class
virtual Int_t Process(){return 0;}
......
......@@ -10,7 +10,7 @@
using namespace std;
using namespace ADF;
const float eScale = 5.f; // normalize output to 0.2 keV/ch
const float eScale = 1.f; // normalize output to 1 keV/ch
const float tScale = 10.f; // normalize output to 1 ns/ch
const int specOffE = 0; // 2*1024; // offset to see the negative amplitudes in the segments
const int specLenE = 16*1024;
......@@ -31,8 +31,10 @@ AncillaryFilterVME::AncillaryFilterVME()
{
#ifdef LOCALSPECTRA
AncSpec_All = NULL;
AncSpec_Cal = NULL;
MatrAll_PRISMA = NULL;
MatrAll_DANTE = NULL;
MatrAll_HELENA = NULL;
#endif //LOCALSPECTRA
fAllPairsMat = true;
......@@ -67,6 +69,11 @@ AncillaryFilterVME::AncillaryFilterVME()
cout << "**** AncillaryFilterVME ==> PRISMA is enabled ****" << endl;
cout << "**************************************************" << endl;
#endif
#ifdef AF_HELENA
cout << "**************************************************" << endl;
cout << "**** AncillaryFilterVME ==>HELENA is enabled ****" << endl;
cout << "**************************************************" << endl;
#endif
}
......@@ -140,17 +147,31 @@ Int_t AncillaryFilterVME::AlgoSpecificInitialise()
}
// Generic version passing everything as float
// Contains special cases for AF_DANTE and AF_PRISMA
// Contains special cases for AF_DANTE, AF_PRISMA and AF_HELENA
Int_t AncillaryFilterVME::Process()
{
// fill the flat output structure with the calibrated Converters
memset(outData, 0, outDataLen*sizeof(Float_t));
UInt_t nnOut = 0;
float refTDCValue = 0;
if(fRefTDC) {
refTDCValue = Converter[fRefTDCModule].GetCalibratedValue(fRefTDCIndex) - fRefTDCOffset; // will it work if calibration is active ??
}
for(UInt_t nn = 0; nn < TotNumMod; nn++) {
UInt_t nch = Converter[nn].NumChan;
for(UInt_t ii = 0; ii < nch; ii++) {
outData[nnOut++] = Converter[nn].GetCalibratedValue(ii);
if(fRefTDC && Converter[nn].Type == Converter_t::TDC) {
for(UInt_t ii = 0; ii < nch; ii++) {
float val = Converter[nn].GetCalibratedValue(ii);
if(val)
outData[nnOut] = val - refTDCValue;
nnOut++;
}
}
else {
for(UInt_t ii = 0; ii < nch; ii++) {
outData[nnOut++] = Converter[nn].GetCalibratedValue(ii);
}
}
}
......@@ -197,12 +218,17 @@ void AncillaryFilterVME::Projections()
for (UInt_t indMod = 0; indMod < TotNumMod; indMod++) {
Converter_t * cv = Converter + indMod;
UInt_t numChan = cv->NumChan;
float xScale = Converter[indMod].Type == Converter_t::TDC ? tScale : eScale;
for(UInt_t indChan = 0; indChan < numChan; indChan++) {
int value = (Int_t)cv->Value[indChan]; // should check what to do for scalers
if(value) {
#ifdef LOCALSPECTRA
if(AncSpec_All)
AncSpec_All->Incr(indMod, indChan, value);
if(AncSpec_Cal) {
int cvalue = Int_t(cv->GetCalibratedValue(indChan)*xScale);
AncSpec_Cal->Incr(indMod, indChan, cvalue);
}
#endif //LOCALSPECTRA
#ifdef _FromGRU_
AllChan->Fill(value+indMod*4096*32+4096*indChan);
......@@ -236,6 +262,26 @@ void AncillaryFilterVME::Projections()
}
}
}
if(MatrAll_HELENA) {
for(unsigned int n1 = 0; n1 < 3*32; n1++) {
float val1 = outData[n1];
if(val1 < 1) continue;
int iMod1 = n1/32;
float xScale1 = Converter[iMod1].Type == Converter_t::TDC ? tScale*mtAllScale : eScale*mtAllScale;
val1 *= xScale1;
if(val1 < mtAllMinval) continue;
for(unsigned int n2 = 0; n2 < 3*32; n2++) {
if(n2==n1) continue;
float val2 = outData[n2];
if(val2 < 1) continue;
int iMod2 = n2/32;
float xScale2 = Converter[iMod2].Type == Converter_t::TDC ? tScale*mtAllScale : eScale*mtAllScale;
val2 *= xScale2;
if(val2 < mtAllMinval) continue;
MatrAll_HELENA->incr(n1, n2, (int)val1, (int)val2);
}
}
}
#endif //LOCALSPECTRA
}
......@@ -304,6 +350,12 @@ bool AncillaryFilterVME::initPresort()
AncSpec_All->setComment("Projection of all parameters");
hGroup.add(AncSpec_All);
if(AncSpec_Cal) delete AncSpec_Cal;
AncSpec_Cal = new nDhist<unsigned int>(TotNumMod, 32, 4096);
AncSpec_Cal->setFileName(fOdirPrefix+"Spec?Cal.spec");
AncSpec_Cal->setComment("Calibrated projection of all parameters");
hGroup.add(AncSpec_Cal);
# ifdef AF_PRISMA
// if(MatrAll_PRISMA) delete MatrAll_PRISMA; MatrAll_PRISMA = NULL;
// if(fAllPairsMat && TotNumMod >= 3) {
......@@ -322,6 +374,15 @@ bool AncillaryFilterVME::initPresort()
// hGroup.add(MatrAll_DANTE);
// }
# endif
# ifdef AF_HELENA
// if(MatrAll_HELENA) delete MatrAll_HELENA; MatrAll_HELENA = NULL;
// if(fAllPairsMat && TotNumMod >= 3) {
// MatrAll_HELENA = new nDhist<unsigned short>(3*32, 3*32, mtAllSize, mtAllSize);
// MatrAll_HELENA->setFileName(fOdirPrefix+"Anc?All_HELENA.matr");
// MatrAll_HELENA->setComment("Matrix of all pairs");
// hGroup.add(MatrAll_HELENA);
//}
# endif
#endif //LOCALSPECTRA
#ifdef _FromGRU_
......
......@@ -66,8 +66,10 @@ public:
#ifdef LOCALSPECTRA
nDhist<unsigned int >*AncSpec_All;
nDhist<unsigned int >*AncSpec_Cal;
nDhist<unsigned short>*MatrAll_PRISMA;
nDhist<unsigned short>*MatrAll_DANTE;
nDhist<unsigned short>*MatrAll_HELENA;
#endif //LOCALSPECTRA
#ifdef AF_PRISMA
......
......@@ -21,19 +21,12 @@ const int specLenT = 2*1000;
const int matLen = 100;
const int matOff = 50;
const int fixSamps = 50; // if 0, the actual number of samples used in the gridSearch is up to 95% of the core amplitude
const bool doSelect = false; // the selection has to be programmed manually in Process()
#ifdef USENETCHARGES
const int diffLag = 0; // use the net-charge signals as they are
#else
const int diffLag = 5; // use them with a delayed-differentiation (in units of signal samples) if !=0
//# define SHOWDIFFERENTIATED // in the saved traces show the differentiated version of the net-charge segments
#endif
PSAFilterGridSearch::PSAFilterGridSearch() :
fpPsaTraces(NULL), fpPsaHits(NULL)
PSAFilterGridSearch::PSAFilterGridSearch()
{
fpPsaTraces = NULL;
for(int nn = 0; nn < NCHAN; nn++) {
memset(hmask[nn], ' ', NCHAN);
hmask[nn][NCHAN] = 0;
......@@ -138,10 +131,11 @@ Int_t PSAFilterGridSearch::AlgoSpecificInitialise()
// apply the cross-talk correction to the basis signals
fBasis.XtalkCorrection();
fBasis.StoreNetCharges(); // the netcharge segment is duplicated into netcharge
if(diffLag > 0) {
// Modify the signal basis because the grid-search uses the differentiated net-charge signals
fBasis.DifferentiateNetChargeSignals(diffLag);
if(DIFFLAG > 0) {
// Modify the signal basis if grid-search uses the differentiated net-charge signals
fBasis.DifferentiateNetChargeSignals(DIFFLAG);
}
// prepare the metrics vectors for the chi2 loops
......@@ -185,12 +179,6 @@ Int_t PSAFilterGridSearch::AlgoSpecificInitialise()
bDoMats = matrXYZR || matrSeg;
#endif //LOCALSPECTRA
#ifdef WRITE_PSA_HITS
cout << "Opening PSA hits file " << "Psa_Hits.txt" << endl;
fpPsaHits = fopen("Psa_Hits.txt", "w");
fprintf(fpPsaHits, "$\n");
#endif
#ifdef USEADAPTIVE
cout << "Grid Search performed using a COARSE/FINE grid" << endl;
#else
......@@ -303,16 +291,30 @@ Int_t PSAFilterGridSearch::Process(int slot)
int samp_first = pS.addr_first;
int samp_last = pS.addr_last;
if(fixSamps <= 0) {
if(SFIXEDLEN <= 0) {
// search up to a fraction of signal amplitude (of the core)
pS.SearchLimits(0.95f, fHitSegThreshold, samp_first, samp_last);
}
else {
// search using a fixed number of samples
samp_last = samp_first + fixSamps - 1;
samp_last = samp_first + SFIXEDLEN - 1;
}
// order the net-charge segments according to the released energy
int segOrder[NSEGS];
float eneOrder[NSEGS];
for(int snn = 0; snn < sMult; snn++) {
segOrder[snn] = snn;
eneOrder[snn] = pS.netChargeEnergy[snn];
}
for(int n1 = sMult-1; n1 >=0; n1--) {
for(int n2 = 0; n2 < n1; n2++) {
if(eneOrder[n2] < eneOrder[n2+1]) {
swap(segOrder[n2], segOrder[n2+1]);
swap(eneOrder[n2], eneOrder[n2+1]);
}
}
}
char localMask[NCHAN+1];
// if needed, clear the "fitted" trace
if(fWriteNumTraces > 0)
......@@ -322,11 +324,15 @@ Int_t PSAFilterGridSearch::Process(int slot)
// the loop on the independently-analysed net-charge segments //
////////////////////////////////////////////////////////////////
for(int snum = 0; snum < sMult; snum++) {
char localMask[NCHAN+1];
for(int snn = 0; snn < sMult; snn++) {
int snum = segOrder[snn];
int netChSeg = pS.netChargeSegnum[snum];
float netChEner = pS.netChargeEnergy[snum];
pS.netChargeSegment = netChSeg; // the point is considered to have this as the netcharge segment
// set mask of segments for the search loop
strcpy(localMask, hmask[netChSeg]);
......@@ -341,19 +347,16 @@ Int_t PSAFilterGridSearch::Process(int slot)
localMask[NCHAN-1] = '0';
#endif
if(diffLag > 0)
if(DIFFLAG > 0)
localMask[netChSeg] = '1'; // (ri)enable the segment-of-interest
// normalize the traces of this segment to the "standard" base amplitude MAXNORM
// prepare sAmplitude (the traces normalized to MAXNORM used by the GridSearch)
// from the subset of fAmplitude given by localMask
float fact = MAXNORM / netChEner;
pS.Normalize(fact, localMask);
pS.MakeSearchWave(fact, localMask);
if(diffLag > 0) {
// apply a delayed differentiation of diffLag samples to the net charge segment
float *ptdata = pS.sAmplitude[netChSeg];
for(int nn = NTIME-1; nn >= diffLag; nn--) {
ptdata[nn] -= ptdata[nn - diffLag];
}
if(DIFFLAG > 0) {
pS.sDiffNetCharge(DIFFLAG); // apply a delayed differentiation of DIFFLAG samples to the net charge segment of sAmplitude
}
pS.chi2min = float(1.e30);
......@@ -366,9 +369,11 @@ Int_t PSAFilterGridSearch::Process(int slot)
int usamp = SearchFullGrid(&pS, netChSeg, localMask, samp_first, samp_last);
#endif
float fx = fBasis.Pts[netChSeg][pS.bestPt].x;
float fy = fBasis.Pts[netChSeg][pS.bestPt].y;
float fz = fBasis.Pts[netChSeg][pS.bestPt].z;
pointPsa *bestPoint = &fBasis.Pts[netChSeg][pS.bestPt];
float fx = bestPoint->x;
float fy = bestPoint->y;
float fz = bestPoint->z;
// save the results
pD->theHits[pD->numHits].Reset();
......@@ -387,62 +392,94 @@ Int_t PSAFilterGridSearch::Process(int slot)
pD->selectIt = true;
}
// traces
// The trace of the best point is normalized to the experimental amplitude and accumulated
// While writing the traces, the best point is normalized to the experimental amplitude and accumulated
if(fWriteNumTraces > 0) {
float netcharge[NTIME]; // to reconstruct the netcharge if grid-search is done using the differentiated net-charge signals.
int time_first = TSHIFT;
fact = eScale/fact;
gs_type * realTrace;
gs_type * baseTrace;
int time_first = TSHIFT-PRETRIG;
float fact1 = eScale/fact;
for(int segm = 0; segm < NCHAN; segm++) {
float * realTrace = pS.rAmplitude[segm];
float * baseTrace = fBasis.Pts[netChSeg][pS.bestPt].amplitude[segm];
realTrace = pS.rAmplitude[segm];
baseTrace = bestPoint->amplitude[segm];
#ifndef SHOWDIFFERENTIATED
// A complication when the grid-search is done using the differentiated net-charge signals.
// To simplify the implementation we have modified (differentiated )the net-charge signal in the basis.
// If, as here, the original trace is needed we reproduce it here by deconvolution of the differentiated one
if(diffLag > 0 && segm == netChSeg ) {
memcpy(netcharge, baseTrace, sizeof(netcharge));
for(int nn = diffLag; nn < NTIME; nn++)
netcharge[nn] += netcharge[nn-diffLag];
baseTrace = netcharge;
}
if(segm == bestPoint->netChargeSegment)
baseTrace = bestPoint->netcharge;
#endif
realTrace += samp_first;
realTrace += samp_first-PRETRIG;
baseTrace += time_first;
for(int nn = 0; nn < usamp; nn++) {
(*realTrace++) += (*baseTrace++)*fact;
(*realTrace++) += gs_type( (*baseTrace++)*fact1 );
}
}
}
#ifdef ORDEREDSEARCH
// subtract the result of this point from the experimental trace
// but not for the last (if not needed to write the partial traces)
#ifndef SHOWPARTIALS
if(snn < sMult-1)
#endif
pS.fRemoveFitted(1.f/fact, localMask, bestPoint, samp_first, TSHIFT-PRETRIG);
#ifdef SHOWPARTIALS
if(fpPsaTraces) {
// Write out the modified trace
// Pay attention that this is writing directly to the disk and therefore cannot work if using more than one thread.
// In that case one would need to store in slot_fAmplitude a variable number of traces but this is too complicated
int chanToCopy = NSEGS < WCHAN ? NSEGS : WCHAN;
int sampToCopy = NTIME < WSAMP ? NTIME : WSAMP;
size_t toWrite = WSAMP;
short wbuf[WSAMP];
gs_type *abuf;
for(int ns = 0; ns < chanToCopy; ns++) {
memset(wbuf, 0, sizeof(wbuf));
abuf = pS.fAmplitude[ns];
for(int nn = 0; nn < sampToCopy; nn++) wbuf[nn] = (short)(abuf[nn]*eScale);
size_t nwritten = fwrite(wbuf, sizeof(short), toWrite, fpPsaTraces);
if(nwritten != toWrite)
return 1;
}
if(chanToCopy < WCHAN) {
memset(wbuf, 0, sizeof(wbuf));
for(int ns = chanToCopy; ns < WCHAN; ns++) {
size_t nwritten = fwrite(wbuf, sizeof(short), toWrite, fpPsaTraces);
if(nwritten != toWrite)
return 1;
}
}
}
#endif // SHOWPARTIALS
#endif // ORDEREDSEARCH
} // end of loop over the net charge segments
// store fAmplitude and rAmplitude to be able to write them in PostProcess
// While writing the traces, save the results in the proper slot_fAmplitude and slot_rAmplitude
if(fWriteNumTraces > 0) {
float *sdata;
int wnsamp = WSAMP <= NTIME ? WSAMP : NTIME;
#ifdef SHOWDIFFERENTIATED
if(DIFFLAG > 0) { // reapply the delayed differentiation to the experimental net-charge segments
for(int snum = 0; snum < sMult; snum++) {
int netChSeg = pS.netChargeSegnum[snum];
gs_type *ptd = pS.oAmplitude[netChSeg];
for(int nn = NTIME-1; nn >= DIFFLAG; nn--) {
ptd[nn] -= ptd[nn - DIFFLAG];
}
}
}
#endif // SHOWDIFFERENTIATED
gs_type *sdata;
sdata = slot_fAmplitude[slot];
for(int segm = 0; segm < NCHAN; segm++) {
float *fdata = pS.fAmplitude[segm];
for(int samp = 0; samp < WSAMP; samp++)
*sdata++ = fdata[samp]*eScale;
gs_type *fdata = pS.oAmplitude[segm];
for(int samp = 0; samp < wnsamp; samp++)
*sdata++ = gs_type(fdata[samp]*eScale);
}
sdata = slot_rAmplitude[slot];
for(int segm = 0; segm < NCHAN; segm++) {
float *fdata = pS.rAmplitude[segm];
for(int samp = 0; samp < WSAMP; samp++)
gs_type *fdata = pS.rAmplitude[segm];
for(int samp = 0; samp < wnsamp; samp++)
*sdata++ = fdata[samp]; // escale already considered in the production
}
if(diffLag > 0) {
#ifdef SHOWDIFFERENTIATED
// reapply the delayed differentiation to the experimental net-charge segments
for(int snum = 0; snum < sMult; snum++) {
int netChSeg = pS.netChargeSegnum[snum];
float *ptd = slot_fAmplitude[slot] + WSAMP*netChSeg;
for(int nn = WSAMP-1; nn >= diffLag; nn--) {
ptd[nn] -= ptd[nn - diffLag];
}
}
#endif
}
}
return 0;
......@@ -482,11 +519,16 @@ void PSAFilterGridSearch::PrepareEvent(PsaData *pD, pointExp *pS)
pS->addr_last = ntocopy-1;
for(Int_t atseg=0; atseg<NSEGS; atseg++) {
if(pS->masksignals[atseg] != '0') {
memcpy(pS->fAmplitude[atseg], pD->fTracesSG[atseg], ntocopy*sizeof(float));
for(int ii = 0; ii < ntocopy; ii++)
pS->fAmplitude[atseg][ii] = (gs_type)pD->fTracesSG[atseg][ii];
}
}
// copy also the CC
memcpy(pS->fAmplitude[NSEGS], pD->fTracesCC[0], ntocopy*sizeof(float));
for(int ii = 0; ii < ntocopy; ii++)
pS->fAmplitude[NSEGS][ii] = (gs_type)pD->fTracesCC[0][ii];
// and save the whole trace into oAmplitude for any possible use
memcpy(pS->oAmplitude, pS->fAmplitude, sizeof(pS->fAmplitude));
}
void PSAFilterGridSearch::SetToSegCenter(PsaData *pD, pointExp *pS)
......@@ -526,10 +568,13 @@ int PSAFilterGridSearch::WriteTraces(int slot)
int sampToCopy = NTIME < WSAMP ? NTIME : WSAMP;
size_t toWrite = WSAMP;
gs_type *abuf;
// First the experimental data
for(int ns = 0; ns < chanToCopy; ns++) {
memset(wbuf, 0, sizeof(wbuf));
//memcpy(wbuf, &slot_fAmplitude[slot][ns*sampToCopy], sizeof(short)*sampToCopy);
float *abuf = slot_fAmplitude[slot] + ns*sampToCopy;
abuf = slot_fAmplitude[slot] + ns*sampToCopy;
for(int nn = 0; nn < sampToCopy; nn++) wbuf[nn] = (short)abuf[nn];
size_t nwritten = fwrite(wbuf, sizeof(short), toWrite, fpPsaTraces);
if(nwritten != toWrite) {
......@@ -550,10 +595,11 @@ int PSAFilterGridSearch::WriteTraces(int slot)
}
}
// Then the "fitted" traces
for(int ns = 0; ns < chanToCopy; ns++) {
memset(wbuf, 0, sizeof(wbuf));
//memcpy(wbuf, &slot_rAmplitude[slot][ns*sampToCopy], sizeof(short)*sampToCopy);
float *abuf = slot_rAmplitude[slot] + ns*sampToCopy;
abuf = slot_rAmplitude[slot] + ns*sampToCopy;
for(int nn = 0; nn < sampToCopy; nn++) wbuf[nn] = (short)abuf[nn];
size_t nwritten = fwrite(wbuf, sizeof(short), toWrite, fpPsaTraces);
if(nwritten != toWrite) {
......@@ -563,13 +609,25 @@ int PSAFilterGridSearch::WriteTraces(int slot)
}
}
if(chanToCopy < WCHAN) {
int remaining = WCHAN - chanToCopy;
// next come the hits
memset(wbuf, 0, sizeof(wbuf));
int numHits = pD->numHits;
size_t pos = 0;
for(int nh = 0; nh < numHits; nh++) {
int pos = nh*10;
if(pos >= (int)toWrite)
break;
if(pos >= toWrite) {
size_t nwritten = fwrite(wbuf, sizeof(short), toWrite, fpPsaTraces);
if(nwritten != toWrite) {
rstat = 1;
fWriteNumTraces = 1;
goto finish;
}
remaining--;
if(remaining == 0)
break;
pos = 0;
memset(wbuf, 0, sizeof(wbuf));
}
ADF::PSAHit *pH = &pD->theHits[nh];
pos++;
wbuf[pos++] = pH->GetID();
......@@ -578,16 +636,20 @@ int PSAFilterGridSearch::WriteTraces(int slot)
wbuf[pos++] = (int)(pH->GetY()*dScale);
wbuf[pos++] = (int)(pH->GetZ()*dScale);
wbuf[pos++] = (int)(dScale*sqrt(pH->GetX()*pH->GetX()+pH->GetY()*pH->GetY()));
pos += 3;