CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/DetectorDescription/ExprAlgo/src/ClhepEvaluator.cc

Go to the documentation of this file.
00001 #include <iostream>
00002 #include "DetectorDescription/ExprAlgo/interface/ClhepEvaluator.h"
00003 #include "DetectorDescription/Base/interface/DDException.h"
00004 #include "DetectorDescription/Base/interface/DDdebug.h"
00005 
00006 ClhepEvaluator::ClhepEvaluator()
00007 { 
00008   // enable standard mathematical funtions
00009   evaluator_.setStdMath();
00010   
00011   // set Geant4 compatible units
00012   evaluator_.setSystemOfUnits(1.e+3, 1./1.60217733e-25, 1.e+9, 1./1.60217733e-10,
00013                               1.0, 1.0, 1.0);
00014 
00015   // set some global vars, which are in fact known by Clhep::SystemOfUnits
00016   // but are NOT set in CLHEP::Evaluator ...
00017   evaluator_.setVariable("mum","1.e-3*mm");
00018   evaluator_.setVariable("fm","1.e-15*meter");                                                
00019 }
00020   
00021   
00022 ClhepEvaluator::~ClhepEvaluator()
00023 { 
00024   clear();
00025 }
00026 
00027 void dd_exchange_value(std::vector<std::string> & vars, std::vector<std::string> & vals, 
00028   const std::string & var, const std::string & val)
00029 {
00030    std::vector<std::string>::iterator it(vars.begin()), ed(vars.end());
00031    std::vector<std::string>::size_type count(0);
00032    for (; it != ed; ++it) {
00033       if ( *it == var) {
00034          // a potential memory leak below! But CLHEP::Evaluator should take care about it!!
00035          vals[count] = val;
00036          break;
00037       }
00038       ++count;
00039    }
00040 } 
00041       
00042   
00043 void ClhepEvaluator::set(const std::string & ns, const std::string & name, const std::string & exprValue)
00044 {
00045    checkname(ns); // fancy characters in ns or name ??
00046    checkname(name);
00047    std::string newVar;
00048    std::string newVal;
00049    prepare(ns,name,exprValue,newVar,newVal);
00050    DCOUT_V('C', "ClhepEvaluator: " 
00051         << "  in: " << ns << " " << name << " " << exprValue 
00052         << "  pr: " << newVar << " " << newVal);
00053    //set(newVar,newVal);
00054    evaluator_.setVariable(newVar.c_str(), newVal.c_str());
00055    switch(evaluator_.status()) {
00056     case HepTool::Evaluator::WARNING_EXISTING_VARIABLE:
00057       dd_exchange_value(variables_,values_,newVar,newVal);
00058       break;
00059     case HepTool::Evaluator::OK:
00060     case HepTool::Evaluator::WARNING_EXISTING_FUNCTION:
00061     case HepTool::Evaluator::WARNING_BLANK_STRING:
00062       variables_.push_back(newVar);
00063       values_.push_back(newVal);
00064       break;
00065     default:
00066       std::cout << "set-var: ns=" << ns << " nm=" << name << " val=" << exprValue << std::endl;
00067       evaluator_.print_error();
00068       throwex(ns,name,exprValue,"can't set parameter !");
00069     }
00070 }
00071   
00072 void ClhepEvaluator::set(const std::string & n, const std::string & v)
00073 {
00074   evaluator_.setVariable(n.c_str(),v.c_str());
00075    switch(evaluator_.status()) {
00076     case HepTool::Evaluator::WARNING_EXISTING_VARIABLE:
00077       dd_exchange_value(variables_,values_,n,v);
00078       break;
00079     case HepTool::Evaluator::OK:
00080     case HepTool::Evaluator::WARNING_EXISTING_FUNCTION:
00081     case HepTool::Evaluator::WARNING_BLANK_STRING:
00082       variables_.push_back(n);
00083       values_.push_back(v);
00084       break;
00085     default:
00086       std::cout << "set-varname=" << n << " val=" << v << std::endl;
00087       evaluator_.print_error();
00088       throwex("",n,v,"can't set parameter !");
00089     }  
00090 }
00091 
00092         
00093 double ClhepEvaluator::eval(const std::string & ns, const std::string & expr)
00094 {
00095 
00096    // eval does not store std::strings in the values_!
00097    // eval throws if it can't evaluate!
00098    std::string pseudo("(evaluating)");
00099    std::string prepared;
00100    
00101    prepare(ns,pseudo,expr, pseudo,prepared);
00102    
00103    double result = evaluator_.evaluate(prepared.c_str());
00104    if(evaluator_.status()!=HepTool::Evaluator::OK) {
00105       std::cout << "expr: " << prepared << std::endl;
00106       std::cout << "------";
00107       for (int i=0; i<evaluator_.error_position(); ++i) std::cout << "-";
00108       std::cout << "^" << std::endl;
00109       evaluator_.print_error();
00110       throwex(ns,prepared,expr,"can't evaluate: " + expr + std::string("!"));
00111     }
00112    
00113    return result;
00114 }
00115   
00116 double ClhepEvaluator::eval(const char * expression)
00117 {
00118    double result = evaluator_.evaluate(expression);
00119    if (evaluator_.status()!=HepTool::Evaluator::OK) {
00120       std::cout << "expr: " << expression << std::endl;
00121       std::cout << "------";
00122       for (int i=0; i<evaluator_.error_position(); ++i) std::cout << "-";
00123       std::cout << "^" << std::endl;
00124       evaluator_.print_error();
00125       throwex("",expression,"","can't evaluate: " + std::string(expression) + std::string("!"));   
00126    }
00127    return result;
00128 }
00129 
00130 bool ClhepEvaluator::isDefined(const std::string & ns, //< current namespace
00131                  const std::string & name //< name of the variable inside current namespace
00132                  ) 
00133 {
00134    std::string newVar; 
00135    std::string newVal;
00136    prepare(ns,name,"0", newVar,newVal);
00137    return evaluator_.findVariable(newVar.c_str());
00138 }                
00139  
00140   
00141 void ClhepEvaluator::clear()
00142 {
00143    // clear the dictionary
00144    evaluator_.clear();
00145    
00146    // clear the cache of values & variable-names   
00147    variables_.clear();
00148    values_.clear();
00149 }
00150 
00151 
00152 void ClhepEvaluator::prepare(const std::string & ns, 
00153                              const std::string & name, 
00154                              const std::string & exprValue,
00155                              std::string & nameResult, 
00156                              std::string & valResult) const
00157 {
00158    static const std::string sep("___"); // separator between ns and name
00159    // SOME SPAGHETTI CODE ...
00160    //  break it down into some addional member functions ... 
00161    
00162    // the name and namespaces are not checked for 'forbidden' symbols like [,],: ...
00163    nameResult = ns + sep + name;
00164    
00165    // scan the expression std::string and remove [ ], and insert the current namespace if it's missing
00166    std::string temp;
00167    
00168    // 2 pass for simplicity (which is NOT efficient ...)
00169    // pass 1: find variables without namespace, e.g. [abcd], and mark them
00170    // pass 2: remove [ ] & ( exchange ':' with '_' | add the namespace at marked variables )
00171    
00172    std::string::size_type sz = exprValue.size();
00173    std::string::size_type idx =0;
00174    bool insideBracket = false;
00175    bool nsFound = false;
00176    int varCount=0; // count the variables from 1,2,3,...
00177    std::vector<int> hasNs(1); // marked[i]=1 ... variable number i has a namespace attached with ':'
00178    
00179    while(idx<sz) {
00180      switch(exprValue[idx]) {
00181 
00182      case '[':     
00183        if (nsFound || insideBracket) { // oops, something went wrong. simply throw!
00184          throwex(ns,name,exprValue,
00185                  "found a ':' outside '[..]' , or too many '[' !",idx); 
00186        }
00187        insideBracket=true; 
00188        ++varCount;
00189        break;
00190      
00191      case ']':
00192        if (!insideBracket) {
00193          throwex(ns,name,exprValue,"too many ']' !",idx);
00194        }
00195        insideBracket=false;  
00196        if (nsFound) {
00197          nsFound=false; // reset
00198          hasNs.push_back(1);
00199        }
00200        else {
00201         hasNs.push_back(0);      
00202        }        
00203        break;
00204      
00205      case ':':
00206        if ( (!insideBracket) || nsFound ) { // oops, a namespace outside [] or a 2nd ':' inside []! !
00207          throwex(ns,name,exprValue,
00208                  "found a ':' outside '[..]' , or multiple ':' inside '[..]'",idx);
00209        }                 
00210        nsFound=true;
00211        break;  
00212      
00213      default:
00214       ;
00215      } // switch
00216      
00217      ++idx;
00218    } // while(sz)
00219    
00220    // status after pass 1 must be: every [ ] is closed and no ':' 
00221    if ( insideBracket || nsFound ) {
00222      throwex(ns,name,exprValue,
00223              "'[..]' not closed , or ':' outside of '[..]'",idx);
00224    }
00225    
00226    // Pass 2: now remove all '[' ']', replace ':' or add 'ns' + '_'
00227    //sz = exprValue.size();
00228    idx=0;
00229    varCount=0;
00230    //bool ommit = false;
00231    while (idx<sz) {
00232      switch(exprValue[idx]) {
00233      
00234      case '[':
00235        ++varCount;
00236        if ( !hasNs[varCount] ) {
00237          valResult = valResult + ns + sep;
00238        }         
00239        break;
00240      
00241      case ']':
00242        break;
00243      
00244      case ':':
00245        valResult = valResult + sep;
00246        break;  
00247        
00248      default:
00249        valResult = valResult + exprValue[idx];
00250      } // switch
00251    
00252      ++idx;
00253    } // while 
00254 }              
00255                
00256         
00257 
00258  void ClhepEvaluator::throwex(const std::string & ns, 
00259                               const std::string & name, 
00260                               const std::string & expr,
00261                               const std::string & reason,
00262                               int idx) const
00263 {
00264    std::string er = std::string("ClhepEvaluator ERROR: ") + reason + std::string("\n")
00265                    + std::string(" nmspace=") + ns 
00266                    + std::string("\n varname=") + name
00267                    + std::string("\n exp=") + expr
00268                    + std::string("\n  at=") + expr.substr(0,idx);
00269          throw DDException(er);    
00270 
00271 }                             
00272 
00273 
00274  void ClhepEvaluator::checkname(const std::string & s) const
00275  {
00276    // '['   ']'   ' '  ':'   are forbidden for names and namespaces of parameters
00277    std::string::size_type sz = s.size();
00278    while(sz) {
00279      --sz;
00280      //bool stop = false;
00281      switch (s[sz]) {
00282      case ']':
00283      case '[':
00284      case ' ':
00285      case ':':
00286      case '\n':
00287      case '\t':
00288     // case '.':
00289      case '&':
00290      case '*':
00291      case '+':
00292      case '-':
00293      case '/':
00294      case '^':
00295        std::string e = std::string("ClhepEvaluator ERROR: forbidden character '")
00296                 + s[sz] + std::string("' found in '") + s + std::string("' !");
00297        throw DDException(e);         
00298        break;  
00299      }
00300    }
00301  
00302  }
00303  
00304