diff --git a/DDCore/include/DD4hep/Detector.h b/DDCore/include/DD4hep/Detector.h index d6e60d6185bcb14b085ebfcc69fc2b73c88c601b..fc44ab3c65be20329b79eae9aca97d8e86772f4d 100644 --- a/DDCore/include/DD4hep/Detector.h +++ b/DDCore/include/DD4hep/Detector.h @@ -113,13 +113,29 @@ namespace DD4hep { PlacedVolume placement; Placements placements; Parent parent; + Parent reference; Children children; + TGeoMatrix* worldTrafo; + TGeoMatrix* parentTrafo; + TGeoMatrix* referenceTrafo; /// Default constructor Object(); /// Construct new empty object virtual Value<TNamed,Object>* construct(int new_id, int flag) const; /// Deep object copy to replicate DetElement trees e.g. for reflection virtual void deepCopy(const Object& source, int new_id, int flag); + /// Conversion to reference object + operator Ref_t(); + /// Conversion to reference object + Ref_t asRef(); + /// Top detector element + Ref_t top(); + /// Create cached matrix to transform to world coordinates + TGeoMatrix* worldTransformation(); + /// Create cached matrix to transform to parent coordinates + TGeoMatrix* parentTransformation(); + /// Create cached matrix to transform to reference coordinates + TGeoMatrix* referenceTransformation(); }; /// Additional data accessor @@ -180,9 +196,9 @@ namespace DD4hep { DetElement& setPlacement(const PlacedVolume& volume); /// Access the physical volumes of the detector element - Placements placements() const; + //Placements placements() const; /// Set the physical volumes of the detector element - DetElement& addPlacement(const PlacedVolume& volume); + //DetElement& addPlacement(const PlacedVolume& volume); /// Access to the logical volume of the placements (all daughters have the same!) Volume volume() const; @@ -191,6 +207,24 @@ namespace DD4hep { const Children& children() const; /// Access to individual children by name DetElement child(const std::string& name) const; + + /// Set detector element for reference transformations. Will delete existing reference trafo. + DetElement& setReference(DetElement reference); + + /// Transformation from local coordinates of the placed volume to the world system + bool localToWorld(const Position& local, Position& global) const; + /// Transformation from local coordinates of the placed volume to the parent system + bool localToParent(const Position& local, Position& parent) const; + /// Transformation from local coordinates of the placed volume to arbitrary parent system set as reference + bool localToReference(const Position& local, Position& reference) const; + + /// Transformation from world coordinates of the local placed volume coordinates + bool worldToLocal(const Position& global, Position& local) const; + /// Transformation from world coordinates of the local placed volume coordinates + bool parentToLocal(const Position& parent, Position& local) const; + /// Transformation from world coordinates of the local placed volume coordinates + bool referenceToLocal(const Position& reference, Position& local) const; + }; } /* End namespace Geometry */ diff --git a/DDCore/include/DD4hep/Objects.h b/DDCore/include/DD4hep/Objects.h index 60422028be753038690a835bbd448eeadeff7dbb..c7328b7efac38b4ef7b0deecbf36435a83ff19f3 100644 --- a/DDCore/include/DD4hep/Objects.h +++ b/DDCore/include/DD4hep/Objects.h @@ -94,44 +94,68 @@ namespace DD4hep { std::string toString() const; }; + // We want the 3 coordinates ass-to-ass, so that they can be interpreted as "double*" +#ifdef _WIN32 +#pragma pack(push,DD4Hep_Objects_Position,1) +#define DD4HEP_BYTE_ALIGN(x) x +#else +#define DD4HEP_BYTE_ALIGN(x) x __attribute__((__packed__)) +#endif /** @class Position Objects.h * * @author M.Frank * @version 1.0 */ - struct Position { + DD4HEP_BYTE_ALIGN(struct) Position { + /// 3-dimensional cartesian coordinates double x, y, z; /// Default constructor Position() : x(0), y(0), z(0) {} /// Initializing constructor - Position(double xval, double yval, double zval) : x(xval), y(yval), z(zval) {} + Position(double xval, double yval, double zval) : x(xval), y(yval), z(zval) { } /// Is it a identity rotation ? - bool isNull() const { return x==0 && y==0 && z==0; } + bool isNull() const { return x==0 && y==0 && z==0; } + /// Access to array like coordinates + const double* coordinates() const { return &x; } + /// Initializer for all member variables + Position& set(double xv, double yv, double zv) { x=xv; y=yv; z=zv; return *this; } }; - - /** @class IdentityPos Objects.h +#ifdef _WIN32 +#pragma pack(pop,DD4Hep_Objects_Position) +#pragma pack(push,DD4Hep_Objects_Rotation,1) +#endif + /** @class Rotation Objects.h * * @author M.Frank * @version 1.0 */ - struct IdentityPos { + DD4HEP_BYTE_ALIGN(struct) Rotation { + double theta, phi, psi; /// Default constructor - IdentityPos() {} + Rotation() : theta(0), phi(0), psi(0) {} + /// Initializing constructor + Rotation(double thetaval, double phival, double psival) : theta(thetaval), phi(phival), psi(psival) {} + /// Is it a identity rotation ? + bool isNull() const { return theta==0 && phi==0 && psi==0; } + /// Access to array like coordinates + const double* angles() const { return θ } + /// Initializer for all member variables + Rotation& set(double th, double ph, double ps) { theta=th; phi=ph; psi=ps;return *this; } }; - /** @class Rotation Objects.h +#ifdef _WIN32 +#pragma pack(pop,DD4Hep_Objects_Rotation,1) +#endif +#undef DD4HEP_BYTE_ALIGN + + /** @class IdentityPos Objects.h * * @author M.Frank * @version 1.0 */ - struct Rotation { - double theta, phi, psi; + struct IdentityPos { /// Default constructor - Rotation() : theta(0), phi(0), psi(0) {} - /// Initializing constructor - Rotation(double thetaval, double phival, double psival) : theta(thetaval), phi(phival), psi(psival) {} - /// Is it a identity rotation ? - bool isNull() const { return theta==0 && phi==0 && psi==0; } + IdentityPos() {} }; /** @class IdentityRot Objects.h diff --git a/DDCore/include/DD4hep/Volumes.h b/DDCore/include/DD4hep/Volumes.h index ef8729cef4bb13c375d1463478ca269b402dbb16..07dba2baa7e9c27503b87062f11be5c33a55ae96 100644 --- a/DDCore/include/DD4hep/Volumes.h +++ b/DDCore/include/DD4hep/Volumes.h @@ -51,10 +51,14 @@ namespace DD4hep { struct PlacedVolume : Handle<TGeoNodeMatrix> { typedef std::map<std::string,int> VolIDs; struct Object { + /// Magic word unsigned long magic; + /// ID container VolIDs volIDs; - Ref_t detector; - Object() : volIDs(), detector() {} + /// Default constructor + Object() : volIDs() {} + /// Copy constructor + Object(const Object& c) : magic(c.magic), volIDs(c.volIDs) {} }; /// Constructor to be used when reading the already parsed DOM tree PlacedVolume(const TGeoNode* e) : Handle<TGeoNodeMatrix>(e) {} @@ -74,10 +78,6 @@ namespace DD4hep { Volume motherVol() const; /// Access to the volume IDs const VolIDs& volIDs() const; - /// Set the detector handle - void setDetElement(Ref_t detector) const; - /// Access to the corresponding detector element (maybe invalid) - Ref_t detElement() const; /// String dump std::string toString() const; }; @@ -144,7 +144,7 @@ namespace DD4hep { void setLimitSet(const LimitSet& obj) const; /// Access to the limit set LimitSet limitSet() const; - + /// Set Visualization attributes to the volume void setVisAttributes(const VisAttr& obj) const; /// Set Visualization attributes to the volume diff --git a/DDCore/src/Detector.cpp b/DDCore/src/Detector.cpp index 7509189d1abad4f0c7564681f1510dfed1dfdeda..bc2c7913025770464d545f2a4d4f0de76d61b7de 100644 --- a/DDCore/src/Detector.cpp +++ b/DDCore/src/Detector.cpp @@ -10,14 +10,113 @@ #include "DD4hep/IDDescriptor.h" #include "DD4hep/LCDD.h" #include "TGeoVolume.h" +#include "TGeoMatrix.h" +#include "TGeoManager.h" using namespace std; using namespace DD4hep::Geometry; +static bool traverse_find(TGeoNode* parent, TGeoNode* child, vector<TGeoMatrix*>& trafos) { + TIter next(parent->GetVolume()->GetNodes()); + for (TGeoNode *daughter=(TGeoNode*)next(); daughter; daughter=(TGeoNode*)next() ) { + if ( daughter == child ) { + trafos.push_back(daughter->GetMatrix()); + return true; + } + } + next.Reset(); + for (TGeoNode *daughter=(TGeoNode*)next(); daughter; daughter=(TGeoNode*)next() ) { + if ( traverse_find(daughter, child, trafos) ) { + trafos.push_back(daughter->GetMatrix()); + return true; + } + } + return false; +} + +static bool traverse_up(const DetElement& parent, const DetElement& child, vector<TGeoMatrix*>& trafos) { + if ( child.ptr() != parent.ptr() ) { + for( DetElement par=parent, cld=child; par.isValid(); cld=par, par=par._data().parent ) { + PlacedVolume cld_place = cld._data().placement; + PlacedVolume par_place = par._data().placement; + if ( !traverse_find(par_place.ptr(),cld_place.ptr(),trafos) ) { + return false; + } + } + } + return true; +} +#include <iostream> +static string find_child(TGeoNode* top, TGeoNode* child, vector<TGeoNode*>& path) { + TIter next(top->GetVolume()->GetNodes()); + for (TGeoNode *daughter=(TGeoNode*)next(); daughter; daughter=(TGeoNode*)next() ) { + if ( daughter == child ) { + cout << "Found child:" << child->GetName() << endl; + path.push_back(daughter); + return child->GetName(); + } + } + next.Reset(); + for (TGeoNode *daughter=(TGeoNode*)next(); daughter; daughter=(TGeoNode*)next() ) { + string res = find_child(daughter, child, path); + if ( !res.empty() ) { + path.push_back(daughter); + return top->GetName() + ("/"+res); + } + } + //cout << "FAILED child:" << (unsigned long)child << endl; + return ""; +} + +/// Create cached matrix to transform to positions to an upper level DetElement +static TGeoHMatrix* create_trafo(const Ref_t& parent, const Ref_t& child) { + if ( parent.isValid() && child.isValid() ) { + TGeoHMatrix* mat = 0; // Now collect all transformations + vector<TGeoMatrix*> trafos; + if ( !traverse_up(parent,child,trafos) ) { + trafos.clear(); + if ( !traverse_up(child,parent,trafos) ) { // Some error, non-existing path! + throw runtime_error("DetElement "+string(parent.name())+" is not connected to child "+string(child.name())+" [Geo-Error]"); + } + else { + /// The two detector elements were only found by reversing the hierarchy. + /// Hence the transformations must be applied in reverse order. + for(vector<TGeoMatrix*>::const_reverse_iterator i=trafos.rbegin(); i!=trafos.rend(); ++i) { + if ( !mat ) mat = new TGeoHMatrix(*(*i)); + else mat->MultiplyLeft(*i); + } + } + } + else { + /// Combine the transformations to a single transformation. + for(vector<TGeoMatrix*>::const_iterator i=trafos.begin(); i!=trafos.end(); ++i) { + if ( !mat ) mat = new TGeoHMatrix(*(*i)); + else mat->MultiplyLeft(*i); + } + } +#if 0 + // Test: find arbitrary child by traversing TGeoNode tree + vector<TGeoNode*> path; + TGeoNode* top = gGeoManager->GetTopNode(); + TGeoNode* node = DetElement(child).placement().ptr(); + string res = find_child(top,node,path); + cout << "Path:" << res << endl; +#endif + return mat; + } + if ( parent.isValid() ) + throw runtime_error("DetElement cannot connect "+string(parent.name())+" to not-existing child!"); + else if ( child.isValid() ) + throw runtime_error("DetElement cannot connect "+string(child.name())+" to not-existing parent!"); + else + throw runtime_error("DetElement cannot connect nonexisting parent to not-existing child!"); +} + /// Default constructor DetElement::Object::Object() : magic(magic_word()), id(0), combine_hits(0), readout(), - alignment(), placement(), placements(), parent(), children() + alignment(), placement(), placements(), parent(), children(), + worldTrafo(0), parentTrafo(0), referenceTrafo(0) { } @@ -55,6 +154,59 @@ void DetElement::Object::deepCopy(const Object& source, int new_id, int flag) { } } +/// Top detector element +Ref_t DetElement::Object::top() { + // This is an ugly staement. Need to rethink it a bit.....(MSF) + if ( !this->parent.isValid() ) return this->asRef(); + return DetElement(this->parent)._data().top(); +} + +/// Conversion to reference object +Ref_t DetElement::Object::asRef() { + return Ref_t(dynamic_cast<Value<TNamed,DetElement::Object>*>(this)); +} + +/// Conversion to reference object +DetElement::Object::operator Ref_t() { + return this->asRef(); +} + +/// Create cached matrix to transform to world coordinates +TGeoMatrix* DetElement::Object::worldTransformation() { + if ( !worldTrafo ) { + DetElement top_det(this->top()); + vector<TGeoMatrix*> trafos; + TGeoHMatrix* mat = create_trafo(top_det,asRef()); + // Now we got the point in the top-most detector element. We now have + // to translate this to the "world volume", which has no transformation matrix anymore + TGeoNode* top_node = gGeoManager->GetTopNode(); + PlacedVolume place = top_det.placement(); + if ( !traverse_find(top_node, place.ptr(), trafos) ) { + // Some error, non-existing path! + throw runtime_error("DetElement "+string(parent.name())+" is not connected to top geo node [Geo-Error]"); + } + for(vector<TGeoMatrix*>::const_iterator i=trafos.begin(); i!=trafos.end(); ++i) + mat->MultiplyLeft(*i); + worldTrafo = mat; + } + return worldTrafo; +} + +/// Create cached matrix to transform to parent coordinates +TGeoMatrix* DetElement::Object::parentTransformation() { + if ( !parentTrafo ) { + parentTrafo = create_trafo(this->parent,asRef()); + } + return parentTrafo; +} + +/// Create cached matrix to transform to reference coordinates +TGeoMatrix* DetElement::Object::referenceTransformation() { + if ( !referenceTrafo ) { + referenceTrafo = create_trafo(this->reference,asRef()); + } + return referenceTrafo; +} /// Constructor for a new subdetector element DetElement::DetElement(const LCDD& /* lcdd */, const string& name, const string& type, int id) @@ -79,9 +231,7 @@ string DetElement::path() const { Object& o = _data(); if ( o.path.empty() ) { DetElement par = o.parent; - if ( par.isValid() ) - return (par.path()+"/")+name(); - return string("/") + name(); + o.path = par.isValid() ? (par.path()+"/")+name() : string("/") + name(); } return o.path; } @@ -134,10 +284,6 @@ DetElement& DetElement::add(const DetElement& sdet) { throw runtime_error("DetElement::add: Self is not defined [Invalid Handle]"); } -DetElement::Placements DetElement::placements() const { - return _data().placements; -} - DetElement DetElement::clone(const string& new_name) const { if ( isValid() ) { return DetElement(_data().construct(_data().id,COPY_NONE), new_name, ptr()->GetTitle()); @@ -167,16 +313,20 @@ PlacedVolume DetElement::placement() const { DetElement& DetElement::setPlacement(const PlacedVolume& placement) { if ( isValid() ) { if ( placement.isValid() ) { - Object& o = _data(); + Object& o = _data(); o.placement = placement; - o.volume = placement.volume(); - placement.setDetElement(*this); + o.volume = placement.volume(); + //placement.setDetElement(*this); return *this; } throw runtime_error("DetElement::addPlacement: Placement is not defined [Invalid Handle]"); } throw runtime_error("DetElement::addPlacement: Self is not defined [Invalid Handle]"); } +#if 0 +DetElement::Placements DetElement::placements() const { + return _data().placements; +} // OBSOLETE: to be replaced by setPlacement DetElement& DetElement::addPlacement(const PlacedVolume& placement) { @@ -190,7 +340,7 @@ DetElement& DetElement::addPlacement(const PlacedVolume& placement) { } throw runtime_error("DetElement::addPlacement: Self is not defined [Invalid Handle]"); } - +#endif /// Access to the logical volume of the placements (all daughters have the same!) Volume DetElement::volume() const { if ( isValid() ) { @@ -263,6 +413,62 @@ bool DetElement::isCalorimeter() const { return false; } +/// Set detector element for reference transformations. Will delete existing reference trafo. +DetElement& DetElement::setReference(DetElement reference) { + Object& o = _data(); + if ( o.referenceTrafo ) { + delete o.referenceTrafo; + o.referenceTrafo = 0; + } + _data().reference = reference; + return *this; +} + +/// Transformation from local coordinates of the placed volume to the world system +bool DetElement::localToWorld(const Position& local, Position& global) const { + Double_t master_point[3]={0,0,0}, local_point[3] = {local.x,local.y,local.z}; + // If the path is unknown an exception will be thrown inside worldTransformation() ! + _data().worldTransformation()->LocalToMaster(local_point,master_point); + global.set(master_point[0],master_point[1],master_point[2]); + return true; +} + +/// Transformation from local coordinates of the placed volume to the parent system +bool DetElement::localToParent(const Position& local, Position& global) const { + // If the path is unknown an exception will be thrown inside parentTransformation() ! + _data().parentTransformation()->LocalToMaster(&local.x,&global.x); + return true; +} + +/// Transformation from local coordinates of the placed volume to arbitrary parent system set as reference +bool DetElement::localToReference(const Position& local, Position& global) const { + // If the path is unknown an exception will be thrown inside referenceTransformation() ! + _data().referenceTransformation()->LocalToMaster(&local.x,&global.x); + return true; +} + +/// Transformation from world coordinates of the local placed volume coordinates +bool DetElement::worldToLocal(const Position& global, Position& local) const { + // If the path is unknown an exception will be thrown inside worldTransformation() ! + _data().worldTransformation()->MasterToLocal(&global.x,&local.x); + return true; +} + +/// Transformation from parent coordinates of the local placed volume coordinates +bool DetElement::parentToLocal(const Position& global, Position& local) const { + // If the path is unknown an exception will be thrown inside parentTransformation() ! + _data().parentTransformation()->MasterToLocal(&global.x,&local.x); + return true; +} + +/// Transformation from arbitrary parent system coordinates of the local placed volume coordinates +bool DetElement::referenceToLocal(const Position& global, Position& local) const { + // If the path is unknown an exception will be thrown inside referenceTransformation() ! + _data().referenceTransformation()->MasterToLocal(&global.x,&local.x); + return true; +} + +/// Constructor SensitiveDetector::SensitiveDetector(const LCDD& /* lcdd */, const std::string& type, const std::string& name) { /* diff --git a/DDCore/src/LCDDImp.cpp b/DDCore/src/LCDDImp.cpp index 4c0d88d350e7a4a1e1552d1896f9d4e811b043bf..a61ac1d1fe7d7f9155efeebf3042e6e9de5d2b1f 100644 --- a/DDCore/src/LCDDImp.cpp +++ b/DDCore/src/LCDDImp.cpp @@ -41,12 +41,12 @@ Volume LCDDImp::pickMotherVolume(const DetElement&) const { // throw if not } LCDD& LCDDImp::addVolume(const Ref_t& x) { - m_structure.append<TGeoVolume>(x); + m_structure.append<TGeoVolume>(x,false); return *this; } LCDD& LCDDImp::addSolid(const Ref_t& x) { - m_structure.append<TGeoShape>(x); + m_structure.append<TGeoShape>(x,false); return *this; } @@ -165,6 +165,135 @@ static void dumpChildren(const DetElement& e, int level) { dumpChildren(DetElement((*i).second),level+1); } +#if 0 +#include "TGeoNode.h" + +static void dumpGeometry(vector<TGeoNode*>& globals, vector<TGeoNode*>& locals, TGeoNode* current) { + typedef Value<TGeoNodeMatrix,PlacedVolume::Object> _P; + TGeoMatrix* matrix = current->GetMatrix(); + TGeoVolume* volume = current->GetVolume(); + TObjArray* nodes = volume->GetNodes(); + int num_children = nodes ? nodes->GetEntriesFast() : 0; + _P* val = dynamic_cast<_P*>(current); + static vector<DetElement> det_cache; + vector<TGeoNode*> loc_cache; + vector<TGeoNode*>* ptrloc_cache = &locals; + const char* tag = val ? "Yes" : "No "; + bool valid_det = false; + bool prt = false; + for(size_t i=0; i<globals.size(); ++i) { + if(strncmp(globals[i]->GetName(),"Muon",4)==0) { prt = true; break;} + } + + if ( val ) { + DetElement d = val->detector; + if ( d.isValid() ) { + valid_det = true; + det_cache.push_back(d); + ptrloc_cache = &loc_cache; + } + } + if ( prt ) { + cout << "[" << int(globals.size()) << " , " << tag << "] \t" << (void*)current << "\t" + << char(valid_det ? '*' : ' ') + << current->GetName(); + if ( num_children > 0 ) + cout << " #Children:" << num_children << "."; + else + cout << " No Children."; + cout << "\t Vol:" << volume->GetName(); + if ( valid_det ) { + DetElement d = val->detector; + cout << " DetElement:" << d->GetName(); + //cout << " Vol:" << d.volume().name(); + cout << " DetTrafos:" << locals.size(); + } + else { + cout << " Trafos:" << locals.size(); + for(size_t i=0; i<locals.size(); ++i) + cout << " " << (void*)locals[i]; + } + cout << endl; + } + if ( num_children > 0 ) { + globals.push_back(current); + for(int i=0; i<num_children; ++i) { + TGeoNode* node = (TGeoNode*)nodes->At(i); + ptrloc_cache->push_back(node); + dumpGeometry(globals,*ptrloc_cache,node); + ptrloc_cache->pop_back(); + } + globals.pop_back(); + } + if ( valid_det ) det_cache.pop_back(); +} + +vector<TGeoMatrix*> Transformations; +vector<TGeoSolid*> Volumes; +map<int, vector<TGeoNode*> > Placements; + + +static void dumpGeo(TGeoNode* current) { + + typedef Value<TGeoNodeMatrix,PlacedVolume::Object> _P; + TGeoMatrix* matrix = current->GetMatrix(); + TGeoVolume* volume = current->GetVolume(); + TObjArray* nodes = volume->GetNodes(); + int num_children = nodes ? nodes->GetEntriesFast() : 0; + _P* val = dynamic_cast<_P*>(current); + static vector<DetElement> det_cache; + vector<TGeoNode*> loc_cache; + vector<TGeoNode*>* ptrloc_cache = &locals; + const char* tag = val ? "Yes" : "No "; + bool valid_det = false; + bool prt = false; + for(size_t i=0; i<globals.size(); ++i) { + if(strncmp(globals[i]->GetName(),"Muon",4)==0) { prt = true; break;} + } + + if ( val ) { + DetElement d = val->detector; + if ( d.isValid() ) { + valid_det = true; + det_cache.push_back(d); + ptrloc_cache = &loc_cache; + } + } + if ( prt ) { + cout << "[" << int(globals.size()) << " , " << tag << "] \t" << (void*)current << "\t" + << char(valid_det ? '*' : ' ') + << current->GetName(); + if ( num_children > 0 ) + cout << " #Children:" << num_children << "."; + else + cout << " No Children."; + cout << "\t Vol:" << volume->GetName(); + if ( valid_det ) { + DetElement d = val->detector; + cout << " DetElement:" << d->GetName(); + //cout << " Vol:" << d.volume().name(); + cout << " DetTrafos:" << locals.size(); + } + else { + cout << " Trafos:" << locals.size(); + for(size_t i=0; i<locals.size(); ++i) + cout << " " << (void*)locals[i]; + } + cout << endl; + } + if ( num_children > 0 ) { + globals.push_back(current); + for(int i=0; i<num_children; ++i) { + TGeoNode* node = (TGeoNode*)nodes->At(i); + ptrloc_cache->push_back(node); + dumpGeometry(globals,*ptrloc_cache,node); + ptrloc_cache->pop_back(); + } + globals.pop_back(); + } + if ( valid_det ) det_cache.pop_back(); +} +#endif void LCDDImp::dump() const { TGeoManager* mgr = gGeoManager; mgr->CloseGeometry(); @@ -178,5 +307,12 @@ void LCDDImp::dump() const { dumpChildren(e,0); //cout << "Detector: " << (*i).first << " : " << e.name() << endl; } +#if 0 + TGeoNode* top = mgr->GetTopNode(); + vector<TGeoNode*> globals; + vector<TGeoNode*> locals; + //dumpGeometry(globals,locals,top); + //dumpGeo(top); +#endif } diff --git a/DDCore/src/LCDDImp.h b/DDCore/src/LCDDImp.h index d75392df330f0a2ec11d6dcc43f76d5bb6a18c2f..1c87cdb58afc19afb5e5da5f91b087dfad94067d 100644 --- a/DDCore/src/LCDDImp.h +++ b/DDCore/src/LCDDImp.h @@ -46,19 +46,21 @@ namespace DD4hep { this->insert(std::make_pair(n,e.ptr())); } } - void append(const Ref_t& e) { + void append(const Ref_t& e, bool throw_on_doubles=true) { if ( e.isValid() ) { std::string n = e.name(); - this->insert(std::make_pair(n,e.ptr())); - return; + std::pair<iterator,bool> r = this->insert(std::make_pair(n,e.ptr())); + if ( !throw_on_doubles || r.second ) + return; + throw InvalidObjectError("Attempt to add an already existing object:"+std::string(e.name())+"."); } - throw InvalidObjectError("Attempt to add an invalid object object"); + throw InvalidObjectError("Attempt to add an invalid object."); } - template <typename T> void append(const Ref_t& e) { + template <typename T> void append(const Ref_t& e, bool throw_on_doubles=true) { T* obj = dynamic_cast<T*>(e.ptr()); if ( obj ) { - this->append(e); - return; + this->append(e,throw_on_doubles); + return; } throw InvalidObjectError("Attempt to add an object, which is of the wrong type."); } @@ -168,7 +170,7 @@ namespace DD4hep { virtual LCDD& addVolume(const Ref_t& x); // { m_structure.append(x); __R;} // These not: - virtual LCDD& addConstant(const Ref_t& x) { m_define.append(x); __R;} + virtual LCDD& addConstant(const Ref_t& x) { m_define.append(x,false); __R;} virtual LCDD& addMaterial(const Ref_t& x) { m_materials.append(x); __R;} virtual LCDD& addLimitSet(const Ref_t& x) { m_limits.append(x); __R;} virtual LCDD& addRegion(const Ref_t& x) { m_regions.append(x); __R;} diff --git a/DDCore/src/Volumes.cpp b/DDCore/src/Volumes.cpp index 46617752343843361dabb0adc4ac0edc56edf9aa..ad18e0d0619f22f535593e1bf04e5eefe9a697a6 100644 --- a/DDCore/src/Volumes.cpp +++ b/DDCore/src/Volumes.cpp @@ -37,6 +37,29 @@ namespace DD4hep { namespace Geometry { Value(const TGeoVolume* v, const TGeoMatrix* m) : TGeoNodeMatrix(v,m), PlacedVolume::Object() { magic = magic_word(); } + Value(const Value& c) : TGeoNodeMatrix(c.GetVolume(),c.GetMatrix()), PlacedVolume::Object(c) { + } + virtual TGeoNode *MakeCopyNode() const { + TGeoNodeMatrix *node = new Value<TGeoNodeMatrix,PlacedVolume::Object>(*this); + node->SetName(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 { @@ -44,20 +67,20 @@ namespace DD4hep { namespace Geometry { virtual ~_VolWrap() {} 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) { + if ( matrix == 0 ) matrix = gGeoIdentity; + else matrix->RegisterYourself(); + if (!vol) { this->T::Error("AddNode", "Volume is NULL"); return; } - if (!vol->IsValid()) { + 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::fNodes ) this->T::fNodes = new TObjArray(); - if (this->T::fFinder) { + 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; @@ -99,7 +122,7 @@ namespace DD4hep { namespace Geometry { ((TObject*)vol)->SetBit(kVolumeClone); return vol; } - TGeoVolume* CloneVolume() const { + virtual TGeoVolume* CloneVolume() const { TGeoVolume *vol = new Value<TGeoVolume,Volume::Object>(GetName(), fShape, fMedium); Int_t i; // copy volume attributes @@ -177,20 +200,58 @@ namespace DD4hep { namespace Geometry { return vol; } }; + }} +/// Add identifier +PlacedVolume& PlacedVolume::addPhysVolID(const std::string& name, int value) { + Object* obj = data<Object>(); + obj->volIDs[name] = value; + return *this; +} + +/// Volume material +Material PlacedVolume::material() const +{ return Material::handle_t(m_element ? m_element->GetMedium()->GetMaterial() : 0); } + +/// Logical volume of this placement +Volume PlacedVolume::volume() const +{ return Volume::handle_t(m_element ? m_element->GetVolume() : 0); } + +/// Parent volume (envelope) +Volume PlacedVolume::motherVol() const +{ return Volume::handle_t(m_element ? m_element->GetMotherVolume() : 0); } + +/// Access to the volume IDs +const PlacedVolume::VolIDs& PlacedVolume::volIDs() const +{ return data<Object>()->volIDs; } + +/// String dump +string PlacedVolume::toString() const { + stringstream s; + Object* obj = data<Object>(); + s << m_element->GetName() << ": vol='" << m_element->GetVolume()->GetName() + << "' mat:'" << m_element->GetMatrix()->GetName() << "' volID[" << obj->volIDs.size() << "] "; + for(VolIDs::const_iterator i=obj->volIDs.begin(); i!=obj->volIDs.end();++i) + s << (*i).first << "=" << (*i).second << " "; + s << ends; + return s.str(); +} +/// Constructor to be used when creating a new geometry tree. Volume::Volume(LCDD& lcdd, const string& name) { m_element = new Value<TGeoVolume,Volume::Object>(name.c_str()); lcdd.addVolume(*this); } +/// Constructor to be used when creating a new geometry tree. Also sets materuial and solid attributes Volume::Volume(LCDD& lcdd, const string& name, const Solid& s, const Material& m) { m_element = new Value<TGeoVolume,Volume::Object>(name.c_str(),s); setMaterial(m); lcdd.addVolume(*this); } +/// Set the volume's material void Volume::setMaterial(const Material& m) const { if ( m.isValid() ) { TGeoMedium* medium = m._ptr<TGeoMedium>(); @@ -203,10 +264,6 @@ void Volume::setMaterial(const Material& m) const { throw runtime_error("Volume: Attempt to assign invalid material."); } -void Volume::setSolid(const Solid& solid) const { - m_element->SetShape(solid); -} - static PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, TGeoMatrix* transform) { TGeoVolume* parent = par; TObjArray* a = parent->GetNodes(); @@ -216,6 +273,7 @@ static PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, TGeoMatrix* return PlacedVolume(n); } +/// Place translated and rotated daughter volume PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos, const Rotation& rot) const { if ( volume.isValid() ) { string nam = string(volume.name())+"_placement"; @@ -227,6 +285,7 @@ PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos, cons throw runtime_error("Volume: Attempt to assign an invalid physical volume."); } +/// Place un-rotated daughter volume at the given position. PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos) const { if ( volume.isValid() ) { string nam = string(volume.name())+"_placement"; @@ -236,6 +295,7 @@ PlacedVolume Volume::placeVolume(const Volume& volume, const Position& pos) con throw runtime_error("Volume: Attempt to assign an invalid physical volume."); } +/// Place rotated daughter volume. The position is automatically the identity position PlacedVolume Volume::placeVolume(const Volume& volume, const Rotation& rot) const { if ( volume.isValid() ) { string nam = string(volume.name())+"_placement"; @@ -245,6 +305,7 @@ PlacedVolume Volume::placeVolume(const Volume& volume, const Rotation& rot) con throw runtime_error("Volume: Attempt to assign an invalid physical volume."); } +/// Place daughter volume. The position and rotation are the identity PlacedVolume Volume::placeVolume(const Volume& volume, const IdentityPos& /* pos */) const { if ( volume.isValid() ) { string nam = string(volume.name())+"_placement"; @@ -253,6 +314,7 @@ PlacedVolume Volume::placeVolume(const Volume& volume, const IdentityPos& /* pos throw runtime_error("Volume: Attempt to assign an invalid physical volume."); } +/// Place daughter volume. The position and rotation are the identity PlacedVolume Volume::placeVolume(const Volume& volume, const IdentityRot& /* rot */) const { if ( volume.isValid() ) { string nam = string(volume.name())+"_placement"; @@ -261,14 +323,7 @@ PlacedVolume Volume::placeVolume(const Volume& volume, const IdentityRot& /* rot throw runtime_error("Volume: Attempt to assign an invalid physical volume."); } -void Volume::setRegion(const Region& obj) const { - data<Object>()->region = obj; -} - -void Volume::setLimitSet(const LimitSet& obj) const { - data<Object>()->limits = obj; -} - +/// Set Visualization attributes to the volume void Volume::setVisAttributes(const VisAttr& attr) const { if ( attr.isValid() ) { VisAttr::Object* vis = attr.data<VisAttr::Object>(); @@ -284,6 +339,7 @@ void Volume::setVisAttributes(const VisAttr& attr) const { data<Object>()->vis = attr; } +/// Set Visualization attributes to the volume void Volume::setVisAttributes(const LCDD& lcdd, const string& name) const { if ( !name.empty() ) { VisAttr attr = lcdd.visAttributes(name); @@ -316,86 +372,49 @@ void Volume::setAttributes(const LCDD& lcdd, setVisAttributes(lcdd,vis); } -/// Assign the sensitive detector structure -void Volume::setSensitiveDetector(const SensitiveDetector& obj) const { - data<Object>()->sens_det = obj; -} +/// Set the volume's solid shape +void Volume::setSolid(const Solid& solid) const +{ m_element->SetShape(solid); } -/// Access to Solid (Shape) -Solid Volume::solid() const { - return Solid((*this)->GetShape()); -} +/// Set the regional attributes to the volume +void Volume::setRegion(const Region& obj) const +{ data<Object>()->region = obj; } -/// Constructor to be used when creating a new geometry tree. -Assembly::Assembly(LCDD& lcdd, const std::string& name) { - m_element = new Value<TGeoVolumeAssembly,Volume::Object>(name.c_str()); - lcdd.addVolume(*this); -} +/// Set the limits to the volume +void Volume::setLimitSet(const LimitSet& obj) const +{ data<Object>()->limits = obj; } -Material Volume::material() const { - return Handle<TGeoMaterial>(m_element->GetMaterial()); -} +/// Assign the sensitive detector structure +void Volume::setSensitiveDetector(const SensitiveDetector& obj) const +{ data<Object>()->sens_det = obj; } -VisAttr Volume::visAttributes() const { - return data<Object>()->vis; -} +/// Access to Solid (Shape) +Solid Volume::solid() const +{ return Solid((*this)->GetShape()); } -Ref_t Volume::sensitiveDetector() const { - return data<Object>()->sens_det; -} +/// Access to the Volume material +Material Volume::material() const +{ return Handle<TGeoMaterial>(m_element->GetMaterial()); } -Region Volume::region() const { - return data<Object>()->region; -} +/// Access the visualisation attributes +VisAttr Volume::visAttributes() const +{ return data<Object>()->vis; } -LimitSet Volume::limitSet() const { - return data<Object>()->limits; -} +/// Access to the handle to the sensitive detector +Ref_t Volume::sensitiveDetector() const +{ return data<Object>()->sens_det; } -PlacedVolume& PlacedVolume::addPhysVolID(const std::string& name, int value) { - Object* obj = data<Object>(); - obj->volIDs[name] = value; - return *this; -} - -/// Volume material -Material PlacedVolume::material() const { - return Material::handle_t(m_element ? m_element->GetMedium()->GetMaterial() : 0); -} +/// Access to the handle to the region structure +Region Volume::region() const +{ return data<Object>()->region; } -/// Logical volume of this placement -Volume PlacedVolume::volume() const { - return Volume::handle_t(m_element ? m_element->GetVolume() : 0); -} +/// Access to the limit set +LimitSet Volume::limitSet() const +{ return data<Object>()->limits; } -/// Parent volume (envelope) -Volume PlacedVolume::motherVol() const { - return Volume::handle_t(m_element ? m_element->GetMotherVolume() : 0); -} - -/// Access to the volume IDs -const PlacedVolume::VolIDs& PlacedVolume::volIDs() const { - return data<Object>()->volIDs; -} - -/// Set the detector handle -void PlacedVolume::setDetElement(Ref_t detector) const { - data<Object>()->detector = detector; -} - -/// Access to the corresponding detector element (maybe invalid) -Ref_t PlacedVolume::detElement() const { - return data<Object>()->detector; +/// Constructor to be used when creating a new geometry tree. +Assembly::Assembly(LCDD& lcdd, const std::string& name) { + m_element = new Value<TGeoVolumeAssembly,Volume::Object>(name.c_str()); + lcdd.addVolume(*this); } -/// String dump -string PlacedVolume::toString() const { - stringstream s; - Object* obj = data<Object>(); - s << m_element->GetName() << ": vol='" << m_element->GetVolume()->GetName() - << "' mat:'" << m_element->GetMatrix()->GetName() << "' volID[" << obj->volIDs.size() << "] "; - for(VolIDs::const_iterator i=obj->volIDs.begin(); i!=obj->volIDs.end();++i) - s << (*i).first << "=" << (*i).second << " "; - s << ends; - return s.str(); -} diff --git a/DDCore/src/compact/LCDD2Output.cpp b/DDCore/src/compact/LCDD2Output.cpp index af0ae3230b2dfe5bf1e433dc569d23c0bea22597..ec5c0bb62ec5b089c20148da5f888e0d4828d1e9 100644 --- a/DDCore/src/compact/LCDD2Output.cpp +++ b/DDCore/src/compact/LCDD2Output.cpp @@ -69,7 +69,7 @@ namespace DD4hep { namespace Geometry { if ( obj ) { char text[256]; const DetElement& sd = val; - PlacedVolume plc = sd.placements()[0]; + PlacedVolume plc = sd.placement(); bool rdo = sd.readout().isValid(); bool vis = plc.isValid(); bool env = plc.isValid();