From 0b13281917fecf804b00be2e46c9209848649f99 Mon Sep 17 00:00:00 2001
From: Paul Gessinger <paul.gessinger@cern.ch>
Date: Tue, 6 Mar 2018 17:27:42 +0100
Subject: [PATCH] introduce serialization to CylinderLayer

---
 Core/include/ACTS/Layers/CylinderLayer.hpp    | 71 ++++++++++++++++++-
 Core/include/ACTS/Surfaces/CylinderBounds.hpp |  5 ++
 Core/include/ACTS/Surfaces/DiamondBounds.hpp  |  2 +
 Core/include/ACTS/Surfaces/EllipseBounds.hpp  |  2 +
 Core/include/ACTS/Surfaces/SurfaceBounds.hpp  |  6 ++
 .../include/ACTS/Surfaces/TrapezoidBounds.hpp |  2 +
 .../ACTS/Utilities/InstanceFactory.hpp        | 39 ++++++++--
 Core/include/ACTS/Utilities/VariantData.hpp   |  6 ++
 Core/src/Surfaces/CylinderBounds.cpp          | 37 ++++++++++
 Core/src/Surfaces/DiamondBounds.cpp           | 32 +++++++--
 Core/src/Surfaces/EllipseBounds.cpp           | 41 ++++++++---
 Core/src/Surfaces/TrapezoidBounds.cpp         | 19 ++++-
 Tests/Layers/CylinderLayerTests.cpp           | 48 +++++++++++--
 Tests/Surfaces/CylinderBoundsTests.cpp        | 28 ++++++++
 Tests/Surfaces/DiamondBoundsTests.cpp         | 29 ++++++++
 Tests/Surfaces/EllipseBoundsTests.cpp         | 30 ++++++++
 Tests/Surfaces/RectangleBoundsTests.cpp       | 15 +++-
 Tests/Surfaces/TrapezoidBoundsTests.cpp       | 25 +++++++
 Tests/Surfaces/TriangleBoundsTests.cpp        | 32 +++++++++
 19 files changed, 436 insertions(+), 33 deletions(-)

diff --git a/Core/include/ACTS/Layers/CylinderLayer.hpp b/Core/include/ACTS/Layers/CylinderLayer.hpp
index 0ef42dd5f..b29cb202f 100644
--- a/Core/include/ACTS/Layers/CylinderLayer.hpp
+++ b/Core/include/ACTS/Layers/CylinderLayer.hpp
@@ -16,8 +16,11 @@
 #include <algorithm>
 #include "ACTS/Layers/Layer.hpp"
 #include "ACTS/Surfaces/CylinderSurface.hpp"
-#include "ACTS/Utilities/BinnedArray.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
+#include "ACTS/Utilities/InstanceFactory.hpp"
+#include "ACTS/Utilities/ThrowAssert.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
+#include "ACTS/Volumes/CylinderVolumeBounds.hpp"
 
 namespace Acts {
 
@@ -64,6 +67,37 @@ public:
                                              laytyp));
   }
 
+  static MutableLayerPtr
+  create(const variant_data& data_)
+  {
+    throw_assert(data_.which() == 4, "Variant data must be map");
+    const variant_map& data = boost::get<variant_map>(data_);
+    std::string        type = data.get<std::string>("type");
+    throw_assert(type == "CylinderLayer", "Type must be CylinderLayer");
+
+    variant_map payload = data.get<variant_map>("payload");
+
+    auto trf = std::make_shared<const Transform3D>(
+        from_variant<Transform3D>(payload.get<variant_map>("transform")));
+
+    LayerType laytyp = passive;
+
+    double thickness = payload.get<double>("thickness");
+
+    InstanceFactory    factory;
+    const variant_map& var_bounds = payload.get<variant_map>("cylinder_bounds");
+
+    auto cbounds = std::dynamic_pointer_cast<const CylinderBounds>(
+        factory.surfaceBounds(var_bounds.get<std::string>("type"), var_bounds));
+
+    return MutableLayerPtr(new CylinderLayer(trf,
+                                             cbounds,
+                                             nullptr,  // SurfaceArray
+                                             thickness,
+                                             nullptr,  // std::move(ad),
+                                             laytyp));
+  }
+
   /// Copy constructor - deleted
   CylinderLayer(const CylinderLayer& cla) = delete;
 
@@ -87,6 +121,39 @@ public:
   CylinderSurface&
   surfaceRepresentation() override;
 
+  variant_data
+  toVariantData() const
+  {
+    using namespace std::string_literals;
+    variant_map payload;
+
+    payload["transform"] = to_variant(*m_transform);
+
+    // we need to recover the bounds
+    const AbstractVolume* absVol = representingVolume();
+    auto                  cvBounds
+        = dynamic_cast<const CylinderVolumeBounds*>(&absVol->volumeBounds());
+
+    double cylR = cvBounds->innerRadius() + 0.5 * thickness();
+    double hlZ  = cvBounds->halflengthZ();
+
+    CylinderBounds cylBounds(cylR, hlZ);
+
+    const variant_data bounds  = cylBounds.toVariantData();
+    payload["cylinder_bounds"] = bounds;
+
+    payload["thickness"] = thickness();
+
+    // payload["surface_array"] = m_surfaceArray->toVariantData();
+    payload["surface_array"] = 0;
+
+    variant_map data;
+    data["type"]    = "CylinderLayer"s;
+    data["payload"] = payload;
+
+    return data;
+  }
+
 private:
   /// build approach surfaces */
   void
@@ -120,6 +187,6 @@ protected:
   CylinderLayer(const CylinderLayer& cla, const Transform3D& shift);
 };
 
-}  // end of namespace
+}  // namespace Acts
 
 #endif  // ACTS_LAYERS_CYLINDERLAYER_H
diff --git a/Core/include/ACTS/Surfaces/CylinderBounds.hpp b/Core/include/ACTS/Surfaces/CylinderBounds.hpp
index fc204c5db..0073d0d23 100644
--- a/Core/include/ACTS/Surfaces/CylinderBounds.hpp
+++ b/Core/include/ACTS/Surfaces/CylinderBounds.hpp
@@ -77,6 +77,8 @@ public:
                  double halfPhi,
                  double halfZ);
 
+  CylinderBounds(const variant_data& data);
+
   virtual ~CylinderBounds();
 
   virtual CylinderBounds*
@@ -134,6 +136,9 @@ public:
   /// This method returns the halflengthZ
   double
   halflengthZ() const;
+  
+  variant_data
+  toVariantData() const;
 
 private:
   double m_radius, m_avgPhi, m_halfPhi, m_halfZ;
diff --git a/Core/include/ACTS/Surfaces/DiamondBounds.hpp b/Core/include/ACTS/Surfaces/DiamondBounds.hpp
index b67b9f94d..2ccc6f4f9 100644
--- a/Core/include/ACTS/Surfaces/DiamondBounds.hpp
+++ b/Core/include/ACTS/Surfaces/DiamondBounds.hpp
@@ -54,6 +54,8 @@ public:
                 double haley1,
                 double haley2);
 
+  DiamondBounds(const variant_data &data);
+
   virtual ~DiamondBounds();
 
   DiamondBounds*
diff --git a/Core/include/ACTS/Surfaces/EllipseBounds.hpp b/Core/include/ACTS/Surfaces/EllipseBounds.hpp
index 479fac5d3..cfabfece6 100644
--- a/Core/include/ACTS/Surfaces/EllipseBounds.hpp
+++ b/Core/include/ACTS/Surfaces/EllipseBounds.hpp
@@ -63,6 +63,8 @@ public:
                 double averagePhi = 0.,
                 double halfPhi    = M_PI);
 
+  EllipseBounds(const variant_data &data);
+
   virtual ~EllipseBounds();
 
   virtual EllipseBounds*
diff --git a/Core/include/ACTS/Surfaces/SurfaceBounds.hpp b/Core/include/ACTS/Surfaces/SurfaceBounds.hpp
index fbd1d63bf..5aa219c7f 100644
--- a/Core/include/ACTS/Surfaces/SurfaceBounds.hpp
+++ b/Core/include/ACTS/Surfaces/SurfaceBounds.hpp
@@ -17,6 +17,8 @@
 
 #include "ACTS/Surfaces/BoundaryCheck.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
+#include "ACTS/Utilities/VariantDataFwd.hpp"
+
 
 namespace Acts {
 
@@ -96,6 +98,10 @@ public:
   /// @param sl is the outstream in which the string dump is done
   virtual std::ostream&
   dump(std::ostream& os) const = 0;
+  
+  //virtual 
+  //variant_data
+  //toVariantData() const = 0;
 };
 
 inline bool
diff --git a/Core/include/ACTS/Surfaces/TrapezoidBounds.hpp b/Core/include/ACTS/Surfaces/TrapezoidBounds.hpp
index 5afd02797..646171151 100644
--- a/Core/include/ACTS/Surfaces/TrapezoidBounds.hpp
+++ b/Core/include/ACTS/Surfaces/TrapezoidBounds.hpp
@@ -52,6 +52,8 @@ public:
   /// @param haley half length Y - defined at x=0
   TrapezoidBounds(double minhalex, double maxhalex, double haley);
 
+  TrapezoidBounds(const variant_data &data);
+
   virtual ~TrapezoidBounds();
 
   virtual TrapezoidBounds*
diff --git a/Core/include/ACTS/Utilities/InstanceFactory.hpp b/Core/include/ACTS/Utilities/InstanceFactory.hpp
index 26ea38f76..876b186bf 100644
--- a/Core/include/ACTS/Utilities/InstanceFactory.hpp
+++ b/Core/include/ACTS/Utilities/InstanceFactory.hpp
@@ -16,11 +16,16 @@
 
 #include "ACTS/Surfaces/RectangleBounds.hpp"
 #include "ACTS/Surfaces/TriangleBounds.hpp"
+#include "ACTS/Surfaces/DiamondBounds.hpp"
+#include "ACTS/Surfaces/EllipseBounds.hpp"
+#include "ACTS/Surfaces/CylinderBounds.hpp"
+#include "ACTS/Surfaces/TrapezoidBounds.hpp"
 
 namespace Acts {
 
+using SurfaceBoundsPtr     = std::shared_ptr<const SurfaceBounds>;
 using PlanarBoundsPtr     = std::shared_ptr<const PlanarBounds>;
-using PlanarBoundsFactory = std::function<PlanarBoundsPtr(const variant_data&)>;
+using SurfaceBoundsFactory = std::function<SurfaceBoundsPtr(const variant_data&)>;
 
 class InstanceFactory
 {
@@ -28,23 +33,45 @@ public:
   InstanceFactory()
   {
     // set up map to store factories
-    m_planarBounds["RectangleBounds"] = [](auto const& data) {
+    m_surfaceBounds["RectangleBounds"] = [](auto const& data) {
       return std::make_shared<const RectangleBounds>(data);
     };
-    m_planarBounds["TriangleBounds"] = [](auto const& data) {
+    m_surfaceBounds["TriangleBounds"] = [](auto const& data) {
       return std::make_shared<const TriangleBounds>(data);
     };
+    m_surfaceBounds["DiamondBounds"] = [](auto const& data) {
+      return std::make_shared<const DiamondBounds>(data);
+    };
+    m_surfaceBounds["EllipseBounds"] = [](auto const& data) {
+      return std::make_shared<const EllipseBounds>(data);
+    };
+    m_surfaceBounds["TrapezoidBounds"] = [](auto const& data) {
+      return std::make_shared<const TrapezoidBounds>(data);
+    };
+    m_surfaceBounds["CylinderBounds"] = [](auto const& data) {
+      return std::make_shared<const CylinderBounds>(data);
+    };
+
   }
 
   PlanarBoundsPtr
   planarBounds(const std::string& cname, const variant_data& data)
   {
-    throw_assert(m_planarBounds.count(cname), "No factory found for class "+cname);
-    return m_planarBounds.at(cname)(data);
+    SurfaceBoundsPtr srfBnd_ptr = surfaceBounds(cname, data);
+    PlanarBoundsPtr plnBnd_ptr = std::dynamic_pointer_cast<const PlanarBounds>(srfBnd_ptr);
+    throw_assert(plnBnd_ptr, "Conversion to PlanarBounds failed");
+    return plnBnd_ptr;
+  }
+
+  SurfaceBoundsPtr
+  surfaceBounds(const std::string& cname, const variant_data& data)
+  {
+    throw_assert(m_surfaceBounds.count(cname), "No factory found for class "+cname);
+    return m_surfaceBounds.at(cname)(data);
   }
 
 private:
-  std::map<std::string, PlanarBoundsFactory> m_planarBounds;
+  std::map<std::string, SurfaceBoundsFactory> m_surfaceBounds;
 };
 
 }  // namespace Acts
diff --git a/Core/include/ACTS/Utilities/VariantData.hpp b/Core/include/ACTS/Utilities/VariantData.hpp
index 9b9f86a65..44c171f68 100644
--- a/Core/include/ACTS/Utilities/VariantData.hpp
+++ b/Core/include/ACTS/Utilities/VariantData.hpp
@@ -78,6 +78,12 @@ public:
     return boost::get<T>(m_map.at(key));
   }
 
+  const variant_data&
+  at(const std::string& key) const
+  {
+    return m_map.at(key);
+  }
+
   iterator
   begin()
   {
diff --git a/Core/src/Surfaces/CylinderBounds.cpp b/Core/src/Surfaces/CylinderBounds.cpp
index 86bc3db5b..e4801365c 100644
--- a/Core/src/Surfaces/CylinderBounds.cpp
+++ b/Core/src/Surfaces/CylinderBounds.cpp
@@ -17,6 +17,7 @@
 #include <iostream>
 
 #include "ACTS/Utilities/detail/periodic.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
 
 Acts::CylinderBounds::CylinderBounds(double radius, double halfZ)
   : CylinderBounds(radius, 0, M_PI, halfZ)
@@ -41,6 +42,22 @@ Acts::CylinderBounds::CylinderBounds(double radius,
 {
 }
 
+Acts::CylinderBounds::CylinderBounds(const variant_data& data_)
+  : m_radius(0), m_avgPhi(0), m_halfPhi(0), m_halfZ(0)
+{
+  throw_assert(data_.which() == 4, "Variant data must be map");
+  const variant_map &data = boost::get<variant_map>(data_);
+  std::string type = data.get<std::string>("type");
+  throw_assert(type == "CylinderBounds", "Type must be CylinderBounds");
+
+  const variant_map &payload = data.get<variant_map>("payload");
+
+  m_radius = payload.get<double>("radius");
+  m_avgPhi = payload.get<double>("avgPhi");
+  m_halfPhi = payload.get<double>("halfPhi");
+  m_halfZ = payload.get<double>("halfZ");
+}
+
 Acts::CylinderBounds::~CylinderBounds()
 {
 }
@@ -129,3 +146,23 @@ Acts::CylinderBounds::dump(std::ostream& sl) const
   sl << std::setprecision(-1);
   return sl;
 }
+
+Acts::variant_data
+Acts::CylinderBounds::toVariantData() const
+{
+  using namespace std::string_literals;
+
+  variant_map payload;
+  payload["radius"] = m_radius;
+  payload["avgPhi"] = m_avgPhi;
+  payload["halfPhi"] = m_halfPhi;
+  payload["halfZ"] = m_halfZ;
+
+  variant_map data({
+    {"type", "CylinderBounds"s},
+    {"payload", payload}
+  });
+
+  
+  return data;
+}
diff --git a/Core/src/Surfaces/DiamondBounds.cpp b/Core/src/Surfaces/DiamondBounds.cpp
index 9924c841a..ff9025290 100644
--- a/Core/src/Surfaces/DiamondBounds.cpp
+++ b/Core/src/Surfaces/DiamondBounds.cpp
@@ -35,10 +35,29 @@ Acts::DiamondBounds::DiamondBounds(double minhalex,
   throw_assert((maxhalex <= medhalex), "Hexagon must be a convex polygon");
 }
 
-Acts::DiamondBounds::~DiamondBounds()
+Acts::DiamondBounds::DiamondBounds(const variant_data& data_)
+  : m_boundingBox(0, 0)
 {
+  throw_assert(data_.which() == 4, "Variant data must be map");
+  const variant_map& data = boost::get<variant_map>(data_);
+  std::string        type = data.get<std::string>("type");
+  throw_assert(type == "DiamondBounds", "Type must be DiamondBounds");
+
+  const variant_map& payload = data.get<variant_map>("payload");
+
+  m_minHalfX = payload.get<double>("minHalfX");
+  m_medHalfX = payload.get<double>("medHalfX");
+  m_maxHalfX = payload.get<double>("maxHalfX");
+  m_minY     = payload.get<double>("minY");
+  m_maxY     = payload.get<double>("maxY");
+
+  m_boundingBox
+      = RectangleBounds(std::max(std::max(m_minHalfX, m_medHalfX), m_maxHalfX),
+                        std::max(m_minY, m_maxY));
 }
 
+Acts::DiamondBounds::~DiamondBounds() {}
+
 Acts::DiamondBounds*
 Acts::DiamondBounds::clone() const
 {
@@ -110,18 +129,19 @@ Acts::DiamondBounds::dump(std::ostream& sl) const
 }
 
 Acts::variant_data
-Acts::DiamondBounds::toVariantData() const {
+Acts::DiamondBounds::toVariantData() const
+{
   using namespace std::string_literals;
 
   variant_map payload;
   payload["minHalfX"] = m_minHalfX;
   payload["medHalfX"] = m_medHalfX;
   payload["maxHalfX"] = m_maxHalfX;
-  payload["minY"] = m_minY;
-  payload["maxY"] = m_maxY;
-  
+  payload["minY"]     = m_minY;
+  payload["maxY"]     = m_maxY;
+
   variant_map data;
-  data["type"] = "DiamondBounds";
+  data["type"]    = "DiamondBounds"s;
   data["payload"] = payload;
 
   return data;
diff --git a/Core/src/Surfaces/EllipseBounds.cpp b/Core/src/Surfaces/EllipseBounds.cpp
index ab8d7d9b3..19a778fa5 100644
--- a/Core/src/Surfaces/EllipseBounds.cpp
+++ b/Core/src/Surfaces/EllipseBounds.cpp
@@ -16,8 +16,8 @@
 #include <iomanip>
 #include <iostream>
 
-#include "ACTS/Utilities/detail/periodic.hpp"
 #include "ACTS/Utilities/VariantData.hpp"
+#include "ACTS/Utilities/detail/periodic.hpp"
 
 Acts::EllipseBounds::EllipseBounds(double minRadius0,
                                    double minRadius1,
@@ -36,10 +36,29 @@ Acts::EllipseBounds::EllipseBounds(double minRadius0,
 {
 }
 
-Acts::EllipseBounds::~EllipseBounds()
+Acts::EllipseBounds::EllipseBounds(const variant_data& data_)
+  : m_boundingBox(0, 0)
 {
+  throw_assert(data_.which() == 4, "Variant data must be map");
+  const variant_map& data = boost::get<variant_map>(data_);
+  std::string        type = data.get<std::string>("type");
+  throw_assert(type == "EllipseBounds", "Type must be EllipseBounds");
+
+  const variant_map& payload = data.get<variant_map>("payload");
+
+  m_rMinX   = payload.get<double>("rMinX");
+  m_rMinY   = payload.get<double>("rMinY");
+  m_rMaxX   = payload.get<double>("rMaxX");
+  m_rMaxY   = payload.get<double>("rMaxY");
+  m_avgPhi  = payload.get<double>("avgPhi");
+  m_halfPhi = payload.get<double>("halfPhi");
+
+  m_boundingBox
+      = RectangleBounds(std::max(m_rMinX, m_rMaxX), std::max(m_rMinY, m_rMaxY));
 }
 
+Acts::EllipseBounds::~EllipseBounds() {}
+
 Acts::EllipseBounds*
 Acts::EllipseBounds::clone() const
 {
@@ -183,21 +202,21 @@ Acts::EllipseBounds::dump(std::ostream& sl) const
 }
 
 Acts::variant_data
-Acts::EllipseBounds::toVariantData() const {
+Acts::EllipseBounds::toVariantData() const
+{
   using namespace std::string_literals;
 
   variant_map payload;
-  payload["rMinX"] = m_rMinX;
-  payload["rMinY"] = m_rMinY;
-  payload["rMaxX"] = m_rMaxX;
-  payload["rMaxY"] = m_rMaxY;
-  payload["avgPhi"] = m_avgPhi;
+  payload["rMinX"]   = m_rMinX;
+  payload["rMinY"]   = m_rMinY;
+  payload["rMaxX"]   = m_rMaxX;
+  payload["rMaxY"]   = m_rMaxY;
+  payload["avgPhi"]  = m_avgPhi;
   payload["halfPhi"] = m_halfPhi;
-  
+
   variant_map data;
-  data["type"] = "EllipseBounds"s;
+  data["type"]    = "EllipseBounds"s;
   data["payload"] = payload;
 
   return data;
-
 }
diff --git a/Core/src/Surfaces/TrapezoidBounds.cpp b/Core/src/Surfaces/TrapezoidBounds.cpp
index 29ee93c66..831374138 100644
--- a/Core/src/Surfaces/TrapezoidBounds.cpp
+++ b/Core/src/Surfaces/TrapezoidBounds.cpp
@@ -27,6 +27,23 @@ Acts::TrapezoidBounds::TrapezoidBounds(double minhalex,
 {
 }
 
+Acts::TrapezoidBounds::TrapezoidBounds(const variant_data& data_)
+  : m_boundingBox(0, 0)
+{
+  throw_assert(data_.which() == 4, "Variant data must be map");
+  const variant_map &data = boost::get<variant_map>(data_);
+  std::string type = data.get<std::string>("type");
+  throw_assert(type == "TrapezoidBounds", "Type must be TrapezoidBounds");
+
+  const variant_map &payload = data.get<variant_map>("payload");
+
+  m_minHalfX = payload.get<double>("minHalfX");
+  m_maxHalfX = payload.get<double>("maxHalfX");
+  m_halfY = payload.get<double>("halfY");
+
+  m_boundingBox = RectangleBounds(m_maxHalfX, m_halfY);
+}
+
 Acts::TrapezoidBounds::~TrapezoidBounds()
 {
 }
@@ -104,7 +121,7 @@ Acts::TrapezoidBounds::toVariantData() const {
   payload["halfY"]    = m_halfY;
   
   variant_map data;
-  data["type"] = "TrapezoidBounds";
+  data["type"] = "TrapezoidBounds"s;
   data["payload"] = payload;
 
   return data;
diff --git a/Tests/Layers/CylinderLayerTests.cpp b/Tests/Layers/CylinderLayerTests.cpp
index 8dad8060a..8e2272441 100644
--- a/Tests/Layers/CylinderLayerTests.cpp
+++ b/Tests/Layers/CylinderLayerTests.cpp
@@ -51,10 +51,10 @@ namespace Test {
       // next level: need an array of Surfaces;
       const std::vector<const Surface*> aSurfaces{new SurfaceStub(),
                                                   new SurfaceStub()};
-      const double        thickness(1.0);
-      SurfaceArrayCreator sac;
-      size_t              binsX(2), binsY(4);
-      auto                pSurfaceArray
+      const double                      thickness(1.0);
+      SurfaceArrayCreator               sac;
+      size_t                            binsX(2), binsY(4);
+      auto                              pSurfaceArray
           = sac.surfaceArrayOnPlane(aSurfaces, 10, 20, binsX, binsY);
       auto pCylinderLayerFromSurfaces = CylinderLayer::create(
           pTransform, pCylinder, std::move(pSurfaceArray));
@@ -101,6 +101,46 @@ namespace Test {
                  == std::string("Acts::CylinderSurface"));
     }
 
+    BOOST_AUTO_TEST_CASE(CylinderLayer_toVariantData)
+    {
+      Translation3D translation{0., 1., 2.};
+      Transform3D   rot;
+      rot = AngleAxis3D(M_PI / 4, Vector3D::UnitZ());
+
+      auto pTransform = std::make_shared<const Transform3D>(translation * rot);
+      double radius(0.5), halfz(10.);
+      auto   pCylinder = std::make_shared<const CylinderBounds>(radius, halfz);
+      auto   pCylinderLayer = std::dynamic_pointer_cast<CylinderLayer>(
+          CylinderLayer::create(pTransform, pCylinder, nullptr, 0.4));
+
+      variant_data var_data = pCylinderLayer->toVariantData();
+      std::cout << var_data << std::endl;
+
+      variant_map var_map = boost::get<variant_map>(var_data);
+      variant_map pl      = var_map.get<variant_map>("payload");
+      BOOST_TEST(pl.get<double>("thickness") == 0.4);
+      Transform3D act = from_variant<Transform3D>(pl.at("transform"));
+      BOOST_TEST(pTransform->isApprox(act));
+
+      auto pCylinderLayer2 = std::dynamic_pointer_cast<CylinderLayer>(
+          CylinderLayer::create(var_data));
+
+      BOOST_TEST(pCylinderLayer->thickness() == pCylinderLayer2->thickness());
+      BOOST_TEST(
+          pCylinderLayer->transform().isApprox(pCylinderLayer2->transform()));
+
+      auto cvBoundsExp = dynamic_cast<const CylinderVolumeBounds*>(
+          &(pCylinderLayer->representingVolume()->volumeBounds()));
+      auto cvBoundsAct = dynamic_cast<const CylinderVolumeBounds*>(
+          &(pCylinderLayer2->representingVolume()->volumeBounds()));
+
+      BOOST_TEST(cvBoundsExp->innerRadius() == cvBoundsAct->innerRadius());
+      BOOST_TEST(cvBoundsExp->outerRadius() == cvBoundsAct->outerRadius());
+      BOOST_TEST(cvBoundsExp->halfPhiSector() == cvBoundsAct->halfPhiSector());
+      BOOST_TEST(cvBoundsExp->halflengthZ() == cvBoundsAct->halflengthZ());
+
+    }
+
     BOOST_AUTO_TEST_SUITE_END()
   }  // end of namespace Layers
 }  // end of namespace Test
diff --git a/Tests/Surfaces/CylinderBoundsTests.cpp b/Tests/Surfaces/CylinderBoundsTests.cpp
index 5e4ae604c..874e26da5 100644
--- a/Tests/Surfaces/CylinderBoundsTests.cpp
+++ b/Tests/Surfaces/CylinderBoundsTests.cpp
@@ -20,6 +20,7 @@
 //
 #include "ACTS/Surfaces/CylinderBounds.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
 //
 #include <limits>
 
@@ -132,6 +133,33 @@ namespace Test {
     BOOST_TEST(assignedCylinderBounds.r() == cylinderBoundsObject.r());
     BOOST_TEST(assignedCylinderBounds == cylinderBoundsObject);
   }
+
+
+  BOOST_AUTO_TEST_CASE(RectangleBounds_toVariantData) {
+    double radius = 10, avgPhi = 0, halfPhi = M_PI, halfZ = 15;
+    CylinderBounds cylBounds(radius, avgPhi, halfPhi, halfZ);
+
+    variant_data var_data = cylBounds.toVariantData();
+    std::cout << var_data << std::endl;
+
+    variant_map var_map = boost::get<variant_map>(var_data);
+    BOOST_TEST(var_map.get<std::string>("type") == "CylinderBounds");
+    variant_map pl = var_map.get<variant_map>("payload");
+
+    BOOST_TEST(pl.get<double>("radius") == radius);
+    BOOST_TEST(pl.get<double>("avgPhi") == avgPhi);
+    BOOST_TEST(pl.get<double>("halfPhi") == halfPhi);
+    BOOST_TEST(pl.get<double>("halfZ") == halfZ);
+
+    CylinderBounds cylBounds2(var_data);
+    BOOST_TEST(cylBounds.r() == cylBounds2.r());
+    BOOST_TEST(cylBounds.averagePhi() == cylBounds2.averagePhi());
+    BOOST_TEST(cylBounds.halfPhiSector() == cylBounds2.halfPhiSector());
+    BOOST_TEST(cylBounds.halflengthZ() == cylBounds2.halflengthZ());
+  }
+
+
+
   BOOST_AUTO_TEST_SUITE_END()
 
 }  // end of namespace Test
diff --git a/Tests/Surfaces/DiamondBoundsTests.cpp b/Tests/Surfaces/DiamondBoundsTests.cpp
index 8b612a21a..45a0157be 100644
--- a/Tests/Surfaces/DiamondBoundsTests.cpp
+++ b/Tests/Surfaces/DiamondBoundsTests.cpp
@@ -21,6 +21,7 @@
 #include "ACTS/Surfaces/DiamondBounds.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
 #include "ACTS/Utilities/ThrowAssert.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
 //
 #include <limits>
 
@@ -144,6 +145,34 @@ namespace Test {
     assignedDiamondBoundsObject = diamondBoundsObject;
     BOOST_TEST(assignedDiamondBoundsObject == diamondBoundsObject);
   }
+
+
+  BOOST_AUTO_TEST_CASE(DiamondBounds_toVariantData) {
+    double minHalfX(10.), midHalfX(50.), maxHalfX(30.), halfY1(10.),
+        halfY2(20.);
+    DiamondBounds diam(minHalfX, midHalfX, maxHalfX, halfY1, halfY2);
+    variant_data var_data = diam.toVariantData();
+
+    std::cout << var_data << std::endl;
+
+    variant_map var_map = boost::get<variant_map>(var_data);
+    BOOST_TEST(var_map.get<std::string>("type") == "DiamondBounds");
+    variant_map pl = var_map.get<variant_map>("payload");
+    BOOST_TEST(pl.get<double>("minHalfX") == minHalfX);
+    BOOST_TEST(pl.get<double>("medHalfX") == midHalfX);
+    BOOST_TEST(pl.get<double>("maxHalfX") == maxHalfX);
+    BOOST_TEST(pl.get<double>("minY") == halfY1);
+    BOOST_TEST(pl.get<double>("maxY") == halfY2);
+
+    DiamondBounds diam2(var_data);
+    BOOST_TEST(diam.minHalflengthX() == diam2.minHalflengthX());
+    BOOST_TEST(diam.medHalflengthX() == diam2.medHalflengthX());
+    BOOST_TEST(diam.maxHalflengthX() == diam2.maxHalflengthX());
+    BOOST_TEST(diam.halflengthY1() == diam2.halflengthY1());
+    BOOST_TEST(diam.halflengthY2() == diam2.halflengthY2());
+  }
+
+
   BOOST_AUTO_TEST_SUITE_END()
 
 }  // end of namespace Test
diff --git a/Tests/Surfaces/EllipseBoundsTests.cpp b/Tests/Surfaces/EllipseBoundsTests.cpp
index 4d5202cf0..fb9aa0eea 100644
--- a/Tests/Surfaces/EllipseBoundsTests.cpp
+++ b/Tests/Surfaces/EllipseBoundsTests.cpp
@@ -20,6 +20,7 @@
 //
 #include "ACTS/Surfaces/EllipseBounds.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
 //
 #include <limits>
 
@@ -137,6 +138,35 @@ namespace Test {
     assignedEllipseBoundsObject = ellipseBoundsObject;
     BOOST_TEST(assignedEllipseBoundsObject == ellipseBoundsObject);
   }
+
+  BOOST_AUTO_TEST_CASE(EllipseBounds_toVariantData) {
+    double minRad1(10.), minRad2(15.), maxRad1(15.), maxRad2(20.),
+        averagePhi(0.), phiSector(M_PI / 2.);
+    EllipseBounds ell(minRad1, minRad2, maxRad1, maxRad2, averagePhi, phiSector);
+    variant_data var_data = ell.toVariantData();
+
+    std::cout << var_data << std::endl;
+
+    variant_map var_map = boost::get<variant_map>(var_data);
+    BOOST_TEST(var_map.get<std::string>("type") == "EllipseBounds");
+    variant_map pl = var_map.get<variant_map>("payload");
+    BOOST_TEST(pl.get<double>("rMinX") == minRad1);
+    BOOST_TEST(pl.get<double>("rMinY") == minRad2);
+    BOOST_TEST(pl.get<double>("rMaxX") == maxRad1);
+    BOOST_TEST(pl.get<double>("rMaxY") == maxRad2);
+    BOOST_TEST(pl.get<double>("avgPhi") == averagePhi);
+    BOOST_TEST(pl.get<double>("halfPhi") == phiSector);
+
+    EllipseBounds ell2(var_data);
+    BOOST_TEST(ell.rMinX() == ell2.rMinX());
+    BOOST_TEST(ell.rMinY() == ell2.rMinY());
+    BOOST_TEST(ell.rMaxX() == ell2.rMaxX());
+    BOOST_TEST(ell.rMaxY() == ell2.rMaxY());
+    BOOST_TEST(ell.averagePhi() == ell2.averagePhi());
+    BOOST_TEST(ell.halfPhiSector() == ell2.halfPhiSector());
+  }
+
+
   BOOST_AUTO_TEST_SUITE_END()
 
 }  // end of namespace Test
diff --git a/Tests/Surfaces/RectangleBoundsTests.cpp b/Tests/Surfaces/RectangleBoundsTests.cpp
index f805d3b4a..0a609587b 100644
--- a/Tests/Surfaces/RectangleBoundsTests.cpp
+++ b/Tests/Surfaces/RectangleBoundsTests.cpp
@@ -124,10 +124,19 @@ namespace Test {
   }
 
   BOOST_AUTO_TEST_CASE(RectangleBounds_toVariantData) {
-    RectangleBounds rect(10, 10);
-    variant_data var_rect = rect.toVariantData();
+    RectangleBounds rect(10, 15);
+    variant_data var_data = rect.toVariantData();
 
-    std::cout << var_rect << std::endl;
+    std::cout << var_data << std::endl;
+    variant_map var_map = boost::get<variant_map>(var_data);
+    BOOST_TEST(var_map.get<std::string>("type") == "RectangleBounds");
+    variant_map pl = var_map.get<variant_map>("payload");
+    BOOST_TEST(pl.get<double>("halflengthX") == 10);
+    BOOST_TEST(pl.get<double>("halflengthY") == 15);
+
+    RectangleBounds rect2(var_data);
+    BOOST_TEST(rect.halflengthX() == rect2.halflengthX());
+    BOOST_TEST(rect.halflengthY() == rect2.halflengthY());
   }
 
   BOOST_AUTO_TEST_SUITE_END()
diff --git a/Tests/Surfaces/TrapezoidBoundsTests.cpp b/Tests/Surfaces/TrapezoidBoundsTests.cpp
index ab6fe3a4f..a3f537a06 100644
--- a/Tests/Surfaces/TrapezoidBoundsTests.cpp
+++ b/Tests/Surfaces/TrapezoidBoundsTests.cpp
@@ -21,6 +21,7 @@
 
 #include "ACTS/Surfaces/TrapezoidBounds.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
 
 namespace utf    = boost::unit_test;
 const double NaN = std::numeric_limits<double>::quiet_NaN();
@@ -118,6 +119,30 @@ namespace Test {
     assignedTrapezoidBoundsObject = trapezoidBoundsObject;
     BOOST_TEST(assignedTrapezoidBoundsObject == trapezoidBoundsObject);
   }
+
+
+  BOOST_AUTO_TEST_CASE(TrapezoidBounds_toVariantData) {
+    double minHlX = 10;
+    double maxHlX = 15;
+    double hlY = 5;
+    TrapezoidBounds trap(minHlX, maxHlX, hlY);
+    variant_data var_data = trap.toVariantData();
+
+    std::cout << var_data << std::endl;
+
+    variant_map var_map = boost::get<variant_map>(var_data);
+    BOOST_TEST(var_map.get<std::string>("type") == "TrapezoidBounds");
+    variant_map pl = var_map.get<variant_map>("payload");
+    BOOST_TEST(pl.get<double>("minHalfX") == minHlX);
+    BOOST_TEST(pl.get<double>("maxHalfX") == maxHlX);
+    BOOST_TEST(pl.get<double>("halfY") == hlY);
+
+    TrapezoidBounds trap2(var_data);
+    BOOST_TEST(trap.minHalflengthX() == trap2.minHalflengthX());
+    BOOST_TEST(trap.maxHalflengthX() == trap2.maxHalflengthX());
+    BOOST_TEST(trap.halflengthY() == trap2.halflengthY());
+  }
+
   BOOST_AUTO_TEST_SUITE_END()
 
 }  // end of namespace Test
diff --git a/Tests/Surfaces/TriangleBoundsTests.cpp b/Tests/Surfaces/TriangleBoundsTests.cpp
index 7d39c4924..e27b9a45b 100644
--- a/Tests/Surfaces/TriangleBoundsTests.cpp
+++ b/Tests/Surfaces/TriangleBoundsTests.cpp
@@ -21,6 +21,7 @@
 
 #include "ACTS/Surfaces/TriangleBounds.hpp"
 #include "ACTS/Utilities/Definitions.hpp"
+#include "ACTS/Utilities/VariantData.hpp"
 
 namespace utf    = boost::unit_test;
 //const double NaN = std::numeric_limits<double>::quiet_NaN();
@@ -112,6 +113,37 @@ namespace Test {
     assignedTriangleBoundsObject = triangleBoundsObject;
     BOOST_TEST(assignedTriangleBoundsObject.vertices() == triangleBoundsObject.vertices());
   }
+
+  BOOST_AUTO_TEST_CASE(TriangleBounds_toVariantData) {
+    std::array<Vector2D, 3> vertices({{
+        Vector2D(1., 1.), Vector2D(4., 1.), Vector2D(4., 5.)}});  // 3-4-5 triangle
+    TriangleBounds triangle(vertices);
+    variant_data var_data = triangle.toVariantData();
+
+    std::cout << var_data << std::endl;
+
+    variant_map var_map = boost::get<variant_map>(var_data);
+    BOOST_TEST(var_map.get<std::string>("type") == "TriangleBounds");
+    variant_map pl = var_map.get<variant_map>("payload");
+
+    variant_vector var_vertices = pl.get<variant_vector>("vertices");
+    BOOST_TEST(var_vertices.size() == 3);
+    
+    for(size_t i=0;i<3;i++) {
+      Vector2D exp = vertices.at(i);
+      variant_map var = var_vertices.get<variant_map>(i);
+      BOOST_TEST(var.get<std::string>("type") == "Vector2D");
+      variant_vector coords = var.get<variant_vector>("payload");
+
+      BOOST_TEST(exp.x() == coords.get<double>(0));
+      BOOST_TEST(exp.y() == coords.get<double>(1));
+    }
+
+    TriangleBounds triangle2(var_data);
+    BOOST_TEST(triangle2.vertices().size() == 3);
+  }
+
+
   BOOST_AUTO_TEST_SUITE_END()
 
 }  // end of namespace Test
-- 
GitLab