BLEvaluator.hh

Go to the documentation of this file.
00001 //      BLEvaluator.hh
00002 
00003 #ifndef BLEVALUATOR_HH
00004 #define BLEVALUATOR_HH
00005 
00006 #include <stdio.h>
00007 #include <math.h>
00008 #include <string.h>
00009 #include <ctype.h>
00010 #include "CLHEP/Evaluator/Evaluator.h"
00011 //@#include <gsl/gsl_sys.h>
00012 
00013 #include "G4Track.hh"
00014 #include "G4RunManager.hh"
00015 #include "G4Event.hh"
00016 
00017 #include "BLAssert.hh"
00018 #include "BLCoordinates.hh"
00019 #include "BLGlobalField.hh"
00020 
00021 /** class BLEvaluator implements an expression evaluator.
00022  *
00023  *      Uses HepTool::Evaluator, but fixes up a few minor bugs:
00024  *              automatically calls setStdMath()
00025  *              adds floor(x) and ceil(x)
00026  *              fixes unary +/- by enclosing them in parens
00027  *
00028  *      NOTE: This is expensive, and should not be used during tracking unless
00029  *      unavoidable.
00030  **/
00031 class BLEvaluator : public HepTool::Evaluator {
00032 public:
00033         /// Constructor
00034         BLEvaluator() : HepTool::Evaluator() {
00035                 setSystemOfUnits(1.e+3, 1./1.60217733e-25, 1.e+9,
00036                                 1./1.60217733e-10, 1.0, 1.0, 1.0);
00037                 setStdMath();
00038                 setFunction("floor",floor);
00039                 setFunction("ceil",ceil);
00040         }
00041 
00042         /// evaluate() will evaluate the expression.
00043         /// returns NAN if the expression is not valid (use either isOK() or
00044         /// std::isnan(double) or gsl_isnan(double) to check).
00045         double evaluate(const char *expression) {
00046                 char out[1024];
00047                 BLAssert(strlen(expression) < sizeof(out));
00048                 // remove whitespace (simpler parsing below)
00049                 int j=0;
00050                 for(int i=0; expression[i]!='\0'; ++i)
00051                         if(!isspace(expression[i])) out[j++] = expression[i];
00052                 out[j] = '\0';
00053                 // Workaround for serious bug in HepTool::Evaluator --
00054                 // it can only handle a unary +/- after a '(', so
00055                 // put parens around unary +/-
00056                 bool again=false;
00057                 do {
00058                     again = false;
00059                     char *in = strdup(out);
00060                     j = 0;
00061                     char prev=' ';
00062                     for(int i=0; in[i]!='\0'; ++i) {
00063                         char c = in[i];
00064                         if((c == '-' || c == '+') && isopchar(prev)) {
00065                                 again = true;
00066                                 out[j++] = '(';
00067                                 out[j++] = c;
00068                                 ++i;
00069                                 int level = 0;
00070                                 while(isumchar(in[i]) || level > 0) {
00071                                     if(in[i] == '(')
00072                                         ++level;
00073                                     if(in[i] == ')')
00074                                         --level;
00075                                     // unary +/- after operator -- copy now,
00076                                     // handle during next loop (again = true)
00077                                     // (^ is the only op with higher precedence)
00078                                     if(in[i]=='^' && (in[i+1]=='-' ||
00079                                                                 in[i+1]=='+'))
00080                                         out[j++] = in[i++];
00081                                     out[j++] = in[i++];
00082                                 }
00083                                 c = ')';
00084                                 --i;
00085                         }
00086                         prev = out[j++] = c;
00087                     }
00088                     BLAssert((unsigned)j < sizeof(out));
00089                     out[j] = '\0';
00090                     // if empty or all whitespace, force invalid
00091                     if(j == 0) strcpy(out,"x+-*/y");
00092                     free(in);
00093                 } while(again);
00094 
00095                 double v = HepTool::Evaluator::evaluate(out);
00096                 if(status() != OK) v = std::numeric_limits<double>::quiet_NaN();
00097                 return v;
00098         }
00099 
00100         /// isOK() returns true if the previous call to expression succeeded.
00101         bool isOK() { return status() == OK; }
00102 
00103         /// setTrackVariables() devines variables in the evaluator
00104         /// corresponding to the usual track variables. These can then
00105         /// be used in expressions.
00106         void setTrackVariables(const G4Track *track, BLCoordinateType coordType,
00107                                         G4String suffix="", bool fields=false) {
00108                 G4RunManager* runmgr = G4RunManager::GetRunManager();
00109                 const G4Event* event = runmgr->GetCurrentEvent();
00110                 int evId = event->GetEventID();
00111                 G4ThreeVector position = track->GetPosition();
00112                 G4double time = track->GetGlobalTime();
00113                 G4ThreeVector momentum = track->GetMomentum();
00114 
00115                 // get B and E fields
00116                 G4ThreeVector B, E;
00117                 if(fields) {
00118                         G4double point[4], field[6];
00119                         point[0] = position[0];
00120                         point[1] = position[1];
00121                         point[2] = position[2];
00122                         point[3] = time;
00123                         BLGlobalField::getObject()->GetFieldValue(point,field);
00124                         B = G4ThreeVector(field[0],field[1],field[2]);
00125                         E = G4ThreeVector(field[3],field[4],field[5]);
00126                 }
00127 
00128                 // transform to desired coordinates, if available
00129                 BLCoordinates *c = (BLCoordinates *)track->GetUserInformation();
00130                 if(c && c->isValid()) {
00131                         c->getCoords(coordType,position);
00132                         momentum = c->getRotation() * momentum;
00133                         B = c->getRotation() * B;
00134                         E = c->getRotation() * E;
00135                 }
00136                 setVariable((G4String("x")+suffix).c_str(), position[0]/mm);
00137                 setVariable((G4String("y")+suffix).c_str(), position[1]/mm);
00138                 setVariable((G4String("z")+suffix).c_str(), position[2]/mm);
00139                 setVariable((G4String("Px")+suffix).c_str(), momentum[0]/MeV);
00140                 setVariable((G4String("Py")+suffix).c_str(), momentum[1]/MeV);
00141                 setVariable((G4String("Pz")+suffix).c_str(), momentum[2]/MeV);
00142                 setVariable((G4String("t")+suffix).c_str(), time/ns);
00143                 setVariable((G4String("PDGid")+suffix).c_str(), track->GetDefinition()->GetPDGEncoding());
00144                 setVariable((G4String("EventID")+suffix).c_str(), evId);
00145                 setVariable((G4String("TrackID")+suffix).c_str(), 
00146                                 BLManager::getObject()->
00147                                     getExternalTrackID(track));
00148                 setVariable((G4String("ParentID")+suffix).c_str(),
00149                                 BLManager::getObject()->
00150                                     getExternalParentID(track));
00151                 setVariable((G4String("wt")+suffix).c_str(),track->GetWeight());
00152                 if(fields) {
00153                         setVariable((G4String("Bx")+suffix).c_str(),B[0]/tesla);
00154                         setVariable((G4String("By")+suffix).c_str(),B[1]/tesla);
00155                         setVariable((G4String("Bz")+suffix).c_str(),B[2]/tesla);
00156                         setVariable((G4String("Ex")+suffix).c_str(),
00157                                                         E[0]/(megavolt/meter));
00158                         setVariable((G4String("Ey")+suffix).c_str(),
00159                                                         E[1]/(megavolt/meter));
00160                         setVariable((G4String("Ez")+suffix).c_str(),
00161                                                         E[2]/(megavolt/meter));
00162                 }
00163         }
00164 
00165         /// isidchar() returns true if the char is valid for an identifier.
00166         bool isidchar(char c) { return isalnum(c) || c == '_'; }
00167 
00168         /// isopchar() returns true if the character is an operator (no parens)
00169         bool isopchar(char c) { return c=='+' || c=='-' || c=='*' || c=='/' ||
00170                                         c=='^' || c=='<' || c=='>' || c=='!' ||
00171                                         c=='|' || c=='&' || c=='=' || c=='%'; }
00172 
00173         /// isumchar() returns true if the char should be inside the parens
00174         /// generated to surround the unary minus (parens matched in evaluate())
00175         bool isumchar(char c) { return isidchar(c) || c=='.' ||
00176                                         c=='^' || c=='(' || c==')'; }
00177 };
00178 
00179 #endif // BLEVALUATOR_HH
g4beamline