26 std::span<const double> pdir,
double tlr,
unsigned int maxcalls)
const
34 unsigned int npar = par.size();
35 unsigned int nfcn = 0;
38 double mgr_tlr = 0.5 * tlr;
43 double up =
fFCN.Up();
45 double tlf = tlr * up;
47 unsigned int maxitr = 30;
49 double aminsv =
fFval;
50 double aim = aminsv + up;
54 std::array<double, 3> alsb{0., 0., 0.};
55 std::array<double, 3> flsb{0., 0., 0.};
57 MnPrint print(
"MnFunctionCross");
59 print.
Debug([&](std::ostream &os) {
60 for (
unsigned int i = 0; i < par.size(); ++i)
61 os <<
"Parameter " << par[i] <<
" value " << pmid[i] <<
" dir " << pdir[i] <<
" function min = " << aminsv
62 <<
" contour value aim = (fmin + up) = " << aim;
68 for (
unsigned int i = 0; i < par.size(); i++) {
69 unsigned int kex = par[i];
70 if (
fState.Parameter(kex).HasLimits()) {
71 double zmid = pmid[i];
72 double zdir = pdir[i];
74 if (zdir > 0. &&
fState.Parameter(kex).HasUpperLimit()) {
75 double zlim =
fState.Parameter(kex).UpperLimit();
76 if (std::fabs(zdir) <
fState.Precision().Eps()) {
78 if (std::fabs(zlim - zmid) <
fState.Precision().Eps())
82 aulim = std::min(aulim, (zlim - zmid) / zdir);
83 }
else if (zdir < 0. &&
fState.Parameter(kex).HasLowerLimit()) {
84 double zlim =
fState.Parameter(kex).LowerLimit();
85 if (std::fabs(zdir) <
fState.Precision().Eps()) {
87 if (std::fabs(zlim - zmid) <
fState.Precision().Eps())
91 aulim = std::min(aulim, (zlim - zmid) / zdir);
96 print.
Debug(
"Largest allowed aulim", aulim);
99 if (limset && npar == 1) {
100 print.
Warn(
"Parameter is at limit", pmid[0],
"delta", pdir[0]);
104 if (aulim < aopt + tla)
109 print.
Info([&](std::ostream &os) {
110 os <<
"Run Migrad with fixed parameters:";
111 for (
unsigned i = 0; i < npar; ++i)
112 os <<
"\n Pos " << par[i] <<
": " <<
fState.Name(par[i]) <<
" = " << pmid[i];
115 for (
unsigned int i = 0; i < npar; i++)
128 print.
Warn(
"New minimum found while scanning parameter", par.front(),
"new value =", min0.
Fval(),
129 "old value =",
fFval);
136 if (limset ==
true && min0.
Fval() < aim)
141 flsb[0] = min0.
Fval();
142 flsb[0] = std::max(flsb[0], aminsv + 0.1 * up);
143 aopt = std::sqrt(up / (flsb[0] - aminsv)) - 1.;
144 if (std::fabs(flsb[0] - aim) < tlf)
157 print.
Debug(
"flsb[0]", flsb[0],
"aopt", aopt);
159 print.
Info([&](std::ostream &os) {
160 os <<
"Run Migrad again (2nd) with fixed parameters:";
161 for (
unsigned i = 0; i < npar; ++i)
162 os <<
"\n Pos " << par[i] <<
": " <<
fState.Name(par[i]) <<
" = " << pmid[i] + (aopt)*pdir[i];
165 for (
unsigned int i = 0; i < npar; i++)
175 print.
Debug(
"A new minimum is found: return");
179 print.
Debug(
"FCN call limit is reached: return");
183 print.
Debug(
"Migrad failed: return ");
186 if (limset ==
true && min1.
Fval() < aim) {
187 print.
Debug(
"Parameter(s) at limit: return ");
193 flsb[1] = min1.
Fval();
194 double dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]);
196 print.
Debug(
"aopt", aopt,
"min1Val", flsb[1],
"dfda", dfda);
201 print.
Debug(
"dfda < 0 - iterate from", ipt,
"to max of", maxitr);
204 unsigned int maxlk = maxitr - ipt;
205 for (
unsigned int it = 0; it < maxlk; it++) {
209 aopt = alsb[0] + 0.2 * (it + 1);
216 print.
Info([&](std::ostream &os) {
217 os <<
"Run Migrad again (iteration " << it <<
" ) :";
218 for (
unsigned i = 0; i < npar; ++i)
219 os <<
"\n parameter " << par[i] <<
" (" <<
fState.Name(par[i]) <<
") fixed to "
220 << pmid[i] + (aopt)*pdir[i];
223 for (
unsigned int i = 0; i < npar; i++)
226 min1 = migrad(maxcalls, mgr_tlr);
232 print.
Debug(
"A new minimum is found: return");
236 print.
Debug(
"FCN call limit is reached: return");
240 print.
Debug(
"Migrad failed: return ");
243 if (limset ==
true && min1.
Fval() < aim) {
244 print.
Debug(
"Parameter(s) at limit: return ");
249 flsb[1] = min1.
Fval();
250 dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]);
253 print.
Debug(
"aopt", aopt,
"min1Val", flsb[1],
"dfda", dfda);
266 aopt = alsb[1] + (aim - flsb[1]) / dfda;
268 print.
Debug(
"dfda > 0 : aopt", aopt);
270 double fdist = std::min(std::fabs(aim - flsb[0]), std::fabs(aim - flsb[1]));
271 double adist = std::min(std::fabs(aopt - alsb[0]), std::fabs(aopt - alsb[1]));
273 if (std::fabs(aopt) > 1.)
274 tla = tlr * std::fabs(aopt);
275 if (adist < tla && fdist < tlf) {
276 print.
Info(
"Return: Found good value for aopt = ",aopt);
280 print.
Info(
"Number of iterations",ipt,
"larger than max",maxitr,
": return");
283 double bmin = std::min(alsb[0], alsb[1]) - 1.;
286 double bmax = std::max(alsb[0], alsb[1]) + 1.;
296 print.
Info([&](std::ostream &os) {
297 os <<
"Run Migrad again (3rd) with fixed parameters:";
298 for (
unsigned i = 0; i < npar; ++i)
299 os <<
"\n Pos " << par[i] <<
": " <<
fState.Name(par[i]) <<
" = " << pmid[i] + (aopt)*pdir[i];
302 for (
unsigned int i = 0; i < npar; i++)
311 print.
Debug(
"A new minimum is found: return");
315 print.
Debug(
"FCN call limit is reached: return");
319 print.
Debug(
"Migrad failed: return ");
322 if (limset ==
true && min2.
Fval() < aim) {
323 print.
Debug(
"Parameter(s) at limit: return ");
329 flsb[2] = min2.
Fval();
333 double ecarmn = std::fabs(flsb[2] - aim);
335 unsigned int ibest = 2;
336 unsigned int iworst = 0;
337 unsigned int noless = 0;
339 for (
unsigned int i = 0; i < 3; i++) {
340 double ecart = std::fabs(flsb[i] - aim);
341 if (ecart > ecarmx) {
345 if (ecart < ecarmn) {
353 print.
Debug(
"have three points : noless < aim; noless", noless,
"ibest", ibest,
"iworst", iworst);
358 if (noless == 1 || noless == 2)
361 if (noless == 0 && ibest != 2) {
362 print.
Debug(
"all 3 points are above - invalid result- return");
367 if (noless == 3 && ibest != 2) {
371 print.
Debug(
"All three points below - look again for positive slope");
377 flsb[iworst] = flsb[2];
378 alsb[iworst] = alsb[2];
379 dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]);
381 print.
Debug(
"New straight line using point 1-2; dfda", dfda);
394 print.
Debug(
"Parabola fit: iteration", ipt);
396 double coeff1 = parbol.
C();
397 double coeff2 = parbol.
B();
398 double coeff3 = parbol.
A();
399 double determ = coeff2 * coeff2 - 4. * coeff3 * (coeff1 - aim);
401 print.
Debug(
"Parabola fit: a =", coeff3,
"b =", coeff2,
"c =", coeff1,
"determ =", determ);
404 if (determ < prec.
Eps())
406 double rt = std::sqrt(determ);
407 double x1 = (-coeff2 + rt) / (2. * coeff3);
408 double x2 = (-coeff2 - rt) / (2. * coeff3);
409 double s1 = coeff2 + 2. * x1 * coeff3;
410 double s2 = coeff2 + 2. * x2 * coeff3;
412 print.
Debug(
"Parabola fit: x1", x1,
"x2", x2,
"s1",
s1,
"s2", s2);
415 print.
Warn(
"Problem 1");
425 print.
Debug(
"Parabola fit: aopt", aopt,
"slope", slope);
429 if (std::fabs(aopt) > 1.)
430 tla = tlr * std::fabs(aopt);
432 print.
Debug(
"Delta(aopt)", std::fabs(aopt - alsb[ibest]),
"tla", tla,
"Delta(F)", std::fabs(flsb[ibest] - aim),
435 if (std::fabs(aopt - alsb[ibest]) < tla && std::fabs(flsb[ibest] - aim) < tlf) {
436 print.
Debug(
"Return: Found best value is within tolerance, aopt",aopt,
"F=",flsb[ibest]);
445 unsigned int ileft = 3;
446 unsigned int iright = 3;
447 unsigned int iout = 3;
450 ecarmn = std::fabs(aim - flsb[0]);
451 for (
unsigned int i = 0; i < 3; i++) {
452 double ecart = std::fabs(flsb[i] - aim);
453 if (ecart < ecarmn) {
462 else if (flsb[i] > flsb[iright])
468 }
else if (ileft == 3)
470 else if (flsb[i] < flsb[ileft])
478 print.
Debug(
"ileft", ileft,
"iright", iright,
"iout", iout,
"ibest", ibest);
482 if (ecarmx > 10. * std::fabs(flsb[iout] - aim))
483 aopt = 0.5 * (aopt + 0.5 * (alsb[iright] + alsb[ileft]));
486 double smalla = 0.1 * tla;
487 if (slope * smalla > tlf)
488 smalla = tlf / slope;
489 double aleft = alsb[ileft] + smalla;
490 double aright = alsb[iright] - smalla;
498 aopt = 0.5 * (aleft + aright);
508 print.
Info([&](std::ostream &os) {
509 os <<
"Run Migrad again at new point (#iter = " << ipt+1 <<
" ):";
510 for (
unsigned i = 0; i < npar; ++i)
511 os <<
"\n\t - parameter " << par[i] <<
" fixed to " << pmid[i] + (aopt)*pdir[i];
514 for (
unsigned int i = 0; i < npar; i++)
517 min2 = migrad(maxcalls, mgr_tlr);
523 print.
Debug(
"A new minimum is found: return");
527 print.
Debug(
"FCN call limit is reached: return");
531 print.
Debug(
"Migrad failed: return ");
534 if (limset ==
true && min2.
Fval() < aim) {
535 print.
Debug(
"Parameter(s) at limit: return ");
542 flsb[iout] = min2.
Fval();
544 }
while (ipt < maxitr);
548 print.
Debug(
"Best point is not found: return invalid result after many trial",ipt);