CMS 3D CMS Logo

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