Blob Blame History Raw
From db974bbe72b97c798b7db52d2481aa24c2ce2b76 Mon Sep 17 00:00:00 2001
From: moneta <lorenzo.moneta@cern.ch>
Date: Thu, 17 Mar 2022 16:28:42 +0100
Subject: [PATCH] Fix TMVA tutorial using internally pyton for MacOS 12.3

With the new MacOS update python (and python2) is not existing anymore, only python3.
Add then a new function TMVA::Python_executable() using ROOT config to determine if ROOT is using python version 2 or 3. In case of 3 returns as executable "python3".

Fix also the correct location of the input ONNX file for TMVA_SOFIE_ONNX.C (copying the file at configure time)
---
 tmva/pymva/inc/TMVA/PyMethodBase.h       |  6 ++++++
 tmva/pymva/src/PyMethodBase.cxx          | 20 ++++++++++++++++++++
 tutorials/CMakeLists.txt                 |  5 ++++-
 tutorials/tmva/TMVA_CNN_Classification.C |  5 +++--
 tutorials/tmva/TMVA_RNN_Classification.C |  2 +-
 tutorials/tmva/TMVA_SOFIE_Keras.C        |  2 +-
 tutorials/tmva/TMVA_SOFIE_ONNX.C         |  2 +-
 tutorials/tmva/TMVA_SOFIE_PyTorch.C      |  2 +-
 8 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/tmva/pymva/inc/TMVA/PyMethodBase.h b/tmva/pymva/inc/TMVA/PyMethodBase.h
index 31a5caada9..a213c3fbad 100644
--- a/tmva/pymva/inc/TMVA/PyMethodBase.h
+++ b/tmva/pymva/inc/TMVA/PyMethodBase.h
@@ -53,6 +53,12 @@ namespace TMVA {
    class MethodBoost;
    class DataSetInfo;
 
+   /// Function to find current Python executable
+   /// used by ROOT
+   /// If Python2 is installed return "python"
+   /// Instead if "Python3" return "python3"
+   TString Python_Executable();
+
    class PyMethodBase : public MethodBase {
 
       friend class Factory;
diff --git a/tmva/pymva/src/PyMethodBase.cxx b/tmva/pymva/src/PyMethodBase.cxx
index 86f979e006..26b0f31135 100644
--- a/tmva/pymva/src/PyMethodBase.cxx
+++ b/tmva/pymva/src/PyMethodBase.cxx
@@ -19,6 +19,9 @@
 #include "TMVA/MsgLogger.h"
 #include "TMVA/Results.h"
 #include "TMVA/Timer.h"
+#include "TMVA/Tools.h"
+
+#include "TSystem.h"
 
 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
 #include <numpy/arrayobject.h>
@@ -37,6 +40,23 @@ public:
    ~PyGILRAII() { PyGILState_Release(m_GILState); }
 };
 } // namespace Internal
+
+/// get current Python executable used by ROOT
+TString Python_Executable() {
+   TString python_version = gSystem->GetFromPipe("root-config --python-version");
+   if (python_version.IsNull()) {
+      TMVA::gTools().Log() << kFATAL << "Can't find a valid Python version used to build ROOT" << Endl;
+      return nullptr;
+   }
+   if(python_version[0] == '2')
+      return "python";
+   else if (python_version[0] == '3')
+      return "python3";
+
+   TMVA::gTools().Log() << kFATAL << "Invalid Python version used to build ROOT : " << python_version << Endl;
+   return nullptr;
+}
+
 } // namespace TMVA
 
 ClassImp(PyMethodBase);
diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt
index de77aaa787..f1f1abda71 100644
--- a/tutorials/CMakeLists.txt
+++ b/tutorials/CMakeLists.txt
@@ -281,8 +281,11 @@ else()
   endif()
   if (NOT tmva-sofie)
     list(APPEND tmva_veto tmva/TMVA_SOFIE_ONNX.C)
+  else()
+    #copy ONNX file needed for the tutorial
+    configure_file(${CMAKE_SOURCE_DIR}/tmva/sofie/test/input_models/Linear_16.onnx ${CMAKE_BINARY_DIR}/tutorials/tmva/Linear_16.onnx COPYONLY)
   endif()
-  
+
 endif()
 
 if (NOT ROOT_pythia6_FOUND)
diff --git a/tutorials/tmva/TMVA_CNN_Classification.C b/tutorials/tmva/TMVA_CNN_Classification.C
index fa03562a8f..31172bb729 100644
--- a/tutorials/tmva/TMVA_CNN_Classification.C
+++ b/tutorials/tmva/TMVA_CNN_Classification.C
@@ -145,6 +145,7 @@ void TMVA_CNN_Classification(std::vector<bool> opt = {1, 1, 1, 1, 1})
    TMVA::PyMethodBase::PyInitialize();
 #else
    useKerasCNN = false;
+   usePyTorchCNN = false;
 #endif
 
    TFile *outputFile = nullptr;
@@ -445,7 +446,7 @@ void TMVA_CNN_Classification(std::vector<bool> opt = {1, 1, 1, 1, 1})
 
       m.SaveSource("make_cnn_model.py");
       // execute
-      gSystem->Exec("python make_cnn_model.py");
+      gSystem->Exec(TMVA::Python_Executable() + " make_cnn_model.py");
 
       if (gSystem->AccessPathName("model_cnn.h5")) {
          Warning("TMVA_CNN_Classification", "Error creating Keras model file - skip using Keras");
@@ -465,7 +466,7 @@ void TMVA_CNN_Classification(std::vector<bool> opt = {1, 1, 1, 1, 1})
       Info("TMVA_CNN_Classification", "Using Convolutional PyTorch Model");
       TString pyTorchFileName = gROOT->GetTutorialDir() + TString("/tmva/PyTorch_Generate_CNN_Model.py");
       // check that pytorch can be imported and file defining the model and used later when booking the method is existing
-      if (gSystem->Exec("python -c 'import torch'")  || gSystem->AccessPathName(pyTorchFileName) ) {
+      if (gSystem->Exec(TMVA::Python_Executable() + " -c 'import torch'")  || gSystem->AccessPathName(pyTorchFileName) ) {
          Warning("TMVA_CNN_Classification", "PyTorch is not installed or model building file is not existing - skip using PyTorch");
       }
       else {
diff --git a/tutorials/tmva/TMVA_RNN_Classification.C b/tutorials/tmva/TMVA_RNN_Classification.C
index eb26d03a2f..b49e4d91c4 100644
--- a/tutorials/tmva/TMVA_RNN_Classification.C
+++ b/tutorials/tmva/TMVA_RNN_Classification.C
@@ -431,7 +431,7 @@ the option string
 
             m.SaveSource("make_rnn_model.py");
             // execute
-            gSystem->Exec("python make_rnn_model.py");
+            gSystem->Exec(TMVA::Python_Executable() + " make_rnn_model.py");
 
             if (gSystem->AccessPathName(modelName)) {
                Warning("TMVA_RNN_Classification", "Error creating Keras recurrent model file - Skip using Keras");
diff --git a/tutorials/tmva/TMVA_SOFIE_Keras.C b/tutorials/tmva/TMVA_SOFIE_Keras.C
index e9fdbba21a..a87269f7f4 100644
--- a/tutorials/tmva/TMVA_SOFIE_Keras.C
+++ b/tutorials/tmva/TMVA_SOFIE_Keras.C
@@ -45,7 +45,7 @@ void TMVA_SOFIE_Keras(){
     TMacro m;
     m.AddLine(pythonSrc);
     m.SaveSource("make_keras_model.py");
-    gSystem->Exec("python make_keras_model.py");
+    gSystem->Exec(TMVA::Python_Executable() + " make_keras_model.py");
 
     //Parsing the saved Keras .h5 file into RModel object
     SOFIE::RModel model = SOFIE::PyKeras::Parse("KerasModel.h5");
diff --git a/tutorials/tmva/TMVA_SOFIE_ONNX.C b/tutorials/tmva/TMVA_SOFIE_ONNX.C
index 30148db4fa..bf66c38896 100644
--- a/tutorials/tmva/TMVA_SOFIE_ONNX.C
+++ b/tutorials/tmva/TMVA_SOFIE_ONNX.C
@@ -13,7 +13,7 @@ using namespace TMVA::Experimental;
 void TMVA_SOFIE_ONNX(){
     //Creating parser object to parse ONNX files
     SOFIE::RModelParser_ONNX Parser;
-    SOFIE::RModel model = Parser.Parse("../../tmva/sofie/test/input_models/Linear_16.onnx");
+    SOFIE::RModel model = Parser.Parse(std::string(gROOT->GetTutorialsDir()) + "/tmva/Linear_16.onnx");
 
     //Generating inference code
     model.Generate();
diff --git a/tutorials/tmva/TMVA_SOFIE_PyTorch.C b/tutorials/tmva/TMVA_SOFIE_PyTorch.C
index b208b042d7..580787cae1 100644
--- a/tutorials/tmva/TMVA_SOFIE_PyTorch.C
+++ b/tutorials/tmva/TMVA_SOFIE_PyTorch.C
@@ -47,7 +47,7 @@ void TMVA_SOFIE_PyTorch(){
     TMacro m;
     m.AddLine(pythonSrc);
     m.SaveSource("make_pytorch_model.py");
-    gSystem->Exec("python make_pytorch_model.py");
+    gSystem->Exec(TMVA::Python_Executable() + " make_pytorch_model.py");
 
     //Parsing a PyTorch model requires the shape and data-type of input tensor
     //Data-type of input tensor defaults to Float if not specified
-- 
2.35.1