SdBaselineFinder.cc
Go to the documentation of this file.
1 #include "SdBaselineFinder.h"
2 
3 #include <fwk/CentralConfig.h>
4 #include <evt/Event.h>
5 #include <sdet/SDetector.h>
6 #include <sevt/SEvent.h>
7 #include <sevt/EventTrigger.h>
8 #include <utl/Accumulator.h>
9 #include <utl/String.h>
10 
11 using namespace fwk;
12 using namespace sevt;
13 using namespace utl;
14 using namespace std;
15 
16 
17 namespace SdBaselineFinderOG {
18 
19  namespace Const {
20 
21  inline
22  constexpr
23  int
24  MinLength(const bool isUUB)
25  {
26  return isUUB ? 120: 40;
27  }
28 
29 
30  inline
31  constexpr
32  unsigned int
33  UsefulBins(const bool isUUB)
34  {
35  return isUUB ? 600 : 200;
36  }
37 
38  }
39 
40 
43  {
44  auto topB = CentralConfig::GetInstance()->GetTopBranch("SdBaselineFinder");
45 
46  fDecreaseLGFlatPieceTolerance = bool(topB.GetChild("decreaseLGFlatPieceTolerance"));
47  fApplyBackwardFlatPieceCheck = bool(topB.GetChild("applyBackwardFlatPieceCheck"));
48 
49  ostringstream info;
50  info << "Parameters:\n"
51  "applyBackwardFlatPieceCheck: " << fApplyBackwardFlatPieceCheck << "\n"
52  "decreaseLGFlatPieceTolerance: " << fDecreaseLGFlatPieceTolerance;
53  INFO(info);
54 
55  return eSuccess;
56  }
57 
58 
60  SdBaselineFinder::Run(evt::Event& event)
61  {
62  if (!event.HasSEvent())
63  return eSuccess;
64  auto& sEvent = event.GetSEvent();
65 
66  for (auto& station : sEvent.StationsRange()) {
67 
68  if (!station.HasTriggerData() ||
69  !station.HasCalibData() ||
70  !station.HasGPSData())
71  continue;
72 
73  const auto& trig = station.GetTriggerData();
74  if (trig.IsRandom() ||
75  (trig.GetErrorCode() & 0xff) || // for UUBs errorcodes are above 256
76  station.GetCalibData().GetVersion() > 32000)
77  continue;
78 
79  // skip "bad compressed data"
80  if (sEvent.HasTrigger()) {
81  const int trigSecond = sEvent.GetTrigger().GetTime().GetGPSSecond();
82  const int timeDiff = int(station.GetGPSData().GetSecond()) - trigSecond;
83  if (abs(timeDiff) > 1)
84  continue;
85  }
86 
87  if (!ComputeBaselines(station)) {
88  station.SetRejected(StationConstants::eBadCalib);
89  continue;
90  }
91 
92  }
93 
94  return eSuccess;
95  }
96 
97 
98  void
99  SdBaselineFinder::MakeFlatBaseline(PMT& pmt, const sdet::PMTConstants::PMTGain gain)
100  const
101  {
102  auto& pmtRec = pmt.GetRecData();
103  if (!pmtRec.HasFADCBaseline(gain))
104  pmtRec.MakeFADCBaseline(gain);
105  auto& baseline = pmtRec.GetFADCBaseline(gain);
106  const double onlineBaseline = pmt.GetCalibData().GetBaseline(gain);
107  for (int i = 0, n = baseline.GetSize(); i < n; ++i)
108  baseline[i] = onlineBaseline;
109  }
110 
111 
112  bool
113  SdBaselineFinder::ComputeBaselines(Station& station)
114  const
115  {
116  int doneSome = 0;
117  for (auto& pmt : station.PMTsRange(sdet::PMTConstants::eAnyType))
118  doneSome +=
119  ComputeBaseline(station, pmt, sdet::PMTConstants::eHighGain) +
120  ComputeBaseline(station, pmt, sdet::PMTConstants::eLowGain);
121 
122  return doneSome;
123  }
124 
125 
126  bool
127  SdBaselineFinder::ComputeBaseline(const Station& station, PMT& pmt, const sdet::PMTConstants::PMTGain gain)
128  const
129  {
130  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
131 
132  if (!pmt.HasFADCTrace() || !pmt.GetCalibData().IsTubeOk())
133  return false;
134 
135  if (gain == sdet::PMTConstants::eLowGain && !pmt.GetCalibData().IsLowGainOk())
136  return false;
137 
138  const auto& trace = pmt.GetFADCTrace(gain);
139  const int traceLength = trace.GetSize();
140 
141  if (!pmt.HasRecData())
142  pmt.MakeRecData();
143  auto& pmtRec = pmt.GetRecData();
144 
145  auto& flatPieces = pmtRec.GetBaselineFlatPieces(gain);
146  flatPieces.clear();
147 
148  int minLength = Const::MinLength(station.IsUUB());
149 
150  const int saturationValue = dStation.GetSaturationValue();
151 
152  // increase signal variability
153  bool seenSaturation = false;
154  bool hitsZero = false;
155  int sigma = (fDecreaseLGFlatPieceTolerance && gain == sdet::PMTConstants::eLowGain) ? 1 : 2;
156 
157  do {
158  ++sigma;
159 
160  int startBin = 0;
161  int stopBin = 0;
162  do {
163 
164  const int startValue = trace[startBin];
165 
166  // find sigma-flat piece
167  while (stopBin < traceLength) {
168  if (abs(startValue - trace[stopBin]) > sigma)
169  break;
170  ++stopBin;
171  }
172 
173  if (startValue >= saturationValue) {
174  if (!startBin && stopBin == traceLength) {
175  // whole trace is saturated
176  flatPieces.push_back(PMTRecData::Piece(0, traceLength));
177  seenSaturation = true;
178  ostringstream warn;
179  warn << "Station " << station.GetId() << ", PMT " << pmt.GetId() << ", "
180  << (gain == sdet::PMTConstants::eHighGain ? "high" : "low")
181  << " gain (saturated): Whole trace saturated.";
182  WARNING(warn);
183  break;
184  } else {
185  // start again
186  stopBin = startBin;
187  minLength = 0.25 * Const::MinLength(station.IsUUB());
188  if (sigma < 4)
189  sigma = 4;
190  seenSaturation = true;
191  }
192  }
193  if (!startValue && seenSaturation) {
194  // (under)saturation of undershoot: baseline is 0 till the end
195  flatPieces.push_back(PMTRecData::Piece(stopBin, traceLength));
196  startBin = stopBin = traceLength;
197  hitsZero = true;
198  }
199  if (stopBin-startBin < minLength) {
200  // nothing useful found
201  ++startBin;
202  stopBin = startBin;
203  } else {
204  // RB : propagate from end of flat piece back, window centered, to check
205  // if the start is found back, if not, try next bin as start
206  if (fApplyBackwardFlatPieceCheck) {
207 
208  const int reverseStartValue =
209  accumulate(&trace[startBin], &trace[stopBin], 0) / (stopBin - startBin);
210  int reverseBin = stopBin - 1;
211  while (reverseBin > startBin) {
212  if (abs(reverseStartValue - trace[reverseBin]) > sigma)
213  break;
214  --reverseBin;
215  }
216 
217  if (reverseBin == startBin) {
218  flatPieces.push_back(PMTRecData::Piece(startBin, stopBin));
219  startBin = stopBin;
220  } else {
221  ++startBin;
222  stopBin = startBin;
223  }
224 
225  } else {
226  flatPieces.push_back(PMTRecData::Piece(startBin, stopBin));
227  startBin = stopBin;
228  }
229 
230  }
231 
232  } while (stopBin < traceLength);
233 
234  // should have some pieces
235  if (!flatPieces.empty() &&
236  flatPieces[0].first > Const::UsefulBins(station.IsUUB()) &&
237  sigma < 5) {
238  // try again with larger sigma
239  flatPieces.clear();
240  sigma = 4;
241  ostringstream warn;
242  warn << "Station " << station.GetId() << ", PMT " << pmt.GetId() << ", "
243  << (gain == sdet::PMTConstants::eHighGain ? "high" : "low") << " gain: "
244  "No useful baseline found in the first "
245  << Const::UsefulBins(station.IsUUB()) << " bins.";
246  WARNING(warn);
247  }
248 
249  } while (flatPieces.empty() && sigma <= saturationValue);
250 
251  if (flatPieces.empty()) {
252  MakeFlatBaseline(pmt, gain);
253  if (seenSaturation)
254  pmtRec.SetFADCSaturatedBins(-1, gain);
255  ostringstream warn;
256  warn << "Station " << station.GetId() << ", PMT " << pmt.GetId() << ", "
257  << (gain == sdet::PMTConstants::eHighGain ? "high" : "low") << " gain"
258  << (seenSaturation ? " (saturated):" : ":")
259  << "No baseline found; using LS value.";
260  WARNING(warn);
261  return false;
262  }
263 
264  // compute baselines
265  vector<double> flatPieceMean;
266  flatPieceMean.reserve(flatPieces.size());
267  double meanErrorMaxPiece = 0;
268  int maxPieceLength = 0;
269  for (const auto& fp : flatPieces) {
270  const auto sigma =
271  for_each(&trace[fp.first], &trace[fp.second], Accumulator::SampleStandardDeviation());
272  flatPieceMean.push_back(sigma.GetAverage());
273  if (sigma.GetN() > maxPieceLength) {
274  maxPieceLength = sigma.GetN();
275  meanErrorMaxPiece = sigma.GetStandardDeviation();
276  }
277  }
278 
279  if (hitsZero)
280  flatPieceMean.back() = 0;
281 
282  pmtRec.SetFADCBaselineError(meanErrorMaxPiece, gain);
283 
284  if (sigma > 3 && !seenSaturation) {
285  ostringstream warn;
286  warn << "Station " << station.GetId() << ", PMT " << pmt.GetId() << ", "
287  << (gain == sdet::PMTConstants::eHighGain ? "high" : "low") << " gain: "
288  "Noisy baseline, sigma = " << sigma << ", RMS = " << meanErrorMaxPiece;
289  WARNING(warn);
290  }
291 
292  pmtRec.SetFADCBaselineWindow(sigma, gain);
293 
294  if (!pmtRec.HasFADCBaseline(gain))
295  pmtRec.MakeFADCBaseline(gain);
296  auto& baseline = pmtRec.GetFADCBaseline(gain);
297 
298  // this comes from the Torino PMT baseline study
299  // done by Simone Maldera and Gianni Navarra, GAP-2005-006 and GAP-2005-025
300  const double recoveryFactor = 0.000158;
301 
302  double previousBaseline = flatPieceMean[0];
303 
304  // beginning of online baseline, before first piece
305  {
306  double charge = 0;
307  for (int i = flatPieces[0].first - 1; i >= 0; --i) {
308  const double signal = trace[i] - previousBaseline;
309  if (signal > 0)
310  charge += signal;
311  baseline[i] = previousBaseline + charge * recoveryFactor;
312  }
313  }
314 
315  // first piece
316  for (unsigned int i = flatPieces[0].first; i < flatPieces[0].second; ++i)
317  baseline[i] = previousBaseline;
318 
319  // hole-centric: previous piece | hole | next piece
320  const unsigned int nPieces = flatPieces.size();
321  for (unsigned int p = 1; p < nPieces; ++p) {
322  const double nextBaseline = flatPieceMean[p];
323  const int start = flatPieces[p-1].second;
324  const int stop = flatPieces[p].first;
325  const int holeLength = stop - start;
326  const double deltaBaselinePerBin = (nextBaseline - previousBaseline) / holeLength;
327  // charge in the hole
328  double charge = 0;
329  for (int i = start ; i < stop; ++i) {
330  const double base = previousBaseline + (i - start) * deltaBaselinePerBin;
331  const double signal = trace[i] - base;
332  if (signal > 0)
333  charge += signal;
334  }
335  const double totalCharge = charge;
336  if (totalCharge / holeLength < 2) {
337  // linear interpolation over bins
338  for (int i = start ; i < stop; ++i)
339  baseline[i] = previousBaseline + (i - start) * deltaBaselinePerBin;
340  } else {
341  const double deltaBaselinePerCharge = (nextBaseline - previousBaseline) / totalCharge;
342  // interpolate in the hole according to the charge increase
343  charge = 0;
344  for (int i = start ; i < stop; ++i) {
345  const double base = previousBaseline + (i - start) * deltaBaselinePerBin;
346  const double signal = trace[i] - base;
347  if (signal > 0)
348  charge += trace[i] - base;
349  baseline[i] = previousBaseline + charge * deltaBaselinePerCharge;
350  }
351  }
352  // fill next piece
353  for (unsigned int i = stop; i < flatPieces[p].second; ++i)
354  baseline[i] = nextBaseline;
355  previousBaseline = nextBaseline;
356  }
357 
358  // fill end (if not there already)
359  {
360  double charge = 0;
361  for (int i = flatPieces[nPieces-1].second; i < traceLength; ++i) {
362  const double signal = trace[i] - previousBaseline;
363  if (signal > 0)
364  charge += signal;
365  baseline[i] = previousBaseline - charge * recoveryFactor;
366  }
367  }
368 
369  if (seenSaturation)
370  pmtRec.SetFADCSaturatedBins(-1, gain);
371 
372  // DV: fix for cyclon boards that send register data in the last 8 bins
373  // of FADC traces: solution is to set baseline equal to FADC values in
374  // these last bins so that the signal there becomes zero.
375  if (station.IsCyclone() &&
376  traceLength == int(dStation.GetFADCTraceLength())) {
377  const int registersStart = int(dStation.GetFADCTraceLength()) - 8;
378  for (int i = registersStart; i < int(dStation.GetFADCTraceLength()); ++i)
379  baseline[i] = trace[i];
380  }
381 
382  return true;
383  }
384 
385 }
int GetId() const
Get the station Id.
bool HasRecData() const
Check for existenc of PMT reconstructed data object.
Definition: SEvent/PMT.h:53
class to hold data at PMT level
Definition: SEvent/PMT.h:28
bool IsTubeOk() const
Definition: PMTCalibData.h:29
PMTCalibData & GetCalibData()
Get object containing PMT calibration data.
Definition: SEvent/PMT.h:56
PMTRecData & GetRecData()
Get object containing PMT reconstructed data.
Definition: SEvent/PMT.h:48
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void Init()
Initialise the registry.
int gain
Definition: dump1090.h:241
void MakeFADCBaseline(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain)
Definition: PMTRecData.h:72
unsigned int GetId() const
Return Id of the PMT.
Definition: SEvent/PMT.h:32
void MakeRecData()
Make PMT reconstructed data object.
Definition: SEvent/PMT.cc:33
bool IsCyclone() const
FlatPieceCollection & GetBaselineFlatPieces(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain)
Definition: PMTRecData.h:91
class to hold data at Station level
bool HasFADCTrace(const StationConstants::SignalComponent source=StationConstants::eTotal) const
Check if a FADC trace exists. Trace source may be specified.
Definition: SEvent/PMT.h:83
constexpr int MinLength(const bool isUUB)
double abs(const SVector< n, T > &v)
constexpr unsigned int UsefulBins(const bool isUUB)
const double second
Definition: GalacticUnits.h:32
SizeType GetSize() const
Definition: Trace.h:156
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
bool IsUUB() const
utl::TraceI & GetFADCTrace(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain, const StationConstants::SignalComponent source=StationConstants::eTotal)
Definition: SEvent/PMT.h:72
bool IsLowGainOk() const
Definition: PMTCalibData.h:31
double GetBaseline(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain) const
Definition: PMTCalibData.h:41
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
std::pair< unsigned int, unsigned int > Piece
pieces of relative FADC flatnes in format [first, second)
Definition: PMTRecData.h:88
bool HasSEvent() const
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)

, generated on Tue Sep 26 2023.