/* ======================================================================== *\ ! ! * ! * 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-2002 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // 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 // abs(x) absolute value of x, |x| // // // 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 "MLog.h" #include "MLogManip.h" #include "MDataList.h" #include "MDataValue.h" #include "MDataMember.h" # ClassImp(MDataChain); MDataChain::MDataChain(const char *rule, OperatorType_t op) : fOperatorType(op) { fName = "MDataChain"; fTitle = rule; fMember=ParseString(rule, 1); } MDataChain::MDataChain() : fMember(NULL), fOperatorType(kENoop) { } MDataChain::MDataChain(const char *rule, const char *name, const char *title) : fOperatorType(kENoop) { fName = name ? name : "MDataChain"; fTitle = title ? title : rule; *fLog << inf << "Trying to resolve rule... " << flush; if (!(fMember=ParseString(rule, 1))) { *fLog << err << dbginf << "Parsing '" << rule << "' failed." << endl; return; } *fLog << inf << "found: " << flush; fMember->Print(); *fLog << 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]!='-' || 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]!='(') { newmember = new MDataMember(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 ? 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; } 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 kEExp: return exp(val); case kEPow10: return pow(10, val); case kESgn: return val<0 ? -1 : 1; case kENegative: return -val; case kENoop: return val; } *fLog << warn << "No Case for " << fOperatorType << " available." << endl; return 0; } void MDataChain::Print(Option_t *opt) const { 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 kENoop: break; } if (bracket) *fLog << "(" << flush; fMember->Print(); if (bracket) *fLog << ")" << flush; }