39 unsigned int maxcalls = 100 * (npoints + 5) * (
fMinimum.UserState().VariableParameters() + 1);
40 unsigned int nfcn = 0;
43 print.
Debug(
"MnContours: finding ",npoints,
" contours points for ",px,py,
" at level ",
fFCN.Up(),
" from value ",
fMinimum.Fval());
45 std::vector<std::pair<double, double>> result;
46 result.reserve(npoints);
47 std::vector<MnUserParameterState> states;
61 double valx =
fMinimum.UserState().Value(px);
62 double valy =
fMinimum.UserState().Value(py);
64 print.
Debug(
"Run Minos to find first 4 contour points. Current minimum is : ",valx,valy);
69 print.
Error(
"unable to find first two points");
72 std::pair<double, double>
ex = mnex();
74 print.
Debug(
"Minos error for p0: ",
ex.first,
ex.second);
79 print.
Error(
"unable to find second two points");
82 std::pair<double, double>
ey = mney();
84 print.
Debug(
"Minos error for p0: ",
ey.first,
ey.second);
95 auto findCrossValue = [&](
unsigned int ipar,
double startValue,
double direction,
bool & status) {
96 std::vector<unsigned int> vpar(1, ipar);
97 std::vector<double> vmid(1, startValue);
98 std::vector<double> vdir(1, direction);
100 MnCross crossResult = cross1(vpar, vmid, vdir, toler, maxcalls);
101 status = crossResult.
IsValid();
102 print.
Debug(
"result of findCrossValue for par",ipar,
"status: ",status,
" searching from ",vmid[0],
"dir",vdir[0],
104 return (status) ? vmid[0] + crossResult.
Value() * vdir[0] : 0;
108 auto findContourPointsAtBorder = [&](
unsigned int p1,
unsigned int p2,
double p1Limit,
FunctionMinimum & minp2,
bool order) {
114 double deltaFCN =
fMinimum.Fval() +
fFCN.Up()- minp2.UserState().Fval();
115 double pmid = minp2.UserState().Value(p2);
116 double pdir = minp2.UserState().Error(p2) * deltaFCN/
fFCN.Up();
117 double y1 = findCrossValue(p2, pmid, pdir, ret1);
118 double y2 = findCrossValue(p2, pmid, -pdir, ret2);
119 if (!ret1 && !ret2) {
120 return std::vector<double>();
122 std::vector<double> yvalues; yvalues.reserve(2);
125 yvalues.push_back(y1);
126 }
else if (!ret1 && ret2) {
127 yvalues.push_back(y2);
130 if (std::abs(y1-y2) > 0.0001 *
fMinimum.UserState().Error(p2)) {
132 int orderDir = (order) ? 1 : -1;
133 if (orderDir*(y2-y1) > 0) {
134 yvalues.push_back(y1);
135 yvalues.push_back(y2);
137 yvalues.push_back(y2);
138 yvalues.push_back(y1);
142 yvalues.push_back(y1);
144 print.
Debug(
"Found contour point at the border: ",ustate.
Value(p1),
" , ",yvalues[0]);
145 if (yvalues.size() > 1) print.
Debug(
"Found additional point at : ",ustate.
Value(p1),
" , ",yvalues[1]);
150 std::vector<double> yvalues_xlo(1);
154 nfcn += exy_lo.
NFcn();
156 print.
Error(
"unable to find Lower y Value for x Parameter", px);
160 print.
Debug(
"Minimum fcn value for px set to ",valx +
ex.first,
" is at py = ",yvalues_xlo[0],
" fcn = ",exy_lo.
UserState().
Fval());
163 yvalues_xlo = findContourPointsAtBorder(px,py,ustate.
Parameter(px).
LowerLimit(),exy_lo,
false);
164 if (yvalues_xlo.empty()) {
165 print.
Error(
"unable to find corresponding value for ",py,
"when Parameter",px,
"is at lower limit: ", ustate.
Value(px));
171 std::vector<double> yvalues_xup(1);
175 nfcn += exy_up.
NFcn();
177 print.
Error(
"unable to find Upper y Value for x Parameter", px);
181 print.
Debug(
"Minimum fcn value for px set to ",valx +
ex.second,
" is at py = ",yvalues_xup[0],
" fcn = ",exy_up.
UserState().
Fval());
184 yvalues_xup = findContourPointsAtBorder(px,py,ustate.
Parameter(px).
UpperLimit(),exy_up,
true);
185 if (yvalues_xup.empty()) {
186 print.
Error(
"unable to find corresponding value for ",py,
"when Parameter",px,
"is at upper limit: ", ustate.
Value(px));
195 std::vector<double> xvalues_ylo(1);
198 nfcn += eyx_lo.
NFcn();
200 print.
Error(
"unable to find Lower x Value for y Parameter", py);
204 print.
Debug(
"Minimum fcn value for py set to ",valy +
ey.first,
" is at px = ",xvalues_ylo[0],
" fcn = ",eyx_lo.
UserState().
Fval());
207 xvalues_ylo = findContourPointsAtBorder(py,px,ustate.
Parameter(py).
LowerLimit(),eyx_lo,
true);
208 if (xvalues_ylo.empty()) {
209 print.
Error(
"unable to find corresponding value for ",px,
"when Parameter",py,
"is at lower limit: ", ustate.
Value(py));
214 std::vector<double> xvalues_yup(1);
218 nfcn += eyx_up.
NFcn();
220 print.
Error(
"unable to find Upper x Value for y Parameter", py);
224 print.
Debug(
"Minimum fcn value for py set to ",valy +
ey.second,
" is at px = ",xvalues_yup[0],
" fcn = ",eyx_up.
UserState().
Fval());
227 xvalues_yup = findContourPointsAtBorder(py,px,ustate.
Parameter(py).
UpperLimit(),eyx_up,
false);
228 if (xvalues_yup.empty()) {
229 print.
Error(
"unable to find corresponding value for ",px,
"when Parameter",py,
"is at upper limit: ", ustate.
Value(py));
235 result.emplace_back(valx +
ex.first, yvalues_xlo[0]);
236 if (yvalues_xlo.size()==2) result.emplace_back(valx +
ex.first, yvalues_xlo[1]);
238 result.emplace_back(xvalues_ylo[0], valy +
ey.first);
239 if (xvalues_ylo.size()==2) result.emplace_back(xvalues_ylo[1],valy +
ey.first );
241 result.emplace_back(valx +
ex.second, yvalues_xup[0]);
242 if (yvalues_xup.size()==2) result.emplace_back(valx +
ex.second, yvalues_xup[1]);
244 result.emplace_back(xvalues_yup[0], valy +
ey.second);
245 if (xvalues_yup.size()==2) result.emplace_back(xvalues_yup[1],valy +
ey.second );
251 print.
Debug([&](std::ostream &os){
252 os <<
"List of first " << result.size() <<
" points found: \n";
253 os <<
"Parameters : " << upar.
Name(px) <<
"\t" << upar.
Name(py) << std::endl;
254 for (
auto & p : result) os << p << std::endl;
257 double scalx = 1. / (
ex.second -
ex.first);
258 double scaly = 1. / (
ey.second -
ey.first);
263 std::vector<unsigned int> par(2);
269 unsigned int np0 = result.size();
270 for (
unsigned int i = np0; i < npoints; i++) {
273 auto idist1 = result.end() - 1;
274 auto idist2 = result.begin();
275 double dx = idist1->first - (idist2)->first;
276 double dy = idist1->second - (idist2)->second;
277 double bigdis = scalx * scalx * dx * dx + scaly * scaly * dy * dy;
279 for (
auto ipair = result.begin(); ipair != result.end() - 1; ++ipair) {
280 double distx = ipair->first - (ipair + 1)->first;
281 double disty = ipair->second - (ipair + 1)->second;
282 double dist = scalx * scalx * distx * distx + scaly * scaly * disty * disty;
302 bool validPoint =
false;
306 if (nfcn > maxcalls) {
307 print.
Error(
"maximum number of function calls exhausted");
311 print.
Debug(
"Find new contour point between points with max sep: (",idist1->first,
", ",idist1->second,
") and (",
312 idist2->first,
", ",idist2->second,
") with weights ",a1,a2);
316 double xmidcr = a1 * idist1->first + a2 * (idist2)->first;
317 double ymidcr = a1 * idist1->second + a2 * (idist2)->second;
319 double xdir = (idist2)->second - idist1->second;
320 double ydir = idist1->first - (idist2)->first;
321 double scalfac = sca * std::max(std::fabs(xdir * scalx), std::fabs(ydir * scaly));
322 double xdircr = xdir / scalfac;
323 double ydircr = ydir / scalfac;
324 std::vector<double> pmid(2);
327 std::vector<double> pdir(2);
331 print.
Debug(
"calling MnCross with pmid: ",pmid[0],pmid[1],
"and pdir ",pdir[0],pdir[1]);
332 MnCross opt = cross(par, pmid, pdir, toler, maxcalls);
339 print.
Info(
"Unable to find point on Contour", i + 1,
'\n',
"found only", i,
"points");
341 }
else if (a1 > 0.5) {
344 print.
Debug(
"Unable to find point, try closer to p2 with weight values",a1,a2);
348 print.
Debug(
"Unable to find point, try closer to p1 with weight values",a1,a2);
354 double aopt = opt.
Value();
355 int pos = result.size();
356 if (idist2 == result.begin()) {
357 result.emplace_back(xmidcr + (aopt)*xdircr, ymidcr + (aopt)*ydircr);
358 print.
Info(result.back());
361 auto itr = result.insert(idist2, {xmidcr + (aopt)*xdircr, ymidcr + (aopt)*ydircr});
362 pos = std::distance(result.begin(),itr);
368 }
while (!validPoint);
371 print.
Info(
"Number of contour points =", result.size());