diff --git a/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoDeDuplicator.h b/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoDeDuplicator.h new file mode 100644 index 0000000000000000000000000000000000000000..b11634c8c25da825806fc5f0c2d5f5f2caba4e04 --- /dev/null +++ b/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoDeDuplicator.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration +*/ +#ifndef GEOMODELFUNCSNIPPETS_GEODEDUPLICATOR_H +#define GEOMODELFUNCSNIPPETS_GEODEDUPLICATOR_H + +#include "GeoModelKernel/GeoPhysVol.h" +#include "GeoModelKernel/GeoShape.h" +#include "GeoModelKernel/GeoTransform.h" + +#include "GeoModelFuncSnippets/GeoLogVolSorter.h" +#include "GeoModelFuncSnippets/GeoPhysVolSorter.h" +#include "GeoModelFuncSnippets/GeoShapeSorter.h" +#include "GeoModelFuncSnippets/TransformSorter.h" + +#include <set> +/*** + * Helper class to deduplicate shapes, volumes and non-alignable transforms in the GeoModel tree that are equivalent + * but instantiated in different places. Every time when the cache function is invoked, it's tried to insert the object + * into its respective store. If another object which is equivalent in terms of the GeoLogVolSorter, GeoPhysVolSorter or + * GeoTransformSorter has been already added, the parsed object is deleted and the pointer to the already cached one is returned + * + * + * Usage for GeoTransforms: + * + * Instead of + * GeoTransform* xtrf = new GeoTransform(<Some transform to the volume> ); + * + * just do + * GeoTransform* xtrf = makeTransform(<Some transform to the volume> ); + * + * NOTE: GeoTransforms are shared across all instances of the GeoDeDuplicator class + * + * Useage for GeoShapes: + * Perform the usual assembly of the shape e.g. + * + * GeoShape* tube = new GeoTube(10,42, 66); + * + * If you combine the GeoShape with the logical volume then do + * + * GeoLogVol* logVol = new GeoLogVol("TheCakeTastes", cacheShape(tube), cakeMaterial); + * + * In a similar fashion repeating components of GeoShapes in Boolean shapes can be made shared as well + * + * NOTE: GeoShapes are shares across all instances of the GeoDeuplicator class + * + * Useage for GeoFullPhysVol: + * GeoFullPhysVol are never shared and can neither be added to the GeoDeDuplicator. However, it's possible + * to share the same logical volume across several physical volumes + * + * GeoFullPhysVol* fullPhyVol = new GeoFullPhyVol(cacheVolume(logVol)); + * + * Useage for ordinary GeoPhysVol: + * + * Assemble the GeoPhysVol as it's needed + * + * GeoPhysVol* subVol = new GeoPhysVol(cacheVolume(logVol2)); + * GeoPhysVol* subVol1 = new GeoPhysVol(cacheVolume(logVol3)); + * + * subVol->add(makeTransform(GeoTrf::TranslateX3D(999))); + * subVol->add(cacheVolume(subVol1)); + * + * fullPhysVol->add(cacheVolume(subVol)); + * +*/ +class GeoDeDuplicator { + public: + using GeoShapePtr = GeoIntrusivePtr<const GeoShape>; + using GeoLogVolPtr = GeoIntrusivePtr<GeoLogVol>; + using GeoTrfPtr = GeoIntrusivePtr<GeoTransform>; + using GeoPhysVolPtr = GeoIntrusivePtr<GeoPhysVol>; + + GeoDeDuplicator() = default; + ~GeoDeDuplicator() = default; + + GeoPhysVolPtr cacheVolume(GeoPhysVolPtr vol) const; + GeoTrfPtr makeTransform(const GeoTrf::Transform3D& trf) const; + GeoLogVolPtr cacheVolume(GeoLogVolPtr vol) const; + GeoShapePtr cacheShape(GeoShapePtr shape) const; + + private: + using PhysVolSet = std::set<GeoIntrusivePtr<GeoPhysVol>, GeoPhysVolSorter>; + using LogVolSet = std::set<GeoLogVolPtr, GeoLogVolSorter>; + using TrfSet = std::set<GeoTrfPtr, GeoTrf::TransformSorter>; + using ShapeSet = std::set<GeoShapePtr, GeoShapeSorter>; + mutable PhysVolSet m_physVolStore{}; + mutable LogVolSet m_logVolStore{}; + + static TrfSet s_trfStore; + static ShapeSet s_shapeStore; +}; + + +#endif diff --git a/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeSorter.h b/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeSorter.h index 388348bec2102334401189f45c58cdb55f41e131..6c04c0ba458677fa3282924d80fad571965ab2d7 100644 --- a/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeSorter.h +++ b/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeSorter.h @@ -40,6 +40,6 @@ struct GeoComposedShapeSorter { /// @brief /// @tparam ShapeType template<class ShapeType> -using GeoShapeSet = std::set<GeoIntrusivePtr<const ShapeType>, GeoShapeSorter>; +using GeoShapeSet = std::set<GeoIntrusivePtr<ShapeType>, GeoShapeSorter>; #endif \ No newline at end of file diff --git a/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeUtils.h b/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeUtils.h index 2fe716d13dd137cd88ddc33933160b6519b7b801..77fb6a9147c2eed9923e44f187f4584755c4eeec 100644 --- a/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeUtils.h +++ b/GeoModelCore/GeoModelFuncSnippets/GeoModelFuncSnippets/GeoShapeUtils.h @@ -25,6 +25,8 @@ GeoIntrusivePtr<const GeoShape> compressShift(const GeoShape* shift); /// In the case of the GeoSubtraction all subtracting shapes std::vector<const GeoShape*> getBooleanComponents(const GeoShape* booleanShape); - +/// @brief Returns the edge points surrounding a shape +std::vector<GeoTrf::Vector3D> getPolyShapeEdges(const GeoShape* shape, + const GeoTrf::Transform3D& refTrf); #endif \ No newline at end of file diff --git a/GeoModelCore/GeoModelFuncSnippets/src/GeoDeDuplicator.cxx b/GeoModelCore/GeoModelFuncSnippets/src/GeoDeDuplicator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0d48d05db8bd4d0e2929d5887f13d01413107bf8 --- /dev/null +++ b/GeoModelCore/GeoModelFuncSnippets/src/GeoDeDuplicator.cxx @@ -0,0 +1,26 @@ + +/* + Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration +*/ + +#include "GeoModelFuncSnippets/GeoDeDuplicator.h" + +GeoDeDuplicator::TrfSet GeoDeDuplicator::s_trfStore{}; +GeoDeDuplicator::ShapeSet GeoDeDuplicator::s_shapeStore{}; + +GeoDeDuplicator::GeoTrfPtr + GeoDeDuplicator::makeTransform(const GeoTrf::Transform3D& trf) const { + return *s_trfStore.emplace(new GeoTransform(trf)).first; + } +GeoDeDuplicator::GeoPhysVolPtr + GeoDeDuplicator::cacheVolume(GeoPhysVolPtr vol) const { + return *m_physVolStore.insert(vol).first; + } +GeoDeDuplicator::GeoLogVolPtr + GeoDeDuplicator::cacheVolume(GeoLogVolPtr vol) const { + return *m_logVolStore.insert(vol).first; + } +GeoDeDuplicator::GeoShapePtr + GeoDeDuplicator::cacheShape(GeoShapePtr shape) const { + return *s_shapeStore.insert(shape).first; + } diff --git a/GeoModelCore/GeoModelFuncSnippets/src/GeoShapeUtils.cxx b/GeoModelCore/GeoModelFuncSnippets/src/GeoShapeUtils.cxx index 4ba5bffcb0eb43375ab05daebe600bdfa756beec..10ba0d3b2850e844df40222965b1789e4d141e10 100644 --- a/GeoModelCore/GeoModelFuncSnippets/src/GeoShapeUtils.cxx +++ b/GeoModelCore/GeoModelFuncSnippets/src/GeoShapeUtils.cxx @@ -3,6 +3,7 @@ */ #include "GeoModelFuncSnippets/GeoShapeUtils.h" #include "GeoModelFuncSnippets/TransformToStringConverter.h" +#include "GeoModelFuncSnippets/throwExcept.h" /// Boolean volume shapes #include "GeoModelKernel/GeoShapeUnion.h" @@ -19,6 +20,7 @@ #include "GeoModelKernel/GeoCons.h" #include "GeoModelKernel/GeoPara.h" #include "GeoModelKernel/GeoTorus.h" +#include "GeoModelKernel/GeoSimplePolygonBrep.h" #include "GeoModelKernel/Units.h" @@ -139,3 +141,72 @@ std::string printGeoShape(const GeoShape* shape) { } return ostr.str(); } + +std::vector<GeoTrf::Vector3D> getPolyShapeEdges(const GeoShape* shape, + const GeoTrf::Transform3D& refTrf) { + + if (!shape) { + THROW_EXCEPTION("Nullptr was given "); + } + constexpr double boundary = 0.; + std::vector<GeoTrf::Vector3D> edgePoints{}; + std::pair<const GeoShape*, const GeoShape*> ops = getOps(shape); + if (shape->typeID() == GeoShapeUnion::getClassTypeID()){ + edgePoints = getPolyShapeEdges(ops.first, refTrf); + std::vector<GeoTrf::Vector3D> edgePoints2{getPolyShapeEdges(ops.second, refTrf)}; + edgePoints.insert(edgePoints.end(), + std::make_move_iterator(edgePoints2.begin()), + std::make_move_iterator(edgePoints2.end())); + } else if (shape->typeID() == GeoShapeSubtraction::getClassTypeID()) { + return getPolyShapeEdges(ops.first, refTrf); + } else if (shape->typeID() == GeoBox::getClassTypeID()) { + edgePoints.reserve(6); + const GeoBox* box = static_cast<const GeoBox*>(shape); + for (double sX :{-1., 1.}) { + for (double sY :{-1., 1.}) { + for (double sZ: {-1., 1.}) { + edgePoints.emplace_back(refTrf * GeoTrf::Vector3D{sX* (box->getXHalfLength() - boundary), + sY* (box->getYHalfLength() - boundary), + sZ* (box->getZHalfLength() - boundary)}); + } + } + } + } else if (shape->typeID() == GeoShapeShift::getClassTypeID()) { + GeoIntrusivePtr<const GeoShape> shift = compressShift(shape); + const GeoShapeShift* shiftPtr = static_cast<const GeoShapeShift*>(shift.get()); + std::vector<GeoTrf::Vector3D> shiftedEdges = getPolyShapeEdges(ops.first, shiftPtr->getX()); + std::transform(shiftedEdges.begin(), shiftedEdges.end(), std::back_inserter(edgePoints), + [&refTrf](const GeoTrf::Vector3D& shift){ + return refTrf * shift; + }); + } else if (shape->typeID() == GeoTrd::getClassTypeID()) { + const GeoTrd* trd = static_cast<const GeoTrd*>(shape); + edgePoints.reserve(6); + for (double sZ : {-1., 1.}){ + double dX = (sZ < 0 ? trd->getXHalfLength1() : trd->getXHalfLength2()) - boundary; + double dY = (sZ < 0 ? trd->getYHalfLength1() : trd->getYHalfLength2()) - boundary; + for (double sX: {-1., 1.}) { + for (double sY: {-1., 1.}) { + edgePoints.emplace_back(refTrf * GeoTrf::Vector3D{sX* dX, sY* dY, + sZ* (trd->getZHalfLength()- boundary)}); + + } + } + + } + } else if (shape->typeID() == GeoSimplePolygonBrep::getClassTypeID()) { + const GeoSimplePolygonBrep* brep = static_cast<const GeoSimplePolygonBrep*>(shape); + edgePoints.reserve(2* brep->getNVertices()); + for (double sZ: {-1., 1.}) { + for (unsigned int vtx = 0 ; vtx < brep->getNVertices(); ++vtx){ + edgePoints.emplace_back(brep->getXVertex(vtx), + brep->getYVertex(vtx), + sZ * brep->getDZ()); + + } + } + } else { + THROW_EXCEPTION("The shape "<<shape->type()<<" is not supported. Please add it to the list"); + } + return edgePoints; +} diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Element2GeoItem.h b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Element2GeoItem.h index 8b084f856e70a5e6a18725086119bb832c4eacce..86cd6ed8f5b0f42491dcc9baa647bce67d275bee 100644 --- a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Element2GeoItem.h +++ b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Element2GeoItem.h @@ -11,6 +11,10 @@ #define GEO_MODEL_XML_ELEMENT2GEO_ITEM_H #include <xercesc/util/XercesDefs.hpp> +#include "GeoModelFuncSnippets/GeoDeDuplicator.h" +#include "GeoModelKernel/RCBase.h" +#include "GeoModelKernel/GeoIntrusivePtr.h" + #include <map> #include <string> @@ -23,14 +27,15 @@ XERCES_CPP_NAMESPACE_END class ProcessorRegistry; namespace HepTool {class Evaluator;} -class Element2GeoItem { +class Element2GeoItem: public GeoDeDuplicator { public: - Element2GeoItem(); - virtual ~Element2GeoItem(); + Element2GeoItem() = default; + virtual ~Element2GeoItem() = default;; RCBase * process(const xercesc::DOMElement *element, GmxUtil &gmxUtil); virtual RCBase * make(const xercesc::DOMElement *element, GmxUtil &gmxUtil) const; protected: - std::map<std::string, RCBase *> m_map; + using EntryMap = std::map<std::string, GeoIntrusivePtr<RCBase>>; + EntryMap m_map{}; }; #endif // ELEMENT2GEO_ITEM_H diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/ElementProcessor.h b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/ElementProcessor.h index 08c92612ac39c52b926a019c51782981d34e7bb1..5b3a71c7e55ec8e5c6ce59f968abf6a3b59b04cf 100644 --- a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/ElementProcessor.h +++ b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/ElementProcessor.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ // @@ -12,13 +12,13 @@ #include <xercesc/util/XercesDefs.hpp> #include "GeoModelXml/GeoNodeList.h" - +#include "GeoModelFuncSnippets/GeoDeDuplicator.h" XERCES_CPP_NAMESPACE_BEGIN class DOMElement; XERCES_CPP_NAMESPACE_END class GmxUtil; -class ElementProcessor { +class ElementProcessor: public GeoDeDuplicator { public: ElementProcessor(); diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Gmx2Geo.h b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Gmx2Geo.h index 30a90db1f26d11f978886729a864272addea3097..9ad3f0f38f7e140fe7fdaae51e0b6b9cd4a13bed 100644 --- a/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Gmx2Geo.h +++ b/GeoModelTools/GeoModelXML/GeoModelXml/GeoModelXml/Gmx2Geo.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ #ifndef GEO_MODEL_XML_GMX2GEO_H @@ -54,15 +54,15 @@ XERCES_CPP_NAMESPACE_END class IEvaluator; -#define processorList std::map<std::string,ElementProcessor*> +using processorList = std::map<std::string,ElementProcessor*>; class Gmx2Geo { public: Gmx2Geo(const std::string& gmxFile, GeoVPhysVol *addHere, GmxInterface &gmxInterface, unsigned int flags = 0, bool useMatManager = 0, std::string levelMapName = "", const processorList& procs=processorList()); private: // Disallow copying - Gmx2Geo(const Gmx2Geo &right); - Gmx2Geo & operator=(const Gmx2Geo &right); + Gmx2Geo(const Gmx2Geo &right) = delete; + Gmx2Geo & operator=(const Gmx2Geo &right) = delete; int doDefines(xercesc::DOMDocument *doc, GeoModelTools::IEvaluator &eval); int doPositionIndex(xercesc::DOMDocument *doc, GmxUtil &gmxUtil, std::string levelMapName = ""); diff --git a/GeoModelTools/GeoModelXML/GeoModelXml/src/Element2GeoItem.cxx b/GeoModelTools/GeoModelXML/GeoModelXml/src/Element2GeoItem.cxx index 7ed20e61ba28671b49f3964bc3ad98d568003378..d37668328a51cd26c9fcb40f390b451d3e5d08df 100644 --- a/GeoModelTools/GeoModelXML/GeoModelXml/src/Element2GeoItem.cxx +++ b/GeoModelTools/GeoModelXML/GeoModelXml/src/Element2GeoItem.cxx @@ -12,13 +12,11 @@ #include "GeoModelXml/GmxUtil.h" #include "GeoModelKernel/RCBase.h" +#include "GeoModelFuncSnippets/throwExcept.h" using namespace std; using namespace xercesc; -Element2GeoItem::Element2GeoItem() {} - -Element2GeoItem::~Element2GeoItem() {} RCBase * Element2GeoItem::process(const xercesc::DOMElement *element, GmxUtil &gmxUtil) { @@ -30,12 +28,11 @@ RCBase * Element2GeoItem::process(const xercesc::DOMElement *element, GmxUtil &g XMLString::release(&name2release); XMLString::release(&name_tmp); - RCBase *item; - map<string, RCBase *>::iterator entry; - if (name == "") { // Unnamed item; cannot store in the map; make a new one + RCBase *item{nullptr}; + EntryMap::iterator entry; + if (name.empty()) { // Unnamed item; cannot store in the map; make a new one item = make(element, gmxUtil); - } - else if ((entry = m_map.find(name)) == m_map.end()) { // Not in; make a new one + } else if ((entry = m_map.find(name)) == m_map.end()) { // Not in; make a new one item = make(element, gmxUtil); m_map[name] = item; // And put it in the map } @@ -48,8 +45,7 @@ RCBase * Element2GeoItem::process(const xercesc::DOMElement *element, GmxUtil &g RCBase * Element2GeoItem::make(const xercesc::DOMElement *element, GmxUtil & /* gmxUtil */) const { char *name2release = XMLString::transcode(element->getNodeName()); - msglog << MSG::FATAL << "Oh oh: called base class make() method of Element2GeoType object; tag " << name2release << endmsg; + std::string nodeName{name2release}; XMLString::release(&name2release); - - std::abort(); + THROW_EXCEPTION("Oh oh: called base class make() method of Element2GeoType object; tag " << nodeName); }