From d0c733dce6f61f89d9971d9030cee7fb207f57c2 Mon Sep 17 00:00:00 2001
From: Riccardo Maria Bianchi <riccardo.maria.bianchi@cern.ch>
Date: Mon, 8 Jul 2024 13:04:40 +0200
Subject: [PATCH 1/3] Add conditional load of newest classes/nodes.

To be able to have new GeoModel nodes/classes while not breaking the load of DBs generated with an earlier version of GeoModel, I added an 'optional' flag to the calls loading the new nodes from the DB. In that way, when loading a DB where we don't expect to see those new nodes, we have no errors as expected.

To achieve that, I also added the optional flag to the 'checkDBTable' and 'getPublishedNodes' methods.
---
 .../step2_read_geo_and_published_nodes.cpp    |   6 +-
 .../GeoModelDBManager/GMDBManager.h           |   8 +-
 .../GeoModelDBManager/src/GMDBManager.cpp     | 118 +++++++++++-------
 .../GeoModelRead/GeoModelRead/ReadGeoModel.h  |   3 +-
 .../GeoModelRead/ReadGeoModel.tpp             |   8 +-
 GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp  |  30 ++++-
 6 files changed, 115 insertions(+), 58 deletions(-)

diff --git a/GeoModelExamples/HelloToy/step2_read_geo_and_published_nodes.cpp b/GeoModelExamples/HelloToy/step2_read_geo_and_published_nodes.cpp
index 654d70c3d..c2a2bb34d 100644
--- a/GeoModelExamples/HelloToy/step2_read_geo_and_published_nodes.cpp
+++ b/GeoModelExamples/HelloToy/step2_read_geo_and_published_nodes.cpp
@@ -156,12 +156,12 @@ int main(int argc, char *argv[])
   //check for a table we know doesn't exist
   if (db->checkTableFromDB("PublishedFullPhysVols_HelloToyExample")) std::cout<<"We find the table that we expected - good!"<<std::endl;
   else std::cout<<"Uh oh, we don't find the expected table - bad!"<<std::endl;
-  if(!db->checkTableFromDB("PublishedFullPhysVols_ByeByeToyExample")) std::cout<<"We don't find the table that we didn't expect - good!"<<std::endl;
+  if(!db->checkTableFromDB("PublishedFullPhysVols_ByeByeToyExample", true)) std::cout<<"We don't find the table that we didn't expect - good!"<<std::endl;
   else std::cout<<"Uh oh, we found a table which doesn't exist - bad!"<<std::endl;  
 
   //Now test via the specific accessors with additional checks
-  std::map<unsigned int, GeoFullPhysVol*> mapFPV_test = readInGeo.getPublishedNodes<unsigned int, GeoFullPhysVol*>("ByeByeToyExample",true);
-  std::map<std::string, GeoAlignableTransform*> mapAXF_test = readInGeo.getPublishedNodes<std::string, GeoAlignableTransform*>("ByeByeToyExample",true);
+  std::map<unsigned int, GeoFullPhysVol*> mapFPV_test = readInGeo.getPublishedNodes<unsigned int, GeoFullPhysVol*>("ByeByeToyExample",true, true);
+  std::map<std::string, GeoAlignableTransform*> mapAXF_test = readInGeo.getPublishedNodes<std::string, GeoAlignableTransform*>("ByeByeToyExample",true, true);
   if(mapFPV_test.size()==0) std::cout<<"Returned an empty FPV map when using checks for a non-existing table - good!"<<std::endl;
   if(mapAXF_test.size()==0) std::cout<<"Returned an empty AXF map when using checks for a non-existing table - good!"<<std::endl;
 
diff --git a/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h b/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h
index 404eab0f6..b1d1f18b1 100644
--- a/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h
+++ b/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h
@@ -295,12 +295,12 @@ class GMDBManager {
     std::vector<std::vector<std::string>> getTableFromNodeType_String(
         std::string nodeType);
     DBRowsList getTableFromNodeType_VecVecData(
-        std::string nodeType);
+        std::string nodeType, const bool optional = false);
     
     DBRowEntry getTableFromTableName_VecData(
-        std::string tableName);
+        std::string tableName, const bool optional = false);
     DBRowsList getTableFromTableName_VecVecData(
-        std::string tableName);
+        std::string tableName, const bool optional = false);
     // specializations
     std::vector<double> getTableFromTableName_VectorDouble(std::string tableName);
     std::deque<double> getTableFromTableName_DequeDouble(std::string tableName);
@@ -314,7 +314,7 @@ class GMDBManager {
 
     //! Test if a given table exists
     //! This requires the *full* table name (i.e. prefix_suffix)
-    bool checkTableFromDB(std::string tableName) const;
+    bool checkTableFromDB(std::string tableName, const bool optional = false) const;
 
     //! Test if a table has been loaded from a DB, that is it exists in the cache
     bool checkTableFromCache(const std::string_view tableName) const;
diff --git a/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp b/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp
index 91e033551..9e5f4ede1 100644
--- a/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp
+++ b/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp
@@ -522,7 +522,6 @@ std::vector<std::vector<std::string>> GMDBManager::getTableFromNodeType_String(
     }
     else
     {
-        // if (!checkTable(tableName))
         if (!checkTableFromDB(tableName))
         {
             THROW_EXCEPTION("ERROR!!! Table name '" << tableName << "' does not exist in the DB!");
@@ -533,7 +532,7 @@ std::vector<std::vector<std::string>> GMDBManager::getTableFromNodeType_String(
 }
 
 DBRowsList GMDBManager::getTableFromNodeType_VecVecData(
-    std::string nodeType)
+    std::string nodeType, const bool optional)
 {
     DBRowsList out;
     std::string tableName = getTableNameFromNodeType(nodeType);
@@ -553,68 +552,85 @@ DBRowsList GMDBManager::getTableFromNodeType_VecVecData(
     }
     else
     {
-        if (!checkTableFromDB(tableName))
-        {
-            THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB!");
-        }
+        // if (!checkTableFromDB(tableName, optional))
+        // {
+        //     if (optional) {
+        //         if (m_debug) {
+        //             std::cout << "WARNING! We could not find the table '" << tableName 
+        //             << "'. However, it has flagged as 'optional', so it is fine not to find it "
+        //             << "if you are running on a DB that has been generated with an earlier version of GeoModel." 
+        //             << std::endl;
+        //         }
+        //     } else {
+        //         THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB!");
+        //     }
+        // }
+        checkTableFromDB(tableName, optional);
         out = getTableRecords_VecVecData(tableName);
     }
     return out;
 }
 DBRowsList GMDBManager::getTableFromTableName_VecVecData(
-    std::string tableName)
+    std::string tableName, const bool optional)
 {
     DBRowsList out;
     if (tableName.empty())
     {
-        std::mutex coutMutex;
-        coutMutex.lock();
-        std::cout << 
-            "\t ===> WARNING! The geometry input file does not contain a "
-            "table for the " 
-            << tableName 
-            << "nodes. That means that you are probably using an "
-            << "old "
-            << "geometry file. Unless you know exactly what you are doing, "
-            << "please "
-            << "expect to see incomplete geometries or crashes.\n"
-            << std::endl;
-        coutMutex.unlock();
+        if (m_debug)
+        {
+            std::mutex coutMutex;
+            coutMutex.lock();
+            std::cout << "\t ===> WARNING! The geometry input file does not contain a "
+                         "table for the "
+                      << tableName
+                      << "nodes. That means that you are probably using an "
+                      << "old "
+                      << "geometry file. Unless you know exactly what you are doing, "
+                      << "please "
+                      << "expect to see incomplete geometries or crashes.\n"
+                      << std::endl;
+            coutMutex.unlock();
+        }
     }
     else
     {
-        if (!checkTableFromDB(tableName))
-        {
-            THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB!");
-        }
+        // if (!checkTableFromDB(tableName))
+        // {
+        //     THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB!");
+        // }
+        checkTableFromDB(tableName, optional);
         out = getTableRecords_VecVecData(tableName);
     }
     return out;
 }
 DBRowEntry GMDBManager::getTableFromTableName_VecData(
-    std::string tableName)
+    std::string tableName, const bool optional)
 {
     DBRowEntry out;
     if (tableName.empty())
     {
-        std::mutex coutMutex;
-        coutMutex.lock();
-        std::cout << "\t ===> WARNING! The geometry input file does not contain a "
-            << "table "
-            << "for the "
-            << tableName 
-            << "nodes. That means that you are probably using an "
-            << "old geometry file. Unless you know exactly what you are doing, "
-            << "please expect to see incomplete geometries or crashes.\n" 
-            << std::endl;
-        coutMutex.unlock();
+        if (m_debug)
+        {
+            std::mutex coutMutex;
+            coutMutex.lock();
+            std::cout << "\t ===> WARNING! The geometry input file does not contain a "
+                      << "table "
+                      << "for the "
+                      << tableName
+                      << "nodes. That means that you are probably using an "
+                      << "old geometry file. Unless you know exactly what you are doing, "
+                      << "please expect to see incomplete geometries or crashes.\n"
+                      << std::endl;
+            coutMutex.unlock();
+        }
     }
     else
     {
-        if (!checkTableFromDB(tableName))
-        {
-            THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB!");
-        }
+        // if (!checkTableFromDB(tableName))
+        // {
+        //     THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB!");
+        // }
+        checkTableFromDB(tableName, optional);
         out = getTableRecords_VecData(tableName);
     }
     return out;
@@ -1383,8 +1399,26 @@ DBRowsList GMDBManager::getPublishedAXFTable(
     return getTableRecords_VecVecData(tableName);
 }
 
-bool GMDBManager::checkTableFromDB(std::string tableName) const {
-    return m_d->checkTableFromDB_imp(tableName);
+bool GMDBManager::checkTableFromDB(std::string tableName, const bool optional) const {
+    const bool checkTableExistsInDB = m_d->checkTableFromDB_imp(tableName);
+    if (!checkTableExistsInDB)
+    {
+        if (optional)
+        {
+            if (m_debug)
+            {
+                std::cout << "WARNING! We could not find the table '" << tableName
+                          << "'. However, it has flagged as 'optional', so it is fine not to find it in the DB "
+                          << "if you are running on a DB that has been generated with an earlier version of GeoModel."
+                          << std::endl;
+            }
+        }
+        else
+        {
+            THROW_EXCEPTION("ERROR!!! Table name '" + tableName + "' does not exist in the DB! [and it was not set to 'optional']");
+        }
+    }
+    return checkTableExistsInDB;
 }
 
 // create a user-defined custom table to store the published nodes
diff --git a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h
index d659f787a..1f934e1d3 100644
--- a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h
+++ b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h
@@ -142,7 +142,8 @@ class ReadGeoModel {
     template <typename T, class N>
     std::map<T, N> getPublishedNodes(
         std::string publisherName = "" /*optional variable*/,
-                                     bool doCheckTable = false);
+        const bool doCheckTable = false  /*optional variable*/, 
+        const bool optionalTable = false  /*optional variable*/);
 
     void printDBTable(const std::string& tableName) {
         m_dbManager->printAllRecords(tableName);
diff --git a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
index 006813743..aea205d5b 100644
--- a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
+++ b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
@@ -21,10 +21,8 @@
 
 namespace GeoModelIO {
 
-    template <typename T, class N> std::map<T,N> ReadGeoModel::getPublishedNodes(std::string publisherName, bool doCheckTable /*optional variables*/) 
+    template <typename T, class N> std::map<T,N> ReadGeoModel::getPublishedNodes(std::string publisherName, bool doCheckTable /*optional variables*/, bool optionalTable /*optional variables*/) 
     {
- 
-
         std::map<T, N> mapNodes;
         std::string keyType = "";
 
@@ -36,13 +34,13 @@ namespace GeoModelIO {
 
         if constexpr ( std::is_same_v<GeoFullPhysVol*, N> ) {
             if(doCheckTable){ 
-                bool tableExists = m_dbManager->checkTableFromDB("PublishedFullPhysVols_"+publisherName);
+                bool tableExists = m_dbManager->checkTableFromDB("PublishedFullPhysVols_"+publisherName, optionalTable);
                 if(!tableExists) return mapNodes;
             }
             vecRecords = m_dbManager->getPublishedFPVTable( publisherName );
         } else if constexpr ( std::is_same_v<GeoAlignableTransform*, N> ) {
             if(doCheckTable){ 
-                bool tableExists = m_dbManager->checkTableFromDB("PublishedAlignableTransforms_"+publisherName);
+                bool tableExists = m_dbManager->checkTableFromDB("PublishedAlignableTransforms_"+publisherName, optionalTable);
                 if(!tableExists) return mapNodes;
             }
             vecRecords = m_dbManager->getPublishedAXFTable( publisherName );
diff --git a/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp b/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp
index 95f0a56f1..06e6a264b 100644
--- a/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp
+++ b/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp
@@ -288,6 +288,30 @@ void ReadGeoModel::loadDB() {
     // timing: get start time
     std::chrono::system_clock::time_point start = std::chrono::system_clock::now();  
     // get all GeoModel nodes from the DB
+
+    /*NOTE:
+    * The GeoModel toolkit has been developed at the beginning 
+    of the design phase of the ATLAS experiment.
+    
+    The original toolkit featured a set of classes and graph nodes: 
+    GeoPhysVol, GeoLogVol, GeoMaterial, and so forth.
+
+    During the latest years, more classes have been added, 
+    and being added, to the toolkit.
+
+    To ensure that adding new classes and nodes to the toolkit does not interfere 
+    with the reading of databases created with an earlier GeoModel version
+    that did not have those, we now can set an "optional" falg to the 
+    load function, such as 'getTableFrom...()'. 
+
+    Please note, a set of GeoModel nodes are **compulsory**: we cannot have a functional
+    GeoModel tree without, for example, GeoPhysVols, LogVols, GeoElements, GeoMaterials, 
+    and GeoBox (we can't even instanciate the top/root 'World' volume without those!). 
+    For those compulsory classes/nodes, the flag should be set to 'false', 
+    which is the default value. However, for other classes/nodes that can be set to 'true'; 
+    e.g., for shapes like the recently introduced 'GeoTorus' and 'GeoGenericTrap', 
+    and all the new shapes and classes that will be added to the toolkit in the future.
+    */
     // m_shapes = m_dbManager->getTableFromNodeType("GeoShape");
     m_physVols = m_dbManager->getTableFromNodeType_String("GeoPhysVol");
     m_fullPhysVols = m_dbManager->getTableFromNodeType_String("GeoFullPhysVol");
@@ -318,7 +342,7 @@ void ReadGeoModel::loadDB() {
     m_shapes_Trap = m_dbManager->getTableFromNodeType_VecVecData("GeoTrap");
     m_shapes_Trd = m_dbManager->getTableFromNodeType_VecVecData("GeoTrd");
     m_shapes_Tubs = m_dbManager->getTableFromNodeType_VecVecData("GeoTubs");
-    m_shapes_Torus = m_dbManager->getTableFromNodeType_VecVecData("GeoTorus");
+    m_shapes_Torus = m_dbManager->getTableFromNodeType_VecVecData("GeoTorus", true); // // optional GeoModel node
     m_shapes_TwistedTrap = m_dbManager->getTableFromNodeType_VecVecData("GeoTwistedTrap");
     m_shapes_UnidentifiedShape = m_dbManager->getTableFromNodeType_VecVecData("GeoUnidentifiedShape");
     
@@ -326,13 +350,13 @@ void ReadGeoModel::loadDB() {
     m_shapes_Pcon = m_dbManager->getTableFromNodeType_VecVecData("GeoPcon");
     m_shapes_Pgon = m_dbManager->getTableFromNodeType_VecVecData("GeoPgon");
     m_shapes_SimplePolygonBrep = m_dbManager->getTableFromNodeType_VecVecData("GeoSimplePolygonBrep");
-    m_shapes_GenericTrap = m_dbManager->getTableFromNodeType_VecVecData("GeoGenericTrap");
+    m_shapes_GenericTrap = m_dbManager->getTableFromNodeType_VecVecData("GeoGenericTrap", true); // optional GeoModel node
 
     // shapes' data, when needed by shapes that have variable numbers of build parameters
     m_shapes_Pcon_data = m_dbManager->getTableFromTableName_VecVecData("Shapes_Pcon_Data");
     m_shapes_Pgon_data = m_dbManager->getTableFromTableName_VecVecData("Shapes_Pgon_Data");
     m_shapes_SimplePolygonBrep_data = m_dbManager->getTableFromTableName_VecVecData("Shapes_SimplePolygonBrep_Data");
-    m_shapes_GenericTrap_data = m_dbManager->getTableFromTableName_VecVecData("Shapes_GenericTrap_Data");
+    m_shapes_GenericTrap_data = m_dbManager->getTableFromTableName_VecVecData("Shapes_GenericTrap_Data", true); // optional GeoModel node
 
     // shape operators & boolean shapes
     m_shapes_Shift = m_dbManager->getTableFromNodeType_VecVecData("GeoShapeShift");
-- 
GitLab


From 9b67afc21130509c472c48059a3caa8d8933ea88 Mon Sep 17 00:00:00 2001
From: Riccardo Maria Bianchi <riccardo.maria.bianchi@cern.ch>
Date: Mon, 8 Jul 2024 13:16:37 +0200
Subject: [PATCH 2/3] fix signature, add missing 'const'

---
 GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
index aea205d5b..1a45473d1 100644
--- a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
+++ b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
@@ -21,7 +21,7 @@
 
 namespace GeoModelIO {
 
-    template <typename T, class N> std::map<T,N> ReadGeoModel::getPublishedNodes(std::string publisherName, bool doCheckTable /*optional variables*/, bool optionalTable /*optional variables*/) 
+    template <typename T, class N> std::map<T,N> ReadGeoModel::getPublishedNodes(std::string publisherName, const bool doCheckTable /*optional variables*/, const bool optionalTable /*optional variables*/) 
     {
         std::map<T, N> mapNodes;
         std::string keyType = "";
-- 
GitLab


From efa3afc90c9fa0eb72ad3e9e974bc216567e6c2f Mon Sep 17 00:00:00 2001
From: Riccardo Maria Bianchi <riccardo.maria.bianchi@cern.ch>
Date: Tue, 9 Jul 2024 23:16:40 +0200
Subject: [PATCH 3/3] add include to silence warning in VS Code

---
 GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
index 1a45473d1..f89704cbf 100644
--- a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
+++ b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.tpp
@@ -17,11 +17,13 @@
 #include "GeoModelHelpers/variantHelpers.h"
 #include "GeoModelHelpers/throwExcept.h"
 
-
+#include <map>
 
 namespace GeoModelIO {
 
-    template <typename T, class N> std::map<T,N> ReadGeoModel::getPublishedNodes(std::string publisherName, const bool doCheckTable /*optional variables*/, const bool optionalTable /*optional variables*/) 
+    template <typename T, class N> std::map<T,N> ReadGeoModel::getPublishedNodes(std::string publisherName, 
+        const bool doCheckTable /*optional variables*/, 
+        const bool optionalTable /*optional variables*/) 
     {
         std::map<T, N> mapNodes;
         std::string keyType = "";
-- 
GitLab