Belle II Software development
MillepedeAlgorithm.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <alignment/calibration/MillepedeAlgorithm.h>
10
11#include <alignment/dataobjects/MilleData.h>
12#include <alignment/dataobjects/PedeSteering.h>
13#include <alignment/GlobalLabel.h>
14#include <alignment/GlobalParam.h>
15#include <alignment/GlobalTimeLine.h>
16#include <alignment/Manager.h>
17#include <alignment/PedeApplication.h>
18#include <alignment/PedeResult.h>
19#include <framework/database/EventDependency.h>
20#include <framework/utilities/FileSystem.h>
21
22#include <TH1F.h>
23#include <TTree.h>
24
25
26
27using namespace std;
28using namespace Belle2;
29using namespace alignment;
30
32{
33 setDescription("Millepede calibration & alignment algorithm");
34}
35
37{
38 auto chisqHist = getObjectPtr<TH1F>("chi2_per_ndf");
39 B2INFO(" Mean of Chi2 / NDF of tracks before calibration: " << chisqHist->GetMean());
40
41 if (chisqHist->GetEntries() < m_minEntries) {
42 B2INFO("Less than " << m_minEntries << " collected: " << chisqHist->GetEntries() << ". Return c_NotEnoughData.");
43 return c_NotEnoughData;
44 }
45
46 // Write out binary files from tree and add to steering
48 auto mille = getObjectPtr<MilleData>("mille");
49 for (auto file : mille->getFiles()) {
50 if (!FileSystem::fileExists(file)) {
51 B2ERROR("Missing file: " << file);
52 continue;
53 }
54 m_steering.addFile(file);
55 }
56
57 // Run calibration on steering
59
60 if (!m_pede.success() || !m_result.isValid()) {
61 B2ERROR(m_pede.getExitMessage());
62 return c_Failure;
63 }
64
65 if (m_result.getNoParameters() == 0) {
66 B2INFO("No parameters to store. Failure.");
67 return c_Failure;
68 }
69
70// for (int ipar = 0; ipar < m_result.getNoParameters(); ipar++) {
71// if (!m_result.isParameterDetermined(ipar)) {
72// if (!m_result.isParameterFixed(ipar)) {
73// ++undeterminedParams;
74// }
75// }
76// }
77
78
79
80 // This function gives you the vector of ExpRuns that were requested for this execution only
81 auto expRuns = getRunList();
82
83 // Do not use full data range - would not work with SequentialRunByRun strategy:
84 //auto expRuns = getRunListFromAllData();
85
86 int undeterminedParams = 0;
87 double maxCorrectionPull = 0.;
88 int maxCorrectionPullLabel = 0;
89 int nParams = 0;
90 double paramChi2 = 0.;
91
92 if (m_events.empty()) {
93 GlobalParamVector result(m_components);
94 GlobalParamVector errors(m_components);
95 GlobalParamVector corrections(m_components);
96
97 GlobalCalibrationManager::initGlobalVector(result);
98 GlobalCalibrationManager::initGlobalVector(errors);
99 GlobalCalibrationManager::initGlobalVector(corrections);
100
101 // <UniqueID, ElementID, ParameterId, value>
102 std::vector<std::tuple<unsigned short, unsigned short, unsigned short, double>> resultTuple;
103
104 for (auto& exprun : expRuns) {
105 auto event1 = EventMetaData(1, exprun.second, exprun.first);
106 result.loadFromDB(event1);
107 errors.construct();
108 corrections.construct();
109 break;
110 }
111
112 // Construct all remaining components not loaded from DB
113 // to easily create new objects not previously in DB :-)
114 // TODO: remove?
115 result.construct();
116
117
118
119 // Loop over all determined parameters:
120 for (int ipar = 0; ipar < m_result.getNoParameters(); ipar++) {
121 if (!m_result.isParameterDetermined(ipar)) {
122 if (!m_result.isParameterFixed(ipar)) {
123 ++undeterminedParams;
124 }
125 continue;
126 }
127
129 double correction = m_result.getParameterCorrection(ipar);
130 double error = m_result.getParameterError(ipar);
131 double pull = correction / error;
132
133 ++nParams;
134 paramChi2 += pull * pull;
135
136 if (fabs(pull) > fabs(maxCorrectionPull)) {
137 maxCorrectionPull = pull;
138 maxCorrectionPullLabel = label.label();
139 }
140
141 if (m_invertSign) correction = - correction;
142
143 result.updateGlobalParam(correction, label.getUniqueId(), label.getElementId(), label.getParameterId());
144 errors.setGlobalParam(error, label.getUniqueId(), label.getElementId(), label.getParameterId());
145 corrections.setGlobalParam(correction, label.getUniqueId(), label.getElementId(), label.getParameterId());
146
147 resultTuple.push_back({label.getUniqueId(), label.getElementId(), label.getParameterId(), correction});
148
149 }
150
151 result.postReadFromResult(resultTuple);
152
153 for (auto object : result.releaseObjects()) {
154 saveCalibration(object);
155 }
156 for (auto object : errors.releaseObjects()) {
157 saveCalibration(object, DataStore::objectName(object->IsA(), "") + "_ERRORS");
158 }
159 for (auto object : corrections.releaseObjects()) {
160 saveCalibration(object, DataStore::objectName(object->IsA(), "") + "_CORRECTIONS");
161 }
162 } else {
163
164 GlobalParamVector gpv(m_components);
165 GlobalCalibrationManager::initGlobalVector(gpv);
166 GlobalLabel label_system;
167
168 alignment::timeline::GlobalParamTimeLine timeline(m_events, label_system, gpv);
169 alignment::timeline::GlobalParamTimeLine timeline_errors(m_events, label_system, gpv);
170 alignment::timeline::GlobalParamTimeLine timeline_corrections(m_events, label_system, gpv);
171 timeline.loadFromDB();
172 timeline_corrections.loadFromDB();
173 timeline_errors.loadFromDB();
174
175 // Loop over all determined parameters:
176 for (int ipar = 0; ipar < m_result.getNoParameters(); ipar++) {
177 if (!m_result.isParameterDetermined(ipar)) {
178 if (!m_result.isParameterFixed(ipar)) {
179 ++undeterminedParams;
180 }
181 continue;
182 }
183
185 double correction = m_result.getParameterCorrection(ipar);
186 double error = m_result.getParameterError(ipar);
187 double pull = correction / error;
188
189 ++nParams;
190 paramChi2 += pull * pull;
191
192 if (fabs(pull) > fabs(maxCorrectionPull)) {
193 maxCorrectionPull = pull;
194 maxCorrectionPullLabel = label.label();
195 }
196
197 if (m_invertSign) correction = - correction;
198
199 timeline.updateGlobalParam(label, correction);
200 timeline_errors.updateGlobalParam(label, error, true);
201 timeline_corrections.updateGlobalParam(label, correction, true);
202 }
203
204 //TODO: if data do not cover all parts of timeline, this will lead to memory leak for
205 // objects not being saved in DB -> delete them here
206 auto objects = timeline.releaseObjects();
207 for (auto iov_obj : objects) {
208 if (iov_obj.second && !iov_obj.first.overlap(getIovFromAllData()).empty()) {
209 if (auto evdep = dynamic_cast<EventDependency*>(iov_obj.second)) {
210 saveCalibration(iov_obj.second, DataStore::objectName(evdep->getAnyObject()->IsA(), ""),
211 iov_obj.first.overlap(getIovFromAllData()));
212 } else {
213 saveCalibration(iov_obj.second, DataStore::objectName(iov_obj.second->IsA(), ""), iov_obj.first.overlap(getIovFromAllData()));
214 }
215 } else {
216 if (iov_obj.second) delete iov_obj.second;
217 }
218 }
219
220 auto objects_errors = timeline_errors.releaseObjects();
221 for (auto iov_obj : objects_errors) {
222 if (iov_obj.second && !iov_obj.first.overlap(getIovFromAllData()).empty()) {
223 if (auto evdep = dynamic_cast<EventDependency*>(iov_obj.second)) {
224 saveCalibration(iov_obj.second, DataStore::objectName(evdep->getAnyObject()->IsA(), "") + "_ERRORS",
225 iov_obj.first.overlap(getIovFromAllData()));
226 } else {
227 saveCalibration(iov_obj.second, DataStore::objectName(iov_obj.second->IsA(), "") + "_ERRORS",
228 iov_obj.first.overlap(getIovFromAllData()));
229 }
230 } else {
231 if (iov_obj.second) delete iov_obj.second;
232 }
233 }
234
235 auto objects_corrections = timeline_corrections.releaseObjects();
236 for (auto iov_obj : objects_corrections) {
237 if (iov_obj.second && !iov_obj.first.overlap(getIovFromAllData()).empty()) {
238 if (auto evdep = dynamic_cast<EventDependency*>(iov_obj.second)) {
239 saveCalibration(iov_obj.second, DataStore::objectName(evdep->getAnyObject()->IsA(), "") + "_CORRECTIONS",
240 iov_obj.first.overlap(getIovFromAllData()));
241 } else {
242 saveCalibration(iov_obj.second, DataStore::objectName(iov_obj.second->IsA(), "") + "_CORRECTIONS",
243 iov_obj.first.overlap(getIovFromAllData()));
244 }
245 } else {
246 if (iov_obj.second) delete iov_obj.second;
247 }
248 }
249
250 }
251
252 if (undeterminedParams) {
253 B2WARNING("There are " << undeterminedParams << " undetermined parameters.");
255 B2WARNING("Not enough data for calibration.");
256 return c_NotEnoughData;
257 }
258 }
259
260 //commit();
261
262 if (paramChi2 / nParams > 1. || fabs(maxCorrectionPull) > 10.) {
263 B2INFO("Largest correction/error is " << maxCorrectionPull << " for parameter with label " << maxCorrectionPullLabel);
264 B2INFO("Parameter corrections Chi2/NDF, e.g. sum[(correction/error)^2]/#params = " << paramChi2 / nParams
265 << " = " << paramChi2 << " / " << nParams << " > 1.");
266
267 B2INFO("Requesting iteration.");
268 return c_Iterate;
269 }
270
271 return c_OK;
272}
273
275{
276 // Clear list of binaries in steering
278
279 // Temp file name
280 const std::string milleFileName("gbl-data.mille");
281
282 // For no entries, no binary file is created
283 auto gblDataTree = getObjectPtr<TTree>("GblDataTree");
284 if (!gblDataTree) {
285 B2WARNING("No GBL data tree object in collected data.");
286 return;
287 } else if (!gblDataTree->GetEntries()) {
288 B2WARNING("No trajectories in GBL data tree.");
289 return;
290 }
291
292 // Create new mille binary
293 auto milleBinary = new gbl::MilleBinary(milleFileName);
294
295 // Containers for GBL data
296 double aValue(0.);
297 double aErr(0.);
298 std::vector<unsigned int>* indLocal;
299 std::vector<double>* derLocal;
300 std::vector<int>* labGlobal;
301 std::vector<double>* derGlobal;
302
303 // Read vectors of GblData from tree branch
304 std::vector<gbl::GblData>* currentGblData = new std::vector<gbl::GblData>();
305 gblDataTree->SetBranchAddress("GblData", &currentGblData);
306
307 B2INFO("Writing Millepede binary files...");
308 for (unsigned int iRecord = 0; iRecord < gblDataTree->GetEntries(); ++iRecord) {
309 gblDataTree->GetEntry(iRecord);
310
311 if (!currentGblData)
312 continue;
313
314 for (gbl::GblData& theData : *currentGblData) {
315 theData.getAllData(aValue, aErr, indLocal, derLocal, labGlobal,
316 derGlobal);
317 milleBinary->addData(aValue, aErr, *indLocal, *derLocal, *labGlobal,
318 *derGlobal);
319 }
320 milleBinary->writeRecord();
321 }
322 // Closes the file
323 delete milleBinary;
324 B2INFO("Millepede binary files written.");
325
326 // Add binary to steering
327 m_steering.addFile(milleFileName);
328}
Base class for calibration algorithms.
IntervalOfValidity getIovFromAllData() const
Get the complete IoV from inspection of collected data.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
EResult
The result of calibration.
@ c_OK
Finished successfully =0 in Python.
@ c_Iterate
Needs iteration =1 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
@ c_Failure
Failed =3 in Python.
static std::string objectName(const TClass *t, const std::string &name)
Return the storage name for an object of the given TClass and name.
Definition: DataStore.cc:151
Class for handling changing conditions as a function of event number.
Store event, run, and experiment numbers.
Definition: EventMetaData.h:33
static bool fileExists(const std::string &filename)
Check if the file with given filename exists.
Definition: FileSystem.cc:32
Class to convert to/from global labels for Millepede II to/from detector & parameter identificators.
Definition: GlobalLabel.h:41
void prepareMilleBinary()
Write out binary files from data in tree with GBL data to be used by Millepede and add them to steeri...
int m_minEntries
Minimum entries collected - report NotEnoughData for less.
std::vector< std::string > m_components
Components (BeamSpot...) to calibrate or empty for all available in data.
std::vector< EventMetaData > m_events
The events at which payloads can change for time-dep calibration (translation from time IDs (aka cont...
bool m_invertSign
Add (true) or subtract (false) corrections?
MillepedeAlgorithm()
Constructor set the prefix to MillepedeCalibration.
alignment::PedeResult & result()
Get the result (invalid until executed) to get parameters etc.
alignment::PedeApplication m_pede
The Pede application (unsuccesfull until execution)
virtual EResult calibrate() override
Run algo on data.
alignment::PedeResult m_result
The result (invalid until execution)
bool m_ignoreUndeterminedParams
Report failure(false) or success (true) even if some parameters could not be determined.
PedeSteering m_steering
The steering with commands.
void clearFiles()
Clear list of files.
Definition: PedeSteering.h:53
void addFile(std::string filename, double weight=1.)
Add a file (optionally with weight) to list of binary files.
Definition: PedeSteering.cc:69
bool success()
Was Pede successfull (can the result be used)?
PedeResult calibrate(PedeSteering &steering)
Run Pede and return full result with parameter corrections.
std::string getExitMessage() const
Returns the Pede exit message (from millepede.end file)
double getParameterCorrection(unsigned int parameterIndex)
Get determined correction of parameter at index.
Definition: PedeResult.cc:136
bool isParameterDetermined(unsigned int parameterIndex)
Is parameter at given index determined?
Definition: PedeResult.cc:156
int getNoParameters() const
Get number of parameters in result (for looping over)
Definition: PedeResult.h:38
bool isParameterFixed(unsigned int parameterIndex)
Is parameter at given index fixed?
Definition: PedeResult.cc:151
unsigned int getParameterLabel(unsigned int parameterIndex)
Get label of parameter at index.
Definition: PedeResult.cc:131
double getParameterError(unsigned int parameterIndex)
Get correction error of parameter at index.
Definition: PedeResult.cc:141
bool isValid()
Was the object initialized properly from a result file?
Definition: PedeResult.h:34
Convenient class to automatically create payloads from allowed time depedence of parameter,...
std::vector< std::pair< IntervalOfValidity, TObject * > > releaseObjects()
Release all the objects (you become the owner!) for DB storage.
void loadFromDB()
Load every single payload with the content in database at its corresponding event (when it should sta...
void updateGlobalParam(GlobalLabel label, double correction, bool resetParam=false)
Add a correction to any payload's parameter in the timeline.
Abstract base class for different kinds of events.
STL namespace.