void TMVAClassification( TString myMethodList = "", int isMC=1, int useSvtx=1)
{
   // The explicit loading of the shared libTMVA is done in TMVAlogon.C, defined in .rootrc
   // if you use your private .rootrc, or run from a different directory, please copy the
   // corresponding lines from .rootrc

   // methods to be processed can be given as an argument; use format:
   //
   // mylinux~> root -l TMVAClassification.C\(\"myMethod1,myMethod2,myMethod3\"\)
   //
   // if you like to use a method via the plugin mechanism, we recommend using
   //
   // mylinux~> root -l TMVAClassification.C\(\"P_myMethod\"\)
   // (an example is given for using the BDT as plugin (see below),
   // but of course the real application is when you write your own
   // method based)

   //---------------------------------------------------------------
   // This loads the library
   TMVA::Tools::Instance();

   // to get access to the GUI and all tmva macros
   TString thisdir = gSystem->DirName(gInterpreter->GetCurrentMacroName());
   gROOT->SetMacroPath(thisdir + ":" + gROOT->GetMacroPath());
   //gROOT->ProcessLine(".L /Users/kjung/root5-34-23/tmva/test/TMVAGui.C");

   // Default MVA methods to be trained + tested
   std::map<std::string,int> Use;

   // --- Cut optimisation
   Use["Cuts"]            = 0;
   Use["CutsD"]           = 0;
   Use["CutsPCA"]         = 0;
   Use["CutsGA"]          = 0;
   Use["CutsSA"]          = 0;
   // 
   // --- 1-dimensional likelihood ("naive Bayes estimator")
   Use["Likelihood"]      = 0;
   Use["LikelihoodD"]     = 0; // the "D" extension indicates decorrelated input variables (see option strings)
   Use["LikelihoodPCA"]   = 0; // the "PCA" extension indicates PCA-transformed input variables (see option strings)
   Use["LikelihoodKDE"]   = 0;
   Use["LikelihoodMIX"]   = 0;
   //
   // --- Mutidimensional likelihood and Nearest-Neighbour methods
   Use["PDERS"]           = 0;
   Use["PDERSD"]          = 0;
   Use["PDERSPCA"]        = 0;
   Use["PDEFoam"]         = 0;
   Use["PDEFoamBoost"]    = 0; // uses generalised MVA method boosting
   Use["KNN"]             = 0; // k-nearest neighbour method
   //
   // --- Linear Discriminant Analysis
   Use["LD"]              = 0; // Linear Discriminant identical to Fisher
   Use["Fisher"]          = 0;
   Use["FisherG"]         = 0;
   Use["BoostedFisher"]   = 0; // uses generalised MVA method boosting
   Use["HMatrix"]         = 0;
   //
   // --- Function Discriminant analysis
   Use["FDA_GA"]          = 0; // minimisation of user-defined function using Genetics Algorithm
   Use["FDA_SA"]          = 0;
   Use["FDA_MC"]          = 0;
   Use["FDA_MT"]          = 0;
   Use["FDA_GAMT"]        = 0;
   Use["FDA_MCMT"]        = 0;
   //
   // --- Neural Networks (all are feed-forward Multilayer Perceptrons)
   Use["MLP"]             = 0; // Recommended ANN
   Use["MLPBFGS"]         = 0; // Recommended ANN with optional training method
   Use["MLPBNN"]          = 0; // Recommended ANN with BFGS training method and bayesian regulator
   Use["CFMlpANN"]        = 0; // Depreciated ANN from ALEPH
   Use["TMlpANN"]         = 0; // ROOT's own ANN
   //
   // --- Support Vector Machine 
   Use["SVM"]             = 0;
   // 
   // --- Boosted Decision Trees
   Use["BDT"]             = 0; // uses Adaptive Boost
   Use["BDTG"]            = 1; // uses Gradient Boost
   Use["BDTB"]            = 0; // uses Bagging
   Use["BDTD"]            = 0; // decorrelation + Adaptive Boost
   Use["BDTF"]            = 0; // allow usage of fisher discriminant for node splitting 
   // 
   // --- Friedman's RuleFit method, ie, an optimised series of cuts ("rules")
   Use["RuleFit"]         = 0;
   // ---------------------------------------------------------------

   std::cout << std::endl;
   std::cout << "==> Start TMVAClassification" << std::endl;

   // Select methods (don't look at this code - not of interest)
   if (myMethodList != "") {
      for (std::map<std::string,int>::iterator it = Use.begin(); it != Use.end(); it++) it->second = 0;

      std::vector<TString> mlist = TMVA::gTools().SplitString( myMethodList, ',' );
      for (UInt_t i=0; i<mlist.size(); i++) {
         std::string regMethod(mlist[i]);

         if (Use.find(regMethod) == Use.end()) {
            std::cout << "Method \"" << regMethod << "\" not known in TMVA under this name. Choose among the following:" << std::endl;
            for (std::map<std::string,int>::iterator it = Use.begin(); it != Use.end(); it++) std::cout << it->first << " ";
            std::cout << std::endl;
            return;
         }
         Use[regMethod] = 1;
      }
   }

   // --------------------------------------------------------------------------------------------------

   // --- Here the preparation phase begins

   // Create a ROOT output file where TMVA will store ntuples, histograms, etc.
   TString outfileName;
   string svtxExt = "noSvtx";
   if(useSvtx) svtxExt = "withSvtx";
   if(!isMC) outfileName = "TMVA_trained_data.root";
   else outfileName = Form("TMVA_trained_cJet_medDCuts_BvC_%s.root",svtxExt.c_str());
   cout << "fn: "<< outfileName << endl;
   TFile* outputFile = TFile::Open( outfileName, "RECREATE" );
   outputFile->cd();

   // Create the factory object. Later you can choose the methods
   // whose performance you'd like to investigate. The factory is 
   // the only TMVA object you have to interact with
   //
   // The first argument is the base of the name of all the
   // weightfiles in the directory weight/
   //
   // The second argument is the output file for the training results
   // All TMVA output can be suppressed by removing the "!" (not) in
   // front of the "Silent" argument in the option string
   TMVA::Factory *factory = new TMVA::Factory( "TMVAClassification", outputFile,
                                               "!V:!Silent:Color:DrawProgressBar:Transformations=I;D;P;G,D:AnalysisType=Classification" );

   // If you wish to modify default settings
   // (please check "src/Config.h" to see all available global options)
   //    (TMVA::gConfig().GetVariablePlotting()).fTimesRMS = 8.0;
   //    (TMVA::gConfig().GetIONames()).fWeightFileDir = "myWeightDirectory";

   // Define the input variables that shall be used for the MVA training
   // note that you may also use variable expressions, such as: "3*var1/var2*abs(var3)"
   // [all types of expressions that can also be parsed by TTree::Draw( "expression" )]
   //factory->AddVariable( "myvar1 := var1+var2", 'F' );

   if(useSvtx) factory->AddVariable("svtxptFrac","svtx pt fraction","units",'F');
   //factory->AddVariable( "djetR", "Closest Meson to Jet dr", "", 'F' );
   factory->AddVariable( "nIP","number of IP trks","units",'I');
   if(useSvtx) factory->AddVariable( "svtxm", "svtx mass", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxmEnergyFrac","svtxmEnergyFrac","units",'F');
   if(useSvtx) factory->AddVariable( "svtxpt", "svtx pt", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxmcorr", "corrected svtx mass", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxdl", "svtx displacement", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxdls", "svtx displacement significance", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxntrk", "svtx ntracks", "units", 'F');
   if(useSvtx) factory->AddVariable( "sv2Trkdl", "2trk svtx close2PV dl", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxTrkSumChi2", "svtx trk sum chi2", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxTrkNetCharge", "svtx trk net chg", "units", 'F');
   if(useSvtx) factory->AddVariable( "svtxNtrkInCone", "svtx ntrk in cone", "units", 'F');
   //factory->AddVariable( "jteta",  "Jet eta", "units", 'F' );
   factory->AddVariable( "closestDMass","Closest DMass", "units", 'F' );
   factory->AddVariable( "closestDType","Closest Type","units",'F');
   factory->AddVariable( "closestDPt","Closest DpT", "units", 'F' );
   /*factory->AddVariable( "chargedMax","chargedMax","units",'F');
   factory->AddVariable( "chargedSum","chargedSum","units",'F');
   factory->AddVariable( "neutralMax","neutralMax","units",'F');
   factory->AddVariable( "neutralSum","neutralSum","units",'F');
   factory->AddVariable( "photonMax","photonMax","units",'F');
   factory->AddVariable( "photonSum","photonSum","units",'F');
   factory->AddVariable( "eSum","eSum","units",'F');
   factory->AddVariable( "muSum","muSum","units",'F');*/
   for(int i=0; i<3; i++){
     //factory->AddVariable( Form("ipProb0_%d",i),Form("prob0 IP part %d",i),"units",'F');
     //factory->AddVariable( Form("ipPt_%d",i),Form("IP pt part %d",i),"units",'F');
     factory->AddVariable( Form("trackIP2dSig_%d",i),Form("IP trk 2d sig part %d",i),"units",'F');
     factory->AddVariable( Form("trackIP3dSig_%d",i),Form("IP trk 3d sig part %d",i),"units",'F');
     factory->AddVariable( Form("trackIP2d_%d",i),Form("IP trk 2d part %d",i),"units",'F');
     factory->AddVariable( Form("trackIP3d_%d",i),Form("IP trk 3d part %d",i),"units",'F');
  }
  for(int i=0; i<1; i++){
     //factory->AddVariable( Form("trackPtRel_%d",i),Form("pt rel part %d",i),"units",'F');
     //factory->AddVariable( Form("trackPPar_%d",i),Form("track ppar part %d",i),"units",'F');
     //factory->AddVariable( Form("trackPParRatio_%d",i),Form("track ppar part %d",i),"units",'F');
     factory->AddVariable( Form("trackJetDist_%d",i),Form("dist to jet part %d",i),"units",'F');
     factory->AddVariable( Form("trackDecayLenVal_%d",i),Form("trk decay len part %d",i),"units",'F');
     //factory->AddVariable( Form("trackDeltaR_%d",i),Form("trk dr to jet part %d",i),"units",'F');
     //factory->AddVariable( Form("trackPtRatio_%d",i),Form("trk pt ratio part %d",i),"units",'F');
   }
   //factory->AddVariable( "trackSip2dSigAboveCharm","trackSip2dSigAboveCharm","units",'F');
   //factory->AddVariable( "trackSip3dSigAboveCharm","trackSip3dSigAboveCharm","units",'F');
   //factory->AddVariable( "trackSip2dValAboveCharm","trackSip2dValAboveCharm","units",'F');
   //factory->AddVariable( "trackSip3dValAboveCharm","trackSip3dValAboveCharm","units",'F');
   //factory->AddVariable( "svJetDeltaR","svJetDeltaR","units",'F');
   factory->AddVariable( "trackSumJetDeltaR","trackSumJetDeltaR","units",'F');
     
   // You can add so-called "Spectator variables", which are not used in the MVA training,
   // but will appear in the final "TestTree" produced by TMVA. This TestTree will contain the
   // input variables, the response values of all trained MVAs, and the spectator variables
   //factory->AddSpectator( "spec1 := var1*2",  "Spectator 1", "units", 'F' );
   
   if(isMC) factory->AddSpectator( "refpt",  "ref pT", "units", 'F' );
   factory->AddSpectator( "rawpt",  "raw pT", "units", 'F' );
   //factory->AddSpectator( "dCandPt", "D-Meson pT", "units" , 'F' );
   if(isMC) factory->AddSpectator( "refparton_flavorForB", "jet flavor", "units" , 'F' );
   //factory->AddSpectator( "evtSelection", "event selection", "units" , 'F' );
   //factory->AddSpectator( "vz", "z-vertex", "units" , 'F' );
   //if(isMC) factory->AddSpectator( "subid", "subid", "units" , 'F' );
   //factory->AddSpectator( "pthat", "pthat", "units" , 'F' );
   //factory->AddSpectator( "run", "run", "units" , 'I' );
   //factory->AddSpectator( "bin", "centrality", "units" , 'I' );
   factory->AddSpectator( "jtpt",  "Jet pT", "units", 'F' );
   
   // Read training and test data
   // (it is also possible to use ASCII format as input -> see TMVA Users Guide)
   TString fname;
   if(!isMC) fname = "/Users/kjung/charmJets/pPb/input/DMesonCJet_pPbData_ppReco_akPu3PF_convertToJetTree_withLHCbVars_medDCuts.root";
   else fname = "/Users/kjung/charmJets/pPb/input/DMesonCJet_QCDJetOnly_pPbMC_ppReco_akPu3PF_convertToJetTree_medDCuts.root";
   
   //if (gSystem->AccessPathName( fname ))  // file does not exist in local directory
   //   gSystem->Exec("curl -O http://root.cern.ch/files/tmva_class_example.root");
   
   TFile *input = TFile::Open( fname );
   
   std::cout << "--- TMVAClassification       : Using input file: " << input->GetName() << std::endl;
   
   // --- Register the training and test trees

   TTree *signal, *background;
   if(useSvtx){
      signal = (TTree*)input->Get("jets");
      background = (TTree*)input->Get("jets");
   }
   else{
      signal = (TTree*)input->Get("jetsNoSvtx");
      background = (TTree*)input->Get("jetsNoSvtx");
   }

   TTree *signal_2 = (TTree*)input->Get("dMesons");
   TTree *background_2 = (TTree*)input->Get("dMesons");

   signal->AddFriend(signal_2);
   background->AddFriend(background_2);
   
   // global event weights per tree (see below for setting event-wise weights)
   Double_t signalWeight     = 1.0;
   Double_t backgroundWeight = 1.0;
   
   // You can add an arbitrary number of signal or background trees
   factory->AddSignalTree    ( signal,     signalWeight     );
   factory->AddBackgroundTree( background, backgroundWeight );
   
   // To give different trees for training and testing, do as follows:
   //    factory->AddSignalTree( signalTrainingTree, signalTrainWeight, "Training" );
   //    factory->AddSignalTree( signalTestTree,     signalTestWeight,  "Test" );
   
   // Use the following code instead of the above two or four lines to add signal and background
   // training and test events "by hand"
   // NOTE that in this case one should not give expressions (such as "var1+var2") in the input
   //      variable definition, but simply compute the expression before adding the event
   //
   //     // --- begin ----------------------------------------------------------
   //     std::vector<Double_t> vars( 4 ); // vector has size of number of input variables
   //     Float_t  treevars[4], weight;
   //     
   //     // Signal
   const int nvars = 35; //67;
   const int nvarsWithInt = 2;
   double weight;
   std::vector<double> vars(nvars);
   double treevars[nvars-nvarsWithInt];
   int treevars2[nvarsWithInt];
   //std::string variables[nvars] = {"djetR","closestDPt","svtxm","svtxdl","jtpt","refpt","rawpt","refparton_flavorForB","svtxdls","trackIP2dSig_0","trackIP3dSig_0","trackIP2d_0","trackIP3d_0","ipProb0_0","trackPtRel_0","trackPPar_0","trackPParRatio_0","trackJetDist_0","trackDecayLenVal_0","trackDeltaR_0","trackPtRatio_0","ipPt_0","trackIP2dSig_1","trackIP3dSig_1","trackIP2d_1","trackIP3d_1","ipProb0_1","trackPtRel_1","trackPPar_1","trackPParRatio_1","trackJetDist_1","trackDecayLenVal_1","trackDeltaR_1","trackPtRatio_1","ipPt_1","trackIP2dSig_2","trackIP3dSig_2","trackIP2d_2","trackIP3d_2","ipProb0_2","trackPtRel_2","trackPPar_2","trackPParRatio_2","trackJetDist_2","trackDecayLenVal_2","trackDeltaR_2","trackPtRatio_2","ipPt_2","trackIP2dSig_3","trackIP3dSig_3","trackIP2d_3","trackIP3d_3","ipProb0_3","trackPtRel_3","trackPPar_3","trackPParRatio_3","trackJetDist_3","trackDecayLenVal_3","trackDeltaR_3","trackPtRatio_3","ipPt_3","trackSip2dValAboveCharm","trackSip3dValAboveCharm","svJetDeltaR","trackSumJetDeltaR","nIP","svtxntrk"};
   
   std::string variables[nvars] = {"jtpt","refpt","rawpt","refparton_flavorForB","svtxptFrac","svtxmEnergyFrac","svtxpt","svtxm",
   "svtxdl","svtxdls","svtxTrkSumChi2","svtxTrkNetCharge","sv2Trkdl", "closestDMass","closestDType","closestDPt","trackIP2dSig_0","trackIP2dSig_1",
"trackIP2dSig_2","trackIP3dSig_0","trackIP3dSig_1","trackIP3dSig_2","trackIP2d_0","trackIP2d_1",
"trackIP2d_2","trackIP3d_0","trackIP3d_1","trackIP3d_2","trackJetDist_0","trackDecayLenVal_0","svJetDeltaR",
"trackSumJetDeltaR","svtxNtrkInCone","svtxntrk","nIP"};

   //std::string variables[nvars] = {"jtpt","refpt","rawpt","refparton_flavorForB","svtxptFrac","svtxdl","svtxdls","closestDPt","closestDType","closestDMass","svtxm","svtxmcorr","svJetDeltaR","trackSumJetDeltaR","svtxpt","sv2Trkdl","svtxTrkSumChi2","svtxTrkNetCharge","svtxNtrkInCone","svtxntrk"};
   signal->SetBranchAddress("weight", &weight);
	
   for (UInt_t ivar=0; ivar<nvars-nvarsWithInt; ivar++) signal->SetBranchAddress( variables[ivar].c_str(), &(treevars[ivar]) );
   for (UInt_t ivar=nvars-nvarsWithInt; ivar<nvars; ivar++) signal->SetBranchAddress( variables[ivar].c_str(), &(treevars2[ivar]) );
   for (UInt_t i=0; i<signal->GetEntries(); i++) {
     signal->GetEntry(i);
     for (UInt_t ivar=0; ivar<nvars-nvarsWithInt; ivar++) vars[ivar] = treevars[ivar];
      for (UInt_t ivar=nvars-nvarsWithInt; ivar<nvars; ivar++) vars[ivar] = treevars2[ivar];
     // add training and test events; here: first half is training, second is testing
     // note that the weight can also be event-wise
     //for(int ij=0; ij<nvars; ij++) cout << ij << " " << vars[ij] << endl;
     if(isMC && (abs(vars[3])==4)) {
       if (i%2==0)  factory->AddSignalTrainingEvent( vars, weight );
       else                              factory->AddSignalTestEvent    ( vars, weight );
     }
   }
   //   
   //     // Background (has event weights)
   background->SetBranchAddress( "weight", &weight );
   for (UInt_t ivar=0; ivar<nvars-nvarsWithInt; ivar++) background->SetBranchAddress( variables[ivar].c_str(), &(treevars[ivar]) );
   for (UInt_t ivar=nvars-nvarsWithInt; ivar<nvars; ivar++) background->SetBranchAddress( variables[ivar].c_str(), &(treevars2[ivar]) );
   for (UInt_t i=0; i<background->GetEntries(); i++) {
     background->GetEntry(i);
     for (UInt_t ivar=0; ivar<nvars-nvarsWithInt; ivar++) vars[ivar] = treevars[ivar];
      for (UInt_t ivar=nvars-nvarsWithInt; ivar<nvars; ivar++) vars[ivar] = treevars2[ivar];
     // add training and test events; here: first half is training, second is testing
     // note that the weight can also be event-wise
     if(isMC && (abs(vars[3])==5)) {
       if (i%2==0) factory->AddBackgroundTrainingEvent( vars, weight );
       else                                factory->AddBackgroundTestEvent    ( vars, weight );
     }
   }
   // --- end ------------------------------------------------------------
   //
   // --- end of tree registration 

   // Set individual event weights (the variables must exist in the original TTree)
   //    for signal    : factory->SetSignalWeightExpression    ("weight1*weight2");
   //    for background: factory->SetBackgroundWeightExpression("weight1*weight2");
   factory->SetSignalWeightExpression("weight");
   factory->SetBackgroundWeightExpression( "weight" );

   // Apply additional cuts on the signal and background samples (can be different)
   TCut mycuts = ""; // for example: TCut mycuts = "abs(var1)<0.5 && abs(var2-0.5)<1";
   TCut mycutb = ""; // for example: TCut mycutb = "abs(var1)<0.5";
   
   // Tell the factory how to use the training and testing events
   //
   // If no numbers of events are given, half of the events in the tree are used 
   // for training, and the other half for testing:
   //    factory->PrepareTrainingAndTestTree( mycut, "SplitMode=random:!V" );
   // To also specify the number of testing events, use:
   //    factory->PrepareTrainingAndTestTree( mycut,
   //                                         "NSigTrain=3000:NBkgTrain=3000:NSigTest=3000:NBkgTest=3000:SplitMode=Random:!V" );
   factory->PrepareTrainingAndTestTree( mycuts, mycutb,
                                        "nTrain_Signal=0:nTrain_Background=0:SplitMode=Random:NormMode=NumEvents:!V" );

   // ---- Book MVA methods
   //
   // Please lookup the various method configuration options in the corresponding cxx files, eg:
   // src/MethoCuts.cxx, etc, or here: http://tmva.sourceforge.net/optionRef.html
   // it is possible to preset ranges in the option string in which the cut optimisation should be done:
   // "...:CutRangeMin[2]=-1:CutRangeMax[2]=1"...", where [2] is the third input variable

   // Cut optimisation
   if (Use["Cuts"])
      factory->BookMethod( TMVA::Types::kCuts, "Cuts",
                           "!H:!V:FitMethod=MC:EffSel:SampleSize=200000:VarProp=FSmart" );

   if (Use["CutsD"])
      factory->BookMethod( TMVA::Types::kCuts, "CutsD",
                           "!H:!V:FitMethod=MC:EffSel:SampleSize=200000:VarProp=FSmart:VarTransform=Decorrelate" );

   if (Use["CutsPCA"])
      factory->BookMethod( TMVA::Types::kCuts, "CutsPCA",
                           "!H:!V:FitMethod=MC:EffSel:SampleSize=200000:VarProp=FSmart:VarTransform=PCA" );

   if (Use["CutsGA"])
      factory->BookMethod( TMVA::Types::kCuts, "CutsGA",
                           "H:!V:FitMethod=GA:CutRangeMin[0]=-10:CutRangeMax[0]=10:VarProp[1]=FMax:EffSel:Steps=30:Cycles=3:PopSize=400:SC_steps=10:SC_rate=5:SC_factor=0.95" );

   if (Use["CutsSA"])
      factory->BookMethod( TMVA::Types::kCuts, "CutsSA",
                           "!H:!V:FitMethod=SA:EffSel:MaxCalls=150000:KernelTemp=IncAdaptive:InitialTemp=1e+6:MinTemp=1e-6:Eps=1e-10:UseDefaultScale" );

   // Likelihood ("naive Bayes estimator")
   if (Use["Likelihood"])
      factory->BookMethod( TMVA::Types::kLikelihood, "Likelihood",
                           "H:!V:TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmoothBkg[1]=10:NSmooth=1:NAvEvtPerBin=50" );

   // Decorrelated likelihood
   if (Use["LikelihoodD"])
      factory->BookMethod( TMVA::Types::kLikelihood, "LikelihoodD",
                           "!H:!V:TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmooth=5:NAvEvtPerBin=50:VarTransform=Decorrelate" );

   // PCA-transformed likelihood
   if (Use["LikelihoodPCA"])
      factory->BookMethod( TMVA::Types::kLikelihood, "LikelihoodPCA",
                           "!H:!V:!TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmooth=5:NAvEvtPerBin=50:VarTransform=PCA" ); 

   // Use a kernel density estimator to approximate the PDFs
   if (Use["LikelihoodKDE"])
      factory->BookMethod( TMVA::Types::kLikelihood, "LikelihoodKDE",
                           "!H:!V:!TransformOutput:PDFInterpol=KDE:KDEtype=Gauss:KDEiter=Adaptive:KDEFineFactor=0.3:KDEborder=None:NAvEvtPerBin=50" ); 

   // Use a variable-dependent mix of splines and kernel density estimator
   if (Use["LikelihoodMIX"])
      factory->BookMethod( TMVA::Types::kLikelihood, "LikelihoodMIX",
                           "!H:!V:!TransformOutput:PDFInterpolSig[0]=KDE:PDFInterpolBkg[0]=KDE:PDFInterpolSig[1]=KDE:PDFInterpolBkg[1]=KDE:PDFInterpolSig[2]=Spline2:PDFInterpolBkg[2]=Spline2:PDFInterpolSig[3]=Spline2:PDFInterpolBkg[3]=Spline2:KDEtype=Gauss:KDEiter=Nonadaptive:KDEborder=None:NAvEvtPerBin=50" ); 

   // Test the multi-dimensional probability density estimator
   // here are the options strings for the MinMax and RMS methods, respectively:
   //      "!H:!V:VolumeRangeMode=MinMax:DeltaFrac=0.2:KernelEstimator=Gauss:GaussSigma=0.3" );
   //      "!H:!V:VolumeRangeMode=RMS:DeltaFrac=3:KernelEstimator=Gauss:GaussSigma=0.3" );
   if (Use["PDERS"])
      factory->BookMethod( TMVA::Types::kPDERS, "PDERS",
                           "!H:!V:NormTree=T:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=0.3:NEventsMin=400:NEventsMax=600" );

   if (Use["PDERSD"])
      factory->BookMethod( TMVA::Types::kPDERS, "PDERSD",
                           "!H:!V:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=0.3:NEventsMin=400:NEventsMax=600:VarTransform=Decorrelate" );

   if (Use["PDERSPCA"])
      factory->BookMethod( TMVA::Types::kPDERS, "PDERSPCA",
                           "!H:!V:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=0.3:NEventsMin=400:NEventsMax=600:VarTransform=PCA" );

   // Multi-dimensional likelihood estimator using self-adapting phase-space binning
   if (Use["PDEFoam"])
      factory->BookMethod( TMVA::Types::kPDEFoam, "PDEFoam",
                           "!H:!V:SigBgSeparate=F:TailCut=0.001:VolFrac=0.0666:nActiveCells=500:nSampl=2000:nBin=5:Nmin=100:Kernel=None:Compress=T" );

   if (Use["PDEFoamBoost"])
      factory->BookMethod( TMVA::Types::kPDEFoam, "PDEFoamBoost",
                           "!H:!V:Boost_Num=30:Boost_Transform=linear:SigBgSeparate=F:MaxDepth=4:UseYesNoCell=T:DTLogic=MisClassificationError:FillFoamWithOrigWeights=F:TailCut=0:nActiveCells=500:nBin=20:Nmin=400:Kernel=None:Compress=T" );

   // K-Nearest Neighbour classifier (KNN)
   if (Use["KNN"])
      factory->BookMethod( TMVA::Types::kKNN, "KNN",
                           "H:nkNN=20:ScaleFrac=0.8:SigmaFact=1.0:Kernel=Gaus:UseKernel=F:UseWeight=T:!Trim" );

   // H-Matrix (chi2-squared) method
   if (Use["HMatrix"])
      factory->BookMethod( TMVA::Types::kHMatrix, "HMatrix", "!H:!V:VarTransform=None" );

   // Linear discriminant (same as Fisher discriminant)
   if (Use["LD"])
      factory->BookMethod( TMVA::Types::kLD, "LD", "H:!V:VarTransform=None:CreateMVAPdfs:PDFInterpolMVAPdf=Spline2:NbinsMVAPdf=50:NsmoothMVAPdf=10" );

   // Fisher discriminant (same as LD)
   if (Use["Fisher"])
      factory->BookMethod( TMVA::Types::kFisher, "Fisher", "H:!V:Fisher:VarTransform=None:CreateMVAPdfs:PDFInterpolMVAPdf=Spline2:NbinsMVAPdf=50:NsmoothMVAPdf=10" );

   // Fisher with Gauss-transformed input variables
   if (Use["FisherG"])
      factory->BookMethod( TMVA::Types::kFisher, "FisherG", "H:!V:VarTransform=Gauss" );

   // Composite classifier: ensemble (tree) of boosted Fisher classifiers
   if (Use["BoostedFisher"])
      factory->BookMethod( TMVA::Types::kFisher, "BoostedFisher", 
                           "H:!V:Boost_Num=20:Boost_Transform=log:Boost_Type=AdaBoost:Boost_AdaBoostBeta=0.2:!Boost_DetailedMonitoring" );

   // Function discrimination analysis (FDA) -- test of various fitters - the recommended one is Minuit (or GA or SA)
   if (Use["FDA_MC"])
      factory->BookMethod( TMVA::Types::kFDA, "FDA_MC",
                           "H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):FitMethod=MC:SampleSize=100000:Sigma=0.1" );

   if (Use["FDA_GA"]) // can also use Simulated Annealing (SA) algorithm (see Cuts_SA options])
      factory->BookMethod( TMVA::Types::kFDA, "FDA_GA",
                           "H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):FitMethod=GA:PopSize=300:Cycles=3:Steps=20:Trim=True:SaveBestGen=1" );

   if (Use["FDA_SA"]) // can also use Simulated Annealing (SA) algorithm (see Cuts_SA options])
      factory->BookMethod( TMVA::Types::kFDA, "FDA_SA",
                           "H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):FitMethod=SA:MaxCalls=15000:KernelTemp=IncAdaptive:InitialTemp=1e+6:MinTemp=1e-6:Eps=1e-10:UseDefaultScale" );

   if (Use["FDA_MT"])
      factory->BookMethod( TMVA::Types::kFDA, "FDA_MT",
                           "H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):FitMethod=MINUIT:ErrorLevel=1:PrintLevel=-1:FitStrategy=2:UseImprove:UseMinos:SetBatch" );

   if (Use["FDA_GAMT"])
      factory->BookMethod( TMVA::Types::kFDA, "FDA_GAMT",
                           "H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):FitMethod=GA:Converger=MINUIT:ErrorLevel=1:PrintLevel=-1:FitStrategy=0:!UseImprove:!UseMinos:SetBatch:Cycles=1:PopSize=5:Steps=5:Trim" );

   if (Use["FDA_MCMT"])
      factory->BookMethod( TMVA::Types::kFDA, "FDA_MCMT",
                           "H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):FitMethod=MC:Converger=MINUIT:ErrorLevel=1:PrintLevel=-1:FitStrategy=0:!UseImprove:!UseMinos:SetBatch:SampleSize=20" );

   // TMVA ANN: MLP (recommended ANN) -- all ANNs in TMVA are Multilayer Perceptrons
   if (Use["MLP"])
      factory->BookMethod( TMVA::Types::kMLP, "MLP", "H:!V:NeuronType=tanh:VarTransform=N:NCycles=600:HiddenLayers=N+5:TestRate=5:!UseRegulator" );

   if (Use["MLPBFGS"])
      factory->BookMethod( TMVA::Types::kMLP, "MLPBFGS", "H:!V:NeuronType=tanh:VarTransform=N:NCycles=600:HiddenLayers=N+5:TestRate=5:TrainingMethod=BFGS:!UseRegulator" );

   if (Use["MLPBNN"])
      factory->BookMethod( TMVA::Types::kMLP, "MLPBNN", "H:!V:NeuronType=tanh:VarTransform=N:NCycles=600:HiddenLayers=N+5:TestRate=5:TrainingMethod=BFGS:UseRegulator" ); // BFGS training with bayesian regulators

   // CF(Clermont-Ferrand)ANN
   if (Use["CFMlpANN"])
      factory->BookMethod( TMVA::Types::kCFMlpANN, "CFMlpANN", "!H:!V:NCycles=2000:HiddenLayers=N+1,N"  ); // n_cycles:#nodes:#nodes:...  

   // Tmlp(Root)ANN
   if (Use["TMlpANN"])
      factory->BookMethod( TMVA::Types::kTMlpANN, "TMlpANN", "!H:!V:NCycles=200:HiddenLayers=N+1,N:LearningMethod=BFGS:ValidationFraction=0.3"  ); // n_cycles:#nodes:#nodes:...

   // Support Vector Machine
   if (Use["SVM"])
      factory->BookMethod( TMVA::Types::kSVM, "SVM", "Gamma=0.25:Tol=0.001:VarTransform=Norm" );

   // Boosted Decision Trees
   if (Use["BDTG"]) // Gradient Boost
      factory->BookMethod( TMVA::Types::kBDT, "BDTG",
                           //"!H:!V:NTrees=850:MinNodeSize=2%:BoostType=Grad:Shrinkage=0.10:UseBaggedBoost:BaggedSampleFraction=0.5:nCuts=20:MaxDepth=2" );
                           "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.05:UseBaggedBoost:GradBaggingFraction=0.9:SeparationType=GiniIndex:nCuts=500:MaxDepth=2" );
   if (Use["BDT"])  // Adaptive Boost
      factory->BookMethod( TMVA::Types::kBDT, "BDT",
                           "!H:!V:NTrees=850:MinNodeSize=2.5%:MaxDepth=3:BoostType=AdaBoost:AdaBoostBeta=0.5:UseBaggedBoost:BaggedSampleFraction=0.5:SeparationType=GiniIndex:nCuts=20" );

   if (Use["BDTB"]) // Bagging
      factory->BookMethod( TMVA::Types::kBDT, "BDTB",
                           "!H:!V:NTrees=400:BoostType=Bagging:SeparationType=GiniIndex:nCuts=20" );

   if (Use["BDTD"]) // Decorrelation + Adaptive Boost
      factory->BookMethod( TMVA::Types::kBDT, "BDTD",
                           "!H:!V:NTrees=400:MinNodeSize=5%:MaxDepth=3:BoostType=AdaBoost:SeparationType=GiniIndex:nCuts=20:VarTransform=Decorrelate" );

   if (Use["BDTF"])  // Allow Using Fisher discriminant in node splitting for (strong) linearly correlated variables
      factory->BookMethod( TMVA::Types::kBDT, "BDTMitFisher",
                           "!H:!V:NTrees=50:MinNodeSize=2.5%:UseFisherCuts:MaxDepth=3:BoostType=AdaBoost:AdaBoostBeta=0.5:SeparationType=GiniIndex:nCuts=20" );

   // RuleFit -- TMVA implementation of Friedman's method
   if (Use["RuleFit"])
      factory->BookMethod( TMVA::Types::kRuleFit, "RuleFit",
                           "H:!V:RuleFitModule=RFTMVA:Model=ModRuleLinear:MinImp=0.001:RuleMinDist=0.001:NTrees=20:fEventsMin=0.01:fEventsMax=0.5:GDTau=-1.0:GDTauPrec=0.01:GDStep=0.01:GDNSteps=10000:GDErrScale=1.02" );

   // For an example of the category classifier usage, see: TMVAClassificationCategory

   // --------------------------------------------------------------------------------------------------

   // ---- Now you can optimize the setting (configuration) of the MVAs using the set of training events

   // ---- STILL EXPERIMENTAL and only implemented for BDT's ! 
   // factory->OptimizeAllMethods("SigEffAt001","Scan");
   // factory->OptimizeAllMethods("ROCIntegral","FitGA");

   // --------------------------------------------------------------------------------------------------

   // ---- Now you can tell the factory to train, test, and evaluate the MVAs

   // Train MVAs using the set of training events
   factory->TrainAllMethods();

   // ---- Evaluate all MVAs using the set of test events
   factory->TestAllMethods();

   // ----- Evaluate and compare performance of all configured MVAs
   factory->EvaluateAllMethods();

   // --------------------------------------------------------------

   // Save the output
   outputFile->Close();

   std::cout << "==> Wrote root file: " << outputFile->GetName() << std::endl;
   std::cout << "==> TMVAClassification is done!" << std::endl;
   
   delete factory;
   
   // Launch the GUI for the root macros
   //if (!gROOT->IsBatch()) TMVAGui( outfileName );
}