8
#include <boost/program_options.hpp>
9
#include <boost/regex.hpp>
11
#include <boost/lambda/lambda.hpp>
12
#include <boost/lambda/bind.hpp>
14
#include <boost/date_time/posix_time/ptime.hpp>
15
#include <boost/date_time/local_time/local_time.hpp>
26
#include <boost/algorithm/string/trim.hpp>
30
#define TIME_CORRECTION 788918400
31
#define SQL_MAXLENGTH 31
35
using namespace boost;
36
using namespace boost::program_options;
37
using namespace boost::lambda;
39
TTree *get_tree(TFile *f, string &loggroup, time_t &latest) {
40
TTree *t = (TTree*)gROOT->FindObject(loggroup.c_str());
42
unsigned long last_entry = t->GetEntries() - 1;
43
if (last_entry != (unsigned long)-1) {
45
t->SetBranchAddress("timestamp", &roottime);
46
if (t->GetEntry(last_entry)) {
47
latest = (roottime + TIME_CORRECTION);
50
else throw string("Read request is failed");
51
} else throw string("ROOT file is empty");
53
throw string("Invalid ROOT file");
56
void fix_name(string &name, size_t channel, bool fix_length = false, bool add_prefix = false) {
57
regex ichars_re("([(<{\\[])|([})>\\]])|([^\\w\\d_()<>{}\\[\\]])");
58
string ichars_replacement("(?1__)(?2__)(?3_)");
60
regex block_re(".*\\[([^\\[\\]]+)\\]$");
62
if ((add_prefix)&&(channel))
63
name = string("c") + lexical_cast<string>(channel) + string("_") + regex_replace(name, ichars_re, ichars_replacement, boost::match_default | boost::format_all);
65
name = regex_replace(name, ichars_re, ichars_replacement, boost::match_default | boost::format_all);
67
if ((!fix_length)||(name.length() < SQL_MAXLENGTH)) return;
71
string prefix = string("c") + lexical_cast<string>(channel);
72
if (regex_match(name, m, block_re)) {
73
string tmp = regex_replace(string(m[1].first, m[1].second), ichars_re, ichars_replacement, boost::match_default | boost::format_all);
74
if (tmp.length() < (SQL_MAXLENGTH - prefix.length() - 1))
75
name = prefix + string("_") + tmp;
80
name = name.substr(0, SQL_MAXLENGTH);
84
void csv2root(TFile *f, string &loggroup, variables_map &vm) {
91
std::size_t n_columns;
92
vector<string> headers;
96
csv.get_headers(headers);
98
n_columns = headers.size() - 1;
99
if (n_columns <= 0) invalid_argument("Invalid format");
101
typedef std::string (*re_replace_func)(const std::string& s, const regex& e, const std::string& fmt, match_flag_type flags);
103
if (vm.count("db")) {
104
for (size_t i = 0;i < n_columns; ++i) fix_name(headers[i+1], i+1, true, true);
106
// for_each(headers.begin(), headers.end(), _1 = bind(static_cast<re_replace_func>(®ex_replace<regex_traits<char>, char >), _1, ichars_re, ichars_replacement, boost::match_default | boost::format_all));
107
for (size_t i = 0;i < n_columns; ++i) fix_name(headers[i+1], i+1, false, true);
111
auto_ptr<double> column_ptr(new double[n_columns]);
112
double *column = column_ptr.get();
114
auto_ptr<TTree> tree_ptr;
117
if (vm.count("overwrite")) {
122
tree = get_tree(f, loggroup, start);
130
TBranch *b = tree->GetBranch("timestamp");
131
b->SetAddress(&roottime);
133
for (size_t i = 0;i < n_columns; ++i) {
134
TBranch *b = tree->GetBranch(headers[i+1].c_str());
135
b->SetAddress(&column[i]);
138
tree_ptr = auto_ptr<TTree>(new TTree(loggroup.c_str(), "ADEI Data"));
139
tree = tree_ptr.get();
141
if (vm.count("group")) tree->SetTitle(vm["group"].as<string>().c_str());
143
tree->Branch("timestamp", &roottime, "timestamp/l");
144
for (size_t i = 0;i < n_columns; ++i) {
145
tree->Branch(headers[i+1].c_str(), &column[i], "s1/D");
149
if (!csv.get_row(timestamp, n_columns, column)) return;
151
time_t from = timestamp;
153
if (timestamp > start) {
154
roottime = timestamp - TIME_CORRECTION; /* ROOT time starts at 1/1/95 */
157
} while (csv.get_row(timestamp, n_columns, column));
158
period = timestamp - from;
160
tree->Write(0, TObject::kOverwrite); // We don't supply a file, the default is used
162
if (vm.count("save-histograms")) {
163
const char *time_format;
165
if (period > 126144000) time_format = "%Y";
166
else if (period > 31536000) time_format = "%b %Y";
167
else if (period > 10368000) time_format = "%b";
168
else if (period > 345600) time_format = "%b %d";
169
else if (period > 86400) time_format = "%b %d-%H:%M";
170
else if (period > 1200) time_format = "%H:%M";
171
else time_format = "%H:%M:%S";
173
f->mkdir("Histograms");
176
for (size_t i = 0; i < n_columns; i++) {
177
TCanvas c(headers[i+1].c_str());
178
string hname("hist" + lexical_cast<string>(i));
179
string gname("graph" + lexical_cast<string>(i));
181
tree->Draw((headers[i+1] + string(":timestamp>>") + hname).c_str(), "", "LIST"); /* cut, type[, number, from] */
182
TGraph *gr = (TGraph*)gPad->GetPrimitive("Graph");
184
gr->SetName(gname.c_str());
185
gr->SetDrawOption("P LIST");
187
throw("Can't find created graphic");
189
TH2F *h = (TH2F*)gPad->GetPrimitive(hname.c_str());
191
h->GetXaxis()->SetTimeDisplay(1);
192
h->GetXaxis()->SetTimeFormat(time_format);
194
throw("Can't find created histogram");
200
if (vm.count("combined-histogram")) {
201
TCanvas c("Combined Histogram");
206
for (size_t i = 0; i < n_columns; i++) {
208
tree->Draw((headers[i+1] + string(":timestamp")).c_str(), "", "P LIST SAME");
210
tree->Draw((headers[i+1] + string(":timestamp>>combined_hist")).c_str(), "", "P LIST");
213
TGraph *gr = (TGraph*)gPad->GetPrimitive("Graph");
214
if (!gr) throw("Can't find created graphic");
216
gr->SetName(headers[i+1].c_str());
217
gr->SetDrawOption("P LIST");
218
gr->SetLineColor(i%14+2);
219
gr->SetMarkerColor(i%14+2);
220
// gr->SetMarkerStyle(20);
221
// gr->SetMarkerSize(1);
222
// gr->SetLineWidth(1);
224
double cmin = gr->GetYaxis()->GetXmin();
225
double cmax = gr->GetYaxis()->GetXmax();
226
if (cmin < min) min = cmin;
227
if (cmax > max) max = cmax;
230
TH2F *h = (TH2F*)gPad->GetPrimitive("combined_hist");
231
if (!h) throw("Can't find created histogram");
233
h->GetXaxis()->SetTimeDisplay(1);
234
h->GetXaxis()->SetTimeFormat(time_format);
235
h->GetYaxis()->SetRangeUser((int)min, (int)max+1);
243
int main(int argc, char *argv[]) {
248
options_description opts("options");
249
opts.add_options() /* returns operator() which handles next lines */
250
("help,h", "Usage info")
251
("file,f", program_options::value<string>(), "ROOT file to use")
252
("db,d", program_options::value<string>(), "Database to use")
253
("group,g", program_options::value<string>(), "ADEI LogGroup Name")
254
("overwrite,o", "Overwrite if file already exists")
255
("save-histograms,s", "Prepare and save histograms in ROOT file")
256
("combined-histogram,c", "Save additionaly combined histogram")
257
("inquiry-latest-data,i", "Output latest data available in the ROOT file")
263
store(parse_command_line(argc, argv, opts), vm);
264
} catch (boost::program_options::unknown_option &e) {
265
cerr << opts << endl;
266
cerr << "ERROR: " << e.what() << endl;
270
if (vm.count("help")) {
271
cout << opts << endl;
275
if ((vm.count("combined-histogram"))&&(!(vm.count("save-histograms")))) {
276
vm.insert(make_pair("save-histograms", variable_value(any(string()), true)));
279
if (vm.count("inquiry-latest-data")) inquiry = 1;
282
if (vm.count("group")) {
283
loggroup = vm["group"].as<string>();
284
fix_name(loggroup, 0, true, false);
286
loggroup = string("ADEI");
288
if (vm.count("db")) {
292
if (!vm.count("group")) {
293
cerr << "ERROR: The group name should be specified" << endl;
297
if ((!std::getline(cin, user, '\n'))||(!std::getline(cin, pass, '\n'))) {
298
cerr << "ERROR: Can't parse user name and password" << endl;
302
if (vm.count("save-histograms")) {
303
cerr << opts << endl;
304
cerr << "ERROR: Storage of histograms in database is not allowed" << endl;
309
root_file = new TSQLFile(vm["db"].as<string>().c_str(), "READ", user.c_str(), pass.c_str());
311
root_file = new TSQLFile(vm["db"].as<string>().c_str(), "UPDATE", user.c_str(), pass.c_str());
312
} else if (vm.count("file")) {
313
bool existing = false;
315
FILE *f = fopen(vm["file"].as<string>().c_str(), "r");
321
f = fopen(vm["file"].as<string>().c_str(), "a+");
324
if (!existing) unlink(vm["file"].as<string>().c_str());
326
cerr << "ERROR: Can't access specified file" << endl;
331
root_file = new TFile(vm["file"].as<string>().c_str(), "READ");
333
if (vm.count("overwrite")) {
334
root_file = new TFile(vm["file"].as<string>().c_str(), "RECREATE");
336
root_file = new TFile(vm["file"].as<string>().c_str(), "UPDATE");
338
if (vm.count("save-histograms")) {
339
cerr << opts << endl;
340
cerr << "ERROR: You should enable overwrite mode in order to generate histograms" << endl;
345
// root_file.Open doesn't open file inside file pointer
346
// root_file.Open(vm["file"].as<string>().c_str(), "UPDATE");
348
cerr << opts << endl;
349
cerr << "ERROR: Please submit the temporary file name" << endl;
353
if (vm.count("inquiry-latest-data")) {
354
if ((!vm.count("file"))&&(!vm.count("db"))) {
355
cerr << opts << endl;
356
cerr << "ERROR: The file or db option is mandatory" << endl;
362
if (vm.count("inquiry-latest-data")) {
365
get_tree(root_file, loggroup, t);
374
csv2root(root_file, loggroup, vm);
375
} catch (char const *msg) {
376
cerr << "ERROR: " << msg << endl;