void MonitorSettingDialog::onMonitorModeChanged()
{
    const bool intersect = m_primary && m_model->monitorsIsIntersect();
    if (intersect)
        updateModeList(m_model->monitorsSameModeList());
    else
        updateModeList(m_monitor->modeList());

    if (!intersect)
    {
        m_resolutionsModel->setSelectedIndex(m_resolutionsModel->index(m_monitor->modeList().indexOf(m_monitor->currentMode())));
    }
    else
    {
        const ResolutionList list = m_model->monitorsSameModeList();
        const Resolution mode = m_model->monitorList().first()->currentMode();

        for (auto it = list.cbegin(); it != list.cend(); ++it) {
            if (it->id() == mode.id()) {
                m_resolutionsModel->setSelectedIndex(m_resolutionsModel->index(it - list.cbegin()));
                break;
            }
        }
    }
}
void MonitorSettingDialog::onMonitorResolutionSelected(const int index)
{
    const bool intersect = m_primary && m_model->monitorsIsIntersect();

    if (intersect)
    {
        const ResolutionList modeList = m_model->monitorsSameModeList();
        Q_ASSERT(modeList.size() > index);
        const Resolution mode = modeList[index];

        for (Monitor* mon : m_model->monitorList()) {
            const ResolutionList& list = mon->modeList();
            for (auto it = list.cbegin(); it != list.cend(); ++it) {
                if (it->width() == mode.width() && it->height() == mode.height()) {
                    Q_EMIT requestSetMonitorResolution(mon, it->id());
                    break;
                }
            }
        }
    } else {
        const auto modeList = m_monitor->modeList();
        Q_ASSERT(modeList.size() > index);

        Q_EMIT requestSetMonitorResolution(m_monitor, modeList[index].id());
    }
}
Example #3
0
// Perform at most one value conversion from the following set:
//
//    - integer conversions
//    - float conversions
//    - numeric conversions (int to float)
//    - boolean conversions (type to bool)
//
// Note that all such conversions take value expressions as operands: a
// reference-to-value conversion must have been previously applied to
// a reference expressions.
//
// TODO: Implement integer and floating point promotion.
//
// TODO: Support conversion of T[N] to T[].
//
// TODO: Support pointer conversions.
//
// TODO: Support character conversions separately from integer
// conversions?
Expr&
convert_value(Context& cxt, Expr& e, Type& t)
{
  try {
    // Note that errors here are not fatal. If we can't find a conversion,
    // that doesn't mean the program is ill-formed.
    Suppress_diagnostics guard(cxt);

    debug(e);
    debug(t);
  
    // Search for a list of conversion operators for the given type.
    Name& id = cxt.get_conversion_id(t);  
    Decl_list decls = unqualified_lookup(cxt, id);

    // FIXME: What do I do with ambiguous resolutions? Fail to convert?
    Resolution res = resolve_call(cxt, decls, e);
    Function_decl& decl = res.function();
    Expr_list& args = res.arguments();

    // Build a call to the selected conversion.
    Expr& fn = cxt.make_reference(decl.type(), decl);
    Call_expr& conv = cxt.make_call(decl.return_type(), fn, std::move(args));
    conv.res_ = &decl;
    return conv;
  }
  catch (...) {
    return e;
  }

  return e;
}
int ScreenOutput::setScreenResolution(Resolution newScreenResolution)
{
	if(newScreenResolution.getWidth() > 0 && newScreenResolution.getHeight() > 0)
	{
		return resize(newScreenResolution, getAntiAliasingFactor());
	}
	return 0;
}
bool contains(const QList<Resolution> &container, const Resolution &item)
{
    for (auto r : container)
        if (r.width() == item.width() && r.height() == item.height())
            return true;

    return false;
}
Example #6
0
 void SDLPlatform::getDesktopResolution( Resolution & _resolution ) const
 {
     SDL_DisplayMode dm;
     if (SDL_GetDesktopDisplayMode(0, &dm) == 0)
     {
         _resolution.setWidth(static_cast<uint32_t>(dm.w));
         _resolution.setHeight(static_cast<uint32_t>(dm.h));
     }
 }
int ScreenOutput::resize(Resolution newResolution, int newAntiAliasingFactor)
{
	screenResolution = newResolution;
	antiAliasingFactor = newAntiAliasingFactor;
	renderResolution.setWidth(newResolution.getWidth() * newAntiAliasingFactor);
	renderResolution.setHeight(newResolution.getHeight() * newAntiAliasingFactor);
	renderBuffer.resize(renderResolution.getWidth(), renderResolution.getHeight());
	screenBuffer.resize(screenResolution.getWidth(), screenResolution.getHeight());
	screenBMP->SetSize(screenResolution.getWidth(), screenResolution.getHeight());
	return 1;
}
Example #8
0
    bool SDLPlatform::createWindow( uint32_t _icon, const Menge::WString & _projectTitle, const Resolution & _resolution, bool _fullscreen )
    {
        PARAM_UNUSED(_icon);
        PARAM_UNUSED(_fullscreen);

        Menge::Char utf8Title[1024] = { 0 };
        size_t utf8Size = 0;
        UNICODE_SERVICE( m_serviceProvider )->unicodeToUtf8(_projectTitle.c_str(), _projectTitle.size(),
                                                            utf8Title, sizeof(utf8Title) - 1, &utf8Size);

        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

        Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
        if( _fullscreen )
        {
            windowFlags |= SDL_WINDOW_FULLSCREEN;
        }

        m_width = static_cast<int>(_resolution.getWidth());
        m_height = static_cast<int>(_resolution.getHeight());

        m_window = reinterpret_cast<WindowHandle>(SDL_CreateWindow(utf8Title,
                                                                   SDL_WINDOWPOS_CENTERED,
                                                                   SDL_WINDOWPOS_CENTERED,
                                                                   m_width, m_height,
                                                                   windowFlags));
        if( m_window == nullptr )
        {
            return false;
        }

        m_glContext = SDL_GL_CreateContext(reinterpret_cast<SDL_Window*>(m_window));

        if( m_glContext == nullptr )
        {
            SDL_DestroyWindow(reinterpret_cast<SDL_Window*>(m_window));
            return false;
        }

        m_sdlInput->updateSurfaceResolution(static_cast<float>(m_width),
                                            static_cast<float>(m_height));

        return true;
    }
int ScreenOutput::initialize(Resolution initResolution, int initAntiAliasingFactor, TCanvas * initOutputCanvas)
{
	// temp!
	screenResolution = initResolution;
	antiAliasingFactor = initAntiAliasingFactor;
	renderResolution.setWidth(initResolution.getWidth() * initAntiAliasingFactor);
	renderResolution.setHeight(initResolution.getHeight() * initAntiAliasingFactor);
	renderBuffer.initialize(renderResolution.getWidth(), renderResolution.getHeight());
	currentForegroundRenderBuffer = &renderBuffer;
	screenBuffer.initialize(screenResolution.getWidth(), screenResolution.getHeight());
	screenBMP = new Graphics::TBitmap;
	screenBMP->PixelFormat = pf32bit;
	screenBMP->SetSize(screenResolution.getWidth(), screenResolution.getHeight());
	outputCanvas = initOutputCanvas;
	return 1;
}
Example #10
0
	void Resolution::calcScale( const Resolution & _resolution, mt::vec2f & _scale ) const
	{
		mt::vec2f self_size;
		this->calcSize( self_size );

		mt::vec2f other_size;
		_resolution.calcSize( other_size );

		_scale = self_size / other_size;
	}
Example #11
0
/*
 * this function tries to be a 1:1 C++ reimplementation of the Perl function
 * 'read_mcstas_res' of the McStas 'mcresplot' program
 */
Resolution calc_res(std::vector<vector<t_real>>&& Q_vec,
	const vector<t_real>& Q_avg, const std::vector<t_real>* pp_vec)
{
	vector<t_real> Q_dir = tl::make_vec({Q_avg[0], Q_avg[1], Q_avg[2]});
	Q_dir = Q_dir / norm_2(Q_dir);
	vector<t_real> Q_perp = tl::make_vec({-Q_dir[1], Q_dir[0], Q_dir[2]});
	vector<t_real> vecUp = tl::cross_3(Q_dir, Q_perp);

	/*
	 * transformation from the <Q_x, Q_y, Q_z, E> system
	 * into the <Q_avg, Q_perp, Q_z, E> system,
	 * i.e. rotate by the (ki,Q) angle
	 */
	matrix<t_real> trafo = identity_matrix<t_real>(4);
	tl::set_column(trafo, 0, Q_dir);
	tl::set_column(trafo, 1, Q_perp);
	tl::set_column(trafo, 2, vecUp);
	tl::log_info("Transformation: ", trafo);


	Resolution reso;
	reso.Q_avg_notrafo = Q_avg;
	reso.Q_avg = prod(trans(trafo), Q_avg);
	tl::log_info("Transformed average Q vector: ", reso.Q_avg);

	reso.res.resize(4,4,0);
	reso.cov.resize(4,4,0);

	reso.cov = tl::covariance(Q_vec, pp_vec);
	reso.cov = tl::transform<matrix<t_real>>(reso.cov, trafo, true);

	tl::log_info("Covariance matrix: ", reso.cov);
	if(!(reso.bHasRes = tl::inverse(reso.cov, reso.res)))
		tl::log_err("Covariance matrix could not be inverted!");

	if(reso.bHasRes)
	{
		reso.dQ.resize(4, 0);
		for(int iQ=0; iQ<4; ++iQ)
			reso.dQ[iQ] = tl::get_SIGMA2HWHM<t_real>()/sqrt(reso.res(iQ,iQ));

		tl::log_info("Resolution matrix: ", reso.res);

		std::ostringstream ostrVals;
		ostrVals << "Gaussian HWHM values: ";
		std::copy(reso.dQ.begin(), reso.dQ.end(),
			std::ostream_iterator<t_real>(ostrVals, ", "));

		std::ostringstream ostrElli;
		ostrElli << "Ellipsoid offsets: ";
		std::copy(reso.Q_avg.begin(), reso.Q_avg.end(),
			std::ostream_iterator<t_real>(ostrElli, ", "));

		reso.vecQ = std::move(Q_vec);

		tl::log_info(ostrVals.str());
		tl::log_info(ostrElli.str());
	}

	return reso;
}
Example #12
0
bool kanaelec::doKinematicFit(Int_t                 fflage,
			      const TLorentzVector     mup, 
			      const TLorentzVector     nvp, 
			      const TLorentzVector     ajp, 
			      const TLorentzVector     bjp, 
			      TLorentzVector     & fit_mup, 
			      TLorentzVector     & fit_nvp,
			      TLorentzVector     & fit_ajp, 
			      TLorentzVector     & fit_bjp, 
			      Float_t            & fit_chi2,
			      Int_t              & fit_NDF, 
			      Int_t              & fit_status)
{

  bool OK                     = false;
  Resolution* resolution      = new Resolution();

  TMatrixD m1(3,3);
  TMatrixD m2(3,3);
  TMatrixD m3(3,3);
  TMatrixD m4(3,3);
  m1.Zero();
  m2.Zero();
  m3.Zero();
  m4.Zero();

  double etRes, etaRes, phiRes;
  // lepton resolution
  const std::string& leptonName = "electron";  const TLorentzVector lepton   = mup;
  if(leptonName == "electron") {
    OK = resolution->electronResolution(lepton.Et(), lepton.Eta(), etRes, etaRes, phiRes);
    if(!OK) return OK;
  } else {
    OK = resolution->muonResolution(    lepton.Et(), lepton.Eta(), etRes, etaRes, phiRes);
    if(!OK) return OK;
  }
  m1(0,0) = resolution->square(etRes);
  m1(1,1) = resolution->square(etaRes);
  m1(2,2) = resolution->square(phiRes);
  // MET resolution
  OK = resolution->PFMETResolution(     nvp.Et(),            etRes, etaRes, phiRes);
  if(!OK) return OK;
  m2(0,0) = resolution->square(etRes);
  m2(1,1) = 999.9; // resolution->square(etaRes)
  m2(2,2) = resolution->square(phiRes);
  // Leading Jet resolution
  OK = resolution->udscPFJetResolution( ajp.Et(), ajp.Eta(), etRes, etaRes, phiRes);
  if(!OK) return OK;
  m3(0,0) = resolution->square(etRes);
  m3(1,1) = resolution->square(etaRes);
  m3(2,2) = resolution->square(phiRes);
  // Leading Jet resolution
  OK = resolution->udscPFJetResolution( bjp.Et(), bjp.Eta(), etRes, etaRes, phiRes);
  if(!OK) return OK;
  m4(0,0) = resolution->square(etRes);
  m4(1,1) = resolution->square(etaRes);
  m4(2,2) = resolution->square(phiRes);

  TLorentzVector tmp_mup = mup;
  TLorentzVector tmp_nvp = nvp;
  TLorentzVector tmp_ajp = ajp;
  TLorentzVector tmp_bjp = bjp;

  // Fit Particle
  TFitParticleEtEtaPhi* particle1 = new TFitParticleEtEtaPhi( "Lepton",   "Lepton",   &tmp_mup,    &m1 );
  TFitParticleEtEtaPhi* particle2 = new TFitParticleEtEtaPhi( "Neutrino", "Neutrino", &tmp_nvp,    &m2 );
  TFitParticleEtEtaPhi* particle3 = new TFitParticleEtEtaPhi( "Jeta",     "Jeta",     &tmp_ajp,    &m3 );
  TFitParticleEtEtaPhi* particle4 = new TFitParticleEtEtaPhi( "Jetb",     "Jetb",     &tmp_bjp,    &m4 );

  // Constraint
  TFitConstraintM *mCons1 = new TFitConstraintM( "WMassConstrainta", "WMass-Constrainta", 0, 0 , 80.4);
  mCons1->addParticles1( particle1, particle2 );

  TFitConstraintM *mCons2 = new TFitConstraintM( "WMassConstraintb", "WMass-Constraintb", 0, 0 , 80.4);
  mCons2->addParticles1( particle3, particle4 );

  TFitConstraintEp *pxCons = new TFitConstraintEp( "PxConstraint", "Px-Constraint", 0, TFitConstraintEp::pX , (mup+nvp+ajp+bjp).Px() );
  pxCons->addParticles( particle1, particle2, particle3, particle4 );

  TFitConstraintEp *pyCons = new TFitConstraintEp( "PyConstraint", "Py-Constraint", 0, TFitConstraintEp::pY , (mup+nvp+ajp+bjp).Py() );
  pyCons->addParticles( particle1, particle2, particle3, particle4 );

  //Definition of the fitter
  TKinFitter* fitter = new TKinFitter("fitter", "fitter");
  if        (fflage == 1 ){
    fitter->addMeasParticle( particle1 );
    fitter->addMeasParticle( particle2 );
    fitter->addMeasParticle( particle3 );
    fitter->addMeasParticle( particle4 );
    fitter->addConstraint( pxCons );
    fitter->addConstraint( pyCons );
    fitter->addConstraint( mCons1 );
    fitter->addConstraint( mCons2 );
  }else   if(fflage == 2 ){
    fitter->addMeasParticle( particle1 );
    fitter->addMeasParticle( particle2 );
    fitter->addConstraint( mCons1 );
  }else {return false;}

  //Set convergence criteria
  fitter->setMaxNbIter( 30 );
  fitter->setMaxDeltaS( 1e-2 );
  fitter->setMaxF( 1e-1 );
  fitter->setVerbosity(1);
  fitter->fit();

  //Return the kinematic fit results
  fit_status   = fitter->getStatus();
  fit_chi2     = fitter->getS();
  fit_NDF      = fitter->getNDF();
  fit_mup      = *(particle1->getCurr4Vec()); 
  fit_nvp      = *(particle2->getCurr4Vec()); 
  fit_ajp      = *(particle3->getCurr4Vec()); 
  fit_bjp      = *(particle4->getCurr4Vec()); 
  
  if(fitter->getStatus() == 0) { OK = true;  } else { OK = false;  }
  delete resolution;
  delete particle1;
  delete particle2;
  delete particle3;
  delete particle4;
  delete mCons1;
  delete mCons2;
  delete pxCons;
  delete pyCons;
  delete fitter;

  return OK;
}
void draw_tof_singleparticle(const string ConfigDir="../..", const string InFileBase = "../../output/SingleParticle_rv02-00-01_sv02-00-01_mILD_l5_o1_v02/", const string OutFileBase = "../../output/SP") {
  string plot_config_path  = ConfigDir + "/PlottingSettings.cnf";
  string ptype_config_path = ConfigDir + "/ParticleTypes.cnf";
  string res_config_path   = ConfigDir + "/TimeResolutions.cnf";

  float min_p    = 0,   max_p    = 100;
  float min_beta = 0.5, max_beta = 1.05;
  ConfigReader plot_settings_reader(plot_config_path);
  auto beta_p_settings = plot_settings_reader["BetaPPlots"];
  int bins_p        = stoi(beta_p_settings["NbinsBeta"]);
  int bins_beta     = stoi(beta_p_settings["NbinsP"]);
  int every_nth_bin = stoi(beta_p_settings["BinJumpsPerSlice"]); // Consider only every n-th bin (=slice) in the momentum distribution
  
  ConfigReader ptype_reader(ptype_config_path);
  ParticleVec particle_types {};
  auto ptype_names = ptype_reader.get_keys();
  for (auto & ptype_name: ptype_names) { 
    auto ptype_sec = ptype_reader[ptype_name]; // Section 
    particle_types.push_back( ParticleType(stoi(ptype_sec["pdgID"]), ptype_sec["name_s"],  ptype_name, stod(ptype_sec["mass"]), stoi(ptype_sec["colour"])) );
  }
  int N_ptypes = particle_types.size();
  
  ConfigReader res_reader(res_config_path);
  ResVec resolutions {};
  auto res_values = res_reader.get_keys();
  for (auto & res_value: res_values) {
    auto res_sec = res_reader[res_value]; 
    resolutions.push_back( Resolution(stof(res_value), stoi(res_sec["colour"])) );
  }
  int N_ress = resolutions.size();
  
  HistoMap beta_histos {};
  
  for ( auto &ptype : particle_types ) {
    for ( auto &res : resolutions) {
      beta_histos.addHisto( ptype, res );
    }
  }
  // TODO Also loop over different time estimators?? (Here: CH -> Closest Hit)

  unique_ptr<TCanvas> c_dummy {new TCanvas("dummy","",1000,800)}; // To write histos to that don't need to be written to current canvas

  unique_ptr<TCanvas> c_beta_p {new TCanvas("c_beta_p","#beta_{CH} vs momentum",400*N_ress,400*N_ptypes)}; 
  unique_ptr<TCanvas> c_beta_p_average {new TCanvas("c_beta_p_average","#beta_{CH}^{average} vs momentum",400*N_ress,400*N_ptypes)}; 
  c_beta_p->Clear();
  c_beta_p_average->Clear();
  c_beta_p->Divide(resolutions.size(), particle_types.size());
  c_beta_p_average->Divide(resolutions.size(), particle_types.size());
  int i_pad=0;
  
  vector<TFile*> closables {}; // Because ROOT... To collect files that I need to close later
  
  unique_ptr<TFile> file_beta_p {new TFile ( ( OutFileBase + "_beta_p.root" ).c_str() ,"recreate")};
  
  // Get the beta vs p histograms and save for each particle type
  for ( auto & ptype : particle_types ) {
    TFile* file = new TFile ( ( InFileBase + to_string(ptype.pdg_id) + "_lctuple.root" ).c_str() ,"r");
    TTree* tree = (TTree*) file->Get("MyLCTuple");
    
    TF1* beta_func = new TF1( ("beta_func_" + ptype.name_s).c_str(), "x / sqrt(x^2 + [0]^2)", min_p, max_p);
    beta_func->SetParameter(0, ptype.mass);
    beta_func->SetLineWidth(1);
    beta_func->SetLineColorAlpha(6, 0.5);
    file_beta_p->WriteTObject(beta_func);
    
    for (auto &res : resolutions) {
      i_pad++;
      c_beta_p->cd(i_pad);

      string h_beta_name = "h_beta_" + ptype.name_s + "_" + res.str();

      TH2F *h_beta = new TH2F( h_beta_name.c_str(),
                              ("#beta_{CH} vs momentum, " + ptype.name_l + ", " + res.w_unit() + "; p [GeV/c] ; #beta ").c_str(),
                              bins_p, min_p, max_p, bins_beta, min_beta, max_beta
                             );
      
      string tof_res = "tof" + res.str();
      string draw_string = tof_res + "len/" + tof_res + "ch/299.8:sqrt(rcmox*rcmox+rcmoy*rcmoy+rcmoz*rcmoz)>>" + h_beta_name;
      string cut_string  = tof_res + "len>1.&&" + tof_res + "ch>0.1&&(" + tof_res + "len/" + tof_res + "ch/299.8)<1.1 && sqrt(rcmox*rcmox+rcmoy*rcmoy+rcmoz*rcmoz)<100.&&abs(rccha)>0.005 && abs(rcmoz)/sqrt(rcmox*rcmox+rcmoy*rcmoy+rcmoz*rcmoz) < 0.792573 && sqrt(rcmox*rcmox+rcmoy*rcmoy) > 0.948543 && nrec==1";
        
      tree->Draw( draw_string.c_str(), cut_string.c_str(), "colz" );
      file_beta_p->WriteTObject(h_beta);
      beta_func->Draw("same");
      
      c_dummy->cd();
      beta_histos.getHisto(res, ptype)->histo = h_beta;
      beta_histos.getHisto(res, ptype)->slice_histo(every_nth_bin);
      
      c_beta_p_average->cd(i_pad);
      string h_beta_average_name = "h_beta_average_" + ptype.name_s + "_" + res.str();
      TH1F* h_beta_average = new TH1F( h_beta_average_name.c_str(),
                                       ("#beta_{CH}^{average} vs momentum, " + ptype.name_l + ", " + res.w_unit() + ", error = #sigma_{gaus}; p [GeV/c] ; #beta ").c_str(),
                                       bins_p, min_p, max_p
                                     );
      for ( auto & slice: beta_histos.getHisto(res, ptype)->slices ) {
        int bin = h_beta_average->FindBin(slice.p);
        if (slice.fit_successful) {
          h_beta_average->SetBinContent(bin, slice.mean);
          h_beta_average->SetBinError(  bin, slice.sigma);
        }
      }
      h_beta_average->SetMarkerSize(0);
      h_beta_average->SetFillColor(2);
      h_beta_average->Draw("E5");
      beta_func->Draw("same");
      
      file_beta_p->WriteTObject(h_beta_average);
      file->cd();
    }
    closables.push_back(file);
  }
  c_beta_p->Print( (OutFileBase + "_beta_p.pdf").c_str() );
  c_beta_p_average->Print( (OutFileBase + "_beta_p_average.pdf").c_str() );
  
  file_beta_p->Close();
  
  // Save the sliced histograms
  for ( auto & res: resolutions ) {
    unique_ptr<TFile> file_slices { new TFile( (OutFileBase + "_slices_" + res.w_unit() + ".root").c_str(), "RECREATE" ) };

    for ( auto & histo: beta_histos.getHistosToRes(res) ) {
      for ( auto & slice: histo->slices ) {
        slice.histo->Write();
      }
    }
    file_slices->Close();
  }
  
  unique_ptr<TFile> file_sep_pwr { new TFile( (OutFileBase + "_separation_powers.root").c_str(), "RECREATE" ) };
  // Find separation power for all combinations 
  for (int i=0; i<N_ptypes-1; i++) {
    if ( 1 == N_ptypes ) {
      cout << "Only one particle type given, not creating separation power plots." << endl;
      break;
    }
    for (int j=i+1; j<N_ptypes; j++) { // Loop avoids dublicats
      ParticleType ptype1 = particle_types[i];
      ParticleType ptype2 = particle_types[j];
      
      unique_ptr<TCanvas> c_sep_pwr {new TCanvas( ("c_sep_pwr_" + ptype1.name_s + "_" + ptype2.name_s).c_str() ,
                                                  "Separation power vs momentum",
                                                  800*resolutions.size(),800)}; 
      c_sep_pwr->Divide(resolutions.size(), 1);
      int i_seppwr_pad = 1;
      
      vector<pair<Resolution,TH1D*>> sep_pwr_hists {};
      
      for ( auto & res: resolutions ) {
        auto slices_p1 = beta_histos.getHisto(res, ptype1)->slices;
        auto slices_p2 = beta_histos.getHisto(res, ptype2)->slices;
      
        int N_slices = slices_p1.size();
        
        TH1D* h_seppwr = new TH1D(("h_seppwr_" + ptype1.name_s + ptype2.name_s + res.str()).c_str(), 
                                  (ptype1.name_l + " - " + ptype2.name_l + " TOF-separation, " + res.w_unit() + "; p [GeV/c] ; Separation Power [#sigma]").c_str(),
                                  N_slices, min_p, max_p);
                                  
        for (int i_slice=0; i_slice<N_slices; i_slice++) {
          auto slice_p1 = slices_p1[i_slice];
          auto slice_p2 = slices_p2[i_slice];
          
          double p = slice_p1.p;
          
          if ( ! (slice_p1.fit_successful && slice_p2.fit_successful) ) {
            cout << ptype1.name_l << " - " << ptype2.name_l << ", " << res.w_unit() << 
                    " : Fit in slice p=" << p << " not successful, point won't be drawn." << endl;
            continue;
          }
          
          double diff_mean     = abs(slice_p1.mean - slice_p2.mean);
          double sigma_sqr_sum = pow(slice_p1.sigma, 2) + pow(slice_p2.sigma, 2); 
          double ms_sigma      = sigma_sqr_sum / 2.0; // ms = mean squared 
          double rms_sigma     = sqrt( ms_sigma );    // rms = root mean squared
          
          double sep_pwr     = diff_mean / rms_sigma;
          double sep_pwr_err = sqrt( (pow(slice_p1.mean_err,2) + pow(slice_p2.mean_err,2))/ms_sigma + pow(diff_mean,2) * (pow(slice_p1.sigma,2)*pow(slice_p1.sigma_err,2) + pow(slice_p2.sigma,2)*pow(slice_p2.sigma_err,2)) / (4*pow(ms_sigma,3)) );
          // Check that sep pwr is not NaN
          if ( sep_pwr != sep_pwr) { sep_pwr = sep_pwr_err = 0; }
          
          h_seppwr->SetBinContent(h_seppwr->FindBin(p), sep_pwr);
          h_seppwr->SetBinError(  h_seppwr->FindBin(p), sep_pwr_err);
        }          
        
        h_seppwr->Write();
        
        c_sep_pwr->cd(i_seppwr_pad++);
        h_seppwr->Draw("pe"); // TODO Better drawing style: Set some better markers, REMOVE X ERROR
        h_seppwr->SetMinimum(0);
        h_seppwr->SetMaximum(40);
        
        sep_pwr_hists.push_back(make_pair(res,h_seppwr));
      }
      c_sep_pwr->Write();
      
      unique_ptr<TCanvas> c_sep_pwr_comb {  new TCanvas( ("c_sep_pwr_comb_" + ptype1.name_s + "_" + ptype2.name_s).c_str() ,
                                                          "Separation power vs momentum",
                                                          800,800)
                                          };
      unique_ptr<THStack> h_sep_pwr_comb { new THStack(
                                                ("h_seppwr_comb_" + ptype1.name_s + ptype2.name_s).c_str(), 
                                                (ptype1.name_l + " - " + ptype2.name_l + " TOF-separation; p [GeV/c] ; Separation Power [#sigma]").c_str())
                                          };
      unique_ptr<TLegend> leg_sep_pwr_comb { new TLegend(0.48,0.7,0.8,0.9) };
      for (auto &res_hist: sep_pwr_hists) {
        Resolution res  = res_hist.first;
        TH1D* h_seppwr  = res_hist.second;
        leg_sep_pwr_comb->AddEntry(h_seppwr, res.w_unit().c_str(), "lep");
        h_sep_pwr_comb->Add(h_seppwr);
        h_seppwr->SetLineColor(res.colour_index);
      }
      h_sep_pwr_comb->Draw("nostack");
      h_sep_pwr_comb->SetMinimum(0);
      if( h_sep_pwr_comb->GetMaximum() > 120 ) { h_sep_pwr_comb->SetMaximum(100); }
      gPad->Modified();
      gPad->Update();
      leg_sep_pwr_comb->Draw();
      c_sep_pwr_comb->Write(); 
    }
  }
  file_sep_pwr->Close();

  for ( auto & closable : closables ) { 
    closable->Close();
    delete closable;
  } 
}