From edbde3b0329974f02dbc2f9ea031592555a9e4ce Mon Sep 17 00:00:00 2001
From: Riccardo Maria Bianchi <riccardo.maria.bianchi@cern.ch>
Date: Wed, 26 Jun 2024 15:56:59 +0200
Subject: [PATCH] Add Torus to Write, DB, and Read. Add GenericTrap to Write
 and DB.

---
 ...ep1_create_store_geo_and_publish_nodes.cpp |  36 ++++-
 .../GeoModelDBManager/src/GMDBManager.cpp     | 137 ++++++++++++------
 .../GeoModelRead/GeoModelRead/ReadGeoModel.h  |   5 +
 .../GeoModelRead/src/BuildGeoShapes_Torus.cpp |  37 +++++
 .../GeoModelRead/src/BuildGeoShapes_Torus.h   |  28 ++++
 GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp  |  38 ++++-
 .../GeoModelWrite/WriteGeoModel.h             |   5 +
 .../GeoModelWrite/src/WriteGeoModel.cpp       | 100 +++++++++----
 8 files changed, 310 insertions(+), 76 deletions(-)
 create mode 100644 GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.cpp
 create mode 100644 GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.h

diff --git a/GeoModelExamples/HelloToy/step1_create_store_geo_and_publish_nodes.cpp b/GeoModelExamples/HelloToy/step1_create_store_geo_and_publish_nodes.cpp
index 26af27678..84df27af3 100644
--- a/GeoModelExamples/HelloToy/step1_create_store_geo_and_publish_nodes.cpp
+++ b/GeoModelExamples/HelloToy/step1_create_store_geo_and_publish_nodes.cpp
@@ -21,8 +21,10 @@
 #include "GeoModelKernel/GeoTrap.h"
 #include "GeoModelKernel/GeoTrd.h"
 #include "GeoModelKernel/GeoTubs.h"
+#include "GeoModelKernel/GeoTorus.h"
 #include "GeoModelKernel/GeoTwistedTrap.h"
 #include "GeoModelKernel/GeoSimplePolygonBrep.h"
+#include "GeoModelKernel/GeoGenericTrap.h"
 #include "GeoModelKernel/GeoPcon.h"
 #include "GeoModelKernel/GeoPgon.h"
 #include "GeoModelKernel/GeoUnidentifiedShape.h"
@@ -441,15 +443,43 @@ int main(int argc, char *argv[])
   // Add a test "UnidentifiedShape" shape node
   const std::string nameUnidentifiedShape = "LAr::Example";
   GeoUnidentifiedShape* sUnidentifiedShape = new GeoUnidentifiedShape("LArCustomShape",nameUnidentifiedShape);
-  GeoLogVol* lUnidentifiedShape = new GeoLogVol("UnidentifiedShape", sUnidentifiedShape, steel);
+  const GeoLogVol* lUnidentifiedShape = new GeoLogVol("UnidentifiedShape", sUnidentifiedShape, steel);
   GeoPhysVol *pUnidentifiedShape = new GeoPhysVol(lUnidentifiedShape);
   GeoNameTag *nUnidentifiedShape = new GeoNameTag("UnidentifiedShape");
   toyPhys->add(nUnidentifiedShape);
   toyPhys->add(pUnidentifiedShape);
 
 
-
-
+  // Add a test "Torus" shape node
+  const GeoTorus* sTorus = new GeoTorus(2*SYSTEM_OF_UNITS::m, 1*SYSTEM_OF_UNITS::m, 10*SYSTEM_OF_UNITS::m, 0*SYSTEM_OF_UNITS::rad, (270*SYSTEM_OF_UNITS::degree)*(SYSTEM_OF_UNITS::rad/SYSTEM_OF_UNITS::degree));
+  const GeoLogVol* lTorus = new GeoLogVol("Torus", sTorus, steel);
+  GeoPhysVol* pTorus = new GeoPhysVol(lTorus);
+  GeoNameTag* nTorus = new GeoNameTag("Shape-Torus");
+  toyPhys->add(nTorus);
+  toyPhys->add(pTorus);
+
+  // Add a test GeoGenericTrap shape
+  const double gt_Zlength = 1 * SYSTEM_OF_UNITS::m;
+  const double gt_xV1 = 1.5 * SYSTEM_OF_UNITS::m;
+  const double gt_yV1 = 1.5 * SYSTEM_OF_UNITS::m;
+  const double gt_xV2 = 3 * SYSTEM_OF_UNITS::m;
+  const double gt_yV2 = 3 * SYSTEM_OF_UNITS::m;
+  const double gt_xV3 = 4 * SYSTEM_OF_UNITS::m;
+  const double gt_yV3 = 4 * SYSTEM_OF_UNITS::m;
+  GeoGenericTrapVertices gt_Vertices;
+  gt_Vertices.push_back(GeoTwoVector(gt_xV1, gt_yV1));
+  gt_Vertices.push_back(GeoTwoVector(gt_xV2, gt_yV2));
+  gt_Vertices.push_back(GeoTwoVector(gt_xV3, gt_yV3));
+  GeoGenericTrap *sGenericTrap = new GeoGenericTrap(gt_Zlength, gt_Vertices);
+  // if (!sGenericTrap->isValid())
+  // {
+  //   THROW_EXCEPTION("ERROR! GeoGenericTrap shape is not valid!!");
+  // }
+  GeoLogVol *lGenericTrap = new GeoLogVol("GeoGenericTrap", sGenericTrap, steel);
+  GeoPhysVol *pGenericTrap = new GeoPhysVol(lGenericTrap);
+  GeoNameTag *nGenericTrap = new GeoNameTag("Shape-GenericTrap");
+  toyPhys->add(nGenericTrap);
+  toyPhys->add(pGenericTrap);
 
   //------------------------------------------------------------------------------------//
   // Writing the geometry to file
diff --git a/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp b/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp
index 0a785fa9c..f9322a493 100644
--- a/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp
+++ b/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp
@@ -1604,48 +1604,6 @@ bool GMDBManager::createTables() {
     rc = execQuery(queryStr);
     tab.clear();
     
-    // create a table to store the numeric data used in GeoPcon shapes
-    tableName = "Shapes_Pcon_Data";
-    tab.push_back(tableName);
-    tab.push_back("id");
-    tab.push_back("ZPlane");
-    tab.push_back("RMinPlane");
-    tab.push_back("RMaxPlane");
-    storeTableColumnNames(tab);
-    queryStr = fmt::format(
-        "create table {0}({1} integer primary key, {2} real, {3} real, {4} real )",
-        tab[0], tab[1], tab[2], tab[3], tab[4]);
-    rc = execQuery(queryStr);
-    tab.clear();
-    
-    // create a table to store the numeric data used in GeoPcon shapes
-    tableName = "Shapes_Pgon_Data";
-    tab.push_back(tableName);
-    tab.push_back("id");
-    tab.push_back("ZPlane");
-    tab.push_back("RMinPlane");
-    tab.push_back("RMaxPlane");
-    storeTableColumnNames(tab);
-    queryStr = fmt::format(
-        "create table {0}({1} integer primary key, {2} real, {3} real, {4} real )",
-        tab[0], tab[1], tab[2], tab[3], tab[4]);
-    rc = execQuery(queryStr);
-    tab.clear();
-    
-    // create a table to store the numeric data used in GeoPcon shapes
-    tableName = "Shapes_SimplePolygonBrep_Data";
-    tab.push_back(tableName);
-    tab.push_back("id");
-    tab.push_back("XVertex");
-    tab.push_back("YVertex");
-    storeTableColumnNames(tab);
-    queryStr = fmt::format(
-        "create table {0}({1} integer primary key, {2} real, {3} real )",
-        tab[0], tab[1], tab[2], tab[3]);
-    rc = execQuery(queryStr);
-    tab.clear();
-
-
     // create a table to store information about the 'root' volume (also
     // known as the 'world' volume)
     tableName = "RootVolume";
@@ -1943,6 +1901,27 @@ bool GMDBManager::createTables() {
     }
     tab.clear();
     
+    // Shapes-Tubs table
+    geoNode = "GeoTorus";
+    tableName = "Shapes_Torus";
+    m_childType_tableName[geoNode] = tableName;
+    tab.push_back(tableName);
+    tab.push_back("id");
+    tab.push_back("computedVolume");
+    tab.push_back("RMin");
+    tab.push_back("RMax");
+    tab.push_back("RTor");
+    tab.push_back("SPhi");
+    tab.push_back("DPhi");
+    storeTableColumnNames(tab);
+    queryStr = fmt::format(
+        "create table {0}({1} integer primary key, {2} real, {3} real, {4} real, {5} real, {6} real, {7} real )",
+        tab[0], tab[1], tab[2], tab[3], tab[4], tab[5], tab[6], tab[7] );
+    if (0 == (rc = execQuery(queryStr))) {
+        storeNodeType(geoNode, tableName);
+    }
+    tab.clear();
+    
     // Shapes-TwistedTrap table
     geoNode = "GeoTwistedTrap";
     tableName = "Shapes_TwistedTrap";
@@ -2032,6 +2011,26 @@ bool GMDBManager::createTables() {
         storeNodeType(geoNode, tableName);
     }
     tab.clear();
+    
+    // Shapes-SimplePolygonBrep table
+    geoNode = "GeoGenericTrap";
+    tableName = "Shapes_GenericTrap";
+    m_childType_tableName[geoNode] = tableName;
+    tab.push_back(tableName);
+    tab.push_back("id");
+    tab.push_back("computedVolume");
+    tab.push_back("ZHalfLength");
+    tab.push_back("NVertices");
+    tab.push_back("dataStart");
+    tab.push_back("dataEnd");
+    storeTableColumnNames(tab);
+    queryStr = fmt::format(
+        "create table {0}({1} integer primary key, {2} real, {3} real, {4} integer, {5} integer, {6} integer )",
+        tab[0], tab[1], tab[2], tab[3], tab[4], tab[5], tab[6]);
+    if (0 == (rc = execQuery(queryStr))) {
+        storeNodeType(geoNode, tableName);
+    }
+    tab.clear();
 
     // Shapes-Intersection table
     geoNode = "GeoShapeIntersection";
@@ -2131,6 +2130,60 @@ bool GMDBManager::createTables() {
     }
     tab.clear();
 
+    // create a table to store the numeric data used in GeoPcon shapes
+    tableName = "Shapes_Pcon_Data";
+    tab.push_back(tableName);
+    tab.push_back("id");
+    tab.push_back("ZPlane");
+    tab.push_back("RMinPlane");
+    tab.push_back("RMaxPlane");
+    storeTableColumnNames(tab);
+    queryStr = fmt::format(
+        "create table {0}({1} integer primary key, {2} real, {3} real, {4} real )",
+        tab[0], tab[1], tab[2], tab[3], tab[4]);
+    rc = execQuery(queryStr);
+    tab.clear();
+    
+    // create a table to store the numeric data used in GeoPcon shapes
+    tableName = "Shapes_Pgon_Data";
+    tab.push_back(tableName);
+    tab.push_back("id");
+    tab.push_back("ZPlane");
+    tab.push_back("RMinPlane");
+    tab.push_back("RMaxPlane");
+    storeTableColumnNames(tab);
+    queryStr = fmt::format(
+        "create table {0}({1} integer primary key, {2} real, {3} real, {4} real )",
+        tab[0], tab[1], tab[2], tab[3], tab[4]);
+    rc = execQuery(queryStr);
+    tab.clear();
+    
+    // create a table to store the numeric data used in GeoPcon shapes
+    tableName = "Shapes_SimplePolygonBrep_Data";
+    tab.push_back(tableName);
+    tab.push_back("id");
+    tab.push_back("XVertex");
+    tab.push_back("YVertex");
+    storeTableColumnNames(tab);
+    queryStr = fmt::format(
+        "create table {0}({1} integer primary key, {2} real, {3} real )",
+        tab[0], tab[1], tab[2], tab[3]);
+    rc = execQuery(queryStr);
+    tab.clear();
+    
+    // create a table to store the numeric data used in GeoPcon shapes
+    tableName = "Shapes_GenericTrap_Data";
+    tab.push_back(tableName);
+    tab.push_back("id");
+    tab.push_back("XVertex");
+    tab.push_back("YVertex");
+    storeTableColumnNames(tab);
+    queryStr = fmt::format(
+        "create table {0}({1} integer primary key, {2} real, {3} real )",
+        tab[0], tab[1], tab[2], tab[3]);
+    rc = execQuery(queryStr);
+    tab.clear();
+
     // SerialDenominators table
     geoNode = "GeoSerialDenominator";
     tableName = "SerialDenominators";
diff --git a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h
index 1381bbda2..48e661229 100644
--- a/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h
+++ b/GeoModelIO/GeoModelRead/GeoModelRead/ReadGeoModel.h
@@ -95,6 +95,7 @@ class BuildGeoShapes_Para;
 class BuildGeoShapes_Trap;
 class BuildGeoShapes_Trd;
 class BuildGeoShapes_Tubs;
+class BuildGeoShapes_Torus;
 class BuildGeoShapes_TwistedTrap;
 class BuildGeoShapes_Pcon;
 class BuildGeoShapes_Pgon;
@@ -186,6 +187,7 @@ class ReadGeoModel {
     unsigned long getNShapes_Trd() { return m_shapes_Trd.size(); };
     unsigned long getNShapes_Tube() { return m_shapes_Tube.size(); };
     unsigned long getNShapes_Tubs() { return m_shapes_Tubs.size(); };
+    unsigned long getNShapes_Torus() { return m_shapes_Torus.size(); };
     unsigned long getNShapes_TwistedTrap() { return m_shapes_TwistedTrap.size(); };
     unsigned long getNShapes_UnidentifiedShape() { return m_shapes_UnidentifiedShape.size(); };
     unsigned long getNShapes_Shift() { return m_shapes_Shift.size(); };
@@ -202,6 +204,7 @@ class ReadGeoModel {
     void buildAllShapes_Trap();
     void buildAllShapes_Trd();
     void buildAllShapes_Tubs();
+    void buildAllShapes_Torus();
     void buildAllShapes_TwistedTrap();
     void buildAllShapes_Pcon();
     void buildAllShapes_Pgon();
@@ -400,6 +403,7 @@ class ReadGeoModel {
     BuildGeoShapes_Trap* m_builderShape_Trap;
     BuildGeoShapes_Trd* m_builderShape_Trd;
     BuildGeoShapes_Tubs* m_builderShape_Tubs;
+    BuildGeoShapes_Torus* m_builderShape_Torus;
     BuildGeoShapes_TwistedTrap* m_builderShape_TwistedTrap;
     BuildGeoShapes_Pcon* m_builderShape_Pcon;
     BuildGeoShapes_Pgon* m_builderShape_Pgon;
@@ -434,6 +438,7 @@ class ReadGeoModel {
     DBRowsList m_shapes_Trap;
     DBRowsList m_shapes_Trd;
     DBRowsList m_shapes_Tubs;
+    DBRowsList m_shapes_Torus;
     DBRowsList m_shapes_TwistedTrap;
     DBRowsList m_shapes_Pcon;
     DBRowsList m_shapes_Pgon;
diff --git a/GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.cpp b/GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.cpp
new file mode 100644
index 000000000..7d27fe56c
--- /dev/null
+++ b/GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.cpp
@@ -0,0 +1,37 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * Created on: June, 2024
+ * Author: Riccardo Maria BIANCHI <riccardo.maria.bianchi@cern.ch>
+ */
+
+#include "BuildGeoShapes_Torus.h"
+
+#include "GeoModelKernel/GeoTorus.h"
+#include "GeoModelHelpers/variantHelpers.h"
+
+#include <vector>
+#include <iostream>
+
+void BuildGeoShapes_Torus::buildShape(const DBRowEntry row)
+{
+  // === get shape numeric data from the DB row
+  // shape ID
+  const int shapeId = GeoModelHelpers::variantHelper::getFromVariant_Int(row[0], "Torus:shapeID");
+  // shape volume
+  const double shapeVolume = GeoModelHelpers::variantHelper::getFromVariant_Double(row[1], "Torus:shapeVolume");
+  // shape parameters
+  const double RMin = GeoModelHelpers::variantHelper::getFromVariant_Double(row[2], "Torus:RMin");
+  const double RMax = GeoModelHelpers::variantHelper::getFromVariant_Double(row[3], "Torus:RMax");
+  const double RTor = GeoModelHelpers::variantHelper::getFromVariant_Double(row[4], "Torus:RTor");
+  const double SPhi = GeoModelHelpers::variantHelper::getFromVariant_Double(row[5], "Torus:SPhi");
+  const double DPhi = GeoModelHelpers::variantHelper::getFromVariant_Double(row[6], "Torus:DPhi");
+  
+  GeoShape *shape = new GeoTorus(RMin, RMax, RTor, SPhi, DPhi);
+
+  storeBuiltShape(shapeId, shape);
+
+  return;
+}
diff --git a/GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.h b/GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.h
new file mode 100644
index 000000000..c319276c6
--- /dev/null
+++ b/GeoModelIO/GeoModelRead/src/BuildGeoShapes_Torus.h
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * BuildGeoShapes_Torus.h
+ *
+ * Created on: June, 2024
+ * Author: Riccardo Maria BIANCHI <riccardo.maria.bianchi@cern.ch>
+ *
+ */
+
+#ifndef GEOMODELREAD_BuildGeoShapes_Torus_H
+#define GEOMODELREAD_BuildGeoShapes_Torus_H
+
+#include "BuildGeoShapes.h"
+
+#include <vector>
+#include <variant>
+
+class BuildGeoShapes_Torus : public BuildGeoShapes
+{
+public:
+  BuildGeoShapes_Torus(const unsigned size):BuildGeoShapes("Torus", size){};
+  void buildShape(const DBRowEntry row) override;
+};
+
+#endif
diff --git a/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp b/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp
index 72d35d529..e2c3d98a6 100644
--- a/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp
+++ b/GeoModelIO/GeoModelRead/src/ReadGeoModel.cpp
@@ -37,6 +37,7 @@
 #include "BuildGeoShapes_Trap.h"
 #include "BuildGeoShapes_Trd.h"
 #include "BuildGeoShapes_Tubs.h"
+#include "BuildGeoShapes_Torus.h"
 #include "BuildGeoShapes_TwistedTrap.h"
 #include "BuildGeoShapes_SimplePolygonBrep.h"
 #include "BuildGeoShapes_UnidentifiedShape.h"
@@ -82,6 +83,7 @@
 #include "GeoModelKernel/GeoTrd.h"
 #include "GeoModelKernel/GeoTube.h"
 #include "GeoModelKernel/GeoTubs.h"
+#include "GeoModelKernel/GeoTorus.h"
 #include "GeoModelKernel/GeoTwistedTrap.h"
 #include "GeoModelKernel/GeoUnidentifiedShape.h"
 
@@ -233,6 +235,7 @@ ReadGeoModel::~ReadGeoModel() {
     delete m_builderShape_Trap;
     delete m_builderShape_Trd;
     delete m_builderShape_Tubs;
+    delete m_builderShape_Torus;
     delete m_builderShape_TwistedTrap;
     delete m_builderShape_SimplePolygonBrep;
     delete m_builderShape_UnidentifiedShape;
@@ -244,6 +247,7 @@ ReadGeoModel::~ReadGeoModel() {
     m_builderShape_Trap = nullptr;
     m_builderShape_Trd = nullptr;
     m_builderShape_Tubs = nullptr;
+    m_builderShape_Torus = nullptr;
     m_builderShape_TwistedTrap = nullptr;
     m_builderShape_SimplePolygonBrep = nullptr;
     m_builderShape_UnidentifiedShape = nullptr;
@@ -310,6 +314,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_TwistedTrap = m_dbManager->getTableFromNodeType_VecVecData("GeoTwistedTrap");
     
     m_shapes_Pcon = m_dbManager->getTableFromNodeType_VecVecData("GeoPcon");
@@ -386,6 +391,7 @@ GeoVPhysVol* ReadGeoModel::buildGeoModelPrivate() {
         std::thread t24(&ReadGeoModel::buildAllShapes_TwistedTrap, this);
         std::thread t25(&ReadGeoModel::buildAllShapes_SimplePolygonBrep, this);
         std::thread t26(&ReadGeoModel::buildAllShapes_UnidentifiedShape, this);
+        std::thread t27(&ReadGeoModel::buildAllShapes_Torus, this);
         
 
         t2.join();  // ok, all Elements have been built
@@ -405,6 +411,7 @@ GeoVPhysVol* ReadGeoModel::buildGeoModelPrivate() {
         t24.join();  // ok, all Shapes-TwistedTrap have been built
         t25.join();  // ok, all Shapes-SimplePolygonBrep have been built
         t26.join();  // ok, all Shapes-UnidentifiedShape have been built
+        t27.join();  // ok, all Shapes-Torus have been built
 
 	    // Build boolean shapes and shape operators,
         // this needs Shapes to be built
@@ -456,6 +463,7 @@ GeoVPhysVol* ReadGeoModel::buildGeoModelPrivate() {
         buildAllShapes_Trap();
         buildAllShapes_Trd();
         buildAllShapes_Tubs();
+        buildAllShapes_Torus();
         buildAllShapes_TwistedTrap();
         buildAllShapes_Operators();
         buildAllMaterials();
@@ -767,6 +775,24 @@ void ReadGeoModel::buildAllShapes_Tubs()
         std::cout << "All " << nSize << " Shapes-Tubs have been built!\n";
     }
 }
+//! Iterate over the list of GeoTorus shape nodes, build them all, 
+//! and store their pointers
+void ReadGeoModel::buildAllShapes_Torus()
+{
+    // create a builder and reserve size of memory map
+    size_t nSize = m_shapes_Torus.size();
+    m_builderShape_Torus = new BuildGeoShapes_Torus(nSize);
+    // loop over the DB rows and build the shapes
+    for (const auto &row : m_shapes_Torus)
+    {
+        // GeoModelIO::CppHelper::printStdVectorVariants(row); // DEBUG MSG
+        m_builderShape_Torus->buildShape(row);
+    }
+    // m_builderShape_Torus->printBuiltShapes(); // DEBUG MSG
+    if (nSize > 0) {
+        std::cout << "All " << nSize << " Shapes-Torus have been built!\n";
+    }
+}
 //! Iterate over the list of GeoTwistedTrap shape nodes, build them all, 
 //! and store their pointers
 void ReadGeoModel::buildAllShapes_TwistedTrap()
@@ -3844,7 +3870,7 @@ return (!(m_memMapShapes_Union.find(id) == m_memMapShapes_Union.end()));
 }
 // --- methods for caching GeoShape nodes ---
 bool ReadGeoModel::isBuiltShape(std::string_view shapeType, const unsigned shapeId) {
-const std::set<std::string> shapesNewDB{"Box", "Tube", "Pcon", "Cons", "Para", "Pgon", "Trap", "Trd", "Tubs", "TwistedTrap", "SimplePolygonBrep", "Shift", "Subtraction", "Intersection", "Union"};
+const std::set<std::string> shapesNewDB{"Box", "Tube", "Pcon", "Cons", "Para", "Pgon", "Trap", "Trd", "Tubs", "Torus", "TwistedTrap", "SimplePolygonBrep", "Shift", "Subtraction", "Intersection", "Union"};
     // get shape parameters
     if (std::count(shapesNewDB.begin(), shapesNewDB.end(), shapeType))
     {
@@ -3884,6 +3910,10 @@ const std::set<std::string> shapesNewDB{"Box", "Tube", "Pcon", "Cons", "Para", "
         {
             return m_builderShape_Tubs->isBuiltShape(shapeId);
         } 
+        else if ("Torus" == shapeType)
+        {
+            return m_builderShape_Torus->isBuiltShape(shapeId);
+        } 
         else if ("TwistedTrap" == shapeType)
         {
             return m_builderShape_TwistedTrap->isBuiltShape(shapeId);
@@ -3947,7 +3977,7 @@ void ReadGeoModel::storeBuiltShapeOperators_Union(const unsigned id, GeoShape* n
 GeoShape *ReadGeoModel::getBuiltShape(const unsigned shapeId, std::string_view shapeType)
 {
 
-    const std::set<std::string> shapesNewDB{"Box", "Tube", "Pcon", "Cons", "Para", "Pgon", "Trap", "Trd", "Tubs", "TwistedTrap", "SimplePolygonBrep", "Shift", "Intersection", "Subtraction", "Union", "UnidentifiedShape"};
+    const std::set<std::string> shapesNewDB{"Box", "Tube", "Pcon", "Cons", "Para", "Pgon", "Trap", "Trd", "Tubs", "Torus", "TwistedTrap", "SimplePolygonBrep", "Shift", "Intersection", "Subtraction", "Union", "UnidentifiedShape"};
     // get shape parameters
     if (std::count(shapesNewDB.begin(), shapesNewDB.end(), shapeType))
     {
@@ -3987,6 +4017,10 @@ GeoShape *ReadGeoModel::getBuiltShape(const unsigned shapeId, std::string_view s
         {
             return m_builderShape_Tubs->getBuiltShape(shapeId);
         } 
+        else if ("Torus" == shapeType)
+        {
+            return m_builderShape_Torus->getBuiltShape(shapeId);
+        } 
         else if ("TwistedTrap" == shapeType)
         {
             return m_builderShape_TwistedTrap->getBuiltShape(shapeId);
diff --git a/GeoModelIO/GeoModelWrite/GeoModelWrite/WriteGeoModel.h b/GeoModelIO/GeoModelWrite/GeoModelWrite/WriteGeoModel.h
index 0d69ccb6e..ed07bcd7a 100644
--- a/GeoModelIO/GeoModelWrite/GeoModelWrite/WriteGeoModel.h
+++ b/GeoModelIO/GeoModelWrite/GeoModelWrite/WriteGeoModel.h
@@ -157,10 +157,12 @@ class WriteGeoModel : public GeoNodeAction {
     unsigned long getNShapes_Pcon() { return m_shapes_Pcon.size(); };
     unsigned long getNShapes_Pgon() { return m_shapes_Pgon.size(); };
     unsigned long getNShapes_SimplePolygonBrep() { return m_shapes_SimplePolygonBrep.size(); };
+    unsigned long getNShapes_GenericTrap() { return m_shapes_GenericTrap.size(); };
     unsigned long getNShapes_Trap() { return m_shapes_Trap.size(); };
     unsigned long getNShapes_Trd() { return m_shapes_Trd.size(); };
     unsigned long getNShapes_Tube() { return m_shapes_Tube.size(); };
     unsigned long getNShapes_Tubs() { return m_shapes_Tubs.size(); };
+    unsigned long getNShapes_Torus() { return m_shapes_Torus.size(); };
     unsigned long getNShapes_TwistedTrap() { return m_shapes_TwistedTrap.size(); };
     unsigned long getNShapes_UnidentifiedShape() { return m_shapes_UnidentifiedShape.size(); };
     unsigned long getNShapes_Shift() { return m_shapes_Shift.size(); };
@@ -394,14 +396,17 @@ class WriteGeoModel : public GeoNodeAction {
     DBRowsList m_shapes_Trap;
     DBRowsList m_shapes_Trd;
     DBRowsList m_shapes_Tubs;
+    DBRowsList m_shapes_Torus;
     DBRowsList m_shapes_TwistedTrap;
     
     DBRowsList m_shapes_Pcon;
     DBRowsList m_shapes_Pgon;
     DBRowsList m_shapes_SimplePolygonBrep;
+    DBRowsList m_shapes_GenericTrap;
     DBRowsList m_shapes_Pcon_Data;
     DBRowsList m_shapes_Pgon_Data;
     DBRowsList m_shapes_SimplePolygonBrep_Data;
+    DBRowsList m_shapes_GenericTrap_Data;
 
     DBRowsList m_shapes_Shift;
     DBRowsList m_shapes_Intersection;
diff --git a/GeoModelIO/GeoModelWrite/src/WriteGeoModel.cpp b/GeoModelIO/GeoModelWrite/src/WriteGeoModel.cpp
index ef1134282..b6d33c58c 100644
--- a/GeoModelIO/GeoModelWrite/src/WriteGeoModel.cpp
+++ b/GeoModelIO/GeoModelWrite/src/WriteGeoModel.cpp
@@ -48,12 +48,14 @@
 #include "GeoModelKernel/GeoShapeSubtraction.h"
 #include "GeoModelKernel/GeoShapeUnion.h"
 #include "GeoModelKernel/GeoSimplePolygonBrep.h"
+#include "GeoModelKernel/GeoGenericTrap.h"
 #include "GeoModelKernel/GeoTessellatedSolid.h"
 #include "GeoModelKernel/GeoTorus.h"
 #include "GeoModelKernel/GeoTrap.h"
 #include "GeoModelKernel/GeoTrd.h"
 #include "GeoModelKernel/GeoTube.h"
 #include "GeoModelKernel/GeoTubs.h"
+#include "GeoModelKernel/GeoTorus.h"
 #include "GeoModelKernel/GeoTwistedTrap.h"
 #include "GeoModelKernel/GeoUnidentifiedShape.h"
 
@@ -700,7 +702,7 @@ std::pair<std::string, unsigned> WriteGeoModel::storeShape(const GeoShape* shape
     // LArCustomShape is deprecated.  Write it out as a GeoUnidentifiedShape;
     if (shapeType == "CustomShape") shapeType = "UnidentifiedShape";
 
-    const std::set<std::string> shapesNewDB{"Box", "Tube", "Cons", "Para", "Trap", "Trd", "Tubs", "TwistedTrap", "Pcon", "Pgon", "SimplePolygonBrep", "Intersection", "Shift", "Subtraction", "Union", "UnidentifiedShape"};
+    const std::set<std::string> shapesNewDB{"Box", "Tube", "Cons", "Para", "Trap", "Trd", "Tubs", "Torus", "TwistedTrap", "Pcon", "Pgon", "SimplePolygonBrep", "GenericTrap", "Intersection", "Shift", "Subtraction", "Union", "UnidentifiedShape"};
 
     // get shape parameters
     if (std::count(shapesNewDB.begin(), shapesNewDB.end(), shapeType))
@@ -1077,6 +1079,23 @@ WriteGeoModel::getShapeParametersV(const GeoShape *shape, const bool data)
         shapePars.push_back(shapeIn->getSPhi());
         shapePars.push_back(shapeIn->getDPhi());
     }
+    else if (shapeType == "Torus")
+    {
+        // Member Data:
+        // * Rmax - outside radius of the torus tube
+        // * Rmin - inside radius  of the torus tube (Rmin=0 if not hollow)
+        // * Rtor - radius of the torus itself
+        // *
+        // * SPhi - starting angle of the segment in radians
+        // * DPhi - delta angle of the segment in radians
+        //
+        const GeoTorus* shapeIn = dynamic_cast<const GeoTorus*>(shape);
+        shapePars.push_back(shapeIn->getRMin());
+        shapePars.push_back(shapeIn->getRMax());
+        shapePars.push_back(shapeIn->getRTor());
+        shapePars.push_back(shapeIn->getSPhi());
+        shapePars.push_back(shapeIn->getDPhi());
+    }
     else if (shapeType == "Pcon")
     {
         const GeoPcon* shapeIn = dynamic_cast<const GeoPcon*>(shape);
@@ -1124,10 +1143,23 @@ WriteGeoModel::getShapeParametersV(const GeoShape *shape, const bool data)
             dataRow.clear();
         }
     }
+    else if (shapeType == "GenericTrap") {
+        const GeoGenericTrap* shapeIn = dynamic_cast<const GeoGenericTrap*>(shape);
+
+        shapePars.push_back(shapeIn->getZHalfLength());
+        // get number of Z planes and loop over them
+        const int nVertices = shapeIn->getVertices().size();
+        shapePars.push_back(nVertices);
+        for (int i = 0; i < nVertices; ++i) {
+            dataRow.push_back(shapeIn->getVertices()[i](0));
+            dataRow.push_back(shapeIn->getVertices()[i](1));
+            shapeData.push_back(dataRow);
+            dataRow.clear();
+        }
+    } 
     else if (shapeType == "Intersection")
     {
-        const GeoShapeIntersection* shapeIn =
-            dynamic_cast<const GeoShapeIntersection*>(shape);
+        const GeoShapeIntersection* shapeIn = dynamic_cast<const GeoShapeIntersection*>(shape);
         
         // get the two referenced Shape nodes used in the 'Intersection' operation, 
         // then store them in the DB
@@ -1148,8 +1180,7 @@ WriteGeoModel::getShapeParametersV(const GeoShape *shape, const bool data)
     }
     else if (shapeType == "Shift")
     {
-        const GeoShapeShift* shapeIn =
-            dynamic_cast<const GeoShapeShift*>(shape);
+        const GeoShapeShift* shapeIn = dynamic_cast<const GeoShapeShift*>(shape);
 
         // get the referenced Shape used in the 'shift' operation, 
         // then store it in the DB
@@ -1167,10 +1198,9 @@ WriteGeoModel::getShapeParametersV(const GeoShape *shape, const bool data)
     }
     else if (shapeType == "Subtraction")
     {
-        const GeoShapeSubtraction* shapeIn =
-            dynamic_cast<const GeoShapeSubtraction*>(shape);
+        const GeoShapeSubtraction* shapeIn = dynamic_cast<const GeoShapeSubtraction*>(shape);
         
-         // get the two referenced Shape nodes used in the 'Subtraction' operation, 
+        // get the two referenced Shape nodes used in the 'Subtraction' operation, 
         // then store them in the DB
         const GeoShape* shapeOpA = shapeIn->getOpA();
         const std::pair<std::string, unsigned> shapeStoredA = storeShape(shapeOpA);
@@ -1190,10 +1220,9 @@ WriteGeoModel::getShapeParametersV(const GeoShape *shape, const bool data)
     }
     else if (shapeType == "Union")
     {
-        const GeoShapeUnion* shapeIn =
-            dynamic_cast<const GeoShapeUnion*>(shape);
+        const GeoShapeUnion* shapeIn = dynamic_cast<const GeoShapeUnion*>(shape);
         
-         // get the two referenced Shape nodes used in the 'Subtraction' operation, 
+        // get the two referenced Shape nodes used in the 'Subtraction' operation, 
         // then store them in the DB
         const GeoShape* shapeOpA = shapeIn->getOpA();
         const std::pair<std::string, unsigned> shapeStoredA = storeShape(shapeOpA);
@@ -1211,8 +1240,7 @@ WriteGeoModel::getShapeParametersV(const GeoShape *shape, const bool data)
         shapePars.push_back(shapeIdB);
 
     } else if (shapeType == "UnidentifiedShape") {
-        const GeoUnidentifiedShape* shapeIn =
-            dynamic_cast<const GeoUnidentifiedShape*>(shape);
+        const GeoUnidentifiedShape* shapeIn = dynamic_cast<const GeoUnidentifiedShape*>(shape);
         shapePars.push_back(shapeIn->name());
         shapePars.push_back(shapeIn->asciiData());
     }
@@ -1261,22 +1289,22 @@ std::string WriteGeoModel::getShapeParameters(const GeoShape* shape) {
     //     pars.push_back("SPhi=" + GeoStrUtils::to_string_with_precision(shapeIn->getSPhi()));
     //     pars.push_back("DPhi=" + GeoStrUtils::to_string_with_precision(shapeIn->getDPhi()));
     // } 
-    else if (shapeType == "Torus") {
-        // Member Data:
-        // * Rmax - outside radius of the torus tube
-        // * Rmin - inside radius  of the torus tube (Rmin=0 if not hollow)
-        // * Rtor - radius of the torus itself
-        // *
-        // * SPhi - starting angle of the segment in radians
-        // * DPhi - delta angle of the segment in radians
-        //
-        const GeoTorus* shapeIn = dynamic_cast<const GeoTorus*>(shape);
-        pars.push_back("Rmin=" + GeoStrUtils::to_string_with_precision(shapeIn->getRMin()));
-        pars.push_back("Rmax=" + GeoStrUtils::to_string_with_precision(shapeIn->getRMax()));
-        pars.push_back("Rtor=" + GeoStrUtils::to_string_with_precision(shapeIn->getRTor()));
-        pars.push_back("SPhi=" + GeoStrUtils::to_string_with_precision(shapeIn->getSPhi()));
-        pars.push_back("DPhi=" + GeoStrUtils::to_string_with_precision(shapeIn->getDPhi()));
-    } 
+    // else if (shapeType == "Torus") {
+    //     // Member Data:
+    //     // * Rmax - outside radius of the torus tube
+    //     // * Rmin - inside radius  of the torus tube (Rmin=0 if not hollow)
+    //     // * Rtor - radius of the torus itself
+    //     // *
+    //     // * SPhi - starting angle of the segment in radians
+    //     // * DPhi - delta angle of the segment in radians
+    //     //
+    //     const GeoTorus* shapeIn = dynamic_cast<const GeoTorus*>(shape);
+    //     pars.push_back("Rmin=" + GeoStrUtils::to_string_with_precision(shapeIn->getRMin()));
+    //     pars.push_back("Rmax=" + GeoStrUtils::to_string_with_precision(shapeIn->getRMax()));
+    //     pars.push_back("Rtor=" + GeoStrUtils::to_string_with_precision(shapeIn->getRTor()));
+    //     pars.push_back("SPhi=" + GeoStrUtils::to_string_with_precision(shapeIn->getSPhi()));
+    //     pars.push_back("DPhi=" + GeoStrUtils::to_string_with_precision(shapeIn->getDPhi()));
+    // } 
     // else if (shapeType == "Para") {
     //     const GeoPara* shapeIn = dynamic_cast<const GeoPara*>(shape);
     //     pars.push_back("XHalfLength=" +
@@ -2049,6 +2077,9 @@ std::pair<unsigned, unsigned> WriteGeoModel::addShapeData(const std::string type
     else if ("SimplePolygonBrep" == type) {
         container = &m_shapes_SimplePolygonBrep_Data;
     } 
+    else if ("GenericTrap" == type) {
+        container = &m_shapes_GenericTrap_Data;
+    } 
     else {
         std::cout << "\nERROR!!! Shape data for shape '" << type << "' have not been set, yet!\n" << std::endl;
     }
@@ -2497,6 +2528,10 @@ unsigned int WriteGeoModel::addShape(const std::string &type,
     {
         container = &m_shapes_Tubs;
     }
+    else if ("Torus" == type)
+    {
+        container = &m_shapes_Torus;
+    }
     else if ("TwistedTrap" == type)
     {
         container = &m_shapes_TwistedTrap;
@@ -2513,6 +2548,10 @@ unsigned int WriteGeoModel::addShape(const std::string &type,
     {
         container = &m_shapes_SimplePolygonBrep;
     }
+    else if ("GenericTrap" == type)
+    {
+        container = &m_shapes_GenericTrap;
+    }
     else if ("Intersection" == type)
     {
         container = &m_shapes_Intersection;
@@ -2662,6 +2701,7 @@ void WriteGeoModel::saveToDB(std::vector<GeoPublisher*>& publishers) {
     m_dbManager->addListOfRecords("GeoTrap", m_shapes_Trap); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecords("GeoTrd", m_shapes_Trd); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecords("GeoTubs", m_shapes_Tubs); // new version, with shape's parameters as numbers
+    m_dbManager->addListOfRecords("GeoTorus", m_shapes_Torus); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecords("GeoTwistedTrap", m_shapes_TwistedTrap); // new version, with shape's parameters as numbers
     
     // store shapes' data // TODO: maybe this should be encapsulated with shapes? 
@@ -2669,9 +2709,11 @@ void WriteGeoModel::saveToDB(std::vector<GeoPublisher*>& publishers) {
     m_dbManager->addListOfRecords("GeoPcon", m_shapes_Pcon); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecords("GeoPgon", m_shapes_Pgon); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecords("GeoSimplePolygonBrep", m_shapes_SimplePolygonBrep); // new version, with shape's parameters as numbers
+    m_dbManager->addListOfRecords("GeoGenericTrap", m_shapes_GenericTrap); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecordsToTable("Shapes_Pcon_Data", m_shapes_Pcon_Data); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecordsToTable("Shapes_Pgon_Data", m_shapes_Pgon_Data); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecordsToTable("Shapes_SimplePolygonBrep_Data", m_shapes_SimplePolygonBrep_Data); // new version, with shape's parameters as numbers
+    m_dbManager->addListOfRecordsToTable("Shapes_GenericTrap_Data", m_shapes_GenericTrap_Data); // new version, with shape's parameters as numbers
 
     m_dbManager->addListOfRecords("GeoShapeShift", m_shapes_Shift); // new version, with shape's parameters as numbers
     m_dbManager->addListOfRecords("GeoShapeIntersection", m_shapes_Intersection); // new version, with shape's parameters as numbers
-- 
GitLab