/dev/trunk

To get this branch, use:
bzr branch http://darksoft.org/webbzr/dev/trunk

« back to all changes in this revision

Viewing changes to apps/csv2root/csv2root.cpp

  • Committer: Suren A. Chilingaryan
  • Date: 2008-04-02 10:23:22 UTC
  • Revision ID: csa@dside.dyndns.org-20080402102322-okib92sicg2dx3o3
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <unistd.h>
 
3
 
 
4
#include <iostream>
 
5
#include <vector>
 
6
#include <string>
 
7
 
 
8
#include <boost/program_options.hpp>
 
9
#include <boost/regex.hpp>
 
10
 
 
11
#include <boost/lambda/lambda.hpp>
 
12
#include <boost/lambda/bind.hpp>
 
13
 
 
14
#include <boost/date_time/posix_time/ptime.hpp>
 
15
#include <boost/date_time/local_time/local_time.hpp>
 
16
 
 
17
#include <TROOT.h>
 
18
#include <TFile.h>
 
19
#include <TSQLFile.h>
 
20
#include <TTree.h>
 
21
 
 
22
#include <TCanvas.h>
 
23
#include <TH2F.h>
 
24
#include <TGraph.h>
 
25
 
 
26
#include <boost/algorithm/string/trim.hpp>
 
27
 
 
28
#include "csv.hpp"
 
29
 
 
30
#define TIME_CORRECTION         788918400
 
31
#define SQL_MAXLENGTH           31
 
32
 
 
33
using namespace ds;
 
34
using namespace std;
 
35
using namespace boost;
 
36
using namespace boost::program_options;
 
37
using namespace boost::lambda;
 
38
 
 
39
TTree *get_tree(TFile *f, string &loggroup, time_t &latest) {
 
40
    TTree *t = (TTree*)gROOT->FindObject(loggroup.c_str());
 
41
    if (t) {
 
42
        unsigned long last_entry = t->GetEntries() - 1;
 
43
        if (last_entry != (unsigned long)-1) {
 
44
            ULong64_t roottime;
 
45
            t->SetBranchAddress("timestamp", &roottime);
 
46
            if (t->GetEntry(last_entry)) {
 
47
                latest = (roottime + TIME_CORRECTION);
 
48
                return t;
 
49
            }
 
50
            else throw string("Read request is failed");
 
51
        } else throw string("ROOT file is empty");
 
52
    } 
 
53
    throw string("Invalid ROOT file");
 
54
}
 
55
 
 
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_)");
 
59
 
 
60
    regex block_re(".*\\[([^\\[\\]]+)\\]$");
 
61
 
 
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);
 
64
    else
 
65
        name = regex_replace(name, ichars_re, ichars_replacement, boost::match_default | boost::format_all);
 
66
 
 
67
    if ((!fix_length)||(name.length() < SQL_MAXLENGTH)) return;
 
68
            
 
69
    if (channel) {
 
70
        smatch m;
 
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;
 
76
            else
 
77
                name = prefix;
 
78
        } else name = prefix;
 
79
    } else {
 
80
        name = name.substr(0, SQL_MAXLENGTH);
 
81
    }
 
82
}
 
83
 
 
84
void csv2root(TFile *f, string &loggroup, variables_map &vm) {
 
85
    time_t timestamp;
 
86
    time_t start;
 
87
    ULong64_t roottime;
 
88
    unsigned long period;
 
89
    
 
90
 
 
91
    std::size_t n_columns;
 
92
    vector<string> headers;
 
93
 
 
94
    CSV csv(std::cin);
 
95
    
 
96
    csv.get_headers(headers);
 
97
 
 
98
    n_columns = headers.size() - 1;
 
99
    if (n_columns <= 0) invalid_argument("Invalid format");
 
100
 
 
101
    typedef std::string (*re_replace_func)(const std::string& s, const regex& e, const std::string& fmt, match_flag_type flags);
 
102
 
 
103
    if (vm.count("db")) {
 
104
        for (size_t i = 0;i < n_columns; ++i) fix_name(headers[i+1], i+1, true, true);
 
105
    } else {
 
106
//      for_each(headers.begin(), headers.end(), _1 = bind(static_cast<re_replace_func>(&regex_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);
 
108
    }
 
109
 
 
110
 
 
111
    auto_ptr<double> column_ptr(new double[n_columns]);
 
112
    double *column = column_ptr.get();
 
113
 
 
114
    auto_ptr<TTree> tree_ptr;
 
115
    TTree *tree;
 
116
    
 
117
    if (vm.count("overwrite")) {
 
118
        start = 0;
 
119
        tree = NULL;
 
120
    } else {
 
121
        try {
 
122
            tree = get_tree(f, loggroup, start);
 
123
        } catch (...) {
 
124
            start = 0;
 
125
            tree = NULL;
 
126
        }
 
127
    }
 
128
    
 
129
    if (tree) {
 
130
        TBranch *b = tree->GetBranch("timestamp");
 
131
        b->SetAddress(&roottime);
 
132
        
 
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]);
 
136
        }
 
137
    } else {
 
138
        tree_ptr = auto_ptr<TTree>(new TTree(loggroup.c_str(), "ADEI Data"));
 
139
        tree = tree_ptr.get();
 
140
        
 
141
        if (vm.count("group")) tree->SetTitle(vm["group"].as<string>().c_str());
 
142
        
 
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");
 
146
        }
 
147
    }
 
148
 
 
149
    if (!csv.get_row(timestamp, n_columns, column)) return;
 
150
    
 
151
    time_t from = timestamp;
 
152
    do {        
 
153
        if (timestamp > start) {
 
154
            roottime = timestamp - TIME_CORRECTION; /* ROOT time starts at 1/1/95 */
 
155
            tree->Fill();
 
156
        }
 
157
    } while (csv.get_row(timestamp, n_columns, column));
 
158
    period = timestamp - from;
 
159
 
 
160
    tree->Write(0, TObject::kOverwrite); // We don't supply a file, the default is used
 
161
 
 
162
    if (vm.count("save-histograms")) {
 
163
        const char *time_format;
 
164
 
 
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";
 
172
        
 
173
        f->mkdir("Histograms");
 
174
        f->cd("Histograms");
 
175
        
 
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));
 
180
            
 
181
            tree->Draw((headers[i+1] + string(":timestamp>>") + hname).c_str(), "", "LIST"); /* cut, type[, number, from] */
 
182
            TGraph *gr = (TGraph*)gPad->GetPrimitive("Graph");
 
183
            if (gr) {
 
184
                gr->SetName(gname.c_str());
 
185
                gr->SetDrawOption("P LIST");
 
186
             } else
 
187
                throw("Can't find created graphic");
 
188
            
 
189
            TH2F *h = (TH2F*)gPad->GetPrimitive(hname.c_str());
 
190
            if (h) {
 
191
                h->GetXaxis()->SetTimeDisplay(1);
 
192
                h->GetXaxis()->SetTimeFormat(time_format);
 
193
            } else
 
194
                throw("Can't find created histogram");
 
195
    
 
196
            c.Write();
 
197
        }
 
198
        f->cd();
 
199
 
 
200
        if (vm.count("combined-histogram")) {
 
201
            TCanvas c("Combined Histogram");
 
202
    
 
203
            double min = 1E+10;
 
204
            double max = -1E+10;
 
205
            
 
206
            for (size_t i = 0; i < n_columns; i++) {
 
207
                if (i) {
 
208
                    tree->Draw((headers[i+1] + string(":timestamp")).c_str(), "", "P LIST SAME");
 
209
                } else {
 
210
                    tree->Draw((headers[i+1] + string(":timestamp>>combined_hist")).c_str(), "", "P LIST");
 
211
                }
 
212
    
 
213
                TGraph *gr = (TGraph*)gPad->GetPrimitive("Graph");
 
214
                if (!gr) throw("Can't find created graphic");
 
215
                
 
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);
 
223
 
 
224
                double cmin = gr->GetYaxis()->GetXmin();
 
225
                double cmax = gr->GetYaxis()->GetXmax();
 
226
                if (cmin < min) min = cmin;
 
227
                if (cmax > max) max = cmax;
 
228
            }
 
229
            
 
230
            TH2F *h = (TH2F*)gPad->GetPrimitive("combined_hist");
 
231
            if (!h) throw("Can't find created histogram");
 
232
                    
 
233
            h->GetXaxis()->SetTimeDisplay(1);
 
234
            h->GetXaxis()->SetTimeFormat(time_format);
 
235
            h->GetYaxis()->SetRangeUser((int)min, (int)max+1);
 
236
            c.Write();
 
237
        }
 
238
 
 
239
    }
 
240
}
 
241
 
 
242
 
 
243
int main(int argc, char *argv[]) {
 
244
    TFile *root_file;
 
245
    string loggroup;
 
246
    bool inquiry;
 
247
    
 
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")
 
258
    ;
 
259
 
 
260
    variables_map vm;
 
261
    
 
262
    try {
 
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;
 
267
        exit(1);
 
268
    }
 
269
    
 
270
    if (vm.count("help")) {
 
271
        cout << opts << endl;
 
272
        exit(0);
 
273
    }
 
274
 
 
275
    if ((vm.count("combined-histogram"))&&(!(vm.count("save-histograms")))) {
 
276
        vm.insert(make_pair("save-histograms", variable_value(any(string()), true)));
 
277
    }
 
278
 
 
279
    if (vm.count("inquiry-latest-data")) inquiry = 1;
 
280
    else inquiry = 0;
 
281
 
 
282
    if (vm.count("group")) {
 
283
        loggroup = vm["group"].as<string>();
 
284
        fix_name(loggroup, 0, true, false);
 
285
    } else 
 
286
        loggroup = string("ADEI");
 
287
 
 
288
    if (vm.count("db")) {
 
289
        string user;
 
290
        string pass;
 
291
 
 
292
        if (!vm.count("group")) {
 
293
            cerr << "ERROR: The group name should be specified" << endl;
 
294
            exit(2);
 
295
        }
 
296
        
 
297
        if ((!std::getline(cin, user, '\n'))||(!std::getline(cin, pass, '\n'))) {
 
298
            cerr << "ERROR: Can't parse user name and password" << endl;
 
299
            exit(3);
 
300
        }
 
301
 
 
302
        if (vm.count("save-histograms")) {
 
303
            cerr << opts << endl;
 
304
            cerr << "ERROR: Storage of histograms in database is not allowed" << endl;
 
305
            exit(4);
 
306
        }
 
307
 
 
308
        if (inquiry) 
 
309
            root_file = new TSQLFile(vm["db"].as<string>().c_str(), "READ", user.c_str(), pass.c_str());
 
310
        else
 
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;  
 
314
 
 
315
        FILE *f = fopen(vm["file"].as<string>().c_str(), "r");
 
316
        if (f) {
 
317
            existing = true;
 
318
            fclose(f);
 
319
        }
 
320
 
 
321
        f = fopen(vm["file"].as<string>().c_str(), "a+");
 
322
        if (f) {
 
323
            fclose(f);
 
324
            if (!existing) unlink(vm["file"].as<string>().c_str());
 
325
        } else {
 
326
            cerr << "ERROR: Can't access specified file" << endl;
 
327
            exit(5);
 
328
        }
 
329
 
 
330
        if (inquiry) 
 
331
            root_file = new TFile(vm["file"].as<string>().c_str(), "READ");
 
332
        else {
 
333
            if (vm.count("overwrite")) {
 
334
                root_file = new TFile(vm["file"].as<string>().c_str(), "RECREATE");
 
335
            } else {
 
336
                root_file = new TFile(vm["file"].as<string>().c_str(), "UPDATE");
 
337
 
 
338
                if (vm.count("save-histograms")) {
 
339
                    cerr << opts << endl;
 
340
                    cerr << "ERROR: You should enable overwrite mode in order to generate histograms" << endl;
 
341
                    exit(6);
 
342
                }
 
343
            }
 
344
        }
 
345
//      root_file.Open doesn't open file inside file pointer
 
346
//      root_file.Open(vm["file"].as<string>().c_str(), "UPDATE");
 
347
    } else {
 
348
        cerr << opts << endl;
 
349
        cerr << "ERROR: Please submit the temporary file name" << endl;
 
350
        exit(8);
 
351
    }
 
352
 
 
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;
 
357
            exit(9);
 
358
        }
 
359
    }
 
360
 
 
361
    if (inquiry) {
 
362
        if (vm.count("inquiry-latest-data")) {
 
363
            try {
 
364
                time_t t;
 
365
                get_tree(root_file, loggroup, t);
 
366
                cout << t << endl;
 
367
            } catch (string e) {
 
368
                cout << -1 << endl;
 
369
                cerr << e << endl;
 
370
            }
 
371
        }
 
372
    } else {
 
373
        try {
 
374
            csv2root(root_file, loggroup,  vm);
 
375
        } catch (char const *msg) {
 
376
            cerr << "ERROR: " << msg << endl;
 
377
        }
 
378
    }
 
379
 
 
380
    root_file->Close();
 
381
    delete root_file;
 
382
 
 
383
    return 0;
 
384
}