3#include "BmnADCDigit.h"
4#include "BmnSyncDigit.h"
5#include "BmnTDCDigit.h"
6#include "BmnTQDCADCDigit.h"
13#include <boost/algorithm/string/classification.hpp>
14#include <boost/algorithm/string/split.hpp>
15#include <boost/lexical_cast.hpp>
16#include <boost/tokenizer.hpp>
17#include <nlohmann/json.hpp>
21 LOG(info) << Form(
"%s",
GetName().Data());
26 , fSaturation(
std::numeric_limits<int16_t>::
max())
27 , fDoRLdeconvolve(false)
38 const std::string& mappingFile,
39 const std::string& calibrationFile)
41 , fSaturation(
std::numeric_limits<int16_t>::
max())
42 , fDoRLdeconvolve(false)
50 LOG(info) << Form(
"%s : Config file: %s",
GetName().Data(), mappingFile.c_str());
51 LOG(info) << Form(
"%s : Calibration file: %s",
GetName().Data(), calibrationFile.c_str());
58 std::string fullPath = std::string(getenv(
"VMCWORKDIR")) +
"/input/" + file;
59 std::ifstream config_file(fullPath);
60 if (!config_file.is_open()) {
61 LOG(error) <<
GetName() <<
"::ParseConfig: Cannot open config file: " << fullPath;
68 }
catch (
const std::exception& e) {
69 LOG(error) <<
GetName() <<
"::ParseConfig: Failed to parse JSON: " << e.what();
73 LOG(debug) <<
GetName() <<
"::ParseConfig. Version: " << j.
value(
"version",
"unknown");
74 LOG(debug) <<
GetName() <<
"::ParseConfig. Comment: " << j.
value(
"comment",
"none");
76 fuoChannelMap.clear();
77 for (
const auto& entry : j[
"mapping"]) {
78 std::string serial = entry[
"serial"];
79 int channel = entry[
"channel"];
80 int strip = entry[
"strip"];
81 int side = entry[
"side"];
82 int gain = entry[
"gain"];
84 auto key = std::make_pair(std::stoul(serial,
nullptr, 16), channel);
91 std::string fullPath = std::string(getenv(
"VMCWORKDIR")) +
"/parameters/hodo/" + file;
92 std::ifstream config_file(fullPath);
93 if (!config_file.is_open()) {
94 LOG(error) <<
GetName() <<
"::ParseCalibration: Cannot open config file: " << fullPath;
101 }
catch (
const std::exception& e) {
102 LOG(error) <<
GetName() <<
"::ParseCalibration: Failed to parse JSON: " << e.what();
106 LOG(debug) <<
GetName() <<
"::ParseCalibration. Version: " << j.
value(
"version",
"unknown");
107 LOG(debug) <<
GetName() <<
"::ParseCalibration. Comment: " << j.
value(
"comment",
"none");
109 const auto& par = j.
at(
"parameters");
115 fSaturation = par.at(
"saturation");
117 bool applyINL = par.value(
"applyINLcorr",
true);
122 for (
const auto& ch : j.
at(
"calibration")) {
123 int strip = ch.at(
"strip");
124 int side = ch.at(
"side");
125 int gain = ch.at(
"gain");
126 float calib = ch.at(
"calib");
127 float integ = ch.at(
"calibIntegral");
132 if (j.
contains(
"deconvParameters")) {
133 const auto& decpar = j.
at(
"deconvParameters");
135 fDoRLdeconvolve = decpar.value(
"isdec",
false);
136 fRLthresold = decpar.value(
"threshold", 0);
137 fR2converge = decpar.value(
"R2converge", 0.f);
138 fMaxIters = decpar.value(
"iterations", 0);
139 fMaxPeaks = decpar.value(
"peaks", 0);
140 if (decpar.contains(
"ethalon") && decpar[
"ethalon"].is_array()) {
141 auto tmp = decpar[
"ethalon"].get<std::vector<float>>();
142 fEthalon.insert(fEthalon.end(), tmp.begin(), tmp.end());
147 const auto& fitpar = j.
at(
"fitParameters");
150 for (
const auto& pair : fitpar.at(
"harmonics")) {
151 float re = pair.at(0).get<
float>();
152 float im = pair.at(1).get<
float>();
159 auto maxElement = std::max_element(
161 [](
const std::complex<float>& a,
const std::complex<float>& b) { return std::abs(a) < std::abs(b); });
164 int maxElementLength = floor(5. / (-
log(real(*maxElement))));
169 fAZik =
new std::complex<float>*[model_order];
170 for (
int i = 0;
i < model_order;
i++) {
171 fAZik[
i] =
new std::complex<float>[model_order];
172 for (
int k = 0; k < model_order; k++)
186 std::string path = std::string(getenv(
"VMCWORKDIR")) +
"/parameters/hodo/INLcorrections/";
187 LOG(info) << Form(
"%s : Loading INL corrections from directory: %s",
GetName().Data(), path.c_str());
189 boost::property_tree::ptree pt;
190 std::string header =
"TQDC16VS";
191 std::string iniheader = header +
"_E";
192 std::string postfix =
"inl_corr";
195 for (
auto& it : fuoChannelMap) {
196 auto boardSerial = (
unsigned int)it.first.first;
197 std::string corrFileName = Form(
"%s%s-%04X-%04X.ini", path.c_str(), header.c_str(),
198 ((boardSerial & 0xffff0000) >> 16), (boardSerial & 0xffff));
199 boost::property_tree::ini_parser::read_ini(corrFileName.c_str(), pt);
200 std::string thisHeader = Form(
"%s-%08x-%s", iniheader.c_str(), boardSerial, postfix.c_str());
202 auto correction_string = pt.get<std::string>(Form(
"%s.%d", thisHeader.c_str(), chan_iter));
203 istringstream ss(correction_string);
206 std::vector<float> corrV;
207 while (std::getline(ss, token,
','))
208 corrV.push_back(stof(token));
209 assert(corrV.size() == 1024);
211 auto key = std::make_pair(boardSerial, chan_iter);
212 fINLcorrMap[key] = corrV;
220 return fuoChannelMap.at(key);
221 }
catch (
const std::out_of_range& e) {
222 LOG(debug) <<
GetName() <<
":: GetAddressFromBoard. Board serial " << std::hex << key.first << std::dec
223 <<
" channel " << key.second <<
" is not connected. Skipping it";
231 return time + fINLcorrMap.at(key).at(time & 1023);
232 }
catch (
const std::out_of_range& e) {
233 LOG(warning) <<
GetName() <<
"::correctINL. Board serial " << std::hex << key.first << std::dec <<
" channel "
234 << key.second <<
" is not connected. Leave without INL correction";
242 return fuoCalibMap.at(address);
243 }
catch (
const std::out_of_range& e) {
244 LOG(debug) <<
GetName() <<
":: GetCalibPairFromAddress " << std::bitset<32>(address)
245 <<
" is marked badly in calibration file.";
253 LOG(debug) <<
GetName() <<
"::fillEvent";
257 for (
int iAdc = 0; iAdc < adc->GetEntriesFast(); iAdc++) {
263 if (!catch_address.has_value())
265 auto address = catch_address.value();
268 if (!catch_calib.has_value())
270 auto calib_pair = catch_calib.value();
273 for (
int iTdc = 0; iTdc < tdc->GetEntriesFast(); iTdc++) {
284 std::vector<BmnHodoDigi> digi_vector;
292 ThisDigi.
fIntegral = (int)std::accumulate(wfm.begin(), wfm.end(), 0.0);
297 if (ThisDigi.
fAmpl + ThisDigi.
fZL >= fSaturation)
300 digi_vector.push_back(ThisDigi);
305 LOG(debug4) <<
GetName() <<
"::ProcessWfm RLDeconvolutor";
306 RLDeconvolutor deconvolution(wfm, fEthalon, fR2converge, fMaxIters);
310 assert(decomposition.size() == positions.size());
311 auto fitR2 = deconvolution.
getR2().back();
314 std::vector<size_t> indices(positions.size());
315 std::iota(indices.begin(), indices.end(), 0);
318 std::sort(indices.begin(), indices.end(),
319 [&positions](
size_t a,
size_t b) { return positions[a].second > positions[b].second; });
320 std::vector<size_t> topIndices = (fMaxPeaks <= indices.size())
321 ? std::vector<size_t>(indices.begin(), indices.begin() + fMaxPeaks)
325 LOG(debug4) <<
GetName() <<
"::ProcessWfm Selection";
326 for (
auto it : topIndices) {
327 auto time_max = positions.at(it).first;
328 auto ampl = positions.at(it).second;
329 auto sub_wfm = decomposition.at(it);
352 digi_vector.push_back(SubDigi);
356 TClonesArray& ar_Hodo = *Hododigit;
357 for (
auto& digi : digi_vector) {
358 digi.fNpeaks = digi_vector.size();
359 new (ar_Hodo[Hododigit->GetEntriesFast()])
BmnHodoDigi(digi);
364 fworkTime_cpu += timer.RealTime();
365 fworkTime_real += timer.CpuTime();
370 LOG(info) << Form(
"%10s: Real time %4.3f s, CPU time %4.3f s",
GetName().Data(), fworkTime_real, fworkTime_cpu);
friend F32vec4 log(const F32vec4 &a)
friend F32vec4 max(const F32vec4 &a, const F32vec4 &b)
UInt_t GetNSamples() const
UShort_t GetChannel() const
Short_t * GetShortValue() const
void SetAddress(uint32_t address)
void SetTime(double time)
void SetSignal(double signal)
std::vector< float > fFitWfm
std::vector< float > fWfm
Time of maximum in fit of waveform [adc samples].
float fFitTimeMax
Quality of waveform fit [] – good near 0.
float fFitR2
Energy deposition from fit of waveform [adc counts].
int fZL
Amplitude from waveform [adc counts].
float fFitAmpl
Time over threshold [adc samples].
int fTimeMax
Energy deposition from waveform [adc counts].
int fIntegral
ZeroLevel from waveform [adc counts].
static uint32_t GetAddress(uint32_t StripId, uint32_t StripSide, uint32_t Gain)
Return address from system ID, StripId, StripSide, Gain.
Data class for BmnHodo digital signal processing.
void reset() override final
std::vector< float > fR2history
void SetIsSaturated(bool satur)
void ParseConfig(const std::string &file)
void ParseCalibration(const std::string &file)
uint32_t correctINL(uint32_t time, std::pair< size_t, size_t > key)
std::optional< std::pair< float, float > > GetCalibPairFromAddress(uint32_t address)
void ParseINLcorrections()
void fillEvent(TClonesArray *tdc_data, TClonesArray *adc_data, TClonesArray *Hododigit)
std::optional< uint32_t > GetAddressFromBoard(std::pair< size_t, size_t > key)
UChar_t GetChannel() const
void SetExternalHarmonics(std::vector< std::complex< float > > harmonics)
void Initialize(int model_order, int exponent_number, int gate_beg, int gate_end)
void MakeInvHarmoMatrix(int signal_length, std::complex< float > **output)
Class to apply Richardson-Lucy deconvolution.
const std::vector< float > & getR2() const
const std::vector< std::pair< size_t, float > > & getSignalInfo() const
const std::vector< std::vector< float > > & getSignalDecomposition() const
std::complex< float > ** fAZik
struct WfmProcessor::digiPars fdigiPars
void ProcessWfm(std::vector< float > &wfm, BmnDigiContainerTemplate *digi)
a class to store JSON values
bool contains(KeyT &&key) const
check the existence of an element in a JSON object
ValueType value(const typename object_t::key_type &key, const ValueType &default_value) const
access specified object element with default value
reference at(size_type idx)
access specified array element with bounds checking
#define TQDC16_CHANNEL_COUNT
#define ADC_CLOCK_TQDC16VS
std::vector< std::complex< float > > harmonics