diff --git a/DDCore/CMakeLists.txt b/DDCore/CMakeLists.txt index 4078194af5f33be7f230de5afc97b16e5ee2be59..5d2f73cf5d38e7c794cbde00b896029ebdb3cbd5 100644 --- a/DDCore/CMakeLists.txt +++ b/DDCore/CMakeLists.txt @@ -89,7 +89,7 @@ endif() dd4hep_add_plugin(DDCorePlugins SOURCES src/plugins/*.cpp USES DDCore) # This plugins depends on the ROOT GDML readers. Hence, extra library -IF(TARGET ROOT::Gdml) +IF(TARGET ROOT::Gdml2) dd4hep_print("|++> Found Root::GDML: Creating DDGDMLPlugins") dd4hep_add_plugin(DDGDMLPlugins SOURCES src/gdml/*.cpp diff --git a/DDCore/include/DD4hep/DetElement.h b/DDCore/include/DD4hep/DetElement.h index 2ec476bb210941ecd505a9b5181007ea62647612..909d1ad4d268a7545043b8c4d94d3a0484f26e1d 100644 --- a/DDCore/include/DD4hep/DetElement.h +++ b/DDCore/include/DD4hep/DetElement.h @@ -166,7 +166,11 @@ namespace dd4hep { * The access to conditions is exposed via the DetConditions interface. * See dd4hep/DetConditions.h for further details. * - alignment information. - * . + * + * Reflection Note: + * - Reflecting a detector element is NOT the same as "clone". + * The placed volumes of the reflected detector element and the + * corresponding volumes/shapes have left-handed coordinates! * * \author M.Frank * \version 1.0 @@ -323,6 +327,12 @@ namespace dd4hep { /// Clone (Deep copy) the DetElement structure with a new name and new identifier DetElement clone(const std::string& new_name, int new_id) const; + /// Reflect (Deep copy) the DetElement structure with a new name + std::pair<DetElement,Volume> reflect(const std::string& new_name) const; + + /// Reflect (Deep copy) the DetElement structure with a new name and new identifier + std::pair<DetElement,Volume> reflect(const std::string& new_name, int new_id) const; + /// Add an extension object to the detector element void* addExtension(ExtensionEntry* entry) const; diff --git a/DDCore/include/DD4hep/Volumes.h b/DDCore/include/DD4hep/Volumes.h index d8f2db09222f653abb350e6553dcd51d5db91ead..d227be84b786568140e2d160ccda072c5886326a 100644 --- a/DDCore/include/DD4hep/Volumes.h +++ b/DDCore/include/DD4hep/Volumes.h @@ -20,28 +20,15 @@ // C/C++ include files #include <map> +#include <memory> // ROOT include file (includes TGeoVolume + TGeoShape) #include "TGeoNode.h" #include "TGeoPatternFinder.h" -#if ROOT_VERSION_CODE > ROOT_VERSION(5,34,9) // Recent ROOT versions #include "TGeoExtension.h" -#else -// Older ROOT version -#define DD4HEP_EMULATE_TGEOEXTENSIONS -class TGeoExtension : public TObject { -public: - virtual ~TGeoExtension() {} - /// TGeoExtension overload: Method called whenever requiring a pointer to the extension - virtual TGeoExtension *Grab() = 0; - /// TGeoExtension overload: Method called always when the pointer to the extension is not needed anymore - virtual void Release() const = 0; -}; -#endif - /// Namespace for the AIDA detector description toolkit namespace dd4hep { @@ -78,14 +65,13 @@ namespace dd4hep { class VolIDs: public std::vector<VolID> { public: typedef std::vector<VolID> Base; - /// Default constructor - VolIDs() = default; - /// Copy constructor - VolIDs(const VolIDs& c) = default; - /// Destructor - ~VolIDs() {} - /// Assignment operator - VolIDs& operator=(const VolIDs& c) = default; + using Base::Base; + /// Copy operator + VolIDs(const VolIDs& copy) = default; + /// Move assignment + VolIDs& operator=(VolIDs&& copy) = default; + /// Assignment operator + VolIDs& operator=(const VolIDs& c) = default; /// Find entry std::vector<VolID>::const_iterator find(const std::string& name) const; /// Insert new entry @@ -117,7 +103,7 @@ namespace dd4hep { PlacedVolumeExtension(const PlacedVolumeExtension& c); /// Default destructor virtual ~PlacedVolumeExtension(); - /// No move assignment + /// Move assignment PlacedVolumeExtension& operator=(PlacedVolumeExtension&& copy) { magic = std::move(copy.magic); volIDs = std::move(copy.volIDs); @@ -235,6 +221,8 @@ namespace dd4hep { VisAttr vis; /// Reference to the sensitive detector Handle<NamedObject> sens_det; + /// Reference to the reflected volume (or to the original volume for reflections) + Handle<TGeoVolume> reflected; /// Default destructor virtual ~VolumeExtension(); @@ -243,11 +231,11 @@ namespace dd4hep { /// No move VolumeExtension(VolumeExtension&& copy) = delete; /// No copy - VolumeExtension(const VolumeExtension& copy) = delete; + VolumeExtension(const VolumeExtension& copy) = default; /// No move assignment VolumeExtension& operator=(VolumeExtension&& copy) = delete; /// No copy assignment - VolumeExtension& operator=(const VolumeExtension& copy) = delete; + VolumeExtension& operator=(const VolumeExtension& copy) = default; /// Copy the object void copy(const VolumeExtension& c) { magic = c.magic; @@ -295,7 +283,8 @@ namespace dd4hep { enum { VETO_SIMU = 1, VETO_RECO = 2, - VETO_DISPLAY = 3 + VETO_DISPLAY = 3, + REFLECTED = 10 }; public: /// Default constructor @@ -328,6 +317,9 @@ namespace dd4hep { /// Check if placement is properly instrumented Object* data() const; + /// Create a reflected volume. The reflected volume has left-handed coordinates + Volume reflect() const; + /// If we import volumes from external sources, we have to attach the extensions to the tree Volume& import(); @@ -335,27 +327,27 @@ namespace dd4hep { Volume divide(const std::string& divname, int iaxis, int ndiv, double start, double step, int numed = 0, const char* option = ""); /** Daughter placements with auto-generated copy number for the daughter volume */ /// Place daughter volume. The position and rotation are the identity - PlacedVolume placeVolume(const Volume& vol) const; + PlacedVolume placeVolume(const Volume& volume) const; /// Place daughter volume according to a generic Transform3D PlacedVolume placeVolume(const Volume& volume, const Transform3D& tr) const; /// Place un-rotated daughter volume at the given position. - PlacedVolume placeVolume(const Volume& vol, const Position& pos) const; + PlacedVolume placeVolume(const Volume& volume, const Position& pos) const; /// Place rotated daughter volume. The position is automatically the identity position - PlacedVolume placeVolume(const Volume& vol, const RotationZYX& rot) const; + PlacedVolume placeVolume(const Volume& volume, const RotationZYX& rot) const; /// Place rotated daughter volume. The position is automatically the identity position - PlacedVolume placeVolume(const Volume& vol, const Rotation3D& rot) const; + PlacedVolume placeVolume(const Volume& volume, const Rotation3D& rot) const; /** Daughter placements with user supplied copy number for the daughter volume */ /// Place daughter volume. The position and rotation are the identity - PlacedVolume placeVolume(const Volume& vol, int copy_no) const; + PlacedVolume placeVolume(const Volume& volume, int copy_no) const; /// Place daughter volume according to a generic Transform3D PlacedVolume placeVolume(const Volume& volume, int copy_no, const Transform3D& tr) const; /// Place un-rotated daughter volume at the given position. - PlacedVolume placeVolume(const Volume& vol, int copy_no, const Position& pos) const; + PlacedVolume placeVolume(const Volume& volume, int copy_no, const Position& pos) const; /// Place rotated daughter volume. The position is automatically the identity position - PlacedVolume placeVolume(const Volume& vol, int copy_no, const RotationZYX& rot) const; + PlacedVolume placeVolume(const Volume& volume, int copy_no, const RotationZYX& rot) const; /// Place rotated daughter volume. The position is automatically the identity position - PlacedVolume placeVolume(const Volume& vol, int copy_no, const Rotation3D& rot) const; + PlacedVolume placeVolume(const Volume& volume, int copy_no, const Rotation3D& rot) const; /// Parametrized volume implementation /** Embedding parametrized daughter placements in a mother volume * @param start start transormation for the first placement @@ -390,6 +382,9 @@ namespace dd4hep { void setFlagBit(unsigned int bit); /// Test the user flag bit bool testFlagBit(unsigned int bit) const; + + /// Test if this volume was reflected + bool isReflected() const; /// Set the volume's option value void setOption(const std::string& opt) const; diff --git a/DDCore/include/DD4hep/detail/DetectorInterna.h b/DDCore/include/DD4hep/detail/DetectorInterna.h index 8cdf5509f8bb3f4349ae08006dcea7841a1b4cd5..c383fe225658db292619eda788d49096c7c21b05 100644 --- a/DDCore/include/DD4hep/detail/DetectorInterna.h +++ b/DDCore/include/DD4hep/detail/DetectorInterna.h @@ -178,6 +178,8 @@ namespace dd4hep { void update(unsigned int tags, void* param); /// Revalidate the caches void revalidate(); + /// Reflect all volumes in a DetElement sub-tree and re-attach the placements + std::pair<DetElement,Volume> reflect(const std::string& new_name, int new_id); }; /// Data class with properties of a detector element diff --git a/DDCore/include/Parsers/Primitives.h b/DDCore/include/Parsers/Primitives.h index 2cf0744ad85b61cb9032d4c33089146aff0267ec..7251a07c142ce8d6d89df5c6e6ea3fb919e317c5 100644 --- a/DDCore/include/Parsers/Primitives.h +++ b/DDCore/include/Parsers/Primitives.h @@ -21,6 +21,9 @@ #include <list> #include <vector> #include <string> +#if __cplusplus >= 201703 || (__clang__ && __APPLE__) +#include <string_view> +#endif #include <limits> #include <typeinfo> diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h index dc35eaa2b18a75e73973ec59f4883b643a532855..a09cb70cdd03a3895dd85867e0acfbe49b0bcf05 100644 --- a/DDCore/include/XML/UnicodeValues.h +++ b/DDCore/include/XML/UnicodeValues.h @@ -430,6 +430,7 @@ UNICODE (shapes); UNICODE (shield); UNICODE (show_daughters); UNICODE (showDaughters); +UNICODE (side); UNICODE (size); UNICODE (signed); UNICODE (skew); diff --git a/DDCore/src/DetElement.cpp b/DDCore/src/DetElement.cpp index d42e136f5de010ddf217413927505a8284dbbcd3..89b41922c39c582ee5f8b407a4cbad0dd2f00da7 100644 --- a/DDCore/src/DetElement.cpp +++ b/DDCore/src/DetElement.cpp @@ -258,15 +258,11 @@ DetElement DetElement::clone(int flg) const { Object* n = o->clone(o->id, flg); n->SetName(o->GetName()); n->SetTitle(o->GetTitle()); - return DetElement(n); + return n; } DetElement DetElement::clone(const string& new_name) const { - Object* o = access(); - Object* n = o->clone(o->id, COPY_NONE); - n->SetName(new_name.c_str()); - n->SetTitle(o->GetTitle()); - return DetElement(n); + return clone(new_name, access()->id); } DetElement DetElement::clone(const string& new_name, int new_id) const { @@ -274,7 +270,20 @@ DetElement DetElement::clone(const string& new_name, int new_id) const { Object* n = o->clone(new_id, COPY_NONE); n->SetName(new_name.c_str()); n->SetTitle(o->GetTitle()); - return DetElement(n); + return n; +} + +pair<DetElement,Volume> DetElement::reflect(const string& new_name) const { + return reflect(new_name, access()->id); +} + +pair<DetElement,Volume> DetElement::reflect(const string& new_name, int new_id) const { + if ( placement().isValid() ) { + return m_element->reflect(new_name, new_id); + } + except("DetElement","reflect: Only placed DetElement objects can be reflected: %s", + path().c_str()); + return make_pair(DetElement(),Volume()); } /// Access to the ideal physical volume of this detector element diff --git a/DDCore/src/DetectorImp.cpp b/DDCore/src/DetectorImp.cpp index ccb1a5ac59a4dd0af1b8028cccf85bce2e9eee36..ece2ef65d4e3c3e4d34e76dc2f5067a171ad39a0 100644 --- a/DDCore/src/DetectorImp.cpp +++ b/DDCore/src/DetectorImp.cpp @@ -162,7 +162,7 @@ DetectorImp::DetectorImp(const string& name) : TNamed(), DetectorData(), DetectorLoad(this), m_buildType(BUILD_NONE) { #if ROOT_VERSION_CODE >= ROOT_VERSION(6,20,0) - TGeoUnit::setUnitType(TGeoUnit::kTGeant4Units); + //TGeoUnit::setUnitType(TGeoUnit::kTGeant4Units); #endif SetTitle("DD4hep detector description object"); set_terminate( description_unexpected ); diff --git a/DDCore/src/DetectorInterna.cpp b/DDCore/src/DetectorInterna.cpp index e7f89d39e133ed41c92fc34b78f00aa8158ee1c0..8b1fdc36cbbf23bc251f6364e0092e92b44917aa 100644 --- a/DDCore/src/DetectorInterna.cpp +++ b/DDCore/src/DetectorInterna.cpp @@ -133,6 +133,44 @@ DetElementObject* DetElementObject::clone(int new_id, int flg) const { return obj; } +/// Reflect all volumes in a DetElement sub-tree and re-attach the placements +pair<DetElement,Volume> DetElementObject::reflect(const std::string& new_name, int new_id) { + struct ChildMapper { + std::map<TGeoNode*,TGeoNode*> nodes; + void match(DetElement de) { + auto i = nodes.find(de.placement().ptr()); + if ( i == nodes.end() ) { + except("DetElement","reflect: Something went wrong when reflecting the source volume!"); + } + de.setPlacement((*i).second); + const auto& children = de.children(); + for(const auto& c : children) + match(c.second); + } + void map(TGeoNode* n1, TGeoNode* n2) { + if ( nodes.find(n1) != nodes.end() ) { + TGeoVolume* v1 = n1->GetVolume(); + TGeoVolume* v2 = n2->GetVolume(); + nodes.insert(make_pair(n1,n2)); + for(Int_t i=0; i<v1->GetNdaughters(); ++i) + map(v1->GetNode(i), v2->GetNode(i)); + } + } + } mapper; + DetElement det(this); + DetElement det_ref = det.clone(new_name, new_id); + Volume vol = det.volume(); + TGeoVolume* vol_det = vol.ptr(); + TGeoVolume* vol_ref = vol.reflect(); + const auto& childrens = det.children(); + + for(Int_t i=0; i<vol_det->GetNdaughters(); ++i) + mapper.map(vol_det->GetNode(i), vol_ref->GetNode(i)); + for(const auto& c : childrens) + mapper.match(c.second); + return make_pair(det_ref,vol_ref); +} + /// Access to the world object. Only possible once the geometry is closed. World DetElementObject::i_access_world() { if ( !privateWorld.isValid() ) { diff --git a/DDCore/src/Shapes.cpp b/DDCore/src/Shapes.cpp index 455c7587dc19dcba9f857cfade8fa9b529e83bfe..c3ba87418abdf7dcb59c37906acf07ab1b803d2e 100644 --- a/DDCore/src/Shapes.cpp +++ b/DDCore/src/Shapes.cpp @@ -28,6 +28,7 @@ #include "TClass.h" #include "TGeoMatrix.h" #include "TGeoBoolNode.h" +#include "TGeoScaledShape.h" #include "TGeoCompositeShape.h" using namespace std; @@ -250,6 +251,15 @@ namespace dd4hep { } return pars; } + else if (cl == TGeoScaledShape::Class()) { + TGeoScaledShape* sh = (TGeoScaledShape*) shape; + TGeoShape* s_sh = sh->GetShape(); + const Double_t* scale = sh->GetScale()->GetScale(); + vector<double> pars {scale[0],scale[1],scale[2]}; + vector<double> s_pars = get_shape_dimensions(s_sh); + for(auto p : s_pars) pars.push_back(p); + return pars; + } else if (cl == TGeoCompositeShape::Class()) { Solid solid(shape); const TGeoCompositeShape* sh = (const TGeoCompositeShape*) shape; @@ -584,6 +594,13 @@ namespace dd4hep { auto pars = params; solid._setDimensions(&pars[0]); } + else if (cl == TGeoScaledShape::Class()) { + TGeoScaledShape* sh = (TGeoScaledShape*) shape; + Solid s_sh(sh->GetShape()); + sh->GetScale()->SetScale(params[0], params[1], params[2]); + auto pars = params; + s_sh._setDimensions(&pars[3]); + } else if (cl == TGeoCompositeShape::Class()) { TGeoCompositeShape* sh = (TGeoCompositeShape*) shape; TGeoBoolNode* boolean = sh->GetBoolNode(); @@ -736,7 +753,7 @@ namespace dd4hep { #endif } else { - printout(ERROR,"Solid","Failed to access dimensions for shape of type:%s.", + printout(ERROR,"Solid","Failed to set dimensions for shape of type:%s.", cl->GetName()); } return; diff --git a/DDCore/src/VolumeManager.cpp b/DDCore/src/VolumeManager.cpp index 4a7d7ee6440224a5e6966d8fbeabbbe57cfd10dd..c30cc39277806b6ad1597a7eb382ae312c93ca4c 100644 --- a/DDCore/src/VolumeManager.cpp +++ b/DDCore/src/VolumeManager.cpp @@ -132,7 +132,7 @@ namespace dd4hep { parent.name(), pv.volume().name(), sd.ptr()); } } - for (Int_t idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) { + for (int idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) { TGeoNode* daughter = node->GetDaughter(idau); PlacedVolume placement(daughter); if ( placement.data() ) { diff --git a/DDCore/src/Volumes.cpp b/DDCore/src/Volumes.cpp index 492bb47dc9ed0b293e3b2403c30d0bfda2ced186..61afc533f6cb4286fdbd766c61b42d4951e59353 100644 --- a/DDCore/src/Volumes.cpp +++ b/DDCore/src/Volumes.cpp @@ -29,6 +29,11 @@ #include "TGeoVoxelFinder.h" #include "TGeoShapeAssembly.h" +#if ROOT_VERSION_CODE >= ROOT_VERSION(6,20,0) +#include "TGeoReflectionFactory.h" +#endif +#include "TGeoScaledShape.h" +#include "TMap.h" // C/C++ include files #include <climits> @@ -41,241 +46,6 @@ using namespace std; using namespace dd4hep; using namespace dd4hep::detail; -#ifdef DD4HEP_EMULATE_TGEOEXTENSIONS -namespace dd4hep { - namespace detail { - - struct DDExtension { - TGeoExtension* m_extension; - DDExtension() : m_extension(0) {} - DDExtension(const DDExtension& c) : m_extension(0) { - if ( c.m_extension ) m_extension = c.m_extension->Grab(); - } - virtual ~DDExtension() { - if ( m_extension ) m_extension->Release(); - } - DDExtension& operator=(const DDExtension& c) { - if ( this != &c ) SetUserExtension(c.GetUserExtension()); - return *this; - } - void SetUserExtension(TGeoExtension *ext) { - if (m_extension) m_extension->Release(); - m_extension = 0; - if (ext) m_extension = ext->Grab(); - } - TGeoExtension* GetUserExtension() const { - return m_extension; - } - }; - struct DD_TGeoNodeMatrix : public TGeoNodeMatrix, public DDExtension { - private: - DD_TGeoNodeMatrix& operator=(const DD_TGeoNodeMatrix&) { return *this; } - public: - DD_TGeoNodeMatrix(const TGeoVolume* v, const TGeoMatrix* m) - : TGeoNodeMatrix(v, m), DDExtension() { - INCREMENT_COUNTER; - } - DD_TGeoNodeMatrix(const DD_TGeoNodeMatrix& c) - : TGeoNodeMatrix(c.GetVolume(), c.GetMatrix()), DDExtension(c) { - INCREMENT_COUNTER; - } - virtual ~DD_TGeoNodeMatrix() { - DECREMENT_COUNTER; - } - virtual TGeoNode *MakeCopyNode() const { - TGeoNodeMatrix *node = new DD_TGeoNodeMatrix(*this); - node->SetName(this->TGeoNodeMatrix::GetName()); - // set the mother - node->SetMotherVolume(fMother); - // set the copy number - node->SetNumber(fNumber); - // copy overlaps - if (fNovlp > 0) { - if (fOverlaps) { - Int_t *ovlps = new Int_t[fNovlp]; - memcpy(ovlps, fOverlaps, fNovlp * sizeof(Int_t)); - node->SetOverlaps(ovlps, fNovlp); - } - else { - node->SetOverlaps(fOverlaps, fNovlp); - } - } - // copy VC - if (IsVirtual()) - node->SetVirtual(); - return node; - } - }; - - template <class T> struct _VolWrap: public T, public DDExtension { - public: - _VolWrap(const char* name) : T(name), DDExtension() { - INCREMENT_COUNTER; - } - virtual ~_VolWrap() { - DECREMENT_COUNTER; - } - virtual void AddNode(const TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat, Option_t* = "") { - TGeoMatrix *matrix = mat; - if (matrix == 0) - matrix = gGeoIdentity; - else - matrix->RegisterYourself(); - if (!vol) { - this->T::Error("AddNode", "Volume is NULL"); - return; - } - if (!vol->IsValid()) { - this->T::Error("AddNode", "Won't add node with invalid shape"); - printf("### invalid volume was : %s\n", vol->GetName()); - return; - } - if (!this->T::fNodes) - this->T::fNodes = new TObjArray(); - - if (this->T::fFinder) { - // volume already divided. - this->T::Error("AddNode", "Cannot add node %s_%i into divided volume %s", vol->GetName(), copy_no, - this->T::GetName()); - return; - } - - TGeoNodeMatrix *node = new DD_TGeoNodeMatrix(vol, matrix); - //node = new TGeoNodeMatrix(vol, matrix); - node->SetMotherVolume(this); - this->T::fNodes->Add(node); - TString name = TString::Format("%s_%d", vol->GetName(), copy_no); - if (this->T::fNodes->FindObject(name)) - this->T::Warning("AddNode", "Volume %s : added node %s with same name", this->T::GetName(), name.Data()); - node->SetName(name); - node->SetNumber(copy_no); - } - }; - - template <> _VolWrap<TGeoVolume>::_VolWrap(const char* name) : TGeoVolume(name,0,0), DDExtension() { - INCREMENT_COUNTER; - } - - struct TGeoVolumeValue : public _VolWrap<TGeoVolume> { - TGeoVolumeValue(const char* name, TGeoShape* s, TGeoMedium* m) : _VolWrap<TGeoVolume>(name) { - SetShape(s); - SetMedium(m); - } - virtual ~TGeoVolumeValue() { } - TGeoVolume *_copyVol(TGeoShape *newshape) const { - TGeoVolumeValue *vol = new TGeoVolumeValue(this->TGeoVolume::GetName(),newshape,fMedium); - if ( m_extension ) vol->m_extension = m_extension->Grab(); - //vol->copy(*this); - return vol; - } - virtual TGeoVolume* MakeCopyVolume(TGeoShape *newshape) { - // make a copy of this volume. build a volume with same name, shape and medium - TGeoVolume *vol = _copyVol(newshape); - vol->SetVisibility(IsVisible()); - vol->SetLineColor(GetLineColor()); - vol->SetLineStyle(GetLineStyle()); - vol->SetLineWidth(GetLineWidth()); - vol->SetFillColor(GetFillColor()); - vol->SetFillStyle(GetFillStyle()); - vol->SetField(fField); - if (fFinder) - vol->SetFinder(fFinder); - CloneNodesAndConnect(vol); - ((TObject*) vol)->SetBit(kVolumeClone); - return vol; - } - virtual TGeoVolume* CloneVolume() const { - TGeoVolume *vol = _copyVol(fShape); - Int_t i; - // copy volume attributes - vol->SetLineColor(GetLineColor()); - vol->SetLineStyle(GetLineStyle()); - vol->SetLineWidth(GetLineWidth()); - vol->SetFillColor(GetFillColor()); - vol->SetFillStyle(GetFillStyle()); - // copy other attributes - Int_t nbits = 8 * sizeof(UInt_t); - for (i = 0; i < nbits; i++) - vol->SetAttBit(1 << i, TGeoAtt::TestAttBit(1 << i)); - for (i = 14; i < 24; i++) - vol->SetBit(1 << i, this->TGeoVolume::TestBit(1 << i)); - - // copy field - vol->SetField(fField); - // Set bits - for (i = 0; i < nbits; i++) - vol->SetBit(1 << i, this->TGeoVolume::TestBit(1 << i)); - vol->SetBit(kVolumeClone); - // copy nodes - // CloneNodesAndConnect(vol); - vol->MakeCopyNodes(this); - // if volume is divided, copy finder - vol->SetFinder(fFinder); - // copy voxels - if (fVoxels) { - TGeoVoxelFinder *voxels = new TGeoVoxelFinder(vol); - vol->SetVoxelFinder(voxels); - } - // copy option, uid - vol->SetOption(fOption); - vol->SetNumber(fNumber); - vol->SetNtotal(fNtotal); - return vol; - } - }; - - struct TGeoVolumeAssemblyValue : public _VolWrap<TGeoVolumeAssembly> { - TGeoVolumeAssemblyValue(const char* name) : _VolWrap<TGeoVolumeAssembly>(name) { - } - virtual ~TGeoVolumeAssemblyValue() { - } - TGeoVolume *CloneVolume() const { - TGeoVolumeAssemblyValue *vol = new TGeoVolumeAssemblyValue(this->TGeoVolume::GetName()); - if ( m_extension ) vol->m_extension = m_extension->Grab(); - Int_t i; - // copy other attributes - Int_t nbits = 8 * sizeof(UInt_t); - for (i = 0; i < nbits; i++) - vol->SetAttBit(1 << i, TGeoAtt::TestAttBit(1 << i)); - for (i = 14; i < 24; i++) - vol->SetBit(1 << i, this->TGeoVolumeAssembly::TestBit(1 << i)); - - // copy field - vol->SetField(fField); - // Set bits - for (i = 0; i < nbits; i++) - vol->SetBit(1 << i, this->TGeoVolumeAssembly::TestBit(1 << i)); - vol->SetBit(kVolumeClone); - // make copy nodes - vol->MakeCopyNodes(this); - ((TGeoShapeAssembly*) vol->GetShape())->NeedsBBoxRecompute(); - // copy voxels - if (fVoxels) { - TGeoVoxelFinder *voxels = new TGeoVoxelFinder(vol); - vol->SetVoxelFinder(voxels); - } - // copy option, uid - vol->SetOption(fOption); - vol->SetNumber(fNumber); - vol->SetNtotal(fNtotal); - return vol; - } - }; - - } -} -typedef DD_TGeoNodeMatrix geo_node_t; -typedef TGeoVolumeValue geo_volume_t; -typedef TGeoVolumeAssemblyValue geo_assembly_t; - -template <typename T> static typename T::Object* _userExtension(const T& v) { - typedef typename T::Object O; - const DDExtension* p = dynamic_cast<const DDExtension*>(v.ptr()); - O* o = (O*)(p ? p->GetUserExtension() : 0); - return o; -} -#else - /* * The section below uses the new ROOT features using user extensions to volumes * and placements. Once this is common, the above mechanism should be thrown away.... @@ -291,7 +61,7 @@ template <typename T> static typename T::Object* _userExtension(const T& v) { O* o = (O*)(v.ptr()->GetUserExtension()); return o; } -#endif + ClassImp(PlacedVolumeExtension) namespace { TGeoVolume* _createTGeoVolume(const string& name, TGeoShape* s, TGeoMedium* m) { @@ -309,8 +79,25 @@ namespace { e->SetUserExtension(new VolumeMulti::Object()); return e; } + PlacedVolume::Object* _data(const PlacedVolume& v) { + PlacedVolume::Object* o = _userExtension(v); + if (o) return o; + throw runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume"); + } + /// Accessor to the data part of the Volume + Volume::Object* _data(const Volume& v, bool throw_exception = true) { + //if ( v.ptr() && v.ptr()->IsA() == TGeoVolume::Class() ) return v.data<Volume::Object>(); + Volume::Object* o = _userExtension(v); + if (o) + return o; + else if (!throw_exception) + return nullptr; + throw runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume"); + } + class VolumeImport { public: + /// Callback for simple imports. Simple add a user extension void operator()(TGeoVolume* v) { TClass* c = v->IsA(); if ( !v->GetUserExtension() ) { @@ -335,7 +122,143 @@ namespace { (*this)(pv->GetVolume()); } } + /// Callback for clone imports, where the user extension should be copied + void operator()(TGeoVolume* new_v, TGeoVolume* old_v, int set_bit) { + if ( !new_v || !old_v ) { + except("dd4hep","VolumeImport: ERROR: The refected volume is INVALID!"); + } + else if ( !old_v->GetUserExtension() ) { + except("dd4hep","VolumeImport: ERROR: Reflection of non-dd4hep volume %s",new_v->IsA()->GetName()); + } + else if ( !new_v->GetUserExtension() ) { + TClass* c = new_v->IsA(); + Volume old_vol(old_v); + Volume new_vol(new_v); + if ( c == geo_volume_t::Class() ) { + Volume::Object *new_e, *old_e = (Volume::Object*)_data(old_vol); + old_e->reflected = new_v; + new_v->SetUserExtension(new_e = new Volume::Object(*old_e)); + new_e->reflected = old_v; + } + else if ( c == geo_assembly_t::Class() ) { + Assembly::Object *new_e, *old_e = (Assembly::Object*)_data(old_vol); + old_e->reflected = new_v; + new_v->SetUserExtension(new_e = new Assembly::Object(*old_e)); + new_e->reflected = old_v; + } + else if ( c == TGeoVolumeMulti::Class() ) { + VolumeMulti::Object *new_e, *old_e = (VolumeMulti::Object*)_data(old_vol); + TGeoVolumeMulti* new_mv = (TGeoVolumeMulti*)new_v; + TGeoVolumeMulti* old_mv = (TGeoVolumeMulti*)old_v; + new_v->SetUserExtension(new_e = new VolumeMulti::Object(*old_e)); + old_e->reflected = new_v; + new_e->reflected = old_v; + for(int i=0, n=new_mv->GetNvolumes(); i<n; ++i) + (*this)(new_mv->GetVolume(i), old_mv->GetVolume(i), set_bit); + } + else + except("dd4hep","VolumeImport: Unknown TGeoVolume sub-class: %s",new_v->IsA()->GetName()); + + new_vol.setSensitiveDetector(old_vol.sensitiveDetector()); + new_vol.setVisAttributes(old_vol.visAttributes()); + new_vol.setLimitSet(old_vol.limitSet()); + new_vol.setRegion(old_vol.region()); + + if ( set_bit >= 0 ) new_vol.setFlagBit(set_bit); + for(Int_t i=0; i<new_v->GetNdaughters(); ++i) { + geo_node_t* pv = new_v->GetNode(i); + geo_node_t* ov = old_v->GetNode(i); + if ( !pv->GetUserExtension() ) { + auto* e = (PlacedVolume::Object*)ov->geo_node_t::GetUserExtension(); + pv->geo_node_t::SetUserExtension(new PlacedVolume::Object(*e)); + } + (*this)(pv->GetVolume(), ov->GetVolume(), set_bit); + } + } + } }; + + TGeoVolume *MakeReflection(TGeoVolume* v, const char *newname=0) { + static TMap map(100); + TGeoVolume *vol = (TGeoVolume*)map.GetValue(v); + if (vol) { + if (newname && newname[0]) vol->SetName(newname); + return vol; + } + vol = v->CloneVolume(); + if (!vol) { + printout(ERROR,"MakeReflection", "Cannot clone volume %s\n", v->GetName()); + return nullptr; + } + map.Add((TObject*)v, vol); + if (newname && newname[0]) vol->SetName(newname); + delete vol->GetNodes(); + vol->SetNodes(NULL); + vol->SetBit(TGeoVolume::kVolumeImportNodes, kFALSE); + v->CloneNodesAndConnect(vol); + // The volume is now properly cloned, but with the same shape. + // Reflect the shape (if any) and connect it. + if (v->GetShape()) { + TGeoScale* scale = new TGeoScale( 1., 1.,-1.); + TGeoShape *reflected_shape = + TGeoScaledShape::MakeScaledShape("", v->GetShape(), scale); + vol->SetShape(reflected_shape); + } + // Reflect the daughters. + Int_t nd = vol->GetNdaughters(); + if (!nd) return vol; + TGeoNodeMatrix *node; + TGeoMatrix *local, *local_cloned; + TGeoVolume *new_vol; + if ( !vol->GetFinder() ) { + for (Int_t i=0; i<nd; i++) { + node = (TGeoNodeMatrix*)vol->GetNode(i); + local = node->GetMatrix(); + // printf("%s before\n", node->GetName()); + // local->Print(); + Bool_t reflected = local->IsReflection(); + local_cloned = new TGeoCombiTrans(*local); + local_cloned->RegisterYourself(); + node->SetMatrix(local_cloned); + if (!reflected) { + // We need to reflect only the translation and propagate to daughters. + // H' = Sz * H * Sz + local_cloned->ReflectZ(kTRUE,kFALSE); + local_cloned->ReflectZ(kFALSE,kFALSE); + // printf("%s after\n", node->GetName()); + // node->GetMatrix()->Print(); + new_vol = MakeReflection(node->GetVolume()); + node->SetVolume(new_vol); + continue; + } + // The next daughter is already reflected, so reflect on Z everything and stop + local_cloned->ReflectZ(kTRUE); // rot + tr + // printf("%s already reflected... After:\n", node->GetName()); + // node->GetMatrix()->Print(); + } + if ( vol->GetVoxels() ) vol->GetVoxels()->Voxelize(); + return vol; + } + // Volume is divided, so we have to reflect the division. + // printf(" ... divided %s\n", fFinder->ClassName()); + TGeoPatternFinder *new_finder = v->GetFinder()->MakeCopy(kTRUE); + if (!new_finder) { + printout(ERROR,"MakeReflection", "Could not copy finder for volume %s", v->GetName()); + return nullptr; + } + new_finder->SetVolume(vol); + vol->SetFinder(new_finder); + TGeoNodeOffset *nodeoff; + new_vol = 0; + for (Int_t i=0; i<nd; i++) { + nodeoff = (TGeoNodeOffset*)vol->GetNode(i); + nodeoff->SetFinder(new_finder); + new_vol = MakeReflection(nodeoff->GetVolume()); + nodeoff->SetVolume(new_vol); + } + return vol; + } + } /// Default constructor @@ -356,14 +279,16 @@ PlacedVolumeExtension::PlacedVolumeExtension() /// Default move PlacedVolumeExtension::PlacedVolumeExtension(PlacedVolumeExtension&& c) - : TGeoExtension(c), magic(move(c.magic)), refCount(0), volIDs(move(c.volIDs)) { + : TGeoExtension(c), magic(move(c.magic)), refCount(0), volIDs() { INCREMENT_COUNTER; + volIDs = move(c.volIDs); } /// Copy constructor PlacedVolumeExtension::PlacedVolumeExtension(const PlacedVolumeExtension& c) - : TGeoExtension(), magic(c.magic), refCount(0), volIDs(c.volIDs) { + : TGeoExtension(), magic(c.magic), refCount(0), volIDs() { INCREMENT_COUNTER; + volIDs = c.volIDs; } /// Default destructor @@ -422,12 +347,6 @@ string PlacedVolumeExtension::VolIDs::str() const { return str.str(); } -static PlacedVolume::Object* _data(const PlacedVolume& v) { - PlacedVolume::Object* o = _userExtension(v); - if (o) return o; - throw runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume"); -} - /// Check if placement is properly instrumented PlacedVolume::Object* PlacedVolume::data() const { PlacedVolume::Object* o = _userExtension(*this); @@ -540,17 +459,6 @@ void VolumeExtension::Release() const { } } -/// Accessor to the data part of the Volume -Volume::Object* _data(const Volume& v, bool throw_exception = true) { - //if ( v.ptr() && v.ptr()->IsA() == TGeoVolume::Class() ) return v.data<Volume::Object>(); - Volume::Object* o = _userExtension(v); - if (o) - return o; - else if (!throw_exception) - return 0; - throw runtime_error("dd4hep: Attempt to access invalid handle of type: PlacedVolume"); -} - /// Constructor to be used when creating a new geometry tree. Volume::Volume(const string& nam) { m_element = _createTGeoVolume(nam,0,0); @@ -579,6 +487,24 @@ Volume::Object* Volume::data() const { return o; } +/// Create a reflected volume. The reflected volume has left-handed coordinates +Volume Volume::reflect() const { + if ( m_element ) { + VolumeImport imp; + string nam = name(); + nam += "_refl"; + Object* o = data(); + if ( !o->reflected.isValid() ) { + TGeoVolume* vol = MakeReflection(m_element, nam.c_str()); + imp(vol, m_element, Volume::REFLECTED); + o->reflected = vol; + } + return o->reflected; + } + except("dd4hep","Volume: Attempt to reflect an invalid Volume handle."); + return *this; +} + /// If we import volumes from external sources, we have to attach the extensions to the tree Volume& Volume::import() { if ( m_element ) { @@ -586,7 +512,7 @@ Volume& Volume::import() { imp(m_element); return *this; } - except("dd4hep","Volume: Attempt to import invalid Volume handle."); + except("dd4hep","Volume: Attempt to import an invalid Volume handle."); return *this; } @@ -608,6 +534,11 @@ bool Volume::testFlagBit(unsigned int bit) const { return false; // Anyhow never called. Only to satisfy the compiler. } +/// Test if this volume was reflected +bool Volume::isReflected() const { + return testFlagBit(REFLECTED); +} + /// Divide volume into subsections (See the ROOT manuloa for details) Volume Volume::divide(const std::string& divname, int iaxis, int ndiv, double start, double step, int numed, const char* option) { @@ -619,7 +550,13 @@ Volume Volume::divide(const std::string& divname, int iaxis, int ndiv, return mvp; } except("dd4hep","Volume: Attempt to divide an invalid logical volume."); - return 0; + return nullptr; +} + +Int_t get_copy_number(TGeoVolume* par) { + TObjArray* a = par ? par->GetNodes() : 0; + Int_t copy_nr = (a ? a->GetEntries() : 0); + return copy_nr; } PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform) { @@ -630,10 +567,18 @@ PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* if ( !daughter ) { except("dd4hep","Volume: Attempt to assign an invalid physical daughter volume."); } - if (transform && transform != detail::matrix::_identity()) { + if ( !transform ) { + except("dd4hep","Volume: Attempt to place volume without placement matrix."); + } + if ( transform != detail::matrix::_identity() ) { string nam = string(daughter->GetName()) + "_placement"; transform->SetName(nam.c_str()); } +#if 0 + if ( transform->IsTranslation() ) { + cout << daughter->GetName() << ": Translation: " << transform->GetTranslation()[2] << endl; + } +#endif TGeoShape* shape = daughter->GetShape(); // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated.... if ( shape->IsA() == TGeoShapeAssembly::Class() ) { @@ -658,40 +603,79 @@ PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* return PlacedVolume(n); } -PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, TGeoMatrix* transform) { - TObjArray* a = par ? par->GetNodes() : 0; - Int_t id = (a ? a->GetEntries() : 0); - return _addNode(par, daughter, id, transform); +PlacedVolume _addNode(TGeoVolume* par, Volume daughter, int copy_nr, const Rotation3D& rot3D) { + Position x,y,z; + Rotation3D rot = rot3D; + rot.GetComponents(x,y,z); + bool left_handed = (x.Cross(y)).Dot(z) < 0; + if ( left_handed ) { + // The reflected volume already scales Z with -1 to be left-handed + // We have to accomplish for and undo this when placing the volume + rot *= Rotation3D(1., 0., 0., 0., 1., 0., 0., 0., -1.); + daughter = daughter.reflect(); + //cout << "REFLECTION: (x.Cross(y)).Dot(z) " << (x.Cross(y)).Dot(z) << endl; + } + double elements[9]; + rot3D.GetComponents(elements); + auto r = new TGeoRotation(); + r->SetMatrix(elements); + auto m = new TGeoCombiTrans(); + m->SetRotation(r); + return _addNode(par, daughter, copy_nr, m); +} + +PlacedVolume _addNode(TGeoVolume* par, Volume daughter, int copy_nr, const Transform3D& tr) { + Position x, y, z, pos3D; + Rotation3D rot3D; + tr.GetRotation(rot3D); + tr.GetTranslation(pos3D); + rot3D.GetComponents(x,y,z); + bool left_handed = (x.Cross(y)).Dot(z) < 0; + if ( left_handed ) { + // The reflected volume already scales Z with -1 to be left-handed + // We have to accomplish for and undo this when placing the volume + rot3D *= Rotation3D(1., 0., 0., 0., 1., 0., 0., 0., -1.); + daughter = daughter.reflect(); + //cout << "REFLECTION: (x.Cross(y)).Dot(z) " << (x.Cross(y)).Dot(z) << endl; + } + double elements[9]; + rot3D.GetComponents(elements); + auto m = new TGeoCombiTrans(); + m->SetTranslation(pos3D.x(), pos3D.y(), pos3D.z()); + auto r = new TGeoRotation(); + r->SetMatrix(elements); + m->SetRotation(r); + return _addNode(par, daughter, copy_nr, m); } /// Place daughter volume according to generic Transform3D PlacedVolume Volume::placeVolume(const Volume& volume, const Transform3D& trans) const { - return _addNode(m_element, volume, detail::matrix::_transform(trans)); + return _addNode(m_element, volume, get_copy_number(m_element), trans); } /// Place daughter volume. The position and rotation are the identity PlacedVolume Volume::placeVolume(const Volume& volume) const { - return _addNode(m_element, volume, detail::matrix::_identity()); + return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_identity()); } /// Place un-rotated daughter volume at the given position. PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos) const { - return _addNode(m_element, volume, detail::matrix::_translation(pos)); + return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_translation(pos)); } /// Place rotated daughter volume. The position is automatically the identity position PlacedVolume Volume::placeVolume(const Volume& volume, const RotationZYX& rot) const { - return _addNode(m_element, volume, detail::matrix::_rotationZYX(rot)); + return _addNode(m_element, volume, get_copy_number(m_element), detail::matrix::_rotationZYX(rot)); } /// Place rotated daughter volume. The position is automatically the identity position PlacedVolume Volume::placeVolume(const Volume& volume, const Rotation3D& rot) const { - return _addNode(m_element, volume, detail::matrix::_rotation3D(rot)); + return _addNode(m_element, volume, get_copy_number(m_element), rot); } /// Place daughter volume according to generic Transform3D PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Transform3D& trans) const { - return _addNode(m_element, volume, copy_no, detail::matrix::_transform(trans)); + return _addNode(m_element, volume, copy_no, trans); } /// Place daughter volume. The position and rotation are the identity @@ -711,7 +695,7 @@ PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Rotati /// Place rotated daughter volume. The position is automatically the identity position PlacedVolume Volume::placeVolume(const Volume& volume, int copy_no, const Rotation3D& rot) const { - return _addNode(m_element, volume, copy_no, detail::matrix::_rotation3D(rot)); + return _addNode(m_element, volume, copy_no, rot); } /// Constructor to be used when creating a new parametrized volume object @@ -737,7 +721,7 @@ void Volume::paramVolume1D(const Transform3D& start, { Transform3D transformation(start); for(size_t i=0; i<count; ++i) { - _addNode(m_element, entity, detail::matrix::_transform(transformation)); + _addNode(m_element, entity, get_copy_number(m_element), detail::matrix::_transform(transformation)); transformation *= trafo; } } @@ -1007,6 +991,14 @@ std::string dd4hep::toStringMesh(PlacedVolume place, int prec) { Solid sol = vol.solid(); stringstream os; + + if ( vol->IsA() == TGeoVolumeAssembly::Class() ) { + for(Int_t i=0; i<vol->GetNdaughters(); ++i) { + os << toStringMesh(vol->GetNode(i), prec) << endl; + } + return os.str(); + } + // Prints shape parameters Int_t nvert = 0, nsegs = 0, npols = 0; sol->GetMeshNumbers(nvert, nsegs, npols); @@ -1048,3 +1040,4 @@ std::string dd4hep::toStringMesh(PlacedVolume place, int prec) { delete [] points; return os.str(); } + diff --git a/DDCore/src/plugins/ShapePlugins.cpp b/DDCore/src/plugins/ShapePlugins.cpp index d464456e36ee655f620b122997256c33cb7ce021..64aedbd0a46c543b619d89c8aade458b323eefeb 100644 --- a/DDCore/src/plugins/ShapePlugins.cpp +++ b/DDCore/src/plugins/ShapePlugins.cpp @@ -487,41 +487,64 @@ static Handle<TObject> create_BooleanMulti(Detector& description, xml_h element) } DECLARE_XML_SHAPE(BooleanShape__shape_constructor,create_BooleanMulti) +#include "DD4hep/MatrixHelpers.h" +#include <TGeoReflectionFactory.h> +TGeoCombiTrans* createPlacement(const Rotation3D& iRot, const Position& iTrans) { + double elements[9]; + iRot.GetComponents(elements); + TGeoRotation r; + r.SetMatrix(elements); + TGeoTranslation t(iTrans.x(), iTrans.y(), iTrans.z()); + return new TGeoCombiTrans(t, r); +} + static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */) { - xml_det_t x_det = e; - string name = x_det.nameStr(); - xml_comp_t x_test = x_det.child(xml_tag_t("test"), false); - DetElement det (name,x_det.id()); - Assembly assembly(name); + xml_det_t x_det = e; + string name = x_det.nameStr(); + xml_dim_t x_reflect = x_det.child(_U(reflect), false); + xml_comp_t x_test = x_det.child(xml_tag_t("test"), false); + DetElement det (name,x_det.id()); + Assembly assembly (name); PlacedVolume pv; int count = 0; for ( xml_coll_t itm(e, _U(check)); itm; ++itm, ++count ) { - xml_dim_t x_check = itm; - xml_comp_t shape (x_check.child(_U(shape))); - xml_dim_t pos (x_check.child(_U(position), false)); - xml_dim_t rot (x_check.child(_U(rotation), false)); - Solid solid (shape.createShape()); - Volume volume (name+_toString(count,"_vol_%d"),solid, description.air()); + xml_dim_t x_check = itm; + xml_comp_t shape (x_check.child(_U(shape))); + xml_dim_t pos (x_check.child(_U(position), false)); + xml_dim_t rot (x_check.child(_U(rotation), false)); + bool reflect = x_check.hasChild(_U(reflect)); + Solid solid (shape.createShape()); + Volume volume (name+_toString(count,"_vol_%d"),solid, description.air()); + + volume.setVisAttributes(description, x_check.visStr()); + solid->SetName(shape.typeStr().c_str()); if ( pos.ptr() && rot.ptr() ) { - Transform3D trafo(Rotation3D(RotationZYX(rot.z(0),rot.y(0),rot.x(0))), - Position(pos.x(0),pos.y(0),pos.z(0))); - pv = assembly.placeVolume(volume,trafo); + Rotation3D rot3D(RotationZYX(rot.z(0),rot.y(0),rot.x(0))); + Position pos3D(pos.x(0),pos.y(0),pos.z(0)); + Rotation3D rrot3D(rot3D); + if ( reflect ) + rrot3D = Rotation3D(1., 0., 0., 0., 1., 0., 0., 0., -1.) * rot3D; + Transform3D tr(rrot3D, pos3D); + pv = assembly.placeVolume(volume,tr); } else if ( pos.ptr() ) { pv = assembly.placeVolume(volume,Position(pos.x(0),pos.y(0),pos.z(0))); } else if ( rot.ptr() ) { - pv = assembly.placeVolume(volume,Rotation3D(RotationZYX(rot.z(0),rot.y(0),rot.x(0)))); + Rotation3D rot3D(RotationZYX(rot.z(0),rot.y(0),rot.x(0))); + if ( reflect ) + rot3D = Rotation3D(1., 0., 0., 0., 1., 0., 0., 0., -1.) * rot3D; + pv = assembly.placeVolume(volume,rot3D); } else { pv = assembly.placeVolume(volume); } - volume.setVisAttributes(description, x_check.visStr()); + if ( x_check.hasAttr(_U(id)) ) { pv.addPhysVolID("check",x_check.id()); } - solid->SetName(shape.typeStr().c_str()); + printout(INFO,"TestShape","Created successfull shape of type: %s", shape.typeStr().c_str()); bool instance_test = false; @@ -584,8 +607,40 @@ static Ref_t create_shape(Detector& description, xml_h e, Ref_t /* sens */) { shape.typeStr().c_str(), solid->GetTitle(), "OK"); } } - pv = description.worldVolume().placeVolume(assembly); - det.setPlacement(pv); + if ( x_reflect ) { + xml_dim_t x_pos(x_reflect.child(_U(position), false)); + xml_dim_t x_rot(x_reflect.child(_U(rotation), false)); + DetElement full_detector(name+"_full",x_det.id()); + Assembly full_assembly(name+"_full"); + RotationZYX refl_rot; + Position refl_pos; + + if ( x_rot ) refl_rot = RotationZYX(x_rot.z(0),x_rot.y(0),x_rot.x(0)); + if ( x_pos ) refl_pos = Position(x_pos.x(0),x_pos.y(0),x_pos.z(0)); + Transform3D refl_trafo(Rotation3D(refl_rot),refl_pos); + + /// Place the regular detector + pv = full_assembly.placeVolume(assembly); + full_detector.add(det); + det.setPlacement(pv); + + /// Place reflected object + auto reflected = det.reflect(name+"_reflected",x_det.id()); + pv = full_assembly.placeVolume(reflected.second, refl_trafo); + full_detector.add(reflected.first); + reflected.first.setPlacement(pv); + + /// Place mother + pv = description.worldVolume().placeVolume(full_assembly); + full_detector.setPlacement(pv); + + det = full_detector; + } + else { + pv = description.worldVolume().placeVolume(assembly); + det.setPlacement(pv); + } + if ( x_test.ptr() ) { string typ = x_test.typeStr(); const void* argv[] = { &e, &pv, 0}; diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp index 460f9c0b3c181128d5d2b51cb6bd067acc40a4c6..19d2628b90fb8eb0cc4bfd1d18fefd4fac575bac 100644 --- a/DDG4/src/Geant4Converter.cpp +++ b/DDG4/src/Geant4Converter.cpp @@ -73,6 +73,7 @@ #include "G4Ellipsoid.hh" #include "G4GenericTrap.hh" #include "G4ExtrudedSolid.hh" +#include "G4ReflectedSolid.hh" #include "G4EllipticalTube.hh" #include "G4SubtractionSolid.hh" #include "G4IntersectionSolid.hh" @@ -698,7 +699,16 @@ void* Geant4Converter::handleSolid(const string& name, const TGeoShape* shape) c vertices.emplace_back(G4TwoVector(vtx_xy[0] * CM_2_MM,vtx_xy[1] * CM_2_MM)); solid = new G4GenericTrap(name, sh->GetDz() * CM_2_MM, vertices); } - else if (shape->IsA() == TGeoCompositeShape::Class()) { + else if (shape->IsA() == TGeoScaledShape::Class()) { + TGeoScaledShape* sh = (TGeoScaledShape*) shape; + const double* vals = sh->GetScale()->GetScale(); + Solid s_sh(sh->GetShape()); + G4VSolid* scaled = (G4VSolid*)handleSolid(s_sh.name(), s_sh.ptr()); + solid = new G4ReflectedSolid(scaled->GetName() + "_refl", + scaled, G4Scale3D(vals[0],vals[1],vals[2])); + printout(INFO,"G4Shapes","Converting scaled shape from reflection: %s",sh->GetName()); + } + else if (shape->IsA() == TGeoCompositeShape::Class()) { const TGeoCompositeShape* sh = (const TGeoCompositeShape*) shape; const TGeoBoolNode* boolean = sh->GetBoolNode(); TGeoBoolNode::EGeoBoolType oper = boolean->GetBooleanOperator(); @@ -851,7 +861,7 @@ void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume info.g4Volumes[v] = vol; printout(lvl, "Geant4Converter", "++ Volume + %s converted: %p ---> G4: %p", n.c_str(), v, vol); } - return 0; + return nullptr; } /// Dump logical volume in GDML format to output stream diff --git a/GaudiPluginService/src/PluginServiceV2.cpp b/GaudiPluginService/src/PluginServiceV2.cpp index 3bad3405316f204613caa8a67e7a2ce409e2128b..f6746d4015c3e86f14a28433147ee4ba6a7f5f11 100644 --- a/GaudiPluginService/src/PluginServiceV2.cpp +++ b/GaudiPluginService/src/PluginServiceV2.cpp @@ -153,16 +153,20 @@ namespace Gaudi { std::regex line_format{"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$"}; std::smatch m; - std::string_view search_path = std::getenv( envVar ); + std::string search_path = std::getenv( envVar ); if ( !search_path.empty() ) { logger().debug( std::string( "searching factories in " ) + envVar ); - std::string_view::size_type start_pos = 0, end_pos = 0; - while ( start_pos != std::string_view::npos ) { + std::string::size_type start_pos = 0, end_pos = 0; + while ( start_pos != std::string::npos ) { // correctly handle begin of string or path separator if ( start_pos ) ++start_pos; end_pos = search_path.find( sep, start_pos ); + if ( end_pos == start_pos ) { + start_pos = std::string::npos; + continue; + } fs::path dirName = #ifdef USE_BOOST_FILESYSTEM std::string{search_path.substr( start_pos, end_pos - start_pos )}; diff --git a/examples/ClientTests/compact/Check_Shape_Eightpoint_Reflect_Volume.xml b/examples/ClientTests/compact/Check_Shape_Eightpoint_Reflect_Volume.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f02ddb5378a7e26af4041a6874b7b196f31fb73 --- /dev/null +++ b/examples/ClientTests/compact/Check_Shape_Eightpoint_Reflect_Volume.xml @@ -0,0 +1,54 @@ +<lccdd> + <includes> + <gdmlFile ref="CheckShape.xml"/> + </includes> + + <detectors> + <detector id="1" name="Shape_Trapezoid" type="DD4hep_TestShape_Creator"> +<a> + <check vis="Shape1_vis"> + <shape type="Trd2" z="30*cm" x1="30*cm" x2="50*cm" y1="15*cm" y2="30*cm"/> + <position x="30" y="30" z="100*cm"/> + <rotation x="0." y="0" z="0"/> + </check> + <check vis="Shape2_vis"> + <shape type="Trd2" z="30*cm" x1="30*cm" x2="50*cm" y1="15*cm" y2="30*cm"/> + <position x="30" y="30" z="-100*cm"/> + <rotation x="0." y="0" z="0"/> + <reflect/> + </check> + <test type="DD4hep_Mesh_Verifier" ref="${DD4hepExamplesINSTALL}/examples/ClientTests/ref/Ref_Trapezoid_Reflect_Volume.txt" create="1"/> +</a> + <check vis="Shape1_vis"> + <shape type="EightPointSolid" dz="30*cm"> + <vertex x="-30*cm" y="-25*cm"/> + <vertex x="-25*cm" y=" 25*cm"/> + <vertex x=" 5*cm" y=" 25*cm"/> + <vertex x=" 25*cm" y="-25*cm"/> + <vertex x="-28*cm" y="-23*cm"/> + <vertex x="-23*cm" y=" 27*cm"/> + <vertex x="-23*cm" y=" 27*cm"/> + <vertex x=" 13*cm" y="-27*cm"/> + </shape> + <position x="0" y="0" z="100"/> + <rotation x="0" y="0" z="0"/> + </check> + <check vis="Shape2_vis"> + <shape type="EightPointSolid" dz="30*cm"> + <vertex x="-30*cm" y="-25*cm"/> + <vertex x="-25*cm" y=" 25*cm"/> + <vertex x=" 5*cm" y=" 25*cm"/> + <vertex x=" 25*cm" y="-25*cm"/> + <vertex x="-28*cm" y="-23*cm"/> + <vertex x="-23*cm" y=" 27*cm"/> + <vertex x="-23*cm" y=" 27*cm"/> + <vertex x=" 13*cm" y="-27*cm"/> + </shape> + <position x="0" y="0" z="-100"/> + <rotation x="0" y="0" z="0"/> + <reflect/> + </check> + + </detector> + </detectors> +</lccdd> diff --git a/examples/ClientTests/compact/Check_Shape_Trapezoid.xml b/examples/ClientTests/compact/Check_Shape_Trapezoid.xml index e1c1595ecd990e3ed9873f75418f46b42c7c117c..c2f6b751ea1b6fd818d9f213123fb88d1fb4f626 100644 --- a/examples/ClientTests/compact/Check_Shape_Trapezoid.xml +++ b/examples/ClientTests/compact/Check_Shape_Trapezoid.xml @@ -7,8 +7,8 @@ <detector id="1" name="Shape_Trapezoid" type="DD4hep_TestShape_Creator"> <check vis="Shape1_vis"> <shape type="Trapezoid" z="30*cm" x1="30*cm" x2="50*cm" y1="15*cm" y2="30*cm"/> - <position x="30" y="30" z="50"/> - <rotation x="0" y="0" z="0"/> + <position x="30*cm" y="30*cm" z="50*cm"/> + <rotation x="0" y="0" z="0"/> </check> <test type="DD4hep_Mesh_Verifier" ref="${DD4hepExamplesINSTALL}/examples/ClientTests/ref/Ref_Trapezoid.txt" create="CheckShape_create"/> </detector> diff --git a/examples/ClientTests/compact/MiniTel.xml b/examples/ClientTests/compact/MiniTel.xml index 8e0b0c1b4074dd1959ce8bca1c6e7f5fa989b1a3..388f1ab9eedf9a685bc9e259a0d2d1dc7db99f8c 100644 --- a/examples/ClientTests/compact/MiniTel.xml +++ b/examples/ClientTests/compact/MiniTel.xml @@ -42,6 +42,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="0*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> <detector name="MyLHCBdetector2" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="2" sensitive="true" readout="MyLHCBdetector2Hits" limits="minitel_limits" region="minitel_region"> @@ -49,6 +50,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="10*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> <detector name="MyLHCBdetector3" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="3" sensitive="true" readout="MyLHCBdetector3Hits" limits="minitel_limits" region="minitel_region"> @@ -56,6 +58,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="20*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="5*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> @@ -64,6 +67,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm"/> <position z="30*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="21*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> @@ -72,6 +76,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm"/> <position z="40*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="10*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> @@ -80,6 +85,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="50*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> @@ -88,6 +94,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="60*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> @@ -96,6 +103,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="70*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> <detector name="MyLHCBdetector9" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="9" sensitive="true" readout="MyLHCBdetector9Hits" limits="minitel_limits" region="minitel_region"> @@ -103,6 +111,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="80*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> <detector name="MyLHCBdetector10" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="10" sensitive="true" readout="MyLHCBdetector10Hits" limits="minitel_limits" region="minitel_region"> @@ -110,6 +119,7 @@ <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="90*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> + <reflect/> </detector> </detectors> @@ -145,43 +155,43 @@ <readouts> <readout name="MyLHCBdetector1Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector2Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector3Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector4Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector5Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector6Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector7Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector8Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector9Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> <readout name="MyLHCBdetector10Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> - <id>system:6,x:12:-6,y:24:-6</id> + <id>system:6,side:1,x:12:-6,y:24:-6</id> </readout> </readouts> diff --git a/examples/ClientTests/ref/Ref_Eightpoint_Reflect_Volume.txt b/examples/ClientTests/ref/Ref_Eightpoint_Reflect_Volume.txt new file mode 100644 index 0000000000000000000000000000000000000000..0df15d900185d3d7f71ee120c502511e177eb9cc --- /dev/null +++ b/examples/ClientTests/ref/Ref_Eightpoint_Reflect_Volume.txt @@ -0,0 +1,22 @@ +ShapeCheck[0] TGeoTrd2 8 Mesh-points: +TGeoTrd2 Trd2 N(mesh)=8 N(vert)=8 N(seg)=12 N(pols)=6 +TGeoTrd2 0 Local ( -30.00, -15.00, -30.00) Global ( 0.00, 15.00, 70.00) +TGeoTrd2 1 Local ( -30.00, 15.00, -30.00) Global ( 0.00, 45.00, 70.00) +TGeoTrd2 2 Local ( 30.00, 15.00, -30.00) Global ( 60.00, 45.00, 70.00) +TGeoTrd2 3 Local ( 30.00, -15.00, -30.00) Global ( 60.00, 15.00, 70.00) +TGeoTrd2 4 Local ( -50.00, -30.00, 30.00) Global ( -20.00, 0.00, 130.00) +TGeoTrd2 5 Local ( -50.00, 30.00, 30.00) Global ( -20.00, 60.00, 130.00) +TGeoTrd2 6 Local ( 50.00, 30.00, 30.00) Global ( 80.00, 60.00, 130.00) +TGeoTrd2 7 Local ( 50.00, -30.00, 30.00) Global ( 80.00, 0.00, 130.00) +TGeoTrd2 Bounding box: dx= 50.00 dy= 30.00 dz= 30.00 Origin: x= 0.00 y= 0.00 z= 0.00 +ShapeCheck[1] TGeoTrd2 8 Mesh-points: +TGeoTrd2 Trd2 N(mesh)=8 N(vert)=8 N(seg)=12 N(pols)=6 +TGeoTrd2 0 Local ( -30.00, -15.00, -30.00) Global ( 0.00, 45.00, -130.00) +TGeoTrd2 1 Local ( -30.00, 15.00, -30.00) Global ( 0.00, 15.00, -130.00) +TGeoTrd2 2 Local ( 30.00, 15.00, -30.00) Global ( 60.00, 15.00, -130.00) +TGeoTrd2 3 Local ( 30.00, -15.00, -30.00) Global ( 60.00, 45.00, -130.00) +TGeoTrd2 4 Local ( -50.00, -30.00, 30.00) Global ( -20.00, 60.00, -70.00) +TGeoTrd2 5 Local ( -50.00, 30.00, 30.00) Global ( -20.00, 0.00, -70.00) +TGeoTrd2 6 Local ( 50.00, 30.00, 30.00) Global ( 80.00, 0.00, -70.00) +TGeoTrd2 7 Local ( 50.00, -30.00, 30.00) Global ( 80.00, 60.00, -70.00) +TGeoTrd2 Bounding box: dx= 50.00 dy= 30.00 dz= 30.00 Origin: x= 0.00 y= 0.00 z= 0.00 diff --git a/examples/ClientTests/src/MiniTel.cpp b/examples/ClientTests/src/MiniTel.cpp index cc317c74f4c88522a638b47f51191b7938366e8a..3d76b40a9a6e01862413a1a5c1f65d5ce826691c 100644 --- a/examples/ClientTests/src/MiniTel.cpp +++ b/examples/ClientTests/src/MiniTel.cpp @@ -79,8 +79,6 @@ static Ref_t create_detector(Detector &description, xml_h e, SensitiveDetector s Volume motherVol = description.pickMotherVolume(sdet); //the mothers volume of our detector - PlacedVolume pv; //struct of Handle giving the volume id(ayto pou 8a kanw volume kai 8a to steilw me setplacement),dld o detector mou - xml_coll_t mi(x_det, _U(module)); xml_comp_t dtc_mod = mi; // considering the module-pixel of the detector double pixelX = dtc_mod.x(); // The x dimension of the module @@ -109,17 +107,29 @@ static Ref_t create_detector(Detector &description, xml_h e, SensitiveDetector s } Volume m_volume(det_name, Box(dim_x, dim_y, dim_z), mat); //as parameters it needs name,solid,material m_volume.setVisAttributes(description.visAttributes(x_det.visStr())); //I DONT MIND ABOUT THIS! - pv = motherVol.placeVolume(m_volume,Transform3D(Position(det_x,det_y,det_z))); //det_x,det_y,det_z are the dimensions of the detector in space - - xml_comp_t dtctr = x_det; + m_volume.setLimitSet(description,x_det.limitsStr()); m_volume.setRegion(description,x_det.regionStr()); + m_volume.setSensitiveDetector(sens); + + PlacedVolume pv1, pv2; + pv1 = assembly.placeVolume(m_volume,Transform3D(Position(det_x,det_y,det_z))); //det_x,det_y,det_z are the dimensions of the detector in space + if ( x_det.hasChild(_U(reflect)) ) { + /// Reflect in XY-plane + pv2 = assembly.placeVolume(m_volume,Transform3D(Rotation3D(1., 0., 0., 0., 1., 0., 0., 0., -1.), + Position(det_x,det_y,-det_z))); + } + xml_comp_t dtctr = x_det; if ( dtctr.isSensitive() ) { - sens.setType("tracker"); - pv.addPhysVolID("system",detectors_id); - m_volume.setSensitiveDetector(sens); // Set volume attributes - m_volume.setLimitSet(description,x_det.limitsStr()); + sens.setType("tracker"); + pv1.addPhysVolID("system",detectors_id); + pv1.addPhysVolID("side",0); + if ( pv2.isValid() ) { + pv2.addPhysVolID("system",detectors_id); + pv2.addPhysVolID("side",1); + } } + auto pv = motherVol.placeVolume(assembly); sdet.setPlacement(pv); // Support additional test if Detector_InhibitConstants is set to TRUE description.constant<double>("world_side");