-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Random start points option for profiled POIs #713
Changes from 3 commits
45fc551
3326195
cf60fa4
4c10a7c
018fe0e
eff8006
032dc17
6ed9c9a
8feba2d
2f19e02
e1f2b66
3177041
2c1e05b
4657a55
a22bb47
a17df94
42c3c82
1889f09
56c4471
1491724
ce5c9d2
b34142c
abb232a
8cfc616
0963769
58bbff0
0af5422
09ad136
3360d4c
709c637
8e7e17d
e2fda6e
c0fcac9
2c31c72
b6b0125
1f7b676
98c9983
0e06eb3
1932f09
2561169
25db367
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,7 @@ float MultiDimFit::centeredRange_ = -1.0; | |
bool MultiDimFit::robustHesse_ = false; | ||
std::string MultiDimFit::robustHesseLoad_ = ""; | ||
std::string MultiDimFit::robustHesseSave_ = ""; | ||
int MultiDimFit::pointsRandProf_ = 0; | ||
|
||
|
||
std::string MultiDimFit::saveSpecifiedFuncs_; | ||
|
@@ -110,6 +111,7 @@ MultiDimFit::MultiDimFit() : | |
("robustHesse", boost::program_options::value<bool>(&robustHesse_)->default_value(robustHesse_), "Use a more robust calculation of the hessian/covariance matrix") | ||
("robustHesseLoad", boost::program_options::value<std::string>(&robustHesseLoad_)->default_value(robustHesseLoad_), "Load the pre-calculated Hessian") | ||
("robustHesseSave", boost::program_options::value<std::string>(&robustHesseSave_)->default_value(robustHesseSave_), "Save the calculated Hessian") | ||
("pointsRandProf", boost::program_options::value<int>(&pointsRandProf_)->default_value(pointsRandProf_), "Number of random start points to try for the profiled POIs") | ||
; | ||
} | ||
|
||
|
@@ -139,6 +141,11 @@ void MultiDimFit::applyOptions(const boost::program_options::variables_map &vm) | |
if (vm["floatOtherPOIs"].defaulted()) floatOtherPOIs_ = true; | ||
if (vm["saveInactivePOI"].defaulted()) saveInactivePOI_ = true; | ||
} else throw std::invalid_argument(std::string("Unknown algorithm: "+algo)); | ||
if (pointsRandProf_ > 0) { | ||
// Probably not the best way of doing this | ||
// But right now the pointsRandProf_ option relies on saveInactivePOI_ being true to include the profiled POIs in specifiedVars_ | ||
saveInactivePOI_ = true; | ||
} | ||
fastScan_ = (vm.count("fastScan") > 0); | ||
squareDistPoiStep_ = (vm.count("squareDistPoiStep") > 0); | ||
skipInitialFit_ = (vm.count("skipInitialFit") > 0); | ||
|
@@ -186,6 +193,7 @@ bool MultiDimFit::runSpecific(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooS | |
if (verbose <= 3) RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CountErrors); | ||
bool doHesse = (algo_ == Singles || algo_ == Impact) || (saveFitResult_) ; | ||
if ( !skipInitialFit_){ | ||
std::cout << "Doing initial fit: " << std::endl; | ||
res.reset(doFit(pdf, data, (doHesse ? poiList_ : RooArgList()), constrainCmdArg, (saveFitResult_ && !robustHesse_), 1, true, false)); | ||
if (!res.get()) { | ||
std::cout << "\n " <<std::endl; | ||
|
@@ -606,7 +614,10 @@ void MultiDimFit::doGrid(RooWorkspace *w, RooAbsReal &nll) | |
//minim.setStrategy(minimizerStrategy_); | ||
std::auto_ptr<RooArgSet> params(nll.getParameters((const RooArgSet *)0)); | ||
RooArgSet snap; params->snapshot(snap); | ||
//snap.Print("V"); | ||
if (verbose > 1) { | ||
std::cout << "Print snap: " << std::endl; | ||
snap.Print("V"); | ||
} | ||
|
||
// check if gridPoints are defined | ||
std::vector<unsigned int> pointsPerPoi; | ||
|
@@ -626,8 +637,12 @@ void MultiDimFit::doGrid(RooWorkspace *w, RooAbsReal &nll) | |
} | ||
|
||
if (n == 1) { | ||
if (verbose > 1) std::cout << "\nStarting n==1. The nll0 from initial fit: " << nll0 << std::endl; | ||
unsigned int points = pointsPerPoi.size() == 0 ? points_ : pointsPerPoi[0]; | ||
|
||
// Set seed for random points | ||
srand(1); | ||
|
||
double xspacing = (pmax[0]-pmin[0]) / points; | ||
double xspacingOffset = 0.5; | ||
if (alignEdges_) { | ||
|
@@ -665,42 +680,148 @@ void MultiDimFit::doGrid(RooWorkspace *w, RooAbsReal &nll) | |
} | ||
|
||
//if (verbose > 1) std::cout << "Point " << i << "/" << points << " " << poiVars_[0]->GetName() << " = " << x << std::endl; | ||
std::cout << "Point " << i << "/" << points << " " << poiVars_[0]->GetName() << " = " << x << std::endl; | ||
std::cout << "Point " << i << "/" << points << " " << poiVars_[0]->GetName() << " = " << x << std::endl; | ||
*params = snap; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From here to L788 or so I think this should also be wrapped in an Here I think it would also good to print a warning / log message to state that this option is active (hopefully avoids people playing with random options and being surprised the fit is taking much longer than before) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a certain caveat to this suggestion. In our current implementation, the default behavior (i.e. just using the default starting point) is incorporated within the random starting point code block. If one wants to retrieve this behavior, one can either choose to set |
||
poiVals_[0] = x; | ||
poiVars_[0]->setVal(x); | ||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////// | ||
/////////////////// Loop over rand points for each profiled POI to get best nll /////////////////// | ||
|
||
bool ok; | ||
int n_prof_params = specifiedVars_.size(); | ||
std::vector<float> nll_at_alt_start_pts; | ||
|
||
// Get vector of points to try | ||
float prof_start_pt_range_max = 20.0; // Is this what we want? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For a generic version of this algorithm, I think you'd want to potentially have a different range for each of the POIs, maybe the range can be read from the ws for each POI? (or the range set by --setParameterRanges) |
||
std::vector<std::vector<float>> wc_vals_vec_of_vec = {}; | ||
|
||
// Append the defualt start pt to the list of points to try | ||
std::vector<float> default_start_pt_vec; | ||
for (int prof_param_idx=0; prof_param_idx<n_prof_params; prof_param_idx++) { | ||
default_start_pt_vec.push_back(specifiedVars_[prof_param_idx]->getVal()); | ||
} | ||
wc_vals_vec_of_vec.push_back(default_start_pt_vec); | ||
|
||
// Append the random points to the vecotr of points to try | ||
for (int pt_idx=0; pt_idx<pointsRandProf_; pt_idx++) { | ||
std::vector<float> wc_vals_vec; | ||
for (int prof_param_idx=0; prof_param_idx<n_prof_params; prof_param_idx++) { | ||
// Get a random number in the range [-prof_start_pt_range_max,prof_start_pt_range_max] | ||
float rand_num = (rand()*2.0*prof_start_pt_range_max)/RAND_MAX - prof_start_pt_range_max; | ||
wc_vals_vec.push_back(rand_num); | ||
} | ||
wc_vals_vec_of_vec.push_back(wc_vals_vec); | ||
} | ||
|
||
// Print vector of points to try | ||
if (verbose > 1) { | ||
std::cout << "List of points to try:" << std::endl; | ||
for (auto vals_vec: wc_vals_vec_of_vec) { | ||
std::cout << "\tThe vals at this point: " << std::endl; | ||
for (auto val: vals_vec) { | ||
std::cout << "\t\tPoint val: " << val << std::endl; | ||
} | ||
} | ||
} | ||
|
||
// Loop over starting points to try for the prof WCs | ||
for (unsigned int start_pt_idx=0; start_pt_idx<wc_vals_vec_of_vec.size(); start_pt_idx++){ | ||
*params = snap; | ||
poiVals_[0] = x; | ||
poiVars_[0]->setVal(x); | ||
|
||
// Loop over prof POIs and set their values | ||
if (verbose > 1) std::cout << "\n\tStart pt idx: " << start_pt_idx << std::endl; | ||
for (unsigned int var_idx=0; var_idx<specifiedVars_.size(); var_idx++){ | ||
if (verbose > 1) std::cout << "\t\tThe var name: " << specifiedVars_[var_idx]->GetName() << std::endl; | ||
if (strcmp(specifiedVars_[var_idx]->GetName(),"r")==0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be skipped in general? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This block of skipping "r" has been removed. We agreed that there is no need to skip this in general. |
||
// Don't bother setting r to anything | ||
if (verbose > 1) std::cout << "\t\t\tSkipping var " << specifiedVars_[var_idx]->GetName() << std::endl; | ||
continue; | ||
} | ||
if (verbose > 1) std::cout << "\t\t\tRange before: " << specifiedVars_[var_idx]->getMin() << " " << specifiedVars_[var_idx]->getMax() << std::endl; | ||
if (verbose > 1) std::cout << "\t\t\t" << specifiedVars_[var_idx]->GetName() << " before setting: " << specifiedVars_[var_idx]->getVal() << " += " << specifiedVars_[var_idx]->getError() << std::endl; | ||
if (pointsRandProf_ > 0) { | ||
specifiedVars_[var_idx]->removeRange(); // Do not impose a range if we're trying multiple random start points | ||
} | ||
specifiedVars_[var_idx]->setVal(wc_vals_vec_of_vec.at(start_pt_idx).at(var_idx)); | ||
if (verbose > 1) std::cout << "\t\t\tRange after: " << specifiedVars_[var_idx]->getMin() << " " << specifiedVars_[var_idx]->getMax() << std::endl; | ||
if (verbose > 1) std::cout << "\t\t\t" << specifiedVars_[var_idx]->GetName() << " after setting: " << specifiedVars_[var_idx]->getVal() << " += " << specifiedVars_[var_idx]->getError() << std::endl; | ||
} | ||
|
||
// now we minimize | ||
nll.clearEvalErrorLog(); | ||
deltaNLL_ = nll.getVal() - nll0; | ||
if (nll.numEvalErrors() > 0) { | ||
deltaNLL_ = 9990; | ||
for(unsigned int j=0; j<specifiedNuis_.size(); j++){ | ||
specifiedVals_[j]=specifiedVars_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedFuncNames_.size(); j++){ | ||
specifiedFuncVals_[j]=specifiedFunc_[j]->getVal(); | ||
} | ||
Combine::commitPoint(true, /*quantile=*/0); | ||
continue; | ||
} | ||
ok = fastScan_ || (hasMaxDeltaNLLForProf_ && (nll.getVal() - nll0) > maxDeltaNLLForProf_) || utils::countFloating(*params)==0 ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just from looking at this I think this instance of |
||
true : | ||
minim.minimize(verbose-1); | ||
|
||
if (verbose > 1) std::cout << "\t\tThe nll.getVal() is: " << nll.getVal() << std::endl; | ||
nll_at_alt_start_pts.push_back(nll.getVal()); | ||
|
||
} | ||
|
||
// Rerun the fit for the point with the min nll | ||
int min_nll_idx; | ||
min_nll_idx = std::min_element(nll_at_alt_start_pts.begin(),nll_at_alt_start_pts.end()) - nll_at_alt_start_pts.begin(); | ||
if (verbose > 1) std::cout << "\tMin nll at idx: " << min_nll_idx << " " << nll_at_alt_start_pts.at(min_nll_idx) << std::endl; | ||
if (verbose > 1) std::cout << "\tResetting for rerunning at the point that gives best nll:" << std::endl; | ||
*params = snap; | ||
poiVals_[0] = x; | ||
poiVars_[0]->setVal(x); | ||
for (unsigned int var_idx=0; var_idx<specifiedVars_.size(); var_idx++){ | ||
if (verbose > 1) std::cout << "\t\tSetting " << specifiedVars_[var_idx]->GetName() << " to " << wc_vals_vec_of_vec.at(min_nll_idx).at(var_idx) << std::endl; | ||
specifiedVars_[var_idx]->setVal(wc_vals_vec_of_vec.at(min_nll_idx).at(var_idx)); | ||
} | ||
// now we minimize | ||
nll.clearEvalErrorLog(); | ||
deltaNLL_ = nll.getVal() - nll0; | ||
if (nll.numEvalErrors() > 0) { | ||
deltaNLL_ = 9990; | ||
for(unsigned int j=0; j<specifiedNuis_.size(); j++){ | ||
specifiedVals_[j]=specifiedVars_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedFuncNames_.size(); j++){ | ||
specifiedFuncVals_[j]=specifiedFunc_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedNuis_.size(); j++){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Restore original spacing? |
||
specifiedVals_[j]=specifiedVars_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedFuncNames_.size(); j++){ | ||
specifiedFuncVals_[j]=specifiedFunc_[j]->getVal(); | ||
} | ||
Combine::commitPoint(true, /*quantile=*/0); | ||
continue; | ||
} | ||
bool ok = fastScan_ || (hasMaxDeltaNLLForProf_ && (nll.getVal() - nll0) > maxDeltaNLLForProf_) || utils::countFloating(*params)==0 ? | ||
ok = fastScan_ || (hasMaxDeltaNLLForProf_ && (nll.getVal() - nll0) > maxDeltaNLLForProf_) || utils::countFloating(*params)==0 ? | ||
true : | ||
minim.minimize(verbose-1); | ||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////// | ||
|
||
if (ok) { | ||
deltaNLL_ = nll.getVal() - nll0; | ||
double qN = 2*(deltaNLL_); | ||
double prob = ROOT::Math::chisquared_cdf_c(qN, n+nOtherFloatingPoi_); | ||
for(unsigned int j=0; j<specifiedNuis_.size(); j++){ | ||
specifiedVals_[j]=specifiedVars_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedFuncNames_.size(); j++){ | ||
specifiedFuncVals_[j]=specifiedFunc_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedCatNames_.size(); j++){ | ||
specifiedCatVals_[j]=specifiedCat_[j]->getIndex(); | ||
} | ||
for(unsigned int j=0; j<specifiedNuis_.size(); j++){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Restore original spacing? |
||
specifiedVals_[j]=specifiedVars_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedFuncNames_.size(); j++){ | ||
specifiedFuncVals_[j]=specifiedFunc_[j]->getVal(); | ||
} | ||
for(unsigned int j=0; j<specifiedCatNames_.size(); j++){ | ||
specifiedCatVals_[j]=specifiedCat_[j]->getIndex(); | ||
} | ||
Combine::commitPoint(true, /*quantile=*/prob); | ||
} | ||
|
||
} | ||
} else if (n == 2) { | ||
RooAbsReal::setEvalErrorLoggingMode(RooAbsReal::CountErrors); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure right now if this could have other knock-on effects, but perhaps it would be better to do this only if
pointsRandProf > 1
just to be safeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved.