import { isStr, clTF2, clTF3 } from '../core.mjs';
import * as jsroot_math from './math.mjs';
/** @summary Assign `evalPar` function for TF1 object
* @private */
function proivdeEvalPar(obj, check_save) {
obj.$math = jsroot_math;
let _func = obj.fTitle, isformula = false, pprefix = '[';
if (_func === 'gaus') _func = 'gaus(0)';
if (isStr(obj.fFormula?.fFormula)) {
if (obj.fFormula.fFormula.indexOf('[](double*x,double*p)') === 0) {
isformula = true; pprefix = 'p[';
_func = obj.fFormula.fFormula.slice(21);
} else {
_func = obj.fFormula.fFormula;
pprefix = '[p';
}
if (obj.fFormula.fClingParameters && obj.fFormula.fParams) {
obj.fFormula.fParams.forEach(pair => {
const regex = new RegExp(`(\\[${pair.first}\\])`, 'g'),
parvalue = obj.fFormula.fClingParameters[pair.second];
_func = _func.replace(regex, (parvalue < 0) ? `(${parvalue})` : parvalue);
});
}
}
if (!_func)
return !check_save || (obj.fSave?.length > 2);
obj.formulas?.forEach(entry => {
_func = _func.replaceAll(entry.fName, entry.fTitle);
});
_func = _func.replace(/\b(TMath::SinH)\b/g, 'Math.sinh')
.replace(/\b(TMath::CosH)\b/g, 'Math.cosh')
.replace(/\b(TMath::TanH)\b/g, 'Math.tanh')
.replace(/\b(TMath::ASinH)\b/g, 'Math.asinh')
.replace(/\b(TMath::ACosH)\b/g, 'Math.acosh')
.replace(/\b(TMath::ATanH)\b/g, 'Math.atanh')
.replace(/\b(TMath::ASin)\b/g, 'Math.asin')
.replace(/\b(TMath::ACos)\b/g, 'Math.acos')
.replace(/\b(TMath::Atan)\b/g, 'Math.atan')
.replace(/\b(TMath::ATan2)\b/g, 'Math.atan2')
.replace(/\b(sin|SIN|TMath::Sin)\b/g, 'Math.sin')
.replace(/\b(cos|COS|TMath::Cos)\b/g, 'Math.cos')
.replace(/\b(tan|TAN|TMath::Tan)\b/g, 'Math.tan')
.replace(/\b(exp|EXP|TMath::Exp)\b/g, 'Math.exp')
.replace(/\b(log|LOG|TMath::Log)\b/g, 'Math.log')
.replace(/\b(log10|LOG10|TMath::Log10)\b/g, 'Math.log10')
.replace(/\b(pow|POW|TMath::Power)\b/g, 'Math.pow')
.replace(/\b(pi|PI)\b/g, 'Math.PI')
.replace(/\b(abs|ABS|TMath::Abs)\b/g, 'Math.abs')
.replace(/\bsqrt\(/g, 'Math.sqrt(')
.replace(/\bxygaus\(/g, 'this.$math.gausxy(this, x, y, ')
.replace(/\bgaus\(/g, 'this.$math.gaus(this, x, ')
.replace(/\bgausn\(/g, 'this.$math.gausn(this, x, ')
.replace(/\bexpo\(/g, 'this.$math.expo(this, x, ')
.replace(/\blandau\(/g, 'this.$math.landau(this, x, ')
.replace(/\blandaun\(/g, 'this.$math.landaun(this, x, ')
.replace(/\b(TMath::|ROOT::Math::)/g, 'this.$math.');
if (_func.match(/^pol[0-9]$/) && (parseInt(_func[3]) === obj.fNpar - 1)) {
_func = '[0]';
for (let k = 1; k < obj.fNpar; ++k)
_func += ` + [${k}] * `+ ((k === 1) ? 'x' : `Math.pow(x,${k})`);
}
if (_func.match(/^chebyshev[0-9]$/) && (parseInt(_func[9]) === obj.fNpar - 1)) {
_func = `this.$math.ChebyshevN(${obj.fNpar-1}, x, `;
for (let k = 0; k < obj.fNpar; ++k)
_func += (k === 0 ? '[' : ', ') + `[${k}]`;
_func += '])';
}
for (let i = 0; i < obj.fNpar; ++i)
_func = _func.replaceAll(pprefix + i + ']', `(${obj.GetParValue(i)})`);
for (let n = 2; n < 10; ++n)
_func = _func.replaceAll(`x^${n}`, `Math.pow(x,${n})`);
if (isformula) {
_func = _func.replace(/x\[0\]/g, 'x');
if (obj._typename === clTF3) {
_func = _func.replace(/x\[1\]/g, 'y');
_func = _func.replace(/x\[2\]/g, 'z');
obj.evalPar = new Function('x', 'y', 'z', _func).bind(obj);
} else if (obj._typename === clTF2) {
_func = _func.replace(/x\[1\]/g, 'y');
obj.evalPar = new Function('x', 'y', _func).bind(obj);
} else
obj.evalPar = new Function('x', _func).bind(obj);
} else if (obj._typename === clTF3)
obj.evalPar = new Function('x', 'y', 'z', 'return ' + _func).bind(obj);
else if (obj._typename === clTF2)
obj.evalPar = new Function('x', 'y', 'return ' + _func).bind(obj);
else
obj.evalPar = new Function('x', 'return ' + _func).bind(obj);
return true;
}
/** @summary Get interpolation in saved buffer
* @desc Several checks must be done before function can be used
* @private */
function _getTF1Save(func, x) {
const np = func.fSave.length - 3,
xmin = func.fSave[np + 1],
xmax = func.fSave[np + 2],
dx = (xmax - xmin) / np;
if (x < xmin)
return func.fSave[0];
if (x > xmax)
return func.fSave[np];
const bin = Math.min(np - 1, Math.floor((x - xmin) / dx));
let xlow = xmin + bin * dx,
xup = xlow + dx,
ylow = func.fSave[bin],
yup = func.fSave[bin + 1];
if (!Number.isFinite(ylow) && (bin < np - 1)) {
xlow += dx; xup += dx;
ylow = yup; yup = func.fSave[bin + 2];
} else if (!Number.isFinite(yup) && (bin > 0)) {
xup -= dx; xlow -= dx;
yup = ylow; ylow = func.fSave[bin - 1];
}
return ((xup * ylow - xlow * yup) + x * (yup - ylow)) / dx;
}
/** @summary Provide TF1 value
* @desc First try evaluate, if not possible - check saved buffer
* @private */
function getTF1Value(func, x, skip_eval = undefined) {
if (!func)
return 0;
let iserr = false;
if (!skip_eval && !func.evalPar) {
try {
if (!proivdeEvalPar(func))
iserr = true;
} catch {
iserr = true;
}
}
if (func.evalPar && !iserr) {
try {
return func.evalPar(x);
} catch {
/* eslint-disable-next-line no-useless-assignment */
iserr = true;
}
}
const np = func.fSave.length - 3;
return (np < 2) || (func.fSave[np + 1] === func.fSave[np + 2]) ? 0 : _getTF1Save(func, x);
}
export { proivdeEvalPar, getTF1Value, _getTF1Save };