Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JTuneHV.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <iomanip>
3 
4 #include "JSystem/JTime.hh"
5 
6 #include "Jeep/JPrint.hh"
7 #include "Jeep/JParser.hh"
8 #include "Jeep/JMessage.hh"
9 
10 #include "JSupport/JMeta.hh"
11 
12 #include "dbclient/KM3NeTDBClient.h"
13 
14 #include "JDB/JDB.hh"
15 #include "JDB/JDBToolkit.hh"
16 #include "JDB/JDBincludes.hh"
17 #include "JDB/JProductRouter.hh"
18 #include "JDB/JSelector.hh"
20 
21 #include "JDetector/JDetector.hh"
24 
25 #include "JCalibrate/JFitToT.hh"
26 
27 #include "JTools/JMap.hh"
28 #include "JTools/JMultiMap.hh"
29 
30 #include "JROOT/JManager.hh"
31 
32 #include "JSon/JSon.hh"
33 
34 #include "TFile.h"
35 #include "TGraphErrors.h"
36 
37 
38 namespace {
39 
40  using namespace std;
41  using namespace JPP;
42 
43 
44  /**
45  * Auxiliary data structure for interpolating (HV, gain)-data
46  */
47  struct interpolator {
48 
49  typedef map<double, pair<double, double>> map_t;
50 
51  /**
52  * Constructor
53  *
54  * \param minHVdiff minimal difference between two HV vlaues
55  * \param minGain minimal valid gain value
56  * \param maxGain maximal valid gain value
57  * \param targetGain target gain value for interpolation
58  */
59  interpolator(const double minHVdiff, const double minGain, const double maxGain, const double targetGain) :
60  dHV(minHVdiff), gainMin(minGain), gainMax(maxGain), gainTarget(targetGain) {}
61 
62 
63  /*
64  * Checks whether the HV-values of two map entries are different
65  *
66  * \param entry1 first map entry
67  * \param entry2 second map entry
68  * \return true if absolute HV difference greater than dHV; else false
69  */
70  const bool checkHV(map_t::const_reference entry1, map_t::const_reference entry2) const {
71 
72  return (fabs(entry1.first - entry2.first) > dHV);
73  }
74 
75 
76  /*
77  * Checks whether the gain of a map entries lies within the specified range
78  *
79  * \param entry map entry
80  * \return true if gain within gainRange; else false
81  */
82  const bool checkGain(map_t::const_reference entry) const {
83 
84  return (entry.second.first > gainMin && entry.second.first < gainMax);
85  }
86 
87 
88  /*
89  * Checks whether the gain of two map entries are strictly increasing as function of the absolute HV
90  *
91  * \param entry1 first map entry
92  * \param entry2 second map entry
93  * \return true if absolute HV difference greater than dHV; else false
94  */
95  const bool areIncreasing(map_t::const_reference entry1, map_t::const_reference entry2) const {
96 
97  return ((entry1.first < entry2.first && entry1.second.first > entry2.second.first) ||
98  (entry1.first > entry2.first && entry1.second.first < entry2.second.first));
99  }
100 
101 
102  /*
103  * Checks whether two map entries are valid for interpolation (i.e. different HV and gain within specified range)
104  *
105  * \param entry1 first map entry
106  * \param entry2 second map entry
107  * \return true if absolute HV difference greater than dHV; else false
108  */
109  const bool areValid(map_t::const_reference entry1,
110  map_t::const_reference entry2) const {
111 
112  return (checkHV (entry1, entry2) && checkGain(entry1) &&
113  areIncreasing(entry1, entry2) && checkGain(entry2));
114  }
115 
116 
117  /*
118  * Get interpolation points
119  *
120  * \param data HV-gain data
121  * \return pair of interpolation points
122  */
123  const pair<map_t::const_reference,
124  map_t::const_reference> getPoints(const map_t& data) const {
125 
126  map_t::const_iterator point0 = data.cbegin();
127  map_t::const_iterator point1 = next(data.cbegin());
128 
129  for (map_t::const_iterator it = next(data.cbegin()); it != data.cend(); ++it) {
130 
131  if (fabs(it->second.first - gainTarget) < fabs(point0->second.first - gainTarget)) {
132 
133  point1 = (areValid(*point0, *it) ? point0 : point1);
134  point0 = it;
135 
136  } else if ((fabs(it->second.first - gainTarget) < fabs(point1->second.first - gainTarget) ||
137  !areValid(*point0, *point1)) && areValid(*point0, *it)) {
138 
139  point1 = it;
140  }
141  }
142 
143  return pair<map_t::const_reference,
144  map_t::const_reference>(*point0, *point1);
145  }
146 
147 
148  /*
149  * Inter-/Extrapolates the nominal high-voltage, given two map entries
150  *
151  * \param entry1 first map entry
152  * \param entry2 second map entry
153  * \return inter-/extrapolated nominal high-voltage and error
154  */
155  const pair<double, double> getNominalHV(map_t::const_reference entry1,
156  map_t::const_reference entry2) const {
157 
158  pair<double, double> result{0.0, 0.0};
159 
160  if (areValid(entry1, entry2)) {
161 
162  const double logHV0 = log(fabs(entry1.first));
163  const double logHV1 = log(fabs(entry2.first));
164 
165  const double logG0 = log(entry1.second.first);
166  const double logG1 = log(entry2.second.first);
167  const double elogG0 = entry1.second.second / entry1.second.first;
168  const double elogG1 = entry2.second.second / entry2.second.first;
169 
170  const double dlogG0 = log(gainTarget) - logG0;
171  const double dlogG1 = log(gainTarget) - logG1;
172 
173  const double slope = (logG1 - logG0) / (logHV1 - logHV0);
174  const double logHVnom = dlogG0 / slope + logHV0;
175  const double elogHVnom = sqrt(dlogG1 * dlogG1 * elogG0 * elogG0 +
176  dlogG0 * dlogG0 * elogG1 * elogG1) / fabs(slope * (logG1 - logG0));
177 
178  result.first = -exp(logHVnom);
179  result.second = exp(logHVnom) * elogHVnom;
180  }
181 
182  return result;
183  }
184 
185 
186  /*
187  * Inter-/Extrapolates the nominal high-voltage, given HV-gain data
188  *
189  * \param data HV-gain data
190  * \return inter-/extrapolated nominal high-voltage and error
191  */
192  const pair<double, double> getNominalHV(const map_t& data) const {
193 
194  pair<map_t::const_reference,
195  map_t::const_reference> intpPoints = getPoints(data);
196 
197  return getNominalHV(intpPoints.first, intpPoints.second);
198  }
199 
200 
201  const double dHV; //!< minimal HV step value [V]
202  const double gainMin; //!< Minimal valid gain value
203  const double gainMax; //!< Maximal valid gain value
204  const double gainTarget; //!< target gain value for interpolation
205  };
206 }
207 
208 
209 
210 /**
211  * \file
212  *
213  * Example program to fit the gain to the high-voltage
214  * \author acreusot, mdejong and bjung
215  */
216 int main(int argc, char **argv)
217 {
218  using namespace std;
219  using namespace JPP;
220 
221  typedef typename JMAPLIST<JMap, JMap, JMap, JMap, JMap>::maplist mapList_t;
222 
223  typedef map<double, pair<double, double>> runMap_t;
224  typedef JMultiMap<int, runMap_t, mapList_t> pmtMap_t;
225 
226  string usr;
227  string pwd;
228  string cookie;
229 
230  map<int, string> inputFiles;
231  string detectorFile;
232  string outputFile;
233  string graphFile;
234  string testType;
235 
236  double HVstepMin = 2 * 3.14; //!< Minimal HV step [V]
237  double gainMin = FITTOT_GAIN_MIN + 0.1; //!< Minimal valid gain fit-value
238  double gainMax = FITTOT_GAIN_MAX - 0.1; //!< Maximal valid gain fit-value
239  double gainTarget = NOMINAL_GAIN; //!< Target nominal gain value
240 
241  int debug;
242 
243 
244  try {
245 
246  JProperties properties;
247 
248  properties.insert(gmake_property(HVstepMin));
249  properties.insert(gmake_property(gainMin));
250  properties.insert(gmake_property(gainMax));
251  properties.insert(gmake_property(gainTarget));
252 
253  JParser<> zap("Example program to find optimal HV-settings.");
254 
255  zap['u'] = make_field(usr) = "";
256  zap['!'] = make_field(pwd) = "";
257  zap['C'] = make_field(cookie) = "";
258  zap['f'] = make_field(inputFiles, "map of run numbers to file strings (i.e. to the output of JFitToT)");
259  zap['a'] = make_field(detectorFile, "detector file");
260  zap['T'] = make_field(testType, "test type") = "HV-TUNING-SEA-GAIN-v1";
261  zap['O'] = make_field(outputFile, "HV tuning calibration file (json format)");
262  zap['o'] = make_field(graphFile, "Graphical output (root format)") = "";
263  zap['@'] = make_field(properties) = JPARSER::initialised();
264  zap['d'] = make_field(debug, "debug") = 1;
265 
266  zap(argc, argv);
267  }
268  catch(const exception &error) {
269  FATAL(error.what() << endl);
270  }
271 
272  JDateAndTime timer;
273 
275  JPersons person;
276 
277  vector<string> runNumbers;
278  vector<int> missingDOMs;
279  pmtMap_t data;
280 
281  JManager<string, TGraphErrors> manager(new TGraphErrors(), MAKE_STRING("%.HVxG"));
282 
283  try {
284 
285  NOTICE("Loading database tables..." << endl);
286 
287  // Load detector file
288  load(detectorFile, detector);
289 
290  JDB::reset(usr, pwd, cookie);
291 
292  // Extract user info
293  {
294  JSelector selector = getSelector<JPersons>(JDB::get()->User());
295  ResultSet& rs = getResultSet(getTable<JPersons>(), selector);
296  rs >> person;
297  rs.Close();
298  }
299 
300  // Extract gain and high-voltage data
301  for (map<int, string>::const_iterator fileIt = inputFiles.cbegin(); fileIt != inputFiles.cend(); ++fileIt) {
302 
303  const int runNr = fileIt->first;
304 
305  NOTICE("Extracting Gain-/HV-data for run " << runNr << endl);
306  runNumbers.push_back(to_string(runNr));
307 
308  {
309  TFile fitData(fileIt->second.c_str(), "READ");
310 
311  JSelector selector = getSelector<JPMTHVRunSettings>(getDetector(detector.getID()), runNr);
312  ResultSet& rs = getResultSet(getTable<JPMTHVRunSettings>(), selector);
313 
314  for (JPMTHVRunSettings table; rs >> table; ) {
315 
316  const int domID = detector.getModule(JLocation(table.DUID, table.FLOORID)).getID();
317 
318  const TH1* h1 = (TH1*) fitData.Get(MAKE_CSTRING(right << domID << FITTOT_SEPARATOR << FILL(2,'0') <<
319  table.PMTINTID << FITTOT_SEPARATOR << FITTOT_SUFFIX));
320  const TF1* f1 = (h1 != NULL ? h1->GetFunction(FITTOT_FNAME.c_str()) : NULL);
321 
322  double gain = (fabs(gainMin - gainTarget) > fabs(gainMax - gainTarget) ? gainMin : gainMax);
323  double gainError = 0.0;
324 
325  if (f1 != NULL) {
326 
327  const int Ngain = f1->GetParNumber("gain");
328 
329  gain = f1->GetParameter(Ngain);
330  gainError = f1->GetParError (Ngain);
331 
332  } else if (h1 == NULL && find(missingDOMs.cbegin(), missingDOMs.cend(), domID) == missingDOMs.cend()) {
333 
334  missingDOMs.push_back(domID);
335  }
336 
337  data[domID][table.PMTSERIAL][table.DUID][table.FLOORID][table.PMTINTID].insert(make_pair(table.HV_VALUE, make_pair(gain, gainError)));
338 
339  const string name = MAKE_STRING(domID << '.' << FILL(2,'0') << table.PMTINTID);
340  const int index = distance(inputFiles.cbegin(), fileIt);
341 
342  manager[name]->SetPoint (index, log10(fabs(table.HV_VALUE)), log10(gain));
343  manager[name]->SetPointError(index, 0.0, gainError / gain / log(10));
344  }
345 
346  rs.Close();
347  }
348  }
349 
350  } catch (const exception& error) {
351 
352  FATAL(error.what() << endl);
353  }
354 
355 
356  // Find optimal HV corresponding to a nominal gain of 1.0
357  // via linear interpolation in log-log scale
358  JHVCalibration HVcalibrations;
359 
360  NOTICE("Searching optimal high-voltage settings..." << endl <<
361  LEFT(30) << "UPI" << CENTER(35) << "(identifer / location)" << RIGHT(35) << "Inter-/Extrapolated high-voltage [-]" << endl);
362 
363  for (pmtMap_t::super_const_iterator pmt = data.super_begin(); pmt != data.super_end(); ++pmt) {
364 
365  // Retrieve upi, location and serialID
366  const int domID = pmt->first;
367  const JUPI_t& pmtUPI = getUPI(PBS::PMT, pmt->second->first);
368  const JLocation_t location(pmt->second->second->first,
369  pmt->second->second->second->first,
370  pmt->second->second->second->second->first);
371 
372  const runMap_t& data = pmt.getValue();
373 
374  NOTICE(LEFT(30) << pmtUPI << "(a.k.a. " << domID << '.' << FILL(2,'0') << location.position << " / " << location << "):");
375 
376  // Check number of entries
377  if (data.size() < 2 || find(missingDOMs.cbegin(), missingDOMs.cend(), domID) != missingDOMs.cend()) {
378 
379  NOTICE (setprecision(2) << right << FIXED(20,2) << 0.0 << " +/- " << FIXED(4,2) << 0.0 << endl);
380  WARNING((data.size() < 2 ? "Insufficient data" : "Missing (dead?) DOM") << endl);
381 
382  HVcalibrations.push_back(JHVCalibration_t(pmtUPI, Failed_t, 0.0, 0.0, runNumbers));
383  continue;
384  }
385 
386  // Find interpolation points
387  const interpolator interpolator(HVstepMin, gainMin, gainMax, gainTarget);
388 
389  const pair<runMap_t::const_reference,
390  runMap_t::const_reference> points = interpolator.getPoints(data);
391  const pair<double, double> result = interpolator.getNominalHV(points.first, points.second);
392 
393  const bool valid = (interpolator.areValid(points.first, points.second) && result.first < 0.0 &&
394  ((log(fabs(result.first)) - log(fabs(points.first.first))) /
395  (log(fabs(points.second.first)) - log(fabs(points.first.first))) < 2.0));
396 
397  NOTICE(setprecision(2) << right << FIXED(20,2) << result.first << " +/- " << FIXED(4,2) << result.second << endl);
398 
399  if (result.first < data.cbegin() -> first ||
400  result.first > data.crbegin() -> first) {
401 
402  WARNING("Nominal gain " << gainTarget << " lies outside of HV-scan range; " <<
403  "Extrapolation " << (valid ? "successful." : "failed; Setting zero.") << endl);
404 
405  } else if (!valid) {
406 
407  WARNING("Could not find optimal high-voltage; Setting zero." << endl);
408  }
409 
410  const JHVCalibration_t HVcal(pmtUPI,
411  valid ? OK_t : Failed_t,
412  valid ? result.first : 0.0,
413  valid ? NOMINAL_GAIN : 0.0,
414  runNumbers);
415 
416  HVcalibrations.push_back(HVcal);
417  }
418 
419 
420  if (! graphFile.empty()) {
421 
422  TFile out(graphFile.c_str(), "RECREATE");
423 
424  putObject(&out, JMeta(argc, argv));
425 
426  for (JManager<string, TGraphErrors>::const_iterator it = manager.cbegin(); it != manager.cend(); ++it) {
427  it->second->SetMarkerStyle(kFullDotSmall);
428  }
429 
430  out << manager;
431 
432  out.Close();
433  }
434 
435  // Write json output
436  json js;
437 
438  js[User_t] = person.LOGIN;
439  js[Location_t] = person.LOCATIONID;
440  js[StartTime_t] = timer.toString();
441  js[EndTime_t] = timer().toString();
442  js[Test_t + Type_t] = testType;
443  js[Tests_t] = json(HVcalibrations);
444 
445  ofstream ofs(outputFile.c_str());
446 
447  ofs << setw(2) << setprecision(8);
448  ofs << js;
449 
450  ofs.close();
451 }
Auxiliary class for ROOT I/O of application specific meta data.
Definition: JMeta.hh:70
Utility class to parse command line options.
Definition: JParser.hh:1500
#define WARNING(A)
Definition: JMessage.hh:65
JMultiMap is a general purpose multidimensional map based on a type list of maps. ...
static const std::string Failed_t
std::vector< T >::difference_type distance(typename std::vector< T >::const_iterator first, typename PhysicsEvent::const_iterator< T > second)
Specialisation of STL distance.
#define gmake_property(A)
macro to convert (template) parameter to JPropertiesElement object
static const std::string Tests_t
static const JPBS_t PMT(3, 4, 2, 3)
PBS of photo-multiplier tube (PMT)
static const std::string OK_t
static const double FITTOT_GAIN_MAX
Default maximal gain.
Definition: JFitToT.hh:41
Detector data structure.
Definition: JDetector.hh:80
static const double FITTOT_GAIN_MIN
Default minimal gain.
Definition: JFitToT.hh:40
Utility class to parse parameter values.
Definition: JProperties.hh:496
T get(const JHead &header)
Get object from header.
#define MAKE_CSTRING(A)
Make C-string.
Definition: JPrint.hh:151
then for HISTOGRAM in h0 h1
Definition: JMatrixNZ.sh:69
static const std::string Location_t
Empty structure for specification of parser element that is initialised (i.e. does not require input)...
Definition: JParser.hh:66
Universal product identifier (UPI).
Definition: JUPI_t.hh:29
Dynamic ROOT object management.
Auxiliary data structure for floating point format specification.
Definition: JManip.hh:445
Auxiliary class for specifying selection of database data.
string outputFile
then set_variable FORMULA *[0] exp(-0.5 *(x-[1])*(x-[1])/([2]*[2]))*exp(-0.5 *(y-[1])*(y-[1])/([2]*[2]))" JF2 -o $WORKDIR/f2.root -F "$FORMULA" -@ "p0
Data structure for detector geometry and calibration.
then echo The file $DIR KM3NeT_00000001_00000000 root already please rename or remove it first
#define MAKE_STRING(A)
Make string.
Definition: JPrint.hh:142
static const std::string FITTOT_SUFFIX
Definition: JFitToT.hh:37
Auxiliary data structure for alignment of data.
Definition: JManip.hh:365
JDetectorsHelper getDetector
Function object for mapping serial number to object identifier of detector and vice versa...
Definition: JDBToolkit.cc:5
Auxiliary class to manage set of compatible ROOT objects (e.g. histograms) using unique keys...
Definition: JManager.hh:43
I/O formatting auxiliaries.
Detector file.
Definition: JHead.hh:196
static const char FITTOT_SEPARATOR
Definition: JFitToT.hh:36
Logical location of module.
Definition: JLocation.hh:37
Auxiliary data structure for location of product in detector.
Map list.
Definition: JMapList.hh:24
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition: JParser.hh:1961
return result
Definition: JPolint.hh:727
ROOT I/O of application specific meta data.
#define NOTICE(A)
Definition: JMessage.hh:64
static const std::string Test_t
int debug
debug level
Definition: JSirene.cc:63
const double NOMINAL_GAIN
Specification for normalized gain corresponding to a one photo-electron pulse.
General purpose messaging.
Auxiliary data structure for sequence of same character.
Definition: JManip.hh:327
#define FATAL(A)
Definition: JMessage.hh:67
then echo n User name
Definition: JCookie.sh:45
then $JPP_DIR examples JDetector JToT o $OUTPUT_FILE n N $NPE P gain
Definition: JToT.sh:45
void reset(T &value)
Reset value.
int position
position in floor
static const std::string EndTime_t
void load(const std::string &file_name, JDetector &detector)
Load detector from input file.
Auxililary class to get date and time.
Utility class to parse command line options.
Data structure for PMT high-voltage calibration.
nlohmann::json json
static const std::string Type_t
std::string to_string(const T &value)
Convert value to string.
ResultSet & getResultSet(const std::string &query)
Get result set.
Definition: JDB.hh:269
static const std::string StartTime_t
static const std::string User_t
Detector calibration key words for JSON I/O.
JUPIHelper getUPI
Function object for mapping PBS and serial number to UPI.
Definition: JDBToolkit.cc:7
System time information.
do set_variable DETECTOR_TXT $WORKDIR detector
Template definition for getting table specific selector.
static const std::string FITTOT_FNAME
Definition: JFitToT.hh:38
Multidimensional map.
Definition: JMultiMap.hh:51
bool putObject(TDirectory *dir, const T &object)
Write object to ROOT directory.
int main(int argc, char *argv[])
Definition: Main.cpp:15