Angular analysis of B+->K*+(K+pi0)mumu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
23 KiB

  1. //Renata Kopecna
  2. #include <toysfit.hh>
  3. #include <constants.hh>
  4. #include <fitter.hh>
  5. #include <bu2kstarmumu_pdf.hh>
  6. #include <bu2kstarmumu_plotter.hh>
  7. #include <folder.hh>
  8. #include "generatetoys.hh"
  9. #include <design.hh>
  10. #include <helpers.hh>
  11. #include <paths.hh>
  12. #include <event.hh>
  13. #include <spdlog.h>
  14. //Fit the toys and save results somewhere
  15. int toysfit(fcnc::options opts, unsigned int nBins, bool fitReference, basic_params params, bool onlySig, bool onlyBkg){
  16. opts.job_id = params.jobID; //Just to be sure
  17. spdlog::info("[TOYSFIT]\t Starting fit with jobID {0:d}", opts.job_id);
  18. //actually fit the toy events
  19. const bool do_fit = true;
  20. if(!do_fit) spdlog::warn("Fitting of the toy sample is disabled. Set hardcoded 'do_fit' to true in toysfit.cc");
  21. //It is useful to save the generated toys in order to debug
  22. const bool SaveTheToys = params.index==-1;
  23. const bool SaveProjections = params.index==-1;
  24. opts.plot_folder = get_ToysFitPlot_path(params);
  25. const bool save_init = (params.index==-1 || params.jobID ==0);
  26. if(!save_init)spdlog::warn("Saving the initialised parameters for the toy generation is disabled. Set hardcoded 'save_init' to true in toysfit.cc");
  27. const bool bkgFromHighMass = true;
  28. const bool bkgFromLowMass = false;
  29. const bool SimultaneousFit = true;
  30. //Fit ranges for angles
  31. double angleStepSize = 0.01;
  32. double PprimeRangeScale = 10.0;
  33. double angleRange = 1.0;
  34. if (params.usePprime) angleRange *= PprimeRangeScale;
  35. double swaveStepSize = 0.1;
  36. //Set what parameters to fix
  37. fixConstr Bmass_FC(!fitReference || onlyBkg,false); //Fix/constrain B mass
  38. fixConstr f_sig_FC(false,false); //Fix/constrain f_sig?
  39. fixConstr ang_params_FC(false,false); //Fix/constrain angular parameters?
  40. fixConstr mass_params_FC(true,false); //Fix/constrain mass parameters?
  41. fixConstr bkg_ang_FC(false,false); //Fix/constrain angular background?
  42. fixConstr bkg_Kpi_FC(false,false); //Fix/constrain Kst mass background?
  43. fixConstr bkg_mass_FC(false, false); //Fix/constrain mass background?
  44. //This boolean decides whether to fit the bkg with order of five or of two //TODO: Should be less hardcody
  45. bool setCtkToTwo = !fitReference;
  46. opts.bkg_order_costhetak = 5;
  47. if(params.folding == 4 && !fitReference){
  48. setCtkToTwo = false;
  49. opts.bkg_order_costhetak = 4;
  50. }
  51. opts.flat_bkg = false;
  52. opts.fit_full_angular_bkg = true; //Do you want to fold also the bkg?
  53. //Init angular parameters according to SM (true) or previous measurements (false)?
  54. opts.initSM = true;
  55. //Weighted fit
  56. opts.weighted_fit = true;
  57. //Set s-wave parameters to fix
  58. fixConstr gammakstar_FC(true,false); //Fix/constrain gammakstar
  59. fixConstr gammakstarplus_FC(true,false); //Fix/constrain gammakstar
  60. fixConstr sWave_FC(onlyBkg || !fitReference ,false); //Fix/constrain sWave parameters?
  61. fixConstr FS_FC(onlyBkg || !fitReference,false);
  62. //FS is fixed no matter what
  63. //Fix to something else afterwards
  64. bool changeFS = false;
  65. //Do or do not fit s-wave
  66. opts.swave = !onlyBkg;//TODO
  67. //Fit kpi or not
  68. opts.fit_mkpi = opts.swave || onlyBkg;
  69. //Quick sanity checks
  70. if (onlyBkg && onlySig){
  71. spdlog::error("Cannot have onlyBkg && onlySig! Returning.");
  72. return 1;
  73. }
  74. if (bkgFromHighMass && bkgFromLowMass){
  75. spdlog::error("Cannot have background taken only from upper and only from lower mass sideband at the same time! Returning.");
  76. return 1;
  77. }
  78. //Save plots?
  79. opts.write_eps = SaveProjections;
  80. opts.write_pdf = false;
  81. //Plot less bins for signal channel as the stats are sad there
  82. if (!fitReference) opts.plots_m_bins = 30;
  83. //Plot less bins for signal channel as the stats are sad there
  84. if (!fitReference) opts.plots_mkpi_bins = 20;
  85. //Fit both mass and angles, use lambda for bkg fit
  86. opts.only_angles = false;
  87. opts.only_Bmass = false;
  88. opts.only_mkpi = false;
  89. //Use weights and squared hesse
  90. opts.shift_lh = false;
  91. opts.use_angular_acc = false;
  92. opts.hesse_postrun = true;
  93. opts.squared_hesse = true;//!(params.index == -1);// fitReference;
  94. opts.minos_errors = false;//(params.index == -1); //!fitReference;
  95. opts.multiply_eff = false; //Toy generated events have saved acceptance weights!
  96. //Fit angular BKG
  97. opts.individual_penalties = false; //forces individual probabilities for sig and bkg to be positive
  98. //How would you like to fit mkpi?
  99. opts.use_mkpi = false;
  100. opts.simple_mkpi = false;
  101. opts.isobar = false;
  102. opts.generate_mkpi = opts.fit_mkpi || opts.use_mkpi;
  103. //Get names for the init parameters file and the fitted parameters file
  104. const std::string results_file = final_result_name_toys(params.jobID,fitReference, nBins, SimultaneousFit, params, opts.run, opts.only_angles, opts.only_Bmass, onlySig, onlyBkg, bkgFromLowMass, bkgFromHighMass);
  105. std::string params_file = init_params_name_toys(params.jobID,fitReference, nBins, SimultaneousFit, params, opts.run, opts.only_angles, opts.only_Bmass, onlySig, onlyBkg, bkgFromLowMass, bkgFromHighMass);
  106. if (existsTest(results_file) && params.index != -1){
  107. spdlog::warn("[SKIP]\t\tJob already run as root-file '"+results_file+"' exists, continue to next job!");
  108. return 0;
  109. }
  110. //Set the available PDFs: this depends on the selected Run for now, so if only one is selected, run over one pdf, if both, use two
  111. std::vector<UInt_t> pdf_idx;
  112. if (params.Run == 1 || params.Run == 12) pdf_idx.push_back(1);
  113. if (params.Run == 2 || params.Run == 12) pdf_idx.push_back(2);
  114. //we are good to go, now; how many individual pdfs are used?
  115. const UInt_t nPDFs = pdf_idx.size();
  116. //current fitter, plotter, parameteres and pdfs:
  117. fcnc::fitter f(&opts);
  118. fcnc::options theOptions[nPDFs];
  119. fcnc::bu2kstarmumu_plotter * thePlotter[nPDFs];
  120. std::vector<fcnc::parameters*> theParams [nBins];
  121. std::vector<fcnc::pdf*> theProbs [nBins];
  122. std::vector< std::vector<fcnc::event>* > selection[nBins];
  123. //Initialize common parameters
  124. std::vector<std::string> common_params = param_string(opts, false); //All the angular observables are shared
  125. if(SimultaneousFit) f.set_common_parameters(common_params);
  126. //--------------------------------
  127. // Read events
  128. //--------------------------------
  129. //Init vector for the events to be saved, in case required
  130. std::vector<fcnc::event> eventsToSave;
  131. //Loop over PDFs and initialize parameters
  132. for(unsigned n = 0; n < nPDFs; n++){
  133. unsigned int idx = pdf_idx.at(n);
  134. opts.run = idx; //Set proper run to options
  135. spdlog::debug("Run {0:d}", opts.run);
  136. opts.name = get_ToysFit_label(params.jobID, fitReference, -1, nBins, SimultaneousFit, params, opts.run, opts.only_angles, opts.only_Bmass, onlySig, onlyBkg, bkgFromLowMass, bkgFromHighMass);
  137. opts.update_angle_ranges(); //Set angles in options back to defaults
  138. opts.update_efficiencies = true; //This ensures the acceptance weights to be taken into account
  139. opts.plot_label = "Toys";
  140. //Get options separate for all PDFs
  141. theOptions[n] = opts;
  142. for(UInt_t b = 0; b < nBins; b++){
  143. opts.q2_min = theOptions[n].TheQ2binsmin.front();
  144. opts.q2_max = theOptions[n].TheQ2binsmax.back();
  145. //-----------------------------------------
  146. // Initialize 1D parameters
  147. //-----------------------------------------
  148. //create parameter sets:
  149. fcnc::bu2kstarmumu_parameters * leParameters = new fcnc::bu2kstarmumu_parameters(&theOptions[n]);
  150. //create PDFs
  151. fcnc::bu2kstarmumu_pdf * lePDF = new fcnc::bu2kstarmumu_pdf(&theOptions[n], leParameters);
  152. //cache the folding and set to -1 for loading mass parameters from non-folded fits to jpsi, MC, etc.
  153. int cached_folding = params.folding;
  154. params.folding = -1;
  155. //Inititalize q2 by hand
  156. leParameters->eff_q2.init_fixed( bin_center_q2(theOptions[n],b));
  157. //Init the fraction betweeen sig and bkg
  158. if (onlySig) leParameters->f_sig.init_fixed(1.0);
  159. else if (onlyBkg) leParameters->f_sig.init_fixed(0.0);
  160. else{ //Or both, in that case load the f_sig from mass only fit
  161. initialize_parameters_from_MassFit(leParameters,fitReference,idx,b,{"f_sig"},params,f_sig_FC);
  162. }
  163. //**********************************//
  164. // //
  165. // Bmass //
  166. // //
  167. //**********************************//
  168. //Set the Bmass separatelly as it's range is important
  169. std::string fileName_dataMass = final_result_name_mass(true, 1, true, params, params.Run);
  170. leParameters->init_Bmass(fileName_dataMass,idx,0.5,Bmass_FC);
  171. //Init B mass fit from Jpsi MC
  172. if (!onlyBkg){
  173. initialize_parameters_from_MCfit(leParameters,true,idx,b, {"alpha_1","alpha_2","n_1","n_2"},params, mass_params_FC);
  174. //Init the ratio of sigmas in signal MC/reference MC
  175. initialize_parameters_from_MassFit(leParameters,true,idx,b,{"m_sigma_1"},params,fixConstr(!fitReference,false));
  176. if (!fitReference){
  177. leParameters->m_scale.init_fixed(get_sigmaRatio_fromMC(params,nBins,b,pdf_idx.at(n)));
  178. }
  179. else{
  180. leParameters->m_scale.init_fixed(1.0);
  181. }
  182. }
  183. //Init the mass background from mass fit to reference for now
  184. //TODO: set as a proper vector depending on using 2 lambdas or anything
  185. if (!onlySig) initialize_parameters_from_MassFit(leParameters,fitReference,idx,b,{"m_lambda"},params,bkg_mass_FC);
  186. //**********************************//
  187. // //
  188. // Angles //
  189. // //
  190. //**********************************//
  191. //Init angular parameters from MC
  192. if (!onlyBkg){
  193. if (opts.initSM){
  194. leParameters->init_angular_parameters(nBins,b,ang_params_FC.fix ? 0.0 : angleStepSize,1.0,false); //TODO: make it better
  195. }
  196. else{
  197. if (fitReference) leParameters->init_ang_parameters_fromRefDavid(b,1.0,0.01);
  198. else initialize_parameters_from_MCfit(leParameters,false,idx,b,param_string(opts, true),params, ang_params_FC);
  199. }
  200. }
  201. //Init the bkg parameters from the BKG fit file
  202. if (!onlySig){
  203. if (opts.flat_bkg) leParameters->use_default_bkg();
  204. else{
  205. //First init the background for angles for all orders
  206. initialize_parameters_from_BkgFit(leParameters, true,
  207. bkgFromLowMass, bkgFromHighMass,false, 12,b,
  208. PAR_BKG_STRING(-1,opts.bkg_order_costhetal,opts.bkg_order_costhetak),
  209. params,fixConstr(true,false));
  210. //Now let float only the ones actually used by the folding
  211. initialize_parameters_from_BkgFit(leParameters, true,
  212. bkgFromLowMass, bkgFromHighMass,false, 12,b,
  213. PAR_BKG_STRING(cached_folding,opts.bkg_order_costhetal,opts.bkg_order_costhetak),
  214. params,bkg_ang_FC);
  215. if (opts.bkg_order_costhetak>=3 && cached_folding!=4){
  216. leParameters->cbkgctk3.init(-2.25,-3.25,1.5,0.05);
  217. }
  218. //Then init the background for m_Kpi
  219. if (opts.generate_mkpi){
  220. initialize_parameters_from_BkgFit(leParameters, true,
  221. bkgFromLowMass, bkgFromHighMass,
  222. true, 12,
  223. b,param_string_bkg_mkpi(),params,bkg_Kpi_FC);
  224. }
  225. }
  226. }
  227. //**********************************//
  228. // //
  229. // S wave and Kstar //
  230. // //
  231. //**********************************//
  232. //Init the Kstar mass fit
  233. if(opts.generate_mkpi){
  234. //p-wave
  235. leParameters->init_mkpi_pWave_parameters(fitReference,gammakstar_FC.fix ? 0.0:0.01);
  236. //s-wave
  237. if (opts.swave) leParameters->init_mkpi_sWave_parameters(fitReference,gammakstarplus_FC.fix ? 0.0:0.001);
  238. }
  239. if (opts.swave){
  240. leParameters->init_sWave_parameters(sWave_FC.fix ? 0.0 : swaveStepSize);
  241. std::string RefMassFile = final_result_name_mass(true,1,true,params,params.Run);
  242. if (!fitReference) leParameters->FS.init(0.25,-0.25,1.0,FS_FC.fix ? 0.0 : 0.1);
  243. else leParameters->get_param_from_rootfile(RefMassFile, {"FS"}, idx, 0,FS_FC);
  244. if (changeFS) leParameters->FS.set_constant();
  245. }
  246. //set folding back to configured value using the cached value from above:
  247. params.folding = cached_folding;
  248. spdlog::info("[PDF{0:d}]\tSaved PDF and parameters!", n);
  249. //Save the events now
  250. std::vector<fcnc::event> * leEvents = new std::vector<fcnc::event>;
  251. if(theOptions[n].job_id >= 0){
  252. //Seed is opts->get_job_id()*opts->ncores+thread_id+12345 if opts->static_seed, else take from the internal clock backwards
  253. std::vector<fcnc::event> evts = generateToys(params, b, pdf_idx.at(n),
  254. leParameters,theOptions[n]);
  255. //copy generated events to pointer vector object
  256. leEvents->clear();
  257. //count the number of dismissed events:
  258. unsigned int dismissed = 0;
  259. for(auto evt: evts){
  260. theOptions[n].update_angle_ranges(); //Update angle ranges based on the folding
  261. //filter events, that are outside the defined angular range:
  262. if(!filterFldFour(&evt, &theOptions[n])){ //I don't think this should be here at all
  263. dismissed++;
  264. continue;
  265. }
  266. leEvents->push_back(evt);
  267. }
  268. spdlog::info("{0:d} generated events are outside the angular range and are dismissed from the sample", dismissed);
  269. assert(leEvents->size()+dismissed == evts.size());
  270. }
  271. else{ //Just load all events TODO
  272. std::vector<fcnc::event> evts = fcnc::load_events("/home/lhcb/kopecna/B2KstarMuMu/code/ewp-Bplus2Kstmumu-AngAna/FCNCfitter/Toys/Toy_toyfit__JpsiFit_1BIN_Run12_SimultaneousFit_6.root","Events", -1); //copy generated events to pointer vector object
  273. leEvents->clear();
  274. for(auto evt: evts)leEvents->push_back(evt);
  275. assert(leEvents->size() == evts.size());
  276. }
  277. spdlog::info("[PDF{0:d}]\tFinished generating the events: {1:d}", n, leEvents->size());
  278. if (!onlySig && setCtkToTwo){
  279. theOptions[n].bkg_order_costhetak = 2;
  280. leParameters->use_default_bkg();
  281. leParameters->init_angular_background_parameters(fitReference,0.01);
  282. }
  283. if (changeFS){
  284. leParameters->FS.init_fixed(0.0);
  285. leParameters->SS1.init_fixed(0.0);
  286. leParameters->SS2.init_fixed(0.0);
  287. leParameters->SS3.init_fixed(0.0);
  288. leParameters->SS4.init_fixed(0.0);
  289. leParameters->SS5.init_fixed(0.0);
  290. }
  291. leParameters->take_current_as_start();
  292. lePDF->load_coeffs_eff_phsp_4d();
  293. lePDF->update_cached_normalization(leParameters);
  294. theParams [b].push_back(leParameters);
  295. theProbs [b].push_back(lePDF);
  296. lePDF->update_cached_efficiencies(leParameters, leEvents);
  297. if (SaveTheToys){
  298. //save all events into one vector, except for the fifth (extra wide bin) in the 5BIN scheme. this would be double counting events
  299. if(!(nBins == 5 && b == 4))eventsToSave.insert(eventsToSave.end(),leEvents->begin(),leEvents->end());
  300. }
  301. //save event vector in vector
  302. selection[b].push_back(leEvents);
  303. } //end loop over bins
  304. theOptions[n].update_efficiencies = false;//Prevent the weights to be applied several more times in fitter::fit
  305. } //end loop over PDFs
  306. //validate correct saving to of all events:
  307. for(unsigned n = 0; n < nPDFs; n++){
  308. for(unsigned int b = 0; b < nBins; b++){
  309. if(selection[b].at(n)->size() > 0){
  310. spdlog::info("[PDF{0:d}]\t[BIN{1:d}]\tDone!", n, b);
  311. }
  312. else{
  313. spdlog::critical("No events found for PDF={0:d} and q2-bin={1:d} Exit!", n, b);
  314. assert(0);
  315. }
  316. }
  317. }
  318. spdlog::info("Finished configurating all parameters, defining all pdfs and generating all toy event samples:");
  319. //If required to save the generated events, save them
  320. if (SaveTheToys){
  321. std::string eventsFile = get_finalToys_file(fitReference,nBins,SimultaneousFit,params,params.Run);
  322. replace(eventsFile,".root","_"+std::to_string(params.jobID)+".root"); //Add the number of the job to the file name
  323. fcnc::save_events(eventsFile,eventsToSave);
  324. }
  325. //Save the initial toy values in a root file
  326. std::vector<int>tmp[nBins]; //Create a vector array with zeros, so you can save init values before the fit
  327. for(unsigned int b = 0; b < nBins; b++)tmp[b] = std::vector<int>(nPDFs, 0);
  328. if(save_init) save_results(params_file,nBins,pdf_idx,tmp,theParams,SimultaneousFit,&opts);
  329. //Save the fit results
  330. std::vector<int>fit_results[nBins];
  331. //fit all bins:
  332. for(unsigned int b = 0; b < nBins; b++){
  333. spdlog::info("");
  334. spdlog::warn("[START]\tStart fit BIN{0:d}", b);
  335. //Int for fit status
  336. int fitresult = 0;
  337. if(!SimultaneousFit){
  338. for(UInt_t n = 0; n < nPDFs; n++){
  339. //Delete the texFile
  340. std::string tag = get_ToysFit_label(params.jobID, fitReference, b, nBins,
  341. false, params, opts.run,
  342. opts.only_angles, opts.only_Bmass,
  343. onlySig, onlyBkg,
  344. bkgFromLowMass, bkgFromHighMass);
  345. spdlog::info("[FIT{0:d}]\tRunning the fitter...", n);
  346. if(do_fit)fitresult = f.fit(theProbs[b].at(n), theParams[b].at(n), selection[b].at(n),tag);
  347. fit_results[b].push_back(fitresult);
  348. }
  349. }
  350. else{
  351. spdlog::info("[FIT]\tFitting simultaenously....");
  352. std::string tag = "";
  353. for(UInt_t n = 0; n < nPDFs; n++)for(UInt_t e = 0; e < selection[b].at(n)->size(); e++)spdlog::trace("Event for fitting: pdf={0:d}\t bin={1:d}\t evt={2:d}\t ctk={3:f}\t ctl={4:f}\t phi={5:f}\t m={6:f}\t mkpi={7:f}", n, b, e, selection[b].at(n)->at(e).costhetak, selection[b].at(n)->at(e).costhetal, selection[b].at(n)->at(e).phi, selection[b].at(n)->at(e).m, selection[b].at(n)->at(e).mkpi);
  354. if(do_fit)fitresult = f.fit(theProbs[b], theParams[b], selection[b], tag);
  355. fit_results[b].push_back(fitresult);
  356. spdlog::info("Q2BIN={0:d}: LLH={1:f}", b, f.likelihood());
  357. }
  358. //Print the fit results
  359. spdlog::info("[BIN{0:d}]: Fitresult: {1:d}", b, fitresult);
  360. spdlog::info("");
  361. }
  362. //Plot stuff if wanted
  363. if (SaveProjections){
  364. //If needed, also save the projections for the toys
  365. //plot each set of pdfs with the data points:
  366. bool plotPulls = true;
  367. for(UInt_t b = 0; b < nBins; b++){
  368. for(UInt_t n = 0; n < nPDFs; n++){
  369. thePlotter[n] = new fcnc::bu2kstarmumu_plotter(&theOptions[n]);
  370. //plot pdf and events:
  371. std::string eps_label = get_ToysFit_label(params.jobID, fitReference, b, nBins,
  372. SimultaneousFit, params, pdf_idx.at(n),
  373. opts.only_angles, opts.only_Bmass,
  374. onlySig, onlyBkg,
  375. bkgFromLowMass, bkgFromHighMass);
  376. theOptions[n].plot_label = "Toys";
  377. if (!fitReference) theOptions[n].plots_m_bins = 30;
  378. if (!fitReference) theOptions[n].plots_mkpi_bins = 20;
  379. theOptions[n].q2_label = q2_label(opts.TheQ2binsmin.at(b), opts.TheQ2binsmax.at(b));
  380. spdlog::info("[PLOT]\t"+eps_label);
  381. thePlotter[n]->SetPulls(plotPulls);
  382. thePlotter[n]->plot_data((fcnc::bu2kstarmumu_pdf*)theProbs[b].at(n), (fcnc::bu2kstarmumu_parameters*)theParams[b].at(n), selection[b].at(n), get_ToysFitPlot_path(params), eps_label, true);
  383. thePlotter[n]->plot_data((fcnc::bu2kstarmumu_pdf*)theProbs[b].at(n), (fcnc::bu2kstarmumu_parameters*)theParams[b].at(n), selection[b].at(n), get_ToysFitPlot_path(params), eps_label+"_incBkg", false);
  384. }
  385. std::vector<fcnc::bu2kstarmumu_pdf*> * prober = (std::vector<fcnc::bu2kstarmumu_pdf*> *) & theProbs[b];
  386. std::string eps_label = get_ToysFit_label(params.jobID, fitReference, b, nBins,
  387. SimultaneousFit, params, params.Run,
  388. opts.only_angles, opts.only_Bmass,
  389. onlySig, onlyBkg,
  390. bkgFromLowMass, bkgFromHighMass);
  391. std::vector<fcnc::bu2kstarmumu_parameters*> * paramser = (std::vector<fcnc::bu2kstarmumu_parameters*> *) & theParams[b];
  392. thePlotter[0]->SetPulls(plotPulls);
  393. thePlotter[0]->plot_added_pdfs(prober, paramser, & selection[b], get_ToysFitPlot_path(params), eps_label, true);
  394. thePlotter[0]->plot_added_pdfs(prober, paramser, & selection[b], get_ToysFitPlot_path(params), eps_label+"_incBkg", false);
  395. }//end loop over bins
  396. }
  397. spdlog::info("[TOYFIT] Fit status results:");
  398. if(SimultaneousFit){
  399. for(UInt_t b = 0; b < nBins; b++)spdlog::info("[BIN{0:d}]: {1:d}", b, fit_results[b].at(0));
  400. }
  401. else{
  402. for(UInt_t b = 0; b < nBins; b++)for(UInt_t n = 0; n < nPDFs; n++)spdlog::info("[BIN{0:d}][PDF{1:d}]: {2:d}", b, n, fit_results[b].at(n));
  403. }
  404. if (params.index == -1) print_all_parameters(nBins, pdf_idx, theParams, spdlog::level::info);
  405. //saving results to root file
  406. save_results(results_file,nBins,pdf_idx,fit_results,theParams,SimultaneousFit,&opts);
  407. spdlog::info("[TOYFIT] Finished.");
  408. return 0;
  409. }