13 #include <ecl/modules/eclDigitizer/ECLDigitizerModule.h>
21 #include <framework/logging/Logger.h>
22 #include <framework/utilities/FileSystem.h>
23 #include <framework/gearbox/Unit.h>
26 #include <ecl/digitization/algorithms.h>
27 #include <ecl/digitization/shaperdsp.h>
28 #include <ecl/digitization/ECLCompress.h>
29 #include <ecl/geometry/ECLGeometryPar.h>
30 #include <ecl/dbobjects/ECLCrystalCalib.h>
31 #include <ecl/dbobjects/ECLWaveformData.h>
32 #include <ecl/dataobjects/ECLHit.h>
33 #include <ecl/dataobjects/ECLSimHit.h>
34 #include <ecl/dataobjects/ECLDigit.h>
35 #include <ecl/dataobjects/ECLDsp.h>
36 #include <ecl/dataobjects/ECLDspWithExtraMCInfo.h>
37 #include <ecl/dataobjects/ECLTrig.h>
38 #include <ecl/dataobjects/ECLWaveforms.h>
39 #include <ecl/utility/ECLDspUtilities.h>
57 setDescription(
"Creates ECLDigiHits from ECLHits.");
58 setPropertyFlags(c_ParallelProcessingCertified);
59 addParam(
"Background", m_background,
"Flag to use the Digitizer configuration with backgrounds (default: false)",
false);
60 addParam(
"Calibration", m_calibration,
"Flag to use the Digitizer for Waveform fit Covariance Matrix calibration (default: false)",
62 addParam(
"DiodeDeposition", m_inter,
63 "Flag to take into account energy deposition in photodiodes; Default diode is sensitive detector (default: true)",
true);
64 addParam(
"WaveformMaker", m_waveformMaker,
"Flag to produce background waveform digits (default: false)",
false);
65 addParam(
"CompressionAlgorithm", m_compAlgo,
"Waveform compression algorithm (default: 0u)", 0u);
66 addParam(
"eclWaveformsName", m_eclWaveformsName,
"Name of the output/input collection (digitized waveforms)",
string(
""));
67 addParam(
"HadronPulseShapes", m_HadronPulseShape,
"Flag to include hadron component in pulse shape construction (default: true)",
69 addParam(
"ADCThreshold", m_ADCThreshold,
"ADC threshold for waveform fits (default: 25)", 25);
70 addParam(
"WaveformThresholdOverride", m_WaveformThresholdOverride,
71 "If gt 0 value is applied to all crystals for waveform saving threshold. If lt 0 dbobject is used. (GeV)", -1.0);
72 addParam(
"StoreDspWithExtraMCInfo", m_storeDspWithExtraMCInfo,
73 "Flag to store Dsp with extra MC information in addition to normal Dsp (default: false)",
false);
74 addParam(
"DspWithExtraMCInfoThreshold", m_DspWithExtraMCInfoThreshold,
75 "Threshold above with to store Dsp with extra MC information [GeV]",
77 addParam(
"DspDataTest", m_dspDataTest,
78 "Use DSP coefficients from the database for the processing. This "
79 "will significantly reduce performance so this option is to be "
80 "used for testing only.",
false);
84 ECLDigitizerModule::~ECLDigitizerModule()
88 void ECLDigitizerModule::initialize()
90 m_eclDsps.registerInDataStore();
91 if (m_storeDspWithExtraMCInfo) m_eclDspsWithExtraMCInfo.registerInDataStore();
92 m_eclDigits.registerInDataStore();
93 m_eclTrigs.registerInDataStore();
95 if (m_HadronPulseShape) {
97 "Hadron pulse shapes for ECL simulations are enabled. Pulse shape simulations use techniques validated with test beam data documented in: S. Longo and J. M. Roney 2018 JINST 13 P03018");
99 B2DEBUG(20,
"Hadron pulse shapes for ECL simulations are disabled.");
103 B2DEBUG(20,
"Diode-crossing pulse shapes for ECL simulations are enabled.");
105 B2DEBUG(20,
"Diode-crossing pulse shapes for ECL simulations are disabled.");
108 m_eclDiodeHits.registerInDataStore(
"ECLDiodeHits");
110 m_eclDsps.registerRelationTo(m_eclDigits);
111 if (m_storeDspWithExtraMCInfo)
112 m_eclDspsWithExtraMCInfo.registerRelationTo(m_eclDigits);
113 m_eclDigits.registerRelationTo(m_eclHits);
115 m_eclWaveforms.registerInDataStore(m_eclWaveformsName);
119 m_adc.resize(EclConfiguration::m_nch);
121 EclConfiguration::get().setBackground(m_background);
124 void ECLDigitizerModule::beginRun()
128 Ael(
"ECLCrystalElectronics"),
129 Aen(
"ECLCrystalEnergy"),
130 Tel(
"ECLCrystalElectronicsTime"),
131 Ten(
"ECLCrystalTimeOffset"),
132 Tct(
"ECLCrateTimeOffset"),
133 Tmc(
"ECLMCTimeOffset"),
134 Awave(
"ECL_FPGA_StoreWaveform");
135 double ns_per_tick = 1.0 / (4.0 * ec.
m_rf) * 1e3;
138 m_calib.assign(8736, def);
140 if (Ael)
for (
int i = 0; i < 8736; i++) m_calib[i].ascale /= Ael->getCalibVector()[i];
141 if (Aen)
for (
int i = 0; i < 8736; i++) m_calib[i].ascale /= Aen->getCalibVector()[i] * 20000.0;
143 if (Tel)
for (
int i = 0; i < 8736; i++) m_calib[i].tshift += Tel->getCalibVector()[i] * ns_per_tick;
144 if (Ten)
for (
int i = 0; i < 8736; i++) m_calib[i].tshift += Ten->getCalibVector()[i] * ns_per_tick;
145 if (Tct)
for (
int i = 0; i < 8736; i++) m_calib[i].tshift += Tct->getCalibVector()[i] * ns_per_tick;
146 if (Tmc)
for (
int i = 0; i < 8736; i++) m_calib[i].tshift += Tmc->getCalibVector()[i] * ns_per_tick;
148 m_Awave.assign(8736, -1);
149 if (m_WaveformThresholdOverride < 0) {
150 if (Awave)
for (
int i = 0; i < 8736; i++) m_Awave[i] = Awave->getCalibVector()[i];
153 for (
int i = 0; i < 8736; i++) m_Awave[i] = m_WaveformThresholdOverride * m_calib[i].ascale;
156 if (m_HadronPulseShape) callbackHadronSignalShapes();
161 void ECLDigitizerModule::shapeFitterWrapper(
const int j,
const int* FitA,
const int ttrig,
162 int& m_lar,
int& m_ltr,
int& m_lq,
int& m_chi)
const
169 if (!m_dspDataTest) {
170 short int*
id = (
short int*)m_idn[t.idn].id;
172 int A0 = (
int) * (
id + 0) - 128;
173 int Askip = (int) * (
id + 1) - 128;
175 int Ahard = (int) * (
id + 2);
176 int k_a = (int) * ((
unsigned char*)
id + 26);
177 int k_b = (int) * ((
unsigned char*)
id + 27);
178 int k_c = (int) * ((
unsigned char*)
id + 28);
179 int k_16 = (int) * ((
unsigned char*)
id + 29);
180 int k1_chi = (int) * ((
unsigned char*)
id + 24);
181 int k2_chi = (int) * ((
unsigned char*)
id + 25);
183 int chi_thres = (int) * (
id + 15);
185 int trg_time = ttrig;
187 result = lftda_((
int*)r.f, (
int*)r.f1, (
int*)r.fg41, (
int*)r.fg43,
188 (
int*)r.fg31, (
int*)r.fg32, (
int*)r.fg33, (
int*)FitA,
189 trg_time, A0, Ahard, Askip, k_a, k_b, k_c, k_16, k1_chi,
192 std::vector<int> adc(31);
193 for (
int i = 0; i < 31; i++) adc[i] = FitA[i];
198 int ttrig_packed = ttrig / 6 * 8 + ttrig % 6;
199 result = ECLDspUtilities::shapeFitter(j + 1, adc, ttrig_packed);
204 m_lq = result.quality;
208 int discarded_bits = 0;
209 if ((m_chi & 0x7800000) != 0) {
211 }
else if ((m_chi & 0x0600000) != 0) {
213 }
else if ((m_chi & 0x0180000) != 0) {
215 }
else if ((m_chi & 0x0060000) != 0) {
217 }
else if ((m_chi & 0x0018000) != 0) {
219 }
else if ((m_chi & 0x0006000) != 0) {
221 }
else if ((m_chi & 0x0001800) != 0) {
223 }
else if ((m_chi & 0x0000600) != 0) {
226 if (discarded_bits > 0) {
227 m_chi >>= discarded_bits;
228 m_chi <<= discarded_bits;
232 int ECLDigitizerModule::shapeSignals()
238 const int DeltaT = gRandom->Uniform(0,
double(ec.
m_ntrg) / 2.);
239 const double timeInt = 2.* (double) DeltaT * trgtick;
240 const int ttrig = 2 * DeltaT;
241 const double timeOffset = timeInt - ec.
s_clock / (2 * ec.
m_rf);
243 const auto eclTrig = m_eclTrigs.appendNew();
244 eclTrig->setTimeTrig(timeInt);
247 memset(m_adc.data(), 0, m_adc.size()*
sizeof(
adccounts_t));
249 const double E2GeV = 1 / Unit::GeV;
250 const double T2us = 1 / Unit::us;
253 for (
const auto& hit : m_eclSimHits) {
254 int j = hit.getCellId() - 1;
255 double hitE = hit.getEnergyDep() * m_calib[j].ascale * E2GeV;
256 double hitTimeAve = (hit.getFlightTime() + m_calib[j].tshift + eclp->time2sensor(j, hit.getPosition())) * T2us;
258 m_adc[j].energyConversion = m_calib[j].ascale * E2GeV * 20000;
259 m_adc[j].flighttime += hit.getFlightTime() * hit.getEnergyDep();
260 m_adc[j].timeshift += m_calib[j].tshift * hit.getEnergyDep();
261 m_adc[j].timetosensor += eclp->time2sensor(j, hit.getPosition()) * hit.getEnergyDep();
262 m_adc[j].totalHadronDep += hit.getHadronEnergyDep();
263 m_adc[j].totalDep += hit.getEnergyDep();
265 if (m_HadronPulseShape ==
true) {
266 double hitHadronE = hit.getHadronEnergyDep() * m_calib[j].ascale * E2GeV;
267 m_adc[j].AddHit(hitE - hitHadronE, hitTimeAve + timeOffset, m_ss_HadronShapeSimulations[0]);
268 m_adc[j].AddHit(hitHadronE, hitTimeAve + timeOffset, m_ss_HadronShapeSimulations[1]);
270 m_adc[j].AddHit(hitE, hitTimeAve + timeOffset, m_ss[m_tbl[j].iss]);
275 for (
const auto& hit : m_eclHits) {
276 if (hit.getBackgroundTag() == BackgroundMetaData::bg_none)
continue;
277 int j = hit.getCellId() - 1;
278 double hitE = hit.getEnergyDep() * m_calib[j].ascale * E2GeV;
279 double hitTimeAve = (hit.getTimeAve() + m_calib[j].tshift) * T2us;
280 m_adc[j].AddHit(hitE, hitTimeAve + timeOffset, m_ss[m_tbl[j].iss]);
288 const double diodeEdep2crystalEdep = E2GeV * (1 / (5000 * 3.6e-6));
289 for (
const auto& hit : m_eclDiodeHits) {
290 int j = hit.getCellId() - 1;
291 double hitE = hit.getEnergyDep() * m_calib[j].ascale * diodeEdep2crystalEdep;
292 double hitTimeAve = (hit.getTimeAve() + m_calib[j].tshift) * T2us;
297 if (m_HadronPulseShape) {
298 a.AddHit(hitE, hitTimeAve + timeOffset, m_ss_HadronShapeSimulations[2]);
300 a.AddHit(hitE, hitTimeAve + timeOffset, m_ss[1]);
309 double hitE = 0.1, hitTimeAve = 0.0;
310 for (
int j = 0; j < ec.
m_nch; j++)
311 m_adc[j].AddHit(hitE, hitTimeAve + timeOffset, m_ss[m_tbl[j].iss]);
317 void ECLDigitizerModule::makeElectronicNoiseAndPedestal(
int J,
int* FitA)
322 for (
int i = 0; i < ec.
m_nsmp; i++) z[i] = gRandom->Gaus(0, 1);
323 m_noise[m_tbl[J].inoise].generateCorrelatedNoise(z, AdcNoise);
324 for (
int i = 0; i < ec.
m_nsmp; i++) FitA[i] = 20 * AdcNoise[i] + 3000;
327 void ECLDigitizerModule::makeWaveforms()
331 out.putNBits(m_compAlgo & 0xff, 8);
334 B2FATAL(
"Unknown compression algorithm: " << m_compAlgo);
338 for (
int j = 0; j < ec.
m_nch; j++) {
340 makeElectronicNoiseAndPedestal(j, FitA);
341 for (
int i = 0; i < ec.
m_nsmp; i++) {
342 int A = 20000 * a.c[i] + FitA[i];
343 FitA[i] = max(0, min(A, (1 << 18) - 1));
350 m_eclWaveforms.assign(wf);
352 std::swap(out.getStore(), wf->
getStore());
353 if (comp)
delete comp;
356 void ECLDigitizerModule::event()
359 const int ttrig = shapeSignals();
363 if (m_waveformMaker) { makeWaveforms();
return; }
366 struct ch_t {
int cell, id;};
368 for (
const auto& hit : m_eclHits) {
369 int j = hit.getCellId() - 1;
370 if (hit.getBackgroundTag() == BackgroundMetaData::bg_none) hitmap.push_back({j, hit.getArrayIndex()});
374 bool isBGOverlay = m_eclWaveforms.isValid();
380 std::swap(out.getStore(), m_eclWaveforms->getStore());
382 unsigned int compAlgo = out.getNBits(8);
383 comp = selectAlgo(compAlgo);
385 B2FATAL(
"Unknown compression algorithm: " << compAlgo);
391 for (
int j = 0; j < ec.
m_nch; j++) {
395 if (m_adc[j].totalDep > 0) {
396 m_adc[j].flighttime /= m_adc[j].totalDep;
397 m_adc[j].timeshift /= m_adc[j].totalDep;
398 m_adc[j].timetosensor /= m_adc[j].totalDep;
407 if (a.total < 0.0001)
continue;
408 makeElectronicNoiseAndPedestal(j, FitA);
411 for (
int i = 0; i < ec.
m_nsmp; i++) {
412 int A = 20000 * a.c[i] + FitA[i];
413 FitA[i] = max(0, min(A, (1 << 18) - 1));
421 shapeFitterWrapper(j, FitA, ttrig, energyFit, tFit, qualityFit, chi);
423 if (energyFit > m_ADCThreshold) {
427 if (energyFit > m_Awave[CellId - 1]) {
429 const auto eclDsp = m_eclDsps.appendNew();
430 eclDsp->setCellId(CellId);
431 eclDsp->setDspA(FitA);
435 if (m_storeDspWithExtraMCInfo and a.totalDep >= m_DspWithExtraMCInfoThreshold) {
436 const auto eclDspWithExtraMCInfo = m_eclDspsWithExtraMCInfo.appendNew();
437 eclDspWithExtraMCInfo->setCellId(CellId);
438 eclDspWithExtraMCInfo->setDspA(FitA);
439 eclDspWithExtraMCInfo->setEnergyDep(a.totalDep);
440 eclDspWithExtraMCInfo->setHadronEnergyDep(a.totalHadronDep);
441 eclDspWithExtraMCInfo->setFlightTime(a.flighttime);
442 eclDspWithExtraMCInfo->setTimeShift(a.timeshift);
443 eclDspWithExtraMCInfo->setTimeToSensor(a.timetosensor);
444 eclDspWithExtraMCInfo->setEnergyConversion(a.energyConversion * 20000);
447 const auto eclDigit = m_eclDigits.appendNew();
448 eclDigit->setCellId(CellId);
449 eclDigit->setAmp(energyFit);
450 eclDigit->setTimeFit(tFit);
451 eclDigit->setQuality(qualityFit);
453 eclDigit->setChi(chi);
454 else eclDigit->setChi(0);
455 for (
const auto& hit : hitmap)
456 if (hit.cell == j) eclDigit->addRelationTo(m_eclHits[hit.id]);
459 for (
auto& DspWithExtraMCInfo : m_eclDspsWithExtraMCInfo) {
460 if (eclDigit->getCellId() == DspWithExtraMCInfo.getCellId()) DspWithExtraMCInfo.addRelationTo(eclDigit);
464 if (comp)
delete comp;
467 void ECLDigitizerModule::endRun()
471 void ECLDigitizerModule::terminate()
475 void ECLDigitizerModule::callbackHadronSignalShapes()
478 if (m_waveformParametersMC.hasChanged()) {
480 m_ss_HadronShapeSimulations.resize(3);
483 float photonParsPSD[10];
484 float hadronParsPSD[10];
485 float diodeParsPSD[10];
486 for (
int i = 0; i < 10; i++) {
487 photonParsPSD[i] = m_waveformParametersMC->getPhotonParameters()[i + 1];
488 hadronParsPSD[i] = m_waveformParametersMC->getHadronParameters()[i + 1];
489 diodeParsPSD[i] = m_waveformParametersMC->getDiodeParameters()[i + 1];
493 m_ss_HadronShapeSimulations[0].InitSample(photonParsPSD, m_waveformParametersMC->getPhotonParameters()[0]);
494 m_ss_HadronShapeSimulations[1].InitSample(hadronParsPSD, m_waveformParametersMC->getHadronParameters()[0]);
495 m_ss_HadronShapeSimulations[2].InitSample(diodeParsPSD, m_waveformParametersMC->getDiodeParameters()[0]);
501 void ECLDigitizerModule::readDSPDB()
507 dataFileName = FileSystem::findFile(
"/data/ecl/ECL-WF-BG.root");
508 B2DEBUG(150,
"ECLDigitizer: Reading configuration data with background from: " << dataFileName);
510 dataFileName = FileSystem::findFile(
"/data/ecl/ECL-WF.root");
511 B2DEBUG(150,
"ECLDigitizer: Reading configuration data without background from: " << dataFileName);
513 assert(! dataFileName.empty());
515 TFile rootfile(dataFileName.c_str());
516 TTree* tree = (TTree*) rootfile.Get(
"EclWF");
517 TTree* tree2 = (TTree*) rootfile.Get(
"EclAlgo");
518 TTree* tree3 = (TTree*) rootfile.Get(
"EclNoise");
520 if (tree == 0 || tree2 == 0 || tree3 == 0) B2FATAL(
"Data not found");
522 m_tbl.resize(ec.
m_nch);
524 const int maxncellid = 512;
526 vector<int> cellId(maxncellid);
528 tree->SetBranchAddress(
"ncellId", &ncellId);
529 tree->SetBranchAddress(
"cellId", cellId.data());
531 vector<int> eclWaveformDataTable(ec.
m_nch);
532 for (Long64_t j = 0, jmax = tree->GetEntries(); j < jmax; j++) {
534 assert(ncellId <= maxncellid);
535 for (
int i = 0; i < ncellId; ++i)
536 eclWaveformDataTable[cellId[i] - 1] = j;
538 B2DEBUG(150,
"ECLDigitizer: " << tree->GetEntries() <<
" sets of wave form covariance matricies will be used.");
541 tree2->SetBranchAddress(
"Algopars", &algo);
542 tree2->SetBranchAddress(
"ncellId", &ncellId);
543 tree2->SetBranchAddress(
"cellId", cellId.data());
544 Long64_t jmax2 = tree2->GetEntries();
545 vector<ECLWFAlgoParams> eclWFAlgoParams;
546 eclWFAlgoParams.reserve(jmax2);
547 for (Long64_t j = 0; j < jmax2; j++) {
549 assert(ncellId <= maxncellid);
550 eclWFAlgoParams.push_back(*algo);
551 for (
int i = 0; i < ncellId; ++i)
552 m_tbl[cellId[i] - 1].idn = j;
554 if (algo)
delete algo;
555 B2DEBUG(150,
"ECLDigitizer: " << eclWFAlgoParams.size() <<
" parameter sets of fitting algorithm were read.");
558 tree3->SetBranchAddress(
"NoiseM", &noise);
559 tree3->SetBranchAddress(
"ncellId", &ncellId);
560 tree3->SetBranchAddress(
"cellId", cellId.data());
562 Long64_t jmax3 = tree3->GetEntries();
563 m_noise.reserve(jmax3);
564 for (Long64_t j = 0; j < jmax3; j++) {
566 assert(ncellId <= maxncellid);
567 m_noise.push_back(*noise);
569 for (
int i = 0; i < ec.
m_nch; i++)
573 for (
int i = 0; i < ncellId; ++i)
574 m_tbl[cellId[i] - 1].inoise = j;
577 if (noise)
delete noise;
578 B2DEBUG(150,
"ECLDigitizer: " << eclWFAlgoParams.size() <<
" noise matricies were loaded.");
581 m_idn.resize(eclWFAlgoParams.size());
582 for (
int i = 0, imax = eclWFAlgoParams.size(); i < imax; i++)
583 repack(eclWFAlgoParams[i], m_idn[i]);
585 vector<uint_pair_t> pairIdx;
586 for (
int i = 0; i < ec.
m_nch; i++) {
587 unsigned int wfIdx = eclWaveformDataTable[i];
588 unsigned int algoIdx = m_tbl[i].idn;
590 vector<uint_pair_t>::iterator ip = find(pairIdx.begin(), pairIdx.end(), p);
591 if (ip != pairIdx.end()) {
592 m_tbl[i].ifunc = ip - pairIdx.begin();
594 m_tbl[i].ifunc = pairIdx.size();
595 pairIdx.push_back(p);
600 m_fitparams.resize(pairIdx.size());
603 tree->SetBranchAddress(
"CovarianceM", &eclWFData);
604 tree->SetBranchStatus(
"ncellId", 0);
605 tree->SetBranchStatus(
"cellId", 0);
608 for (
unsigned int ip = 0; ip < pairIdx.size(); ip++) {
610 tree->GetEntry(p.first);
611 getfitparams(*eclWFData, eclWFAlgoParams[p.second], m_fitparams[ip]);
613 B2DEBUG(150,
"ECLDigitizer: " << m_fitparams.size() <<
" fitting crystals groups were created.");
619 m_ss[0].InitSample(MP, 27.7221);
625 for (
int i = 0; i < ec.
m_nch; i++) m_tbl[i].iss = 0;
629 double diode_params[] = {0 + 0.5, 0.100002, 0.756483, 0.456153, 0.0729031, 0.3906 / 9.98822, 2.85128, 0.842469, 0.854184, 0.110284};
630 m_ss[1].InitSample(diode_params, 0.9569100 * 9.98822);
632 B2DEBUG(150,
"ECLDigitizer: " << m_ss.size() <<
" sampled signal templates were created.");
634 if (eclWFData)
delete eclWFData;
642 t.id[ 0] = eclWFAlgo.getlAT() + 128;
643 t.id[ 1] = eclWFAlgo.getsT() + 128;
644 t.id[ 2] = eclWFAlgo.gethT();
656 t.ic[12 * 2 + 0] = eclWFAlgo.getk1();
657 t.ic[12 * 2 + 1] = eclWFAlgo.getk2();
658 t.ic[13 * 2 + 0] = eclWFAlgo.getka();
659 t.ic[13 * 2 + 1] = eclWFAlgo.getkb();
660 t.ic[14 * 2 + 0] = eclWFAlgo.getkc();
661 t.ic[14 * 2 + 1] = eclWFAlgo.gety0s() - 16;
664 t.id[15] = eclWFAlgo.getcT();
673 vector<double> MP(10);
679 int ia = 1 << eclWFAlgo.getka();
680 int ib = 1 << eclWFAlgo.getkb();
681 int ic = 1 << eclWFAlgo.getkc();
699 double g0g0 = 0, g0g1 = 0, g1g1 = 0, g0g2 = 0, g1g2 = 0, g2g2 = 0;
700 double sg0[16], sg1[16], sg2[16];
701 for (
int j = 0; j < 16; j++) {
702 double g0 = 0, g1 = 0, g2 = 0;
703 for (
int i = 0; i < 16; i++) {
704 g0 += ssd[j][i] * f[i].first;
705 g1 += ssd[j][i] * f[i].second;
708 g0g0 += g0 * f[j].first;
709 g0g1 += g1 * f[j].first;
710 g1g1 += g1 * f[j].second;
719 double a00 = g1g1 * g2g2 - g1g2 * g1g2;
720 double a11 = g0g0 * g2g2 - g0g2 * g0g2;
721 double a22 = g0g0 * g1g1 - g0g1 * g0g1;
722 double a01 = g1g2 * g0g2 - g0g1 * g2g2;
723 double a02 = g0g1 * g1g2 - g1g1 * g0g2;
724 double a12 = g0g1 * g0g2 - g0g0 * g1g2;
726 double igg2 = 1 / (a11 * g1g1 + g0g1 * a01 + g1g2 * a12);
729 const double isd = 3. / 4., sd = 1 / isd ;
730 for (
int i = 0; i < 16; i++) {
731 double w = i ? 1.0 : 1. / 16.;
733 ref_f [k][i] = lrint(f[i].first * iff * w);
734 ref_f1 [k][i] = lrint(f[i].second * iff * w * sd);
736 double fg31 = (a00 * sg0[i] + a01 * sg1[i] + a02 * sg2[i]) * igg2;
737 double fg32 = (a01 * sg0[i] + a11 * sg1[i] + a12 * sg2[i]) * igg2;
738 double fg33 = (a02 * sg0[i] + a12 * sg1[i] + a22 * sg2[i]) * igg2;
740 ref_fg31[k][i] = lrint(fg31 * ia * w);
741 ref_fg32[k][i] = lrint(fg32 * ib * w * isd);
742 ref_fg33[k][i] = lrint(fg33 * ic * w);
746 int jk = 23 + ((48 - k) >> 2);
747 if (jk >= 0 && jk < 24 && (48 - k) % 4 == 0) {
749 double igg1 = 1 / a11;
751 for (
int i = 0; i < 16; i++) {
752 double w = i ? 1.0 : 1. / 16.;
754 double fg41 = (g2g2 * sg0[i] - g0g2 * sg2[i]) * igg1;
755 double fg43 = (g0g0 * sg2[i] - g0g2 * sg0[i]) * igg1;
756 ref_fg41[jk][i] = lrint(fg41 * ia * w);
757 ref_fg43[jk][i] = lrint(fg43 * ic * w);