Skip to content
Snippets Groups Projects
THcParmList.cxx 16.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • //*-- 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"
    
    
    
    /* #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    
    
    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];
    
      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("");
    
        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;
        }
    
    
        // 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;
    
        // 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;
          }
        }
    
    
        // 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) {
    
    	  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
    
    	  Int_t* existingp= (Int_t*) existingvar->GetValuePointer();
    	  for(Int_t i=0;i<existinglength;i++) {
    	    ip[i] = existingp[i];
    	  }
    	} else {
    	  cout << "Whoops!" << endl;
    	}
    
    	// 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
    
    	char *arrayname=new char [strlen(varname)+20];
    	sprintf(arrayname,"%s[%d]",varname,newlength);
    	if(newtype == kInt) {
    	  Define(arrayname, current_comment.c_str(), *ip);
    
    	  Define(arrayname, current_comment.c_str(), *fp);
    
    	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) {
    
    	} else {
    	  if(valstr.IsFloat()) {
    
    	  } else {
    	    THaFormula* formula = new THaFormula("temp",valstr.Data()
    						 ,this, 0);
    
          char *arrayname=new char [strlen(varname)+20];
    
          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;
    
    
        string keystr(prefix); keystr.append(ti->name);
        const char* key = keystr.c_str();
    
        ///    cout <<"Now at "<<ti->name<<endl;
    
          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;
    	  }
    
    	  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);
    
    //  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];
          }
    
    //_____________________________________________________________________________
    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();
    }