Newer
Older
//*-- Author : Stephen A. Wood 10.02.2012
// THcParmList
//
// A THaVarList that holds parameters read from
// the legacy ENGINE parameter file format
//
#define INCLUDESTR "#include"
#include "TObjArray.h"
#include "TObjString.h"
#include "THcParmList.h"
#include "THaVar.h"
#include "THaFormula.h"
#include "TMath.h"
/* #incluce <algorithm> include <fstream> include <cstring> */
#include <iostream>
#include <fstream>
#include <cassert>
#include <cstdlib>
using namespace std;
Int_t fDebug = 1; // Keep this at one while we're working on the code
ClassImp(THcParmList)
THcParmList::THcParmList() : THaVarList()
{
TextList = new THaTextvars;
}
inline static bool IsComment( const string& s, string::size_type pos )
{
return ( pos != string::npos && pos < s.length() &&
(s[pos] == '#' || s[pos] == ';' || s.substr(pos,2) == "//") );
}
void THcParmList::Load( const char* fname, Int_t RunNumber )
// Read a CTP style parameter file.
//
// Parameter values and arrays of values are cached in a THaVarList
// and are available for use elsewhere in the analyzer.
// Text strings are saved in a THaTextvars list.
// Parameter files can contain "include" statements of the form
// #include "filename"
//
// If a run number is given, ignore input until a line with a matching
// run number or run number range is found. All parameters following
// the are read until a non matching run number or range is encountered.
static const char* const whtspc = " \t";
ifstream ifiles[100]; // Should use stack instead
Int_t nfiles=0;
ifiles[nfiles].open(fname);
if(ifiles[nfiles].is_open()) {
cout << nfiles << ": " << "Opened \"" << fname << "\"" << endl;
nfiles++;
}
if(!nfiles) {
static const char* const here = "THcParmList::LoadFromFile";
Error (here, "error opening parameter file %s",fname);
return; // Need a success argument returned
}
string line;
char varname[100];
Int_t InRunRange;
Stephen A. Wood
committed
Int_t currentindex = 0;
varname[0] = '\0';
if(RunNumber > 0) {
InRunRange = 0; // Wait until run number range matching RunNumber is found
cout << "Reading Parameters for run " << RunNumber << endl;
} else {
InRunRange = 1; // Interpret all lines
}
while(nfiles) {
string current_comment("");
// EJB_Note: existing_comment is never used.
// string existing_comment("");
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
string::size_type start, pos = 0;
if(!getline(ifiles[nfiles-1],line)) {
ifiles[nfiles-1].close();
nfiles--;
cout << nfiles << ": " << "Closed" << endl;
continue;
}
// Look for include statement
if(line.compare(0,strlen(INCLUDESTR),INCLUDESTR)==0) {
line.erase(0,strlen(INCLUDESTR));
pos = line.find_first_not_of(whtspc);
// Strip leading white space
if(pos != string::npos && pos > 0 && pos < line.length()) {
line.erase(0,pos);
}
char quotechar=line[0];
if(quotechar == '"' || quotechar == '\'') {
line.erase(0,1);
line.erase(line.find_first_of(quotechar));
} else {
line.erase(line.find_first_of(whtspc));
}
cout << line << endl;
ifiles[nfiles].open(line.c_str());
if(ifiles[nfiles].is_open()) {
cout << nfiles << ": " << "Opened \"" << line << "\"" << endl;
nfiles++;
}
continue;
}
// Blank line or comment?
if( line.empty()
|| (start = line.find_first_not_of( whtspc )) == string::npos
|| IsComment(line, start) )
continue;
// Get rid of trailing comments and leading and trailing whitespace
// Need to save the comment and put it in the thVar
while( (pos = line.find_first_of("#;/", pos+1)) != string::npos ) {
if( IsComment(line, pos) ) {
current_comment.assign(line,pos+1,line.length());
line.erase(pos); // Strip off comment
// Strip leading white space from comment
cout << "CommentA: " << current_comment << endl;
pos = current_comment.find_first_not_of(whtspc);
if(pos!=string::npos && pos > 0 && pos < current_comment.length()) {
current_comment.erase(0,pos);
}
cout << "CommentB: " << current_comment << endl;
break;
}
}
pos = line.find_last_not_of( whtspc );
assert( pos != string::npos );
if( pos != string::npos && ++pos < line.length() )
line.erase(pos);
pos = line.find_first_not_of(whtspc);
// Strip leading white space
if(pos != string::npos && pos > 0 && pos < line.length()) {
line.erase(0,pos);
}
// Ignore begin and end statements
if(line.compare(0,5,"begin")==0 ||
line.compare(0,3,"end")==0) {
cout << "Skipping: " << line << endl;
continue;
}
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
// Get rid of all white space not in quotes
// Step through one char at a time
pos = 0;
int inquote=0;
char quotechar=' ';
// cout << "Unstripped line: |" << line << "|" << endl;
while(pos<line.length()) {
if(inquote) {
if(line[pos++] == quotechar) { // Possibly end of quoted string
if(line[pos] == quotechar) { // Protected quote
pos++; // Skip the protected quote
} else { // End of quoted string
inquote = 0;
quotechar = ' ';
pos++;
}
}
} else {
if(line[pos] == ' ' || line[pos] == '\t') {
line.erase(pos,1);
} else if(line[pos] == '"' || line[pos] == '\'') {
quotechar = line[pos++];\
inquote = 1;
} else {
pos++;
}
}
// cout << "Stripped line: |" << line << "|" << endl;
// Need to do something to bug out if line is empty
// If in Engine database mode, check if line is a number range AAAA-BBBB
if(RunNumber>0) {
if(line.find_first_not_of("0123456789-")==string::npos) { // Interpret as runnum range
if( (pos=line.find_first_of("-")) != string::npos) {
Int_t RangeStart=atoi(line.substr(0,pos).c_str());
Int_t RangeEnd=atoi(line.substr(pos+1,string::npos).c_str());
if(RunNumber >= RangeStart && RunNumber <= RangeEnd) {
InRunRange = 1;
} else {
InRunRange = 0;
}
} else { // A single number. Run
if(atoi(line.c_str()) == RunNumber) {
InRunRange = 1;
} else {
InRunRange = 0;
}
}
}
}
if(!InRunRange) continue;
// Interpret left of = as var name
Int_t valuestartpos=0; // Stays zero if no = found
Int_t ttype = 0; // Are any of the values floating point?
if((pos=line.find_first_of("="))!=string::npos) {
strcpy(varname, (line.substr(0,pos)).c_str());
valuestartpos = pos+1;
Stephen A. Wood
committed
currentindex = 0;
// If first char after = is a quote, then this is a string assignment
if(line[valuestartpos] == '"' || line[valuestartpos] == '\'') {
quotechar = line[valuestartpos++];
// Scan until end of line or terminating quote
// valuestartpos++;
pos = valuestartpos;
while(pos<line.length()) {
if(line[pos++] == quotechar) { // Possibly end of quoted string
if(line[pos] == quotechar) { // Protected quote
pos++;
} else {
pos--;
break;
}
}
}
if(TextList) {
// Should check that a numerical assignment doesn't exist, but for
// now, the same variable name can be used for strings and numbers
string varnames(varname);
AddString(varnames, line.substr(valuestartpos,pos-valuestartpos));
}
continue;
}
TString values((line.substr(valuestartpos)).c_str());
TObjArray *vararr = values.Tokenize(",");
Int_t nvals = vararr->GetLast()+1;
Int_t* ip;
Double_t* fp;
// or expressions
for(Int_t i=0;(ttype==0&&i<nvals);i++) {
TString valstr = ((TObjString *)vararr->At(i))->GetString();
if(valstr.IsFloat()) { // Is a number
if(valstr.Contains(".") || valstr.Contains("e",TString::kIgnoreCase)) {
ttype = 1;
break;
}
} else {
ttype = 2; // Force float if expression or Var
break;
}
}
Stephen A. Wood
committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// New pseudo code
// currentindex = where next item goes
// nvals = number of new items on line
// newlength = curentindex+nvals
// if (variable already exists) (valuestartpos is 0 or a find succeeded)
// get existinglegnth
// if (existinglength > newlength && type doesn't change) {
// copy nvals values directly into array
// else
// make new longer array of length max(existinglength, newlength)
// copy existinglength values into longer array changing type if needed
// delete old varname
// recreate varname of proper length
// else (variable doesn't exist)
// make array of newlength
// create varname
//
// There is some code duplication here. Refactor later
Int_t newlength = currentindex + nvals;
THaVar* existingvar=Find(varname);
if(existingvar) {
string existingcomment;
existingcomment.assign(existingvar->GetTitle());
if(!existingcomment.empty()) {
current_comment.assign(existingcomment);
}
Int_t existingtype=existingvar->GetType();
Int_t existinglength=existingvar->GetLen();
if(newlength > existinglength ||
(existingtype == kInt && ttype > 0)) { // Length or type change needed
if(newlength < existinglength) newlength = existinglength;
Int_t newtype=-1;
if(ttype>0 || existingtype == kDouble) {
Stephen A. Wood
committed
newtype = kDouble;
fp = new Double_t[newlength];
if(existingtype == kDouble) {
Double_t* existingp= (Double_t*) existingvar->GetValuePointer();
for(Int_t i=0;i<existinglength;i++) {
fp[i] = existingp[i];
}
} else if(existingtype == kInt) {
Int_t* existingp= (Int_t*) existingvar->GetValuePointer();
for(Int_t i=0;i<existinglength;i++) {
fp[i] = existingp[i];
}
} else {
cout << "Whoops!" << endl;
}
} else if(existingtype == kInt) { // Stays int
Stephen A. Wood
committed
newtype = kInt;
ip = new Int_t[newlength];
Int_t* existingp= (Int_t*) existingvar->GetValuePointer();
for(Int_t i=0;i<existinglength;i++) {
ip[i] = existingp[i];
}
} else {
cout << "Whoops!" << endl;
}
Stephen A. Wood
committed
// Now copy new values in
for(Int_t i=0;i<nvals;i++) {
TString valstr = ((TObjString *)vararr->At(i))->GetString();
if(newtype == kInt) {
ip[currentindex+i] = valstr.Atoi();
} else {
if(valstr.IsFloat()) {
fp[currentindex+i] = valstr.Atof();
} else {
THaFormula* formula = new THaFormula("temp",valstr.Data()
,this, 0);
fp[currentindex+i] = formula->Eval();
delete formula;
}
}
}
currentindex += nvals;
// Remove old variable and recreate
RemoveName(varname);
Stephen A. Wood
committed
char *arrayname=new char [strlen(varname)+20];
sprintf(arrayname,"%s[%d]",varname,newlength);
if(newtype == kInt) {
Define(arrayname, current_comment.c_str(), *ip);
Stephen A. Wood
committed
Define(arrayname, current_comment.c_str(), *fp);
Stephen A. Wood
committed
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
delete[] arrayname;
} else {
// Existing array long enough and of right type, just copy to it.
if(ttype == 0 && existingtype == kInt) {
Int_t* existingp= (Int_t*) existingvar->GetValuePointer();
for(Int_t i=0;i<nvals;i++) {
TString valstr = ((TObjString *)vararr->At(i))->GetString();
existingp[currentindex+i] = valstr.Atoi();
}
} else {
Double_t* existingp= (Double_t*) existingvar->GetValuePointer();
for(Int_t i=0;i<nvals;i++) {
TString valstr = ((TObjString *)vararr->At(i))->GetString();
if(valstr.IsFloat()) {
existingp[currentindex+i] = valstr.Atof();
} else {
THaFormula* formula = new THaFormula("temp",valstr.Data()
,this, 0);
existingp[currentindex+i] = formula->Eval();
delete formula;
}
}
}
currentindex += nvals;
}
} else {
if(currentindex !=0) {
cout << "currentindex=" << currentindex << " shouldn't be!" << endl;
}
if(ttype==0) {
ip = new Int_t[nvals];
} else {
fp = new Double_t[nvals];
}
for(Int_t i=0;i<nvals;i++) {
TString valstr = ((TObjString *)vararr->At(i))->GetString();
if(ttype==0) {
Stephen A. Wood
committed
ip[i] = valstr.Atoi();
} else {
if(valstr.IsFloat()) {
Stephen A. Wood
committed
fp[i] = valstr.Atof();
} else {
THaFormula* formula = new THaFormula("temp",valstr.Data()
,this, 0);
Stephen A. Wood
committed
fp[i] = formula->Eval();
delete formula;
}
}
}
Stephen A. Wood
committed
currentindex = nvals;
char *arrayname=new char [strlen(varname)+20];
Stephen A. Wood
committed
sprintf(arrayname,"%s[%d]",varname,nvals);
if(ttype==0) {
Define(arrayname, current_comment.c_str(), *ip);
} else {
Define(arrayname, current_comment.c_str(), *fp);
}
delete[] arrayname;
}
// cout << line << endl;
}
return;
}
//_____________________________________________________________________________
Int_t THcParmList::LoadParmValues(const DBRequest* list, const char* prefix)
{
// Load a number of entries from the database.
// For array entries, the number of elements to be read in
// must be given, and the memory already allocated
// NOTE: initial code taken wholesale from THaDBFile.
// GN 2012
// If prefix is specified, prepend each requested parameter name with
// the prefix.
const DBRequest *ti = list;
Int_t cnt=0;
Int_t this_cnt=0;
if( !prefix ) prefix = "";
while ( ti && ti->name ) {
string keystr(prefix); keystr.append(ti->name);
const char* key = keystr.c_str();
/// cout <<"Now at "<<ti->name<<endl;
this_cnt = 0;
if(this->Find(key)) {
VarType ty = this->Find(key)->GetType();
if (ti->nelem>1) {
// it is an array, use the appropriateinterface
switch (ti->type) {
case (kDouble) :
this_cnt = GetArray(key,static_cast<Double_t*>(ti->var),ti->nelem);
break;
case (kInt) :
this_cnt = GetArray(key,static_cast<Int_t*>(ti->var),ti->nelem);
break;
default:
Error("THcParmList","Invalid type to read %s",key);
break;
}
} else {
switch (ti->type) {
case (kDouble) :
if(ty == kInt) {
*static_cast<Double_t*>(ti->var)=*(Int_t *)this->Find(key)->GetValuePointer();
} else if (ty == kDouble) {
*static_cast<Double_t*>(ti->var)=*(Double_t *)this->Find(key)->GetValuePointer();
} else {
cout << "*** ERROR!!! Type Mismatch " << key << endl;
}
this_cnt=1;
break;
case (kInt) :
if(ty == kInt) {
*static_cast<Int_t*>(ti->var)=*(Int_t *)this->Find(key)->GetValuePointer();
} else if (ty == kDouble) {
*static_cast<Int_t*>(ti->var)=TMath::Nint(*(Double_t *)this->Find(key)->GetValuePointer());
cout << "*** WARNING!!! Rounded " << key << " to nearest integer " << endl;
} else {
cout << "*** ERROR!!! Type Mismatch " << key << endl;
}
this_cnt=1;
break;
default:
Error("THcParmList","Invalid type to read %s",key);
break;
}
}
} else { // See if it is a text variable
const char* value = GetString(key);
if(value) {
this_cnt = 1;
if(ti->type == kString) {
*((string*)ti->var) = string(value);
} else if (ti->type == kTString) {
*((TString*)ti->var) = (TString) value;
} else {
Error("THcParmList","No conversion for strings: %s",key);
}
}
}
if (this_cnt<=0) {
if ( !ti->optional ) {
Fatal("THcParmList","Could not find %s in database!",key);
}
}
cnt += this_cnt;
ti++;
}
return cnt;
}
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
// READING AN ARRAY INTO A C-style ARRAY
//_____________________________________________________________________________
Int_t THcParmList::GetArray(const char* attr, Int_t* array, Int_t size)
{
// Read in a set of Int_t's in to a C-style array.
return ReadArray(attr,array,size);
}
//_____________________________________________________________________________
Int_t THcParmList::GetArray(const char* attr, Double_t* array, Int_t size)
{
// Read in a set of Double_t's in to a vector.
return ReadArray(attr,array,size);
}
//_____________________________________________________________________________
template<class T>
Int_t THcParmList::ReadArray(const char* attrC, T* array, Int_t size)
{
// Copy values from parameter store to array
// No resizing is done, so only 'size' elements may be stored.
Int_t cnt=0;
THaVar *var = Find(attrC);
if(!var) return(cnt);
VarType ty = var->GetType();
if( ty != kInt && ty != kDouble) {
cout << "*** ERROR: " << attrC << " has unsupported type " << ty << endl;
return(cnt);
}
Int_t sz = var->GetLen();
const void *vp = var->GetValuePointer();
if(size != sz) {
cout << "*** WARNING: requested " << size << " elements of " << attrC <<
" which has length " << sz << endl;
}
if(size<sz) sz = size;
Int_t donint = 0;
if(ty == kDouble && typeid(array[0]) == typeid(Int_t)) {
donint = 1; // Use nint when putting doubles in nint
cout << "*** WARNING!!! Rounded " << attrC << " elements to nearest integer " << endl;
}
for(cnt=0;cnt<sz;cnt++) {
if(ty == kInt) {
array[cnt] = ((Int_t*)vp)[cnt];
} else
if(donint) {
array[cnt] = TMath::Nint(((Double_t*)vp)[cnt]);
} else {
array[cnt] = ((Double_t*)vp)[cnt];
}
}
return(cnt);
}
//_____________________________________________________________________________
void THcParmList::PrintFull( Option_t* option ) const
{
// Print all the numeric parameter desciptions and values.
// Print all the text parameters
THaVarList::PrintFull(option);
TextList->Print();
}
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
#ifdef WITH_CCDB
//_____________________________________________________________________________
Int_t THcParmList::OpenCCDB(Int_t runnum)
{
// Use the Environment variable "CCDB_CONNECTION" as the
// connection string
const char* connection_string = gSystem->Getenv("CCDB_CONNECTION");
return(OpenCCDB(runnum,connection_string));
}
Int_t THcParmList::OpenCCDB(Int_t runnum, const char* connection_string)
{
// Connect to a CCDB database pointed to by connection_string
std::string s (connection_string);
CCDB_obj = new SQLiteCalibration(runnum);
Int_t result = CCDB_obj->Connect(s);
if(!result) return -1; // Need some error codes
cout << "Opened " << s << " for run " << runnum << endl;
return 0;
}
Int_t THcParmList::CloseCCDB()
{
delete CCDB_obj;
return(0);
}
Int_t THcParmList::LoadCCDBDirectory(const char* directory,
const char* prefix)
{
// Load all parameters in directory
// Prepend prefix onto the name of each
std::string dirname (directory);
if(dirname[dirname.length()-1]!='/') {
dirname.append("/");
}
Int_t dirlen=dirname.length();
vector<string> namepaths;
CCDB_obj->GetListOfNamepaths(namepaths);
for(UInt_t iname=0;iname<namepaths.size();iname++) {
std::string varname (namepaths[iname]);
if(varname.compare(0,dirlen,dirname) == 0) {
varname.replace(0,dirlen,prefix);
// cout << namepaths[iname] << " -> " << varname << endl;
// To what extent is there duplication here with Load() method?
// Retrieve the data as floats
vector<vector<double> > data;
CCDB_obj->GetCalib(data, namepaths[iname]);
for(UInt_t row=0; row<data.size(); row++) {
for(UInt_t col=0;col<data[0].size(); col++) {
cout << data[row][col] << "\t";
}
cout << endl;
}
if(data[0].size()==1) { // Only handle single column tables
// Could stuff 2d arrays in, and assume that the application knows
// the number of columns. Then the matrix stuff would just need to
// see if the variable exists, then copy the data into the right kind
// of structure instead of reading from the recon files.
THaVar* existingvar=Find(varname.c_str());
if(existingvar) {
// Does the array of data need to deleted too?
RemoveName(varname.c_str());
}
Double_t* fp = new Double_t[data.size()];
for(UInt_t row=0;row<data.size(); row++) {
fp[row] = data[row][0];
}
// Need to append [size] to end of varname
char sizestring[20];
sprintf(sizestring,"[%d]",(Int_t) data.size());
std::string size_str (sizestring);
varname.append(size_str);
Define(varname.c_str(), "comment", *fp);
}
}
}
return 0;
}
#endif