Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:54:56

0001 #include <ext/alloc_traits.h>
0002 #include <iostream>
0003 #include <string>
0004 #include <vector>
0005 
0006 #include "CLHEP/Evaluator/Evaluator.h"
0007 #include "DetectorDescription/Core/interface/ClhepEvaluator.h"
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009 #include "FWCore/Utilities/interface/Exception.h"
0010 
0011 ClhepEvaluator::ClhepEvaluator() {
0012   // enable standard mathematical funtions
0013   evaluator_.setStdMath();
0014 
0015   // set Geant4 compatible units
0016   evaluator_.setSystemOfUnits(1.e+3, 1. / 1.60217733e-25, 1.e+9, 1. / 1.60217733e-10, 1.0, 1.0, 1.0);
0017 
0018   // set some global vars, which are in fact known by Clhep::SystemOfUnits
0019   // but are NOT set in CLHEP::Evaluator ...
0020   evaluator_.setVariable("mum", "1.e-3*mm");
0021   evaluator_.setVariable("fm", "1.e-15*meter");
0022 }
0023 
0024 ClhepEvaluator::~ClhepEvaluator() { clear(); }
0025 
0026 void dd_exchange_value(std::vector<std::string>& vars,
0027                        std::vector<std::string>& vals,
0028                        const std::string& var,
0029                        const std::string& val) {
0030   std::vector<std::string>::iterator it(vars.begin()), ed(vars.end());
0031   std::vector<std::string>::size_type count(0);
0032   for (; it != ed; ++it) {
0033     if (*it == var) {
0034       // a potential memory leak below! But CLHEP::Evaluator should take care about it!!
0035       vals[count] = val;
0036       break;
0037     }
0038     ++count;
0039   }
0040 }
0041 
0042 void ClhepEvaluator::set(const std::string& ns, const std::string& name, const std::string& exprValue) {
0043   checkname(ns);  // fancy characters in ns or name ??
0044   checkname(name);
0045   std::string newVar;
0046   std::string newVal;
0047   prepare(ns, name, exprValue, newVar, newVal);
0048   evaluator_.setVariable(newVar.c_str(), newVal.c_str());
0049   switch (evaluator_.status()) {
0050     case HepTool::Evaluator::WARNING_EXISTING_VARIABLE:
0051       dd_exchange_value(variables_, values_, newVar, newVal);
0052       break;
0053     case HepTool::Evaluator::OK:
0054     case HepTool::Evaluator::WARNING_EXISTING_FUNCTION:
0055     case HepTool::Evaluator::WARNING_BLANK_STRING:
0056       variables_.emplace_back(newVar);
0057       values_.emplace_back(newVal);
0058       break;
0059     default:
0060       std::cout << "set-var: ns=" << ns << " nm=" << name << " val=" << exprValue << std::endl;
0061       evaluator_.print_error();
0062       throwex(ns, name, exprValue, "can't set parameter !");
0063   }
0064 }
0065 
0066 void ClhepEvaluator::set(const std::string& n, const std::string& v) {
0067   evaluator_.setVariable(n.c_str(), v.c_str());
0068   switch (evaluator_.status()) {
0069     case HepTool::Evaluator::WARNING_EXISTING_VARIABLE:
0070       dd_exchange_value(variables_, values_, n, v);
0071       break;
0072     case HepTool::Evaluator::OK:
0073     case HepTool::Evaluator::WARNING_EXISTING_FUNCTION:
0074     case HepTool::Evaluator::WARNING_BLANK_STRING:
0075       variables_.emplace_back(n);
0076       values_.emplace_back(v);
0077       break;
0078     default:
0079       std::cout << "set-varname=" << n << " val=" << v << std::endl;
0080       evaluator_.print_error();
0081       throwex("", n, v, "can't set parameter !");
0082   }
0083 }
0084 
0085 double ClhepEvaluator::eval(const std::string& ns, const std::string& expr) {
0086   // eval does not store std::strings in the values_!
0087   // eval throws if it can't evaluate!
0088   std::string pseudo("(evaluating)");
0089   std::string prepared;
0090 
0091   prepare(ns, pseudo, expr, pseudo, prepared);
0092 
0093   double result = evaluator_.evaluate(prepared.c_str());
0094   if (evaluator_.status() != HepTool::Evaluator::OK) {
0095     std::cout << "expr: " << prepared << std::endl;
0096     std::cout << "------";
0097     for (int i = 0; i < evaluator_.error_position(); ++i)
0098       std::cout << "-";
0099     std::cout << "^" << std::endl;
0100     evaluator_.print_error();
0101     throwex(ns, prepared, expr, "can't evaluate: " + expr + std::string("!"));
0102   }
0103 
0104   return result;
0105 }
0106 
0107 double ClhepEvaluator::eval(const char* expression) {
0108   double result = evaluator_.evaluate(expression);
0109   if (evaluator_.status() != HepTool::Evaluator::OK) {
0110     std::cout << "expr: " << expression << std::endl;
0111     std::cout << "------";
0112     for (int i = 0; i < evaluator_.error_position(); ++i)
0113       std::cout << "-";
0114     std::cout << "^" << std::endl;
0115     evaluator_.print_error();
0116     throwex("", expression, "", "can't evaluate: " + std::string(expression) + std::string("!"));
0117   }
0118   return result;
0119 }
0120 
0121 bool ClhepEvaluator::isDefined(const std::string& ns,   //< current namespace
0122                                const std::string& name  //< name of the variable inside current namespace
0123 ) {
0124   std::string newVar;
0125   std::string newVal;
0126   prepare(ns, name, "0", newVar, newVal);
0127   return evaluator_.findVariable(newVar.c_str());
0128 }
0129 
0130 void ClhepEvaluator::clear() {
0131   // clear the dictionary
0132   evaluator_.clear();
0133 
0134   // clear the cache of values & variable-names
0135   variables_.clear();
0136   values_.clear();
0137 }
0138 
0139 void ClhepEvaluator::prepare(const std::string& ns,
0140                              const std::string& name,
0141                              const std::string& exprValue,
0142                              std::string& nameResult,
0143                              std::string& valResult) const {
0144   static const std::string sep("___");  // separator between ns and name
0145   // SOME SPAGHETTI CODE ...
0146   //  break it down into some addional member functions ...
0147 
0148   // the name and namespaces are not checked for 'forbidden' symbols like [,],: ...
0149   nameResult = ns + sep + name;
0150 
0151   // scan the expression std::string and remove [ ], and insert the current namespace if it's missing
0152   std::string temp;
0153 
0154   // 2 pass for simplicity (which is NOT efficient ...)
0155   // pass 1: find variables without namespace, e.g. [abcd], and mark them
0156   // pass 2: remove [ ] & ( exchange ':' with '_' | add the namespace at marked variables )
0157 
0158   std::string::size_type sz = exprValue.size();
0159   std::string::size_type idx = 0;
0160   bool insideBracket = false;
0161   bool nsFound = false;
0162   int varCount = 0;           // count the variables from 1,2,3,...
0163   std::vector<int> hasNs(1);  // marked[i]=1 ... variable number i has a namespace attached with ':'
0164 
0165   while (idx < sz) {
0166     switch (exprValue[idx]) {
0167       case '[':
0168         if (nsFound || insideBracket) {  // oops, something went wrong. simply throw!
0169           throwex(ns, name, exprValue, "found a ':' outside '[..]' , or too many '[' !", idx);
0170         }
0171         insideBracket = true;
0172         ++varCount;
0173         break;
0174       case ']':
0175         if (!insideBracket) {
0176           throwex(ns, name, exprValue, "too many ']' !", idx);
0177         }
0178         insideBracket = false;
0179         if (nsFound) {
0180           nsFound = false;  // reset
0181           hasNs.emplace_back(1);
0182         } else {
0183           hasNs.emplace_back(0);
0184         }
0185         break;
0186       case ':':
0187         if ((!insideBracket) || nsFound) {  // oops, a namespace outside [] or a 2nd ':' inside []! !
0188           throwex(ns, name, exprValue, "found a ':' outside '[..]' , or multiple ':' inside '[..]'", idx);
0189         }
0190         nsFound = true;
0191         break;
0192       default:;
0193     }  // switch
0194     ++idx;
0195   }  // while(sz)
0196 
0197   // status after pass 1 must be: every [ ] is closed and no ':'
0198   if (insideBracket || nsFound) {
0199     throwex(ns, name, exprValue, "'[..]' not closed , or ':' outside of '[..]'", idx);
0200   }
0201 
0202   // Pass 2: now remove all '[' ']', replace ':' or add 'ns' + '_'
0203   //sz = exprValue.size();
0204   idx = 0;
0205   varCount = 0;
0206   //bool ommit = false;
0207   while (idx < sz) {
0208     switch (exprValue[idx]) {
0209       case '[':
0210         ++varCount;
0211         if (!hasNs[varCount]) {
0212           valResult = valResult + ns + sep;
0213         }
0214         break;
0215       case ']':
0216         break;
0217       case ':':
0218         valResult = valResult + sep;
0219         break;
0220       default:
0221         valResult = valResult + exprValue[idx];
0222     }  // switch
0223     ++idx;
0224   }  // while
0225 }
0226 
0227 void ClhepEvaluator::throwex(
0228     const std::string& ns, const std::string& name, const std::string& expr, const std::string& reason, int idx) const {
0229   std::string er = std::string("ClhepEvaluator ERROR: ") + reason + std::string("\n") + std::string(" nmspace=") + ns +
0230                    std::string("\n varname=") + name + std::string("\n exp=") + expr + std::string("\n  at=") +
0231                    expr.substr(0, idx);
0232   throw cms::Exception("DDException") << er;
0233 }
0234 
0235 void ClhepEvaluator::checkname(const std::string& s) const {
0236   // '['   ']'   ' '  ':'   are forbidden for names and namespaces of parameters
0237   std::string::size_type sz = s.size();
0238   while (sz) {
0239     --sz;
0240     //bool stop = false;
0241     switch (s[sz]) {
0242       case ']':
0243       case '[':
0244       case ' ':
0245       case ':':
0246       case '\n':
0247       case '\t':
0248         // case '.':
0249       case '&':
0250       case '*':
0251       case '+':
0252       case '-':
0253       case '/':
0254       case '^':
0255         std::string e = std::string("ClhepEvaluator ERROR: forbidden character '") + s[sz] +
0256                         std::string("' found in '") + s + std::string("' !");
0257         throw cms::Exception("DDException") << e;
0258         break;
0259     }
0260   }
0261 }