43#include <boost/spirit/home/x3.hpp>
69 const char *home = std::getenv(
"HOME");
70 std::string path = std::string(home ? home :
".") +
"/.musrfit/mupp/mupp_err.log";
71 std::ofstream fout(path.c_str(), std::ios::app);
73 fout << msg << std::endl;
76 std::cerr << msg << std::endl;
84static std::string mupp_pyNum(
double d)
87 return "float('nan')";
89 return (d < 0) ?
"float('-inf')" :
"float('inf')";
90 std::ostringstream os;
91 os << std::setprecision(17) << d;
99static std::string mupp_pyList(
const std::vector<double> &v)
101 std::ostringstream os;
103 for (
size_t i=0; i<v.size(); i++) {
106 os << mupp_pyNum(v[i]);
119static std::string mupp_pyStr(
const std::string &s)
121 std::ostringstream os;
123 for (
size_t i=0; i<s.size(); i++) {
124 if (s[i] ==
'\\' || s[i] ==
'\'')
139static std::vector<double> mupp_collValues(
PmuppCollection *coll,
int pidx)
141 std::vector<double> v;
154static std::vector<double> mupp_collErrors(
PmuppCollection *coll,
int pidx)
156 std::vector<double> v;
160 v.push_back(std::sqrt(std::fabs(p*n)));
172static bool mupp_isSafePyName(
const std::string &s)
176 if (!(std::isalpha((
unsigned char)s[0]) || s[0] ==
'_'))
178 for (
size_t i=0; i<s.size(); i++) {
179 if (!(std::isalnum((
unsigned char)s[i]) || s[i] ==
'_'))
182 static const std::set<std::string> kw = {
183 "False",
"None",
"True",
"and",
"as",
"assert",
"async",
"await",
"break",
"class",
184 "continue",
"def",
"del",
"elif",
"else",
"except",
"finally",
"for",
"from",
"global",
185 "if",
"import",
"in",
"is",
"lambda",
"nonlocal",
"not",
"or",
"pass",
"raise",
"return",
186 "try",
"while",
"with",
"yield"
188 return kw.find(s) == kw.end();
197static std::string mupp_indentLines(
const std::string &code,
const std::string &prefix)
199 std::ostringstream os;
200 std::istringstream is(code);
202 while (std::getline(is, line))
203 os << prefix << line <<
"\n";
219static bool mupp_getPyString(
const std::string &pyExpr, std::string &out)
222 std::string cmd =
"_anyresult = ROOT.std.make_any['std::string'](" + pyExpr +
")";
223 if (!TPython::Exec(cmd.c_str(), &res))
225 if (!res.has_value())
228 out = std::any_cast<std::string>(res);
229 }
catch (
const std::bad_any_cast &) {
247static std::vector<double> mupp_readPyList(
const std::string &name,
bool &ok)
250 std::vector<double> out;
255 " _mupp_s = '1 ' + ' '.join(repr(float(_mupp_x)) for _mupp_x in " + name +
")\n"
256 "except Exception:\n"
258 if (!TPython::Exec(prep.c_str()))
262 if (!mupp_getPyString(
"_mupp_s", s))
265 std::istringstream is(s);
267 if (!(is >> status) || status != 1)
313 const std::vector<PmuppCollection*> &allColl) :
317 if (
fParseStr.find(
"<python>") != std::string::npos) {
324 typedef std::string::const_iterator iterator_type;
332 namespace x3 = boost::spirit::x3;
334 if (success && iter == end) {
336 std::vector<double> data, dataErr;
337 for (
unsigned int i=0; i<
fColl->GetRun(0).GetNoOfParam(); i++) {
350 std::cerr <<
"**ERROR** evalution failed..." << std::endl;
357 std::cerr <<
"**ERROR** parsing failed..." << std::endl;
375 static bool s_pythonPathSet =
false;
376 if (!s_pythonPathSet) {
377 TString pp = TROOT::GetLibDir();
378 const char *cur = gSystem->Getenv(
"PYTHONPATH");
379 if (cur !=
nullptr && cur[0] !=
'\0') {
383 gSystem->Setenv(
"PYTHONPATH", pp.Data());
384 s_pythonPathSet =
true;
388 const std::string openTag(
"<python>");
389 const std::string closeTag(
"</python>");
390 std::size_t p0 =
fParseStr.find(openTag);
391 std::size_t p1 =
fParseStr.find(closeTag, p0);
392 if (p0 == std::string::npos || p1 == std::string::npos) {
393 mupp_writeErrLog(
"**ERROR** python block: missing <python> ... </python> tags.");
397 std::size_t codeStart = p0 + openTag.size();
398 std::string code =
fParseStr.substr(codeStart, p1 - codeStart);
401 std::ostringstream py;
402 py <<
"import ROOT\n";
404 py <<
"parErr = {}\n";
406 int nParam =
fColl->GetRun(0).GetNoOfParam();
407 for (
int i=0; i<nParam; i++) {
408 std::string name =
fColl->GetRun(0).GetParam(i).GetName().toLatin1().data();
409 std::vector<double> val =
getData(i);
411 py <<
"par['" << name <<
"'] = " << mupp_pyList(val) <<
"\n";
412 py <<
"parErr['" << name <<
"'] = " << mupp_pyList(err) <<
"\n";
413 if (mupp_isSafePyName(name)) {
414 py << name <<
" = par['" << name <<
"']\n";
415 py << name <<
"Err = parErr['" << name <<
"']\n";
424 py <<
"collErr = {}\n";
425 for (
size_t c=0; c<
fAllColl.size(); c++) {
432 for (
int j=0; j<np; j++) {
434 py <<
"_c[" << mupp_pyStr(pname) <<
"] = " << mupp_pyList(mupp_collValues(pc, j)) <<
"\n";
435 py <<
"_ce[" << mupp_pyStr(pname) <<
"] = " << mupp_pyList(mupp_collErrors(pc, j)) <<
"\n";
437 std::string cname = pc->
GetName().toLatin1().data();
438 py <<
"coll[" << c <<
"] = _c\n";
439 py <<
"collErr[" << c <<
"] = _ce\n";
440 py <<
"coll[" << mupp_pyStr(cname) <<
"] = _c\n";
441 py <<
"collErr[" << mupp_pyStr(cname) <<
"] = _ce\n";
445 py <<
"import traceback as _mupp_tb\n";
446 py <<
"_mupp_err = ''\n";
448 py << mupp_indentLines(code,
" ");
450 py <<
"except Exception:\n";
451 py <<
" _mupp_err = _mupp_tb.format_exc()\n";
453 if (!TPython::Exec(py.str().c_str())) {
455 "(syntax error or interpreter problem). See stderr for details.");
462 if (mupp_getPyString(
"_mupp_err", errStr) && !errStr.empty()) {
463 mupp_writeErrLog(std::string(
"**ERROR** python evaluation failed:\n") + errStr);
475 bool okVal =
false, okErr =
false;
476 std::vector<double> val = mupp_readPyList(
fVarName, okVal);
477 std::vector<double> err = mupp_readPyList(
fVarName +
"Err", okErr);
485 int nRuns =
fColl->GetNoOfRuns();
486 if ((
int)val.size() != nRuns) {
487 std::ostringstream msg;
488 msg <<
"**ERROR** python variable '" <<
fVarName <<
"' has " << val.size()
489 <<
" values, but the collection has " << nRuns <<
" runs.";
496 if (!okErr || err.size() != val.size())
497 err.assign(val.size(), 0.0);
504 "rebuild ROOT with -Dtpython=ON to use <python> variable blocks.");
520 std::vector<double> data;
522 data =
fVar.GetValue();
538 std::vector<double> data;
540 data =
fVar.GetError();
560 std::string varName, errVarName;
564 errVarName = varName +
"Err";
568 fAst.push_front(var_stat);
572 fAst.push_front(var_stat);
588 std::string name(
"??");
591 if (idx >=
fColl->GetRun(0).GetNoOfParam())
594 return fColl->GetRun(0).GetParam(idx).GetName().toLatin1().data();
609 std::vector<double> data;
612 if (idx >=
fColl->GetRun(0).GetNoOfParam())
616 for (
int i=0; i<
fColl->GetNoOfRuns(); i++) {
617 dval =
fColl->GetRun(i).GetParam(idx).GetValue();
618 data.push_back(dval);
637 std::vector<double> err;
640 if (idx >=
fColl->GetRun(0).GetNoOfParam())
643 double dvalPos, dvalNeg;
644 for (
int i=0; i<
fColl->GetNoOfRuns(); i++) {
645 dvalPos =
fColl->GetRun(i).GetParam(idx).GetPosErr();
646 dvalNeg =
fColl->GetRun(i).GetParam(idx).GetNegErr();
647 dvalPos = sqrt(fabs(dvalPos*dvalNeg));
648 err.push_back(dvalPos);
static void mupp_writeErrLog(const std::string &msg)
Appends an error message to ~/.musrfit/mupp/mupp_err.log and stderr.
PmuppCollection * fColl
pointer to collection containing run data needed for parsing and evaluation
std::vector< double > getErrors()
Gets the computed errors for the variable.
QString getVarName()
Gets the variable name.
std::vector< PmuppCollection * > fAllColl
all loaded collections (handler-index order); Python path only, exposed as coll[]/collErr[]
PVarHandler()
Default constructor.
void evaluatePython()
Evaluates the variable using an embedded Python3 interpreter (TPython).
std::vector< double > getData(int idx)
Gets the data values for a specific parameter across all runs.
std::string fParseStr
the variable input string to be parsed
void injectPredefVariables()
Injects predefined variables from the collection into the AST.
bool fIsValid
flag indicating whether parsing and evaluation succeeded
mupp::prog::PVarHandler fVar
variable handler storing the computed values and errors
std::vector< double > getValues()
Gets the computed values for the variable.
mupp::ast::statement_list fAst
Abstract Syntax Tree generated from parsing.
std::string fVarName
name of the variable to extract from evaluation results
std::vector< double > getDataErr(int idx)
Gets the error values for a specific parameter across all runs.
Represents a collection of related experimental runs.
PmuppRun GetRun(unsigned int idx)
Retrieves a run from a collection by index.
int GetNoOfRuns()
Gets the number of runs in this collection.
QString GetName()
Gets the collection name.
double GetNegErr()
Gets the negative error of the parameter.
double GetPosErr()
Gets the positive error of the parameter.
double GetValue()
Gets the parameter value.
QString GetName()
Gets the parameter name.
Represents all fit parameters from a single experimental run.
PmuppParam GetParam(unsigned int idx)
Retrieves a parameter from a run by index.
int GetNoOfParam()
Gets the number of parameters in this run.
boost::variant< variable_declaration, assignment > statement
Variant type representing a single statement.
statement_list_type const statement_list
The PErrorHandler struct handles parsing and semantic errors.
Represents a variable declaration with optional initialization.
variable lhs
The variable being declared.
std::string name
Variable name without the '$' prefix.
The PProgEval struct evaluates expressions using the AST.
PVarHandler getVar(const std::string name, bool &ok)
Retrieves a variable by name after evaluation.
The PProgram struct performs semantic analysis on the AST.
std::vector< PVarHandler > getVars()
Gets all variables from the symbol table.
void add_predef_var_values(const std::string &name, std::vector< double > &val, std::vector< double > &err)
Injects predefined variable values from collection data.