-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFitEditorAnalytic.cpp
243 lines (205 loc) · 5.92 KB
/
FitEditorAnalytic.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
This software is Copyright by the Board of Trustees of Michigan
State University (c) Copyright 2017.
You may use this software under the terms of the GNU public license
(GPL). The terms of this license are described at:
http://www.gnu.org/licenses/gpl.txt
Authors:
Ron Fox
Giordano Cerriza
Aaron Chester
FRIB
Michigan State University
East Lansing, MI 48824-1321
*/
/**
* @file FitEditorAnalytic.cpp
* @brief Implementation of the FitEditor class for analytic fitting.
*/
#include "FitEditorAnalytic.h"
#include <iostream>
#include <DDASHit.h>
#include <DDASHitUnpacker.h>
#include "Configuration.h"
#include "lmfit_analytic.h"
using namespace ddasfmt;
using namespace ddastoys;
/**
* @details
* Sets up the configuration manager to parse config files and manage
* configuration data. Reads the fit config file.
*/
ddastoys::FitEditorAnalytic::FitEditorAnalytic() :
m_pConfig(new Configuration)
{
try {
m_pConfig->readConfigFile();
}
catch (std::exception& e) {
std::cerr << "Error configuring FitEditor: " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}
ddastoys::FitEditorAnalytic::FitEditorAnalytic(const FitEditorAnalytic& rhs) :
m_pConfig(new Configuration(*rhs.m_pConfig))
{}
/**
* @details
* Constructs using move assignment.
*/
ddastoys::FitEditorAnalytic::FitEditorAnalytic(FitEditorAnalytic&& rhs) noexcept :
m_pConfig(nullptr)
{
*this = std::move(rhs);
}
FitEditorAnalytic&
ddastoys::FitEditorAnalytic::operator=(const FitEditorAnalytic& rhs)
{
if (this != &rhs) {
delete m_pConfig;
m_pConfig = new Configuration(*rhs.m_pConfig);
}
return *this;
}
FitEditorAnalytic&
ddastoys::FitEditorAnalytic::operator=(FitEditorAnalytic&& rhs) noexcept
{
if (this != &rhs) {
delete m_pConfig;
m_pConfig = rhs.m_pConfig;
rhs.m_pConfig = nullptr;
}
return *this;
}
/**
* @details
* Delete the Configuration object managed by this class.
*/
ddastoys::FitEditorAnalytic::~FitEditorAnalytic()
{
delete m_pConfig;
}
/**
* @details
* This is the hook into the FitEditorAnalytic class. Here we:
* - Parse the fragment into a hit.
* - Produce a IOvec element for the existing hit (without any fit
* that might have been there).
* - See if the configuration manager says we should fit and if so, create
* the trace.
* - Get the fit limits and saturation value.
* - Get the number of pulses to fit.
* - Do the fits.
* - Create an IOvec entry for the extension we created (dynamic).
*/
std::vector<CBuiltRingItemEditor::BodySegment>
ddastoys::FitEditorAnalytic::operator()(
pRingItemHeader pHdr, pBodyHeader pBHdr, size_t bodySize, void* pBody
)
{
std::vector<CBuiltRingItemEditor::BodySegment> result;
// Regardless we want a segment that includes the hit. Note that the first
// uint32_t of the body is the size of the standard hit part in
// uint16_t words.
uint16_t* pSize = static_cast<uint16_t*>(pBody);
CBuiltRingItemEditor::BodySegment hitInfo(
*pSize*sizeof(uint16_t), pSize, false
);
result.push_back(hitInfo);
// Make the hit:
DDASHit hit;
DDASHitUnpacker unpacker;
unpacker.unpack(
static_cast<uint32_t*>(pBody),
static_cast<uint32_t*>(nullptr),
hit
);
auto crate = hit.getCrateID();
auto slot = hit.getSlotID();
auto chan = hit.getChannelID();
if (m_pConfig->fitChannel(crate, slot, chan)) {
std::vector<uint16_t> trace = hit.getTrace();
FitInfo* pFit = new FitInfo; // Have an extension tho may be zero.
if (trace.size() > 0) { // Need a trace to fit
auto limits = m_pConfig->getFitLimits(crate, slot, chan);
auto sat = m_pConfig->getSaturationValue(crate, slot, chan);
int classification = pulseCount(hit);
if (classification) {
// Bit 0 do single fit, bit 1 do double fit.
if (classification & 1) {
analyticfit::lmfit1(
&(pFit->s_extension.onePulseFit), trace, limits, sat
);
}
if (classification & 2 ) {
// The single pulse fit guides the double pulse fit.
// Note that lmfit2 will perform a single fit if no guess
// is provided. If we have already fit the single pulse,
// set the guess to those results.
if (classification & 1) {
fit1Info guess = pFit->s_extension.onePulseFit;
analyticfit::lmfit2(
&(pFit->s_extension.twoPulseFit), trace, limits,
&guess, sat
);
} else {
// nullptr: no guess for single params.
analyticfit::lmfit2(
&(pFit->s_extension.twoPulseFit), trace, limits,
nullptr, sat
);
}
}
}
}
CBuiltRingItemEditor::BodySegment fit(sizeof(FitInfo), pFit, true);
result.push_back(fit);
} else { // No fit performed
nullExtension* p = new nullExtension;
CBuiltRingItemEditor::BodySegment nofit(
sizeof(nullExtension), p, true
);
result.push_back(nofit);
}
return result;
}
void
ddastoys::FitEditorAnalytic::free(iovec& e)
{
if (e.iov_len == sizeof(FitInfo)) {
FitInfo* pFit = static_cast<FitInfo*>(e.iov_base);
delete pFit;
} else {
nullExtension* p = static_cast<nullExtension*>(e.iov_base);
delete p;
}
}
///
// Private methods
//
/**
* @details
* In the absence of the classifier, perform single- and double-pulse fits
* for every mapped channel.
*/
int
ddastoys::FitEditorAnalytic::pulseCount(DDASHit& hit)
{
return 3; // In absence of classifier.
}
/////////////////////////////////////////////////////////////////////////////
// Factory for our editor:
//
/**
* @brief Factory method to create this FitEditor.
*
* @details
* $DAQBIN/EventEditor expects a symbol called createEditor to exist in the
* plugin library it loads at runtime. Wrapping the factory method in
* extern "C" prevents namespace mangling by the C++ compiler.
*/
extern "C" {
ddastoys::FitEditorAnalytic* createEditor() {
return new ddastoys::FitEditorAnalytic;
}
}