base/func.mjs

  1. import { isStr, clTF2, clTF3 } from '../core.mjs';
  2. import * as jsroot_math from './math.mjs';
  3. /** @summary Assign `evalPar` function for TF1 object
  4. * @private */
  5. function proivdeEvalPar(obj, check_save) {
  6. obj.$math = jsroot_math;
  7. let _func = obj.fTitle, isformula = false, pprefix = '[';
  8. if (_func === 'gaus') _func = 'gaus(0)';
  9. if (isStr(obj.fFormula?.fFormula)) {
  10. if (obj.fFormula.fFormula.indexOf('[](double*x,double*p)') === 0) {
  11. isformula = true; pprefix = 'p[';
  12. _func = obj.fFormula.fFormula.slice(21);
  13. } else {
  14. _func = obj.fFormula.fFormula;
  15. pprefix = '[p';
  16. }
  17. if (obj.fFormula.fClingParameters && obj.fFormula.fParams) {
  18. obj.fFormula.fParams.forEach(pair => {
  19. const regex = new RegExp(`(\\[${pair.first}\\])`, 'g'),
  20. parvalue = obj.fFormula.fClingParameters[pair.second];
  21. _func = _func.replace(regex, (parvalue < 0) ? `(${parvalue})` : parvalue);
  22. });
  23. }
  24. }
  25. if (!_func)
  26. return !check_save || (obj.fSave?.length > 2);
  27. obj.formulas?.forEach(entry => {
  28. _func = _func.replaceAll(entry.fName, entry.fTitle);
  29. });
  30. _func = _func.replace(/\b(TMath::SinH)\b/g, 'Math.sinh')
  31. .replace(/\b(TMath::CosH)\b/g, 'Math.cosh')
  32. .replace(/\b(TMath::TanH)\b/g, 'Math.tanh')
  33. .replace(/\b(TMath::ASinH)\b/g, 'Math.asinh')
  34. .replace(/\b(TMath::ACosH)\b/g, 'Math.acosh')
  35. .replace(/\b(TMath::ATanH)\b/g, 'Math.atanh')
  36. .replace(/\b(TMath::ASin)\b/g, 'Math.asin')
  37. .replace(/\b(TMath::ACos)\b/g, 'Math.acos')
  38. .replace(/\b(TMath::Atan)\b/g, 'Math.atan')
  39. .replace(/\b(TMath::ATan2)\b/g, 'Math.atan2')
  40. .replace(/\b(sin|SIN|TMath::Sin)\b/g, 'Math.sin')
  41. .replace(/\b(cos|COS|TMath::Cos)\b/g, 'Math.cos')
  42. .replace(/\b(tan|TAN|TMath::Tan)\b/g, 'Math.tan')
  43. .replace(/\b(exp|EXP|TMath::Exp)\b/g, 'Math.exp')
  44. .replace(/\b(log|LOG|TMath::Log)\b/g, 'Math.log')
  45. .replace(/\b(log10|LOG10|TMath::Log10)\b/g, 'Math.log10')
  46. .replace(/\b(pow|POW|TMath::Power)\b/g, 'Math.pow')
  47. .replace(/\b(pi|PI)\b/g, 'Math.PI')
  48. .replace(/\b(abs|ABS|TMath::Abs)\b/g, 'Math.abs')
  49. .replace(/\bsqrt\(/g, 'Math.sqrt(')
  50. .replace(/\bxygaus\(/g, 'this.$math.gausxy(this, x, y, ')
  51. .replace(/\bgaus\(/g, 'this.$math.gaus(this, x, ')
  52. .replace(/\bgausn\(/g, 'this.$math.gausn(this, x, ')
  53. .replace(/\bexpo\(/g, 'this.$math.expo(this, x, ')
  54. .replace(/\blandau\(/g, 'this.$math.landau(this, x, ')
  55. .replace(/\blandaun\(/g, 'this.$math.landaun(this, x, ')
  56. .replace(/\b(TMath::|ROOT::Math::)/g, 'this.$math.');
  57. if (_func.match(/^pol[0-9]$/) && (parseInt(_func[3]) === obj.fNpar - 1)) {
  58. _func = '[0]';
  59. for (let k = 1; k < obj.fNpar; ++k)
  60. _func += ` + [${k}] * `+ ((k === 1) ? 'x' : `Math.pow(x,${k})`);
  61. }
  62. if (_func.match(/^chebyshev[0-9]$/) && (parseInt(_func[9]) === obj.fNpar - 1)) {
  63. _func = `this.$math.ChebyshevN(${obj.fNpar-1}, x, `;
  64. for (let k = 0; k < obj.fNpar; ++k)
  65. _func += (k === 0 ? '[' : ', ') + `[${k}]`;
  66. _func += '])';
  67. }
  68. for (let i = 0; i < obj.fNpar; ++i)
  69. _func = _func.replaceAll(pprefix + i + ']', `(${obj.GetParValue(i)})`);
  70. for (let n = 2; n < 10; ++n)
  71. _func = _func.replaceAll(`x^${n}`, `Math.pow(x,${n})`);
  72. if (isformula) {
  73. _func = _func.replace(/x\[0\]/g, 'x');
  74. if (obj._typename === clTF3) {
  75. _func = _func.replace(/x\[1\]/g, 'y');
  76. _func = _func.replace(/x\[2\]/g, 'z');
  77. obj.evalPar = new Function('x', 'y', 'z', _func).bind(obj);
  78. } else if (obj._typename === clTF2) {
  79. _func = _func.replace(/x\[1\]/g, 'y');
  80. obj.evalPar = new Function('x', 'y', _func).bind(obj);
  81. } else
  82. obj.evalPar = new Function('x', _func).bind(obj);
  83. } else if (obj._typename === clTF3)
  84. obj.evalPar = new Function('x', 'y', 'z', 'return ' + _func).bind(obj);
  85. else if (obj._typename === clTF2)
  86. obj.evalPar = new Function('x', 'y', 'return ' + _func).bind(obj);
  87. else
  88. obj.evalPar = new Function('x', 'return ' + _func).bind(obj);
  89. return true;
  90. }
  91. /** @summary Get interpolation in saved buffer
  92. * @desc Several checks must be done before function can be used
  93. * @private */
  94. function _getTF1Save(func, x) {
  95. const np = func.fSave.length - 3,
  96. xmin = func.fSave[np + 1],
  97. xmax = func.fSave[np + 2],
  98. dx = (xmax - xmin) / np;
  99. if (x < xmin)
  100. return func.fSave[0];
  101. if (x > xmax)
  102. return func.fSave[np];
  103. const bin = Math.min(np - 1, Math.floor((x - xmin) / dx));
  104. let xlow = xmin + bin * dx,
  105. xup = xlow + dx,
  106. ylow = func.fSave[bin],
  107. yup = func.fSave[bin + 1];
  108. if (!Number.isFinite(ylow) && (bin < np - 1)) {
  109. xlow += dx; xup += dx;
  110. ylow = yup; yup = func.fSave[bin + 2];
  111. } else if (!Number.isFinite(yup) && (bin > 0)) {
  112. xup -= dx; xlow -= dx;
  113. yup = ylow; ylow = func.fSave[bin - 1];
  114. }
  115. return ((xup * ylow - xlow * yup) + x * (yup - ylow)) / dx;
  116. }
  117. /** @summary Provide TF1 value
  118. * @desc First try evaluate, if not possible - check saved buffer
  119. * @private */
  120. function getTF1Value(func, x, skip_eval = undefined) {
  121. if (!func)
  122. return 0;
  123. let iserr = false;
  124. if (!skip_eval && !func.evalPar) {
  125. try {
  126. if (!proivdeEvalPar(func))
  127. iserr = true;
  128. } catch {
  129. iserr = true;
  130. }
  131. }
  132. if (func.evalPar && !iserr) {
  133. try {
  134. return func.evalPar(x);
  135. } catch {
  136. /* eslint-disable-next-line no-useless-assignment */
  137. iserr = true;
  138. }
  139. }
  140. const np = func.fSave.length - 3;
  141. return (np < 2) || (func.fSave[np + 1] === func.fSave[np + 2]) ? 0 : _getTF1Save(func, x);
  142. }
  143. export { proivdeEvalPar, getTF1Value, _getTF1Save };