/* ======================================================================== *\ ! ! * ! * This file is part of MARS, the MAGIC Analysis and Reconstruction ! * Software. It is distributed to you in the hope that it can be a useful ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. ! * It is distributed WITHOUT ANY WARRANTY. ! * ! * Permission to use, copy, modify and distribute this software and its ! * documentation for any purpose is hereby granted without fee, ! * provided that the above copyright notice appear in all copies and ! * that both that copyright notice and this permission notice appear ! * in supporting documentation. It is provided "as is" without express ! * or implied warranty. ! * ! ! ! Author(s): Thomas Bretz 04/2002 ! ! Copyright: MAGIC Software Development, 2000-2003 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // MDataChain // // With this chain you can concatenate simple mathematical operations on // members of mars containers. // // In the constructor you can give rule, like // "HillasSource.fDist / MHillas.fLength" // Where MHillas/HillasSource is the name of the parameter container in // the parameter list and fDist/fLength is the name of the data members // in the containers. The result will be fDist divided by fLength. // // You can also use brackets: // "HillasDource.fDist / (MHillas.fLength + MHillas.fWidth)" // // The allowed operations are: +, -, *, / // // Warning: There is no priority rule build in. So better use brackets // to get correct results. The rule is parsed/evaluated from the left // to the right, which means: // // "MHillas.fWidth + MHillas.fLength / HillasSource.fDist" // // is parses as // // "(MHillas.fWidth + MHillas.fLength) / HillasSource.fDist" // // You can also use mathmatical operators, eg: // "5*log10(MMcEvt.fEnergy*MHillas.fSize)" // // The allowed operators are: // exp(x) e^x // log(x) natural logarithm of x // pow10(x) 10^x // log10(x) logarithm of x to base ten // cos(x) cosine of x // sin(x) sine of x // tan(x) tangent of x // cosh(x) hyperbolic cosine of x // sinh(x) hyperbolic sine of x // tanh(x) hyperbolic tangent of x // acos(x) arc cosine (inverse cosine) of x // asin(x) arc sine (inverse sine) of x // atan(x) arc tangent (inverse tangent) of x // sqrt(x) square root of x // sqr(x) square of x // abs(x) absolute value of x, |x| // floor(x) round down to the nearest integer (floor(9.9)=9) // r2d(x) transform radians to degrees // d2r(x) transform degrees to radians // rand(x) returns a uniform deviate on the interval ( 0, x ]. // (gRandom->Uniform(x) is returned) // randp(x) returns gRandom->Poisson(x) // rande(x) returns gRandom->Exp(x) // randi(x) returns gRandom->Integer(x) // randg(x) returns gRandom->Gaus(0, x) // randl(x) returns gRandom->Landau(0, x) // // // Constants are implemented in ParseDataMember, namely: // kPi: TMath::Pi() // kRad2Deg: 180/kPi // kDeg2Rad: kPi/180 // // You can also defined constants which are defined in TMath by: // kLn10 for static Double_t TMath::Ln10(); // kLogE for static Double_t TMath::LogE(); // kRadToDeg for static Double_t TMath::RadToDeg(); // kDegToRad for static Double_t TMath::DegToRad(); // Remark: In older root versions only Pi() and E() are implemented in // TMath. // // // REMARK: // - All the random functions are returning 0 if gRandom==0 // - You may get better results if you are using a TRandom3 // // FIXME: The possibility to use other objects inheriting from MData // is missing. // Maybe we can use gInterpreter->Calc("") for this. // gROOT->ProcessLineFast("line"); // ///////////////////////////////////////////////////////////////////////////// #include "MDataChain.h" #include // fabs on Alpha #include // isalnum, ... #include // strtod, ... #include #include #include "MLog.h" #include "MLogManip.h" #include "MDataList.h" #include "MDataValue.h" #include "MDataMember.h" #include "MDataElement.h" ClassImp(MDataChain); using namespace std; // -------------------------------------------------------------------------- // // Constructor which takes a rule and a surrounding operator as argument // MDataChain::MDataChain(const char *rule, OperatorType_t op) : fOperatorType(op) { fName = "MDataChain"; fTitle = rule; fMember=ParseString(rule, 1); } // -------------------------------------------------------------------------- // // Constructor taking a rule as an argument. For more details see // class description // MDataChain::MDataChain(const char *rule, const char *name, const char *title) : fMember(NULL), fOperatorType(kENoop) { fName = name ? name : "MDataChain"; fTitle = title ? title : rule; if (TString(rule).IsNull()) return; *fLog << inf << "Trying to resolve rule... " << flush; if (!(fMember=ParseString(rule, 1))) { *fLog << err << dbginf << "Parsing '" << rule << "' failed." << endl; return; } *fLog << inf << "found: " << GetRule() << endl; } // -------------------------------------------------------------------------- // // PreProcesses all members in the list // Bool_t MDataChain::PreProcess(const MParList *pList) { return fMember ? fMember->PreProcess(pList) : kFALSE; } // -------------------------------------------------------------------------- // // Checks whether at least one member has the ready-to-save flag. // Bool_t MDataChain::IsReadyToSave() const { *fLog << all << "fM=" << fMember << "/" << (int)fMember->IsReadyToSave() << " " << endl; return fMember ? fMember->IsReadyToSave() : kFALSE; } // -------------------------------------------------------------------------- // // Destructor. Delete filters. // MDataChain::~MDataChain() { if (fMember) delete fMember; } // -------------------------------------------------------------------------- // // Returns the number of alphanumeric characters (including '.') // in the given string // Int_t MDataChain::IsAlNum(TString txt) { int l = txt.Length(); for (int i=0; iInheritsFrom(MDataMember::Class()) ||*/ type!=is) { MDataList *list = new MDataList(is); list->SetName(Form("List_%c_%d", is, 10*level+nlist++)); list->SetOwner(); list->AddToList(member0); member0 = list; type = is; } continue; } if (txt[0]!='-' && txt[0]!='+') { *fLog << err << dbginf << "Syntax Error: First argument of symbol '"; *fLog << txt[0] << "' missing." << endl; if (member0) delete member0; return NULL; } // FALLTHROU case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ((txt[0]!='-' && txt[0]!='+') || isdigit(txt[1]) || txt[1]=='.') { char *end; Double_t num = strtod(txt.Data(), &end); if (!end || txt.Data()==end) { *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl; if (member0) delete member0; return NULL; } txt.Remove(0, end-txt.Data()); newmember = new MDataValue(num); break; } // FALLTHROUH default: int i = IsAlNum(txt); if (i==0) { *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl; if (member0) delete member0; return NULL; } TString text = txt(0, i); txt.Remove(0, i); txt = txt.Strip(TString::kBoth); if (!txt.IsNull() && txt[0]=='[') { Int_t first = GetBracket(txt, '[', ']'); TString op = txt(1, first-1); txt.Remove(0, first+1); newmember = new MDataElement(text, atoi(op)); break; } if ((txt.IsNull() || txt[0]!='(') && text[0]!='-' && text[0]!='+') { newmember = ParseDataMember(text.Data()); break; } OperatorType_t op = ParseOperator(text); if (op==kENoop) { *fLog << err << dbginf << "Syntax Error: Operator '" << text << "' unknown." << endl; if (member0) delete member0; return NULL; } Int_t first = GetBracket(txt, '(', ')'); TString sub = op==kENegative || op==kEPositive ? text.Remove(0,1) + txt : txt(1, first-1); txt.Remove(0, first+1); newmember = new MDataChain(sub, op); if (!newmember->IsValid()) { *fLog << err << dbginf << "Syntax Error: Error parsing contents '" << sub << "' of operator " << text << endl; delete newmember; if (member0) delete member0; return NULL; } } if (!member0) { member0 = newmember; continue; } if (!member0->InheritsFrom(MDataList::Class())) continue; ((MDataList*)member0)->AddToList(newmember); } return member0; } // -------------------------------------------------------------------------- // // Returns the value described by the rule // Double_t MDataChain::GetValue() const { if (!fMember) { //*fLog << warn << "MDataChain not valid." << endl; return 0; } const Double_t val = fMember->GetValue(); switch (fOperatorType) { case kEAbs: return fabs(val); case kELog: return log(val); case kELog10: return log10(val); case kESin: return sin(val); case kECos: return cos(val); case kETan: return tan(val); case kESinH: return sinh(val); case kECosH: return cosh(val); case kETanH: return tanh(val); case kEASin: return asin(val); case kEACos: return acos(val); case kEATan: return atan(val); case kESqrt: return sqrt(val); case kESqr: return val*val; case kEExp: return exp(val); case kEPow10: return pow(10, val); case kESgn: return val<0 ? -1 : 1; case kENegative: return -val; case kEPositive: return val; case kEFloor: return floor(val); case kERad2Deg: return val*180/TMath::Pi(); case kEDeg2Rad: return val*TMath::Pi()/180; case kERandom: return gRandom ? gRandom->Uniform(val) : 0; case kERandomP: return gRandom ? gRandom->Poisson(val) : 0; case kERandomE: return gRandom ? gRandom->Exp(val) : 0; case kERandomI: return gRandom ? gRandom->Integer((int)val) : 0; case kERandomG: return gRandom ? gRandom->Gaus(0, val) : 0; case kERandomL: return gRandom ? gRandom->Landau(0, val) : 0; case kENoop: return val; } *fLog << warn << "No Case for " << fOperatorType << " available." << endl; return 0; } /* void MDataChain::Print(Option_t *opt) const { *fLog << GetRule() << flush; Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class()); switch (fOperatorType) { case kEAbs: *fLog << "abs" << flush; break; case kELog: *fLog << "log" << flush; break; case kELog10: *fLog << "log10" << flush; break; case kESin: *fLog << "sin" << flush; break; case kECos: *fLog << "cos" << flush; break; case kETan: *fLog << "tan" << flush; break; case kESinH: *fLog << "sinh" << flush; break; case kECosH: *fLog << "cosh" << flush; break; case kETanH: *fLog << "tanh" << flush; break; case kEASin: *fLog << "asin" << flush; break; case kEACos: *fLog << "acos" << flush; break; case kEATan: *fLog << "atan" << flush; break; case kESqrt: *fLog << "sqrt" << flush; break; case kEExp: *fLog << "exp" << flush; break; case kEPow10: *fLog << "pow10" << flush; break; case kESgn: *fLog << "sgn" << flush; break; case kENegative: *fLog << "-" << flush; break; case kEPositive: *fLog << "+" << flush; break; case kENoop: break; } if (bracket) *fLog << "(" << flush; fMember->Print(); if (bracket) *fLog << ")" << flush; } */ // -------------------------------------------------------------------------- // // Builds a rule from all the chain members. This is a rule which could // be used to rebuild the chain. // TString MDataChain::GetRule() const { if (!fMember) return ""; TString str; Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class()); switch (fOperatorType) { case kEAbs: str += "abs" ; break; case kELog: str += "log" ; break; case kELog10: str += "log10"; break; case kESin: str += "sin" ; break; case kECos: str += "cos" ; break; case kETan: str += "tan" ; break; case kESinH: str += "sinh" ; break; case kECosH: str += "cosh" ; break; case kETanH: str += "tanh" ; break; case kEASin: str += "asin" ; break; case kEACos: str += "acos" ; break; case kEATan: str += "atan" ; break; case kESqrt: str += "sqrt" ; break; case kESqr: str += "sqr" ; break; case kEExp: str += "exp" ; break; case kEPow10: str += "pow10"; break; case kESgn: str += "sgn" ; break; case kENegative: str += "-" ; break; case kEPositive: str += "+" ; break; case kEFloor: str += "floor"; break; case kERad2Deg: str += "r2d" ; break; case kEDeg2Rad: str += "d2r" ; break; case kERandom: str += "rand" ; break; case kERandomP: str += "randp"; break; case kERandomE: str += "rande"; break; case kERandomI: str += "randi"; break; case kERandomG: str += "randg"; break; case kERandomL: str += "randl"; break; case kENoop: break; } if (bracket) str += "("; str += fMember->GetRule(); if (bracket) str += ")"; return str; } // -------------------------------------------------------------------------- // // Return a comma seperated list of all data members used in the chain. // This is mainly used in MTask::AddToBranchList // TString MDataChain::GetDataMember() const { return fMember->GetDataMember(); }