8 #include "TDecompSVD.h" 40 template<
class RootMatrix>
41 int responseVectorToMatrix(
const DoubleVector& vrcol,
Index ishiftin, RootMatrix& mres,
42 int logLevel,
string smsgpre =
"") {
43 string myname = smsgpre +
"reponseVectorToMatrix: ";
45 Index nvec = vrcol.size();
46 Index nrow = mres.GetNrows();
47 Index ncol = mres.GetNcols();
49 if ( logLevel > 0 ) cout << myname <<
"WARNING: Response vector is empty." <<
endl;
52 if ( ishiftin >= nvec ) {
53 if ( logLevel > 0 ) cout << myname <<
"WARNING: Shift " << ishiftin
54 <<
" is outside vector range (0, " << nvec <<
"]" <<
endl;
57 if ( logLevel >= 4 ) {
58 cout << myname <<
"Matrix is " << nrow <<
" x " << ncol <<
endl;
59 cout << myname <<
"Vector has length " << nvec <<
" and shift " << ishiftin <<
endl;
61 Index ishift = nvec - 1 - ishiftin;
63 for (
Index ircol=0, irrow=nvec-1; ircol<nvec; ++ircol, --irrow ) {
64 vrrow[irrow] = vrcol[ircol];
67 if ( nvec == 0 )
return 0;
68 for (
Index irow=0; irow<ncol; ++irow ) {
69 Index icol = irow > ishift ? irow - ishift : 0;
70 Index ivec = icol + ishift - irow;
71 Index nvecInsert = icol + nvec < nrow ? nvec - ivec : nrow - icol;
72 if ( logLevel >= 4 ) {
73 cout << smsgpre <<
"Column " << icol <<
": inserting " << nvecInsert
74 <<
" entries at row " << irow <<
endl;
76 mres.InsertRow(irow, icol, &vrrow[ivec], nvecInsert);
81 template<
class RootMatrix>
82 int responseVectorToMatrix(
const FloatVector& vresf,
Index ishift, RootMatrix& mres,
83 int logLevel,
string smsgpre =
"") {
85 return responseVectorToMatrix(vresd, ishift, mres, logLevel, smsgpre);
95 : m_LogLevel(ps.
get<
int>(
"LogLevel")),
104 m_IndexMapTool(ps.
get<
Name>(
"IndexMapTool")),
105 m_useResponse(false), m_useFilter(false),
106 m_doFFTConvolute(false), m_doDirectConvolute(false),
107 m_doDeconvolute(false), m_directDeconvolute(0) {
108 const Name myname =
"AdcDeconvoluteFFT:ctor: ";
117 amsg =
"Deconvolution.";
121 amsg =
"FFT response convolution.";
125 amsg =
"FFT filter convolution.";
129 amsg =
"Direct response convolution.";
133 amsg =
"Direct filter convolution.";
136 amsg =
"Direct matrix deconvolution.";
139 amsg =
"Filtered matrix deconvolution.";
142 amsg =
"Chi-square matrix deconvolution.";
145 amsg =
"Direct deconvolution.";
147 cout << myname <<
"ERROR: Invalid action flag: " <<
m_Action <<
endl;
156 cout << myname <<
"WARNING: Channel mapping tool not found: " <<
m_IndexMapTool <<
endl;
160 std::ios cout_state(
nullptr);
161 cout_state.copyfmt(std::cout);
162 cout << myname <<
"Parameters:" <<
endl;
164 cout << myname <<
" Action: " <<
m_Action <<
" (" << amsg <<
")" <<
endl;
165 cout << myname <<
" ResponseVectors: [";
169 if ( first ) first =
false;
171 for (
Index isam=0; isam<vec.size(); ++isam ) {
172 float val = vec[isam];
173 if ( isam != 0 ) cout <<
", ";
174 if ( isam == 0 ) cout <<
"\n" << myname <<
setw(indent) <<
"[";
175 else if ( 10*(isam/10) == isam ) cout <<
"\n" << myname <<
setw(indent) <<
" ";
181 cout << myname <<
setw(indent-2) <<
"]" <<
endl;
182 cout << myname <<
" ResponseShifts: [";
185 if ( first ) first =
false;
190 cout << myname <<
" SmoothVectors: [";
194 if ( first ) first =
false;
196 for (
Index isam=0; isam<vec.size(); ++isam ) {
197 float val = vec[isam];
198 if ( isam != 0 ) cout <<
", ";
199 if ( isam == 0 ) cout <<
"\n" << myname <<
setw(indent) <<
"[";
200 else if ( 10*(isam/10) == isam ) cout <<
"\n" << myname <<
setw(indent) <<
" ";
206 cout << myname <<
setw(indent-2) <<
"]" <<
endl;
207 cout << myname <<
" SmoothScales: [";
210 if ( first ) first =
false;
215 cout << myname <<
" GausFilterSigmas: [";
218 if ( first ) first =
false;
223 cout << myname <<
" LowFilterWidths: [";
226 if ( first ) first =
false;
231 cout << myname <<
" LowFilterPowers: [";
234 if ( first ) first =
false;
240 std::cout.copyfmt(cout_state);
247 const string myname =
"AdcDeconvoluteFFT::update: ";
250 if (
m_LogLevel >= 2 ) cout << myname <<
"Processing run " << acd.
run() <<
" event " << acd.
event()
251 <<
" channel " << icha <<
endl;
258 cout <<
"WARNING: There is no response vector for index " << ivec
259 <<
" (channel " << icha <<
")." <<
endl;
265 cout <<
"WARNING: There is no Gaus filter sigma for index " 266 << ivec <<
" (channel " << icha <<
")." <<
endl;
273 float lfwidth = -1.0;
276 cout <<
"WARNING: There is no low-filter width for index " 277 << ivec <<
" (channel " << icha <<
")." <<
endl;
281 cout <<
"WARNING: There is no low-filter width for index " 282 << ivec <<
" (channel " << icha <<
")." <<
endl;
299 Index nsam = xdasInp.size();
300 if ( nsam == 0 )
return ret;
304 Index nres = responseVector.size();
306 if (
m_LogLevel >= 3 ) cout << myname <<
"Building time-domain response vector." <<
endl;
308 cout << myname <<
"ERROR: Response function is undefined." <<
endl;
312 cout << myname <<
"WARNING: Data is shorter than the response function. No action taken." <<
endl;
315 for (
Index isam=0; isam<nres; ++isam ) {
316 Index jsam = isam >= ishift ? isam - ishift : nsam + isam - ishift;
317 xdasRes[jsam] = responseVector[isam];
324 DFT dftRes(fnormConv);
326 if (
m_LogLevel >= 3 ) cout << myname <<
"Using FFT to build frequency-domain response vectors." <<
endl;
329 cout << myname <<
"WARNING: Unable to xform response function. No action taken." <<
endl;
333 cout << myname <<
"Frequency components:" <<
endl;
335 cout << myname <<
setw(4) << ifrq <<
": " <<
setw(10) << fixed << dftRes.
amplitude(ifrq);
336 if ( ifrq < dftRes.
nPhase() ) cout <<
" @ " <<
setw(10) << fixed << dftRes.
phase(ifrq);
343 DFT dftInp(fnormData);
346 if (
m_LogLevel >= 3 ) cout << myname <<
"Using FFT to build frequency-domain input vectors." <<
endl;
350 cout << myname <<
"WARNING: Unable to xform input data. No action taken." <<
endl;
354 cout << myname <<
"Frequency components:" <<
endl;
356 cout << myname <<
setw(4) << ifrq <<
": " <<
setw(10) << fixed << dftInp.
amplitude(ifrq);
357 if ( ifrq < dftRes.
nPhase() ) cout <<
" @ " <<
setw(10) << fixed << dftInp.
phase(ifrq);
367 const float xmin = 1.e-20;
369 DFT dftFil(fnormConv);
373 if (
m_LogLevel >= 3 ) cout << myname <<
"Building frequency-domain filter vectors." <<
endl;
374 if ( gausFilterSigma > 0.0 ) {
375 static float novertwopi = 0.5*nsam/acos(-1);
376 float sigmaFreq = novertwopi/gausFilterSigma;
377 for (
Index ifrq=0; ifrq<xamsFil.size(); ++ifrq ) {
378 float val = TMath::Gaus(ifrq, 0.0, sigmaFreq,
false);
382 if ( lfwidth == 0.0 ) xamsFil[0] = 0.0;
383 if ( lfwidth > 0.0 ) {
384 double fac = lfwidth/nsam;
385 bool square = lfpower == 2.0;
386 for (
Index ifrq=0; ifrq<xamsFil.size(); ++ifrq ) {
387 double term = fac*ifrq;
388 double termp = square ? term*term :
std::pow(term, lfpower);
389 double fac = termp/(1 + termp);
390 xamsFil[ifrq] *= fac;
393 dftFil.
moveIn(xamsFil, xphsFil);
395 cout << myname <<
"Filter frequency components:" <<
endl;
397 cout << myname <<
setw(4) << ifrq <<
": " <<
setw(10) << fixed << dftFil.
amplitude(ifrq);
398 if ( ifrq < dftFil.
nPhase() ) cout <<
" @ " <<
setw(10) << fixed << dftFil.
phase(ifrq);
410 xamsOut.resize(namp, 0.0);
411 xphsOut.resize(npha, 0.0);
412 if (
m_LogLevel >= 3 ) cout << myname <<
"Building frequency-domain output vectors." <<
endl;
413 DFT dftOut(fnormData, nsam);
414 for (
Index ifrq=0; ifrq<namp; ++ifrq ) {
416 float xphOut = dftInp.
phase(ifrq);
420 xphOut += dftFil.
phase(ifrq);
423 xphOut += dftRes.
phase(ifrq);
428 xphOut += dftFil.
phase(ifrq);
430 if ( xamOut > xmin ) {
432 if ( fabs(den) < xmin ) {
433 cout << myname <<
"WARNING: Ignoring near-zero division in deconvolution. " <<
endl;
437 xphOut -= dftRes.
phase(ifrq);
440 cout << myname <<
"ERROR: Unxpected error in FFT (de)convolution." <<
endl;
443 cout << myname <<
setw(4) << ifrq <<
": " <<
setw(10) << fixed << xamOut;
444 if ( ifrq < npha ) cout <<
" @ " <<
setw(10) << fixed << xphOut;
448 xamsOut[ifrq] = xamOut;
451 xphsOut[ifrq] = xphOut;
456 if (
m_LogLevel >= 3 ) cout << myname <<
"Using FFT to build time-domain output vector." <<
endl;
459 cout << myname <<
"WARNING: Inverse xform failed. No action taken." <<
endl;
466 if (
m_LogLevel >= 3 ) cout << myname <<
"Directly building time-domain output vector." <<
endl;
467 xdasOut.resize(nsam);
470 for (
Index isam=0; isam<nsam; ++isam ) {
472 for (
Index jsam=0; jsam<nsam; ++jsam ) {
473 Index imj = (isam + nsam - jsam) % nsam;
474 xsam += xdasInp[jsam]*xdasFld[imj];
476 xdasOut[isam] = xsam;
482 if (
m_LogLevel >= 1 ) cout << myname <<
"Deconvoluting with Root: option " 485 TMatrixDSparse mres(nsam, nsam);
486 if ( responseVectorToMatrix(responseVector, ishift, mres,
m_LogLevel, myname) )
return ret.
setStatus(6);
489 for (
Index isam=0; isam<nsam; ++isam ) {
490 vdat[isam] = xdasInp[isam];
496 cout <<
"Performing direct matrix deconvolution." <<
endl;
498 cout <<
"Performing filtered matrix deconvolution." <<
endl;
503 DoubleVector vfil(smoothVector.begin(), smoothVector.end());
504 Index nfil = vfil.size();
505 TMatrixDSparse mfil(nsam, nsam);
506 if ( responseVectorToMatrix(vfil, nfil/2, mfil,
m_LogLevel, myname) )
return ret.
setStatus(7);
508 TMatrixDSparse mfil_t(nsam,nsam);
509 mfil_t.Transpose(mfil);
510 TMatrixD rsinv_t(nsam,nsam);
511 rsinv_t.Transpose(mres);
512 TDecompSVD ssolver(mfil_t);
513 if ( ssolver.Decompose() ) {
514 cout << myname <<
"Filtering condition is " << ssolver.Condition() <<
endl;
515 cout << myname <<
"S_t is " << (ssolver.GetMatrix().IsValid() ?
"" :
"not ") <<
"valid." << endl;
516 cout << myname <<
"R_t is " << (rsinv_t.IsValid() ?
"" :
"not ") <<
"valid." << endl;
517 ssolver.MultiSolve(rsinv_t);
518 cout << myname <<
"(R Sinv)_t is " << (rsinv_t.IsValid() ?
"" :
"not ") <<
"valid." << endl;
520 mres.Transpose(rsinv_t);
522 cout << myname <<
"Unable to decompose smearing matrix!" <<
endl;
527 cout <<
"Performing chi-square matrix deconvolution." <<
endl;
528 TMatrixDSparse mres_t(nsam, nsam);
529 mres_t.Transpose(mres);
530 TMatrixDSparse mresres(mres_t);
535 DoubleVector vsmr(smoothVector.begin(), smoothVector.end());
536 for (
double&
val : vsmr )
val*= smoothScale;
537 Index nsmr = vsmr.size();
538 TMatrixDSparse msmr(nsam, nsam);
539 if ( responseVectorToMatrix(vsmr, nsmr/2, msmr,
m_LogLevel, myname) )
return ret.
setStatus(9);
540 TMatrixDSparse msmr_t(nsam, nsam);
541 msmr_t.Transpose(msmr);
542 TMatrixDSparse msmrsmr(msmr_t);
545 mres.SetSparseIndexAB(mresres, msmrsmr);
546 mres = mresres + msmrsmr;
549 Index nsmr = vsmr.size();
550 TMatrixDSparse msmr(nsam, nsam);
551 if ( responseVectorToMatrix(vsmr, nsmr/2, msmr,
m_LogLevel, myname) )
return ret.
setStatus(9);
554 mres.SetSparseIndex(msmr);
561 TDecompSVD solver(mres);
562 if ( solver.Decompose() ) {
563 cout << myname <<
"Final matrix condition is " << solver.Condition() <<
endl;
565 for (
Index isam=0; isam<nsam; ++isam ) {
566 acd.
samples[isam] = vdat[isam];
569 cout << myname <<
"Unable to decompose response matrix!" <<
endl;
575 if ( xamsOut.size() ) {
FloatVector m_LowFilterWidths
DataMap & setStatus(int stat)
int setPhase(Index ifrq, F val)
FloatVector m_SmoothScales
ResponseVectorVector m_SmoothVectors
AdcDeconvoluteFFT(fhicl::ParameterSet const &ps)
ChannelGroupService::Name Name
ResponseVectorVector m_ResponseVectors
static AdcIndex dftNormalization()
std::vector< float > FloatVector
CompactRealDftData< float > DFT
Q_EXPORT QTSManip setprecision(int p)
static RealDftNormalization convolutionNormalization()
F amplitude(Index ifrq) const override
AdcSignalVector ResponseVector
Index nCompact() const override
F phase(Index ifrq) const override
static int fftForward(Index ntick, const float *psam, DFT &dft, Index logLevel=0)
IndexVector m_ResponseCenters
std::vector< double > DoubleVector
AdcSignalVector dftphases
static constexpr double ps
int setAmplitude(Index ifrq, F val)
DataMap update(AdcChannelData &acd) const override
Q_EXPORT QTSManip setw(int w)
FloatVector m_LowFilterPowers
static int fftInverse(const DFT &dft, FloatVector &sams, Index logLevel=0)
std::vector< AdcSignal > AdcSignalVector
int moveIn(FloatVector &s, FloatVector &phas)
IndexMapToolPtr m_channelToIndex
FloatVector m_GausFilterSigmas
Dft::FloatVector FloatVector
auto const & get(AssnsNode< L, R, D > const &r)
std::vector< ResponseVector > ResponseVectorVector
std::vector< Index > IndexVector
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
QTextStream & endl(QTextStream &s)