36 #include "Minuit2/Minuit2Minimizer.h" 37 #include "Math/Functor.h" 45 for (
const auto &s : node)
47 const auto key = s.first.as<std::string>();
48 if (std::find(keys.begin(), keys.end(), key) == keys.end())
59 if (node && node[key])
61 return node[key].as<
double>();
69 reqd_headers(
"Minuit2/Minuit2Minimizer.h",
"Math/Functor.h");
74 const int dim = get_dimension();
78 MPI_Comm_size(MPI_COMM_WORLD, &size);
79 const int elements = dim * (dim - 1) / 2;
88 const auto offset = get_inifile_value<double>(
"likelihood: lnlike_offset", 0.);
89 model->setPurposeOffset(offset);
93 const auto algorithm{get_inifile_value<std::string>(
"algorithm",
"combined")};
94 const auto max_loglike_calls{get_inifile_value<int>(
"max_loglike_calls", 100000)};
95 const auto max_iterations{get_inifile_value<int>(
"max_iterations", 100000)};
96 const auto tolerance{get_inifile_value<double>(
"tolerace", 0.0001)};
97 const auto precision{get_inifile_value<double>(
"precision", 0.0001)};
98 const auto print_level{get_inifile_value<int>(
"print_level", 1)};
99 const auto strategy{get_inifile_value<int>(
"strategy", 2)};
104 const auto hypercube_start_node = get_inifile_node(
"unit_hypercube_start");
105 const auto physical_start_node = get_inifile_node(
"start");
107 if (hypercube_start_node && physical_start_node)
109 std::string msg =
"Minuit2: start specified by unit hypercube or physical parameters";
113 check_node_keys(physical_start_node ? physical_start_node : hypercube_start_node, names);
115 const double default_hypercube_start = 0.5;
116 std::vector<double> hypercube_start(dim, default_hypercube_start);
117 std::unordered_map<std::string, double> physical_start_map;
119 if (physical_start_node)
121 physical_start_map = model.
transform(hypercube_start);
122 for (
auto &s : physical_start_map)
124 s.second =
get_node_value(physical_start_node, s.first, s.second);
130 for (
int i = 0; i < dim; i++)
132 hypercube_start[i] =
get_node_value(hypercube_start_node, names[i], hypercube_start[i]);
134 physical_start_map = model.
transform(hypercube_start);
140 const double default_hypercube_step = 0.01;
141 const auto hypercube_step_node = get_inifile_node(
"unit_hypercube_step");
142 const auto physical_step_node = get_inifile_node(
"step");
144 if (hypercube_step_node && physical_step_node)
146 std::string msg =
"Minuit2: step specified by unit hypercube or physical parameters";
150 check_node_keys(physical_step_node ? physical_step_node : hypercube_step_node, names);
152 std::vector<double> hypercube_step;
154 if (physical_step_node)
156 const auto center = model.
transform(hypercube_start);
158 for (
int i = 0; i < dim; i++)
160 if (!physical_step_node[names[i]])
162 hypercube_step.push_back(default_hypercube_step);
166 double physical_step = physical_step_node[names[i]].as<
double>();
167 auto forward = center;
168 forward.at(names[i]) += physical_step;
169 auto backward = center;
170 backward.at(names[i]) -= physical_step;
174 const double mean_step = 0.5 * (hypercube_forward[i] - hypercube_backward[i]);
175 hypercube_step.push_back(mean_step);
181 for (
const auto&
n : names)
183 hypercube_step.push_back(
get_node_value(hypercube_step_node,
n, default_hypercube_step));
189 ROOT::Minuit2::EMinimizerType kalgorithm;
190 if (algorithm ==
"simplex")
192 kalgorithm = ROOT::Minuit2::kSimplex;
194 else if (algorithm ==
"combined")
196 kalgorithm = ROOT::Minuit2::kCombined;
198 else if (algorithm ==
"scan")
200 kalgorithm = ROOT::Minuit2::kScan;
202 else if (algorithm ==
"fumili")
204 kalgorithm = ROOT::Minuit2::kFumili;
206 else if (algorithm ==
"bfgs")
208 kalgorithm = ROOT::Minuit2::kMigradBFGS;
210 else if (algorithm ==
"migrad")
212 kalgorithm = ROOT::Minuit2::kMigrad;
216 std::string msg =
"Minuit2: Unknown algorithm: " + algorithm;
220 ROOT::Math::Minimizer* min =
new ROOT::Minuit2::Minuit2Minimizer(kalgorithm);
221 min->SetStrategy(strategy);
222 min->SetMaxFunctionCalls(max_loglike_calls);
223 min->SetMaxIterations(max_iterations);
224 min->SetTolerance(tolerance);
225 min->SetPrintLevel(print_level);
226 min->SetPrecision(precision);
228 auto chi_squared = [&model, dim] (
const double* x)
230 std::vector<double> v;
231 for (
int i = 0; i < dim; i++)
235 return -2. * model(v);
238 ROOT::Math::Functor
f(chi_squared, dim);
243 for (
int i = 0; i < dim; i++)
245 const bool added = min->SetLimitedVariable(i, names[i], hypercube_start[i], hypercube_step[i], 0., 1.);
248 std::cout << names[i] <<
". hypercube = " << hypercube_start[i]
249 <<
" +/- " << hypercube_step[i]
250 <<
". physical = " << physical_start_map.at(names[i]) << std::endl;
261 std::cout <<
"minimum chi-squared = " << min->MinValue() << std::endl;
263 const double *best_fit_hypercube = min->X();
264 for (
int i = 0; i < dim; i++)
266 std::cout <<
"best-fit hypercube " << i <<
" = " 267 << best_fit_hypercube[i] << std::endl;
271 std::vector<double> v;
272 for (
int i = 0; i < dim; i++)
274 v.push_back(best_fit_hypercube[i]);
276 auto best_fit_physical = model.
transform(v);
277 std::cout <<
"best-fit physical = " << best_fit_physical << std::endl;
280 const int status = min->Status();
std::vector< std::string > get_names() const
Declarations for the YAML options class.
General small utility functions.
ScannerBit interface to Minuit2.
std::unordered_map< std::string, double > transform(const std::vector< double > &vec)
#define plugin_main(...)
Declaration of the main function which will be ran by the interface.
scanner_plugin(minuit2, version(6, 23, 01))
Utility Functions for the Gambit Scanner.
Simple header file for turning compiler warnings back on after having included one of the begin_ignor...
Pragma directives to suppress compiler warnings coming from including MPI library headers...
void check_node_keys(YAML::Node node, std::vector< std::string > keys)
Check that a yaml node does not contain unexpected keys.
EXPORT_SYMBOLS error & scan_error()
Scanner errors.
#define reqd_libraries(...)
Tells ScannerBit that these libraries are requested.
double get_node_value(YAML::Node node, std::string key, double default_)
Get a particular key from a node.
std::vector< double > inverse_transform(const std::unordered_map< std::string, double > &physical)
#define reqd_headers(...)
Tells ScannerBit that these include files must exist.
declaration for scanner module
likelihood container for scanner plugins.