diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 20782c675..4a9ff607d 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - LCG: ["dev4/x86_64-centos7-clang12-opt"] + LCG: ["dev4/x86_64-el9-clang16-opt"] steps: - uses: actions/checkout@v3 - uses: cvmfs-contrib/github-action-cvmfs@v3 diff --git a/DDCAD/src/plugins/CADPlugins.cpp b/DDCAD/src/plugins/CADPlugins.cpp index 8a646ebe9..17f9c037a 100644 --- a/DDCAD/src/plugins/CADPlugins.cpp +++ b/DDCAD/src/plugins/CADPlugins.cpp @@ -20,11 +20,36 @@ #include // C/C++ include files +#include using namespace std; using namespace dd4hep; using namespace dd4hep::detail; +/// If the path to the CAD file does not directly exist try to resolve it: +static string resolve_path(xml_h e, const string& file) { + error_code errc; + std::string fname; + /// Use the xml utilities in the DocumentHandler to resolve the relative path + if ( file.length() > 7 && file.substr(0,7) == "file://" ) + fname = file.substr(7); + else + fname = file; + if ( !filesystem::exists(fname, errc) ) { + string fn = xml::DocumentHandler::system_path(e, fname); + if ( fn.length() > 7 && fn.substr(0,7) == "file://" ) + fn = fn.substr(7); + if ( !std::filesystem::exists(fn, errc) ) { + auto fp = filesystem::path(xml::DocumentHandler::system_path(e)).parent_path(); + except("CAD_Shape","+++ CAD file: %s (= %s + %s) is not accessible [%d: %s]", + fn.c_str(), fp.c_str(), fname.c_str(), + errc.value(), errc.message().c_str()); + } + return fn; + } + return fname; +} + static void* read_CAD_Volume(Detector& dsc, int argc, char** argv) { string fname; double scale = 1.0; @@ -61,7 +86,7 @@ DECLARE_DD4HEP_CONSTRUCTOR(DD4hep_read_CAD_volumes,read_CAD_Volume) static Handle create_CAD_Shape(Detector& dsc, xml_h e) { xml_elt_t elt(e); cad::ASSIMPReader rdr(dsc); - string fname = elt.attr(_U(ref)); + string fname = resolve_path(e, elt.attr(_U(ref))); long flags = elt.hasAttr(_U(flags)) ? elt.attr(_U(flags)) : 0; double unit = elt.hasAttr(_U(unit)) ? elt.attr(_U(unit)) : dd4hep::cm; @@ -97,7 +122,7 @@ DECLARE_XML_SHAPE(CAD_Shape__shape_constructor,create_CAD_Shape) static Handle create_CAD_Assembly(Detector& dsc, xml_h e) { xml_elt_t elt(e); - string fname = elt.attr(_U(ref)); + string fname = resolve_path(e, elt.attr(_U(ref))); double unit = elt.hasAttr(_U(unit)) ? elt.attr(_U(unit)) : dd4hep::cm; auto volumes = cad::ASSIMPReader(dsc).readVolumes(fname, unit); if ( volumes.empty() ) { @@ -159,8 +184,8 @@ DECLARE_XML_VOLUME(CAD_Assembly__volume_constructor,create_CAD_Assembly) */ static Handle create_CAD_Volume(Detector& dsc, xml_h e) { xml_elt_t elt(e); - string fname = elt.attr(_U(ref)); double unit = elt.attr(_U(unit)); + string fname = resolve_path(e, elt.attr(_U(ref))); long flags = elt.hasAttr(_U(flags)) ? elt.attr(_U(flags)) : 0; cad::ASSIMPReader rdr(dsc); diff --git a/DDCore/include/DDSegmentation/CartesianGridXYStaggered.h b/DDCore/include/DDSegmentation/CartesianGridXYStaggered.h new file mode 100644 index 000000000..441026adf --- /dev/null +++ b/DDCore/include/DDSegmentation/CartesianGridXYStaggered.h @@ -0,0 +1,150 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +//========================================================================== + + + + +/* + * CartesianGridXYStaggered.h + * + * Created on: September 15, 2023 + * Author: Sebouh J. Paul, UCR + */ + +#ifndef DDSEGMENTATION_CARTESIANGRIDXYSTAGGERED_H +#define DDSEGMENTATION_CARTESIANGRIDXYSTAGGERED_H + +#include "DDSegmentation/CartesianGrid.h" + +namespace dd4hep { + namespace DDSegmentation { + + /// Segmentation base class describing cartesian grid segmentation in the X-Y plane + class CartesianGridXYStaggered: public CartesianGrid { + public: + /// Default constructor passing the encoding string + CartesianGridXYStaggered(const std::string& cellEncoding = ""); + /// Default constructor used by derived classes passing an existing decoder + CartesianGridXYStaggered(const BitFieldCoder* decoder); + /// destructor + virtual ~CartesianGridXYStaggered(); + + /// determine the position based on the cell ID + virtual Vector3D position(const CellID& cellID) const; + /// determine the cell ID based on the position + virtual CellID cellID(const Vector3D& localPosition, const Vector3D& globalPosition, const VolumeID& volumeID) const; + /// access the grid size in X + double gridSizeX() const { + return _gridSizeX; + } + /// access the grid size in Y + double gridSizeY() const { + return _gridSizeY; + } + /// access the coordinate offset in X + double offsetX() const { + return _offsetX; + } + /// access the coordinate offset in Y + double offsetY() const { + return _offsetY; + } + /// access the field name used for X + const std::string& fieldNameX() const { + return _xId; + } + /// access the field name used for Y + const std::string& fieldNameY() const { + return _yId; + } + /// access the staggering option in X + int staggerX() const { + return _staggerX; + } + /// access the staggering option in Y + int staggerY() const { + return _staggerY; + } + /// access the keyword used to determine which volumes to stagger + const std::string& staggerKeyword() const { + return _staggerKeyword; + } + /// set the grid size in X + void setGridSizeX(double cellSize) { + _gridSizeX = cellSize; + } + /// set the grid size in Y + void setGridSizeY(double cellSize) { + _gridSizeY = cellSize; + } + /// set the coordinate offset in X + void setOffsetX(double offset) { + _offsetX = offset; + } + /// set the coordinate offset in Y + void setOffsetY(double offset) { + _offsetY = offset; + } + /// set the field name used for X + void setFieldNameX(const std::string& fieldName) { + _xId = fieldName; + } + /// set the field name used for Y + void setFieldNameY(const std::string& fieldName) { + _yId = fieldName; + } + /// set the staggering option in X + void setStaggerX(int staggerX) { + _staggerX = staggerX; + } + /// set the staggering option in Y + void setStaggerY(int staggerY) { + _staggerY = staggerY; + } + /// set the keyword used to determine which volumes to stagger + void setStaggerKeyword(const std::string& staggerKeyword) { + _staggerKeyword = staggerKeyword; + } + /** \brief Returns a vector of the cellDimensions of the given cell ID + in natural order of dimensions, e.g., dx/dy/dz, or dr/r*dPhi + + Returns a vector of the cellDimensions of the given cell ID + \param cellID is ignored as all cells have the same dimension + \return std::vector size 2: + -# size in x + -# size in y + */ + virtual std::vector cellDimensions(const CellID& cellID) const; + + protected: + /// the grid size in X + double _gridSizeX; + /// the coordinate offset in X + double _offsetX; + /// staggering option in X. 0 = no staggering. 1 = stagger by _gridSizeX/2.0 in odd layers + int _staggerX; + /// the grid size in Y + double _gridSizeY; + /// the coordinate offset in Y + double _offsetY; + /// staggering option in Y. 0 = no staggering. 1 = stagger by _gridSizeY/2.0 in odd layers + int _staggerY; + /// the field name used for X + std::string _xId; + /// the field name used for Y + std::string _yId; + /// the keyword used to determine which volumes to stagger + std::string _staggerKeyword; + }; + + } /* namespace DDSegmentation */ +} /* namespace dd4hep */ +#endif // DDSEGMENTATION_CARTESIANGRIDXYSTAGGERED_H diff --git a/DDCore/include/DDSegmentation/HexGrid.h b/DDCore/include/DDSegmentation/HexGrid.h new file mode 100644 index 000000000..434177790 --- /dev/null +++ b/DDCore/include/DDSegmentation/HexGrid.h @@ -0,0 +1,131 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +//========================================================================== + +/* + * HexGrid.h + * + * Created on: August 9, 2023 + * Author: Sebouh J. Paul, UC Riverside + */ + +#ifndef DDSEGMENTATION_HEXGRID_H +#define DDSEGMENTATION_HEXGRID_H + +#include "DDSegmentation/Segmentation.h" + +namespace dd4hep { + namespace DDSegmentation { + + /// Segmentation base class describing hexagonal grid segmentation, with or without staggering + class HexGrid: public Segmentation { + public: + /// Destructor + virtual ~HexGrid(); + //protected: + /// Default constructor used by derived classes passing the encoding string + HexGrid(const std::string& cellEncoding = ""); + /// Default constructor used by derived classes passing an existing decoder + HexGrid(const BitFieldCoder* decoder); + + /// determine the position based on the cell ID + virtual Vector3D position(const CellID& cellID) const; + /// determine the cell ID based on the position + virtual CellID cellID(const Vector3D& localPosition, const Vector3D& globalPosition, const VolumeID& volumeID) const; + // access the stagger mode: 0=no stagger; 1=stagger cycling through 3 offsets + int stagger() const { + return _stagger; + } + + /// access the grid size + double sideLength() const { + return _sideLength; + } + /// access the coordinate offset in X + double offsetX() const { + return _offsetX; + } + /// access the coordinate offset in Y + double offsetY() const { + return _offsetY; + } + /// access the field name used for X + const std::string& fieldNameX() const { + return _xId; + } + /// access the field name used for Y + const std::string& fieldNameY() const { + return _yId; + } + /// access the keyword for staggering + const std::string& staggerKeyword() const { + return _staggerKeyword; + } + + /// set the stagger mode: 0=no stagger; 1=stagger cycling through 3 offsets + void setStagger(int stagger) { + _stagger= stagger; + } + /// set the grid size in X + void setSideLength(double cellSize) { + _sideLength = cellSize; + } + /// set the coordinate offset in X + void setOffsetX(double offset) { + _offsetX = offset; + } + /// set the coordinate offset in Y + void setOffsetY(double offset) { + _offsetY = offset; + } + /// set the field name used for X + void setFieldNameX(const std::string& fieldName) { + _xId = fieldName; + } + /// set the field name used for Y + void setFieldNameY(const std::string& fieldName) { + _yId = fieldName; + } + /// set the keyword used to determine which volumes to stagger + void setStaggerKeyword(const std::string& staggerKeyword) { + _staggerKeyword = staggerKeyword; + } + /** \brief Returns a vector of the cellDimensions of the given cell ID + in natural order of dimensions, e.g., dx/dy/dz, or dr/r*dPhi + + Returns a vector of the cellDimensions of the given cell ID + \param cellID is ignored as all cells have the same dimension + \return std::vector size 2: + -# size in x + -# size in y + */ + virtual std::vector cellDimensions(const CellID& cellID) const; + + protected: + /// the stagger mode: 0=off ; 1=cycle through 3 different offsets (H3) + // 2=cycle through 4 differnt offsets (H4) + int _stagger; + /// the length of one side of a hexagon + double _sideLength; + /// the coordinate offset in X + double _offsetX; + /// the coordinate offset in Y + double _offsetY; + /// the field name used for X + std::string _xId; + /// the field name used for Y + std::string _yId; + /// the keyword used to determine which volumes to stagger + std::string _staggerKeyword; + }; + + } /* namespace DDSegmentation */ +} /* namespace dd4hep */ +#endif // DDSEGMENTATION_HEXGRID_H diff --git a/DDCore/src/Handle.cpp b/DDCore/src/Handle.cpp index a7d70c77a..7cfa46fcb 100644 --- a/DDCore/src/Handle.cpp +++ b/DDCore/src/Handle.cpp @@ -280,26 +280,40 @@ namespace dd4hep { } /// Evaluate string constant using environment stored in the evaluator - string _getEnviron(const string& env) { - size_t id1 = env.find("${"); - size_t id2 = env.rfind("}"); - if ( id1 == string::npos || id2 == string::npos ) { - return ""; - } - else { + string _getEnviron(const string& env) { + // We are trying to deal with the case when several variables are being replaced in the + // string. + size_t current_index = 0; + stringstream processed_variable; + while (true) { + // Looking for the start of a variable use, with the syntax + // "path1/path2/${VAR1}/path3/${VAR2}" + size_t id1 = env.find("${", current_index); + // variable start found, do a greedy search for the variable end + if (id1 == string::npos) { + // In this case we did not find the ${ to indicate a start of variable, + // we just copy the rest of the variable to the stringstream and exit + processed_variable << env.substr(current_index); + break; + } + size_t id2 = env.find("}", id1); + if (id2 == string::npos) { + runtime_error("dd4hep: Syntax error, bad variable syntax: " + env); + } + processed_variable << env.substr(current_index, id1 -current_index ); + string v = env.substr(id1, id2-id1+1); stringstream err; - string v = env.substr(id1,id2-id1+1); auto ret = eval.getEnviron(v, err); + // Checking that the variable lookup worked if ( ret.first != tools::Evaluator::OK) { - cerr << env << ": " << err.str() << endl; - throw runtime_error("dd4hep: Severe error during environment lookup of " + env + - " " + err.str()); + cerr << v << ": " << err.str() << endl; + throw runtime_error("dd4hep: Severe error during environment lookup of " + v + " " + err.str()); } - v = env.substr(0,id1); - v += ret.second; - v += env.substr(id2+1); - return v; + // Now adding the variable + processed_variable << ret.second; + current_index = id2 + 1; } + return processed_variable.str(); } /// String manipulations: Remove unconditionally all white spaces diff --git a/DDCore/src/Objects.cpp b/DDCore/src/Objects.cpp index 67b1ccc53..181f07ca7 100644 --- a/DDCore/src/Objects.cpp +++ b/DDCore/src/Objects.cpp @@ -452,7 +452,7 @@ string Limit::toString() const { string res = name + " = " + content; if (!unit.empty()) res += unit + " "; - res + " (" + particles + ")"; + res += " (" + particles + ")"; return res; } diff --git a/DDCore/src/Shapes.cpp b/DDCore/src/Shapes.cpp index c0115d55a..10d4643d5 100644 --- a/DDCore/src/Shapes.cpp +++ b/DDCore/src/Shapes.cpp @@ -89,7 +89,7 @@ template const char* Solid_type::type() const { /// Access the dimensions of the shape: inverse of the setDimensions member function template vector Solid_type::dimensions() { - return move( get_shape_dimensions(this->access()) ); + return get_shape_dimensions(this->access()); } /// Set the shape dimensions. As for the TGeo shape, but angles in rad rather than degrees. diff --git a/DDCore/src/Volumes.cpp b/DDCore/src/Volumes.cpp index e7e3f18b5..a46861b83 100644 --- a/DDCore/src/Volumes.cpp +++ b/DDCore/src/Volumes.cpp @@ -1155,14 +1155,17 @@ const Volume& Volume::setVisAttributes(const VisAttr& attr) const { if (draw_style == VisAttr::SOLID) { m_element->SetFillStyle(1001); // Root: solid -#if ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0) +#if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,0) + // Set directly transparency to the volume, NOT to the material as for ROOT < 6.29 + m_element->ResetTransparency(Char_t((1.0-vis->alpha)*100)); +#elif ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0) // As suggested by Valentin Volkl https://sft.its.cern.ch/jira/browse/DDFORHEP-20 // // According to https://root.cern.ch/phpBB3/viewtopic.php?t=2309#p66013 // a transparency>50 will make a volume invisible in the normal pad. // Hence: possibly restrict transparency to a maximum of 50. // but let's see first how this behaves. - m_element->SetTransparency((1.0-vis->alpha)*100); + m_element->SetTransparency(Char_t((1.0-vis->alpha)*100)); #endif } else { diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp index aae992573..20a286f2b 100644 --- a/DDCore/src/plugins/Compact2Objects.cpp +++ b/DDCore/src/plugins/Compact2Objects.cpp @@ -50,9 +50,10 @@ #include // C/C++ include files -#include +#include #include #include +#include #include using namespace std; @@ -1443,17 +1444,38 @@ template <> void Converter::operator()(xml_h element) const { template <> void Converter::operator()(xml_h element) const { string base = xml::DocumentHandler::system_directory(element); string file = element.attr(_U(ref)); - vector argv{&file[0],&base[0]}; + vector argv{&file[0], &base[0]}; description.apply("DD4hep_JsonProcessor",int(argv.size()), &argv[0]); } /// Read alignment entries from a seperate file in one of the include sections of the geometry template <> void Converter::operator()(xml_h element) const { + PrintLevel level = s_debug.includes ? ALWAYS : DEBUG; string fname = element.attr(_U(ref)); - if ( s_debug.includes ) { - printout(ALWAYS, "Compact","++ Processing xml document %s.", fname.c_str()); + size_t idx = fname.find("://"); + std::error_code ec; + + if ( idx == string::npos && filesystem::exists(fname, ec) ) { + // Regular file without protocol specification + printout(level, "Compact","++ Processing xml document %s.", fname.c_str()); + this->description.fromXML(fname); + } + else if ( idx == string::npos ) { + // File relative to location of xml tag (protocol specification not possible) + string location = xml::DocumentHandler::system_path(element, fname); + printout(level, "Compact","++ Processing xml document %s.", location.c_str()); + this->description.fromXML(location); + } + else if ( idx > 0 ) { + // File with protocol specification: must trust the location and the parser capabilities + printout(level, "Compact","++ Processing xml document %s.", fname.c_str()); + this->description.fromXML(fname); + } + else { + // Are there any other possibilities ? + printout(level, "Compact","++ Processing xml document %s.", fname.c_str()); + this->description.fromXML(fname); } - this->description.fromXML(fname); } /// Read material entries from a seperate file in one of the include sections of the geometry @@ -1716,6 +1738,7 @@ template <> void Converter::operator()(xml_h element) const { } xml_coll_t(compact, _U(plugins)).for_each(_U(plugin), Converter (description)); xml_coll_t(compact, _U(plugins)).for_each(_U(include), Converter (description)); + xml_coll_t(compact, _U(plugins)).for_each(_U(xml), Converter (description)); } #ifdef _WIN32 diff --git a/DDCore/src/segmentations/CartesianGridXYStaggered.cpp b/DDCore/src/segmentations/CartesianGridXYStaggered.cpp new file mode 100644 index 000000000..871958ffe --- /dev/null +++ b/DDCore/src/segmentations/CartesianGridXYStaggered.cpp @@ -0,0 +1,102 @@ +/* + * CartesianGridXYStaggered.cpp + * + * Created on: Sept 15, 2023 + * Author: Sebouh J. Paul, UCR + */ + +#include "DDSegmentation/CartesianGridXYStaggered.h" + +namespace dd4hep { +namespace DDSegmentation { + +/// default constructor using an encoding string +CartesianGridXYStaggered::CartesianGridXYStaggered(const std::string& cellEncoding) : + CartesianGrid(cellEncoding) { + // define type and description + _type = "CartesianGridXYStaggered"; + _description = "Cartesian segmentation in the local XY-plane, with options for staggering"; + + // register all necessary parameters + registerParameter("grid_size_x", "Cell size in X", _gridSizeX, 1., SegmentationParameter::LengthUnit); + registerParameter("grid_size_y", "Cell size in Y", _gridSizeY, 1., SegmentationParameter::LengthUnit); + registerParameter("offset_x", "Cell offset in X", _offsetX, 0., SegmentationParameter::LengthUnit, true); + registerParameter("offset_y", "Cell offset in Y", _offsetY, 0., SegmentationParameter::LengthUnit, true); + registerParameter("stagger_x", "Option to stagger the layers in x (ie, add grid_size_x/2 to offset_x for odd layers)", _staggerX, 0, + SegmentationParameter::NoUnit, true); + registerParameter("stagger_y", "Option to stagger the layers in y (ie, add grid_size_y/2 to offset_y for odd layers)", _staggerY, 0, + SegmentationParameter::NoUnit, true); + registerIdentifier("identifier_x", "Cell ID identifier for X", _xId, "x"); + registerIdentifier("identifier_y", "Cell ID identifier for Y", _yId, "y"); + registerParameter("stagger_keyword", "Volume ID identifier used for determining which volumes to stagger", _staggerKeyword, (std::string)"layer", + SegmentationParameter::NoUnit, true); +} + +/// Default constructor used by derived classes passing an existing decoder +CartesianGridXYStaggered::CartesianGridXYStaggered(const BitFieldCoder* decode) : + CartesianGrid(decode) +{ + // define type and description + _type = "CartesianGridXYStaggered"; + _description = "Cartesian segmentation in the local XY-plane, with options for staggering"; + + // register all necessary parameters + registerParameter("grid_size_x", "Cell size in X", _gridSizeX, 1., SegmentationParameter::LengthUnit); + registerParameter("grid_size_y", "Cell size in Y", _gridSizeY, 1., SegmentationParameter::LengthUnit); + registerParameter("offset_x", "Cell offset in X", _offsetX, 0., SegmentationParameter::LengthUnit, true); + registerParameter("offset_y", "Cell offset in Y", _offsetY, 0., SegmentationParameter::LengthUnit, true); + registerParameter("stagger_x", "Option to stagger the layers in x (ie, add grid_size_x/2 to offset_x for odd layers)", _staggerX, 0, + SegmentationParameter::NoUnit, true); + registerParameter("stagger_y", "Option to stagger the layers in y (ie, add grid_size_y/2 to offset_y for odd layers)", _staggerY, 0, + SegmentationParameter::NoUnit, true); + registerIdentifier("identifier_x", "Cell ID identifier for X", _xId, "x"); + registerIdentifier("identifier_y", "Cell ID identifier for Y", _yId, "y"); + registerParameter("stagger_keyword", "Volume ID identifier used for determining which volumes to stagger", _staggerKeyword, (std::string)"layer", + SegmentationParameter::NoUnit, true); +} + +/// destructor +CartesianGridXYStaggered::~CartesianGridXYStaggered() { + +} + +/// determine the position based on the cell ID +Vector3D CartesianGridXYStaggered::position(const CellID& cID) const { + Vector3D cellPosition; + if (_staggerX || _staggerY){ + int layer= _decoder->get(cID,_staggerKeyword); + cellPosition.X = binToPosition( _decoder->get(cID,_xId ), _gridSizeX, _offsetX+_staggerX*_gridSizeX*(layer%2)/2.); + cellPosition.Y = binToPosition( _decoder->get(cID,_yId ), _gridSizeY, _offsetY+_staggerY*_gridSizeY*(layer%2)/2.); + } else { + cellPosition.X = binToPosition( _decoder->get(cID,_xId ), _gridSizeX, _offsetX); + cellPosition.Y = binToPosition( _decoder->get(cID,_yId ), _gridSizeY, _offsetY); + } + return cellPosition; +} + +/// determine the cell ID based on the position + CellID CartesianGridXYStaggered::cellID(const Vector3D& localPosition, const Vector3D& /* globalPosition */, const VolumeID& vID) const { + CellID cID = vID ; + if (_staggerX || _staggerY){ + int layer= _decoder->get(cID,_staggerKeyword); + _decoder->set( cID,_xId, positionToBin(localPosition.X, _gridSizeX, _offsetX+_staggerX*_gridSizeX*(layer%2)/2) ); + _decoder->set( cID,_yId, positionToBin(localPosition.Y, _gridSizeY, _offsetY+_staggerY*_gridSizeY*(layer%2)/2) ); + } else { + _decoder->set( cID,_xId, positionToBin(localPosition.X, _gridSizeX, _offsetX)); + _decoder->set( cID,_yId, positionToBin(localPosition.Y, _gridSizeY, _offsetY)); + } + return cID ; +} + + +std::vector CartesianGridXYStaggered::cellDimensions(const CellID& cellID) const { + return {_gridSizeX, _gridSizeY}; +} + + +} /* namespace DDSegmentation */ +} /* namespace dd4hep */ + +// This is done DDCore/src/plugins/ReadoutSegmentations.cpp so the plugin is not part of libDDCore +// needs also #include "DD4hep/Factories.h" +// DECLARE_SEGMENTATION(CartesianGridXYStaggered,dd4hep::create_segmentation) diff --git a/DDCore/src/segmentations/HexGrid.cpp b/DDCore/src/segmentations/HexGrid.cpp new file mode 100644 index 000000000..f051a8f61 --- /dev/null +++ b/DDCore/src/segmentations/HexGrid.cpp @@ -0,0 +1,149 @@ +/* + * AIDA Detector description implementation + * + * Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) + * All rights reserved. + * + * For the licensing terms see $DD4hepINSTALL/LICENSE. + * For the list of contributors see $DD4hepINSTALL/doc/CREDITS. + * + * HexGrid.cpp + * + * Created on: August 9, 2023 + * Author: Sebouh J. Paul, UC Riverside + */ +#include "DD4hep/Factories.h" +#include "DDSegmentation/HexGrid.h" + +namespace dd4hep { + namespace DDSegmentation { + + /// Default constructor used by derived classes passing the encoding string + HexGrid::HexGrid(const std::string& cellEncoding) : + Segmentation(cellEncoding) { + _type = "HexGridXY"; + _description = "Hexagonal segmentation in the local XY-plane"; + + // register all necessary parameters + registerParameter("stagger", "stagger mode", _stagger, 1); + registerParameter("side_length", "Cell size", _sideLength, 1., SegmentationParameter::LengthUnit); + registerParameter("offset_x", "Cell offset in X", _offsetX, 0., SegmentationParameter::LengthUnit, true); + registerParameter("offset_y", "Cell offset in Y", _offsetY, 0., SegmentationParameter::LengthUnit, true); + registerIdentifier("identifier_x", "Cell ID identifier for X", _xId, "x"); + registerIdentifier("identifier_y", "Cell ID identifier for Y", _yId, "y"); + registerParameter("stagger_keyword", "Volume ID identifier used for determining which volumes to stagger", _staggerKeyword, (std::string)"layer", SegmentationParameter::NoUnit, true); + } + + /// Default constructor used by derived classes passing an existing decoder + HexGrid::HexGrid(const BitFieldCoder* decode) : Segmentation(decode) { + // define type and description + _type = "HexGridXY"; + _description = "Hexagonal segmentation in the local XY-plane"; + + // register all necessary parameters + registerParameter("stagger", "stagger mode", _stagger, 1); + registerParameter("side_length", "Cell size", _sideLength, 1., SegmentationParameter::LengthUnit); + registerParameter("offset_x", "Cell offset in X", _offsetX, 0., SegmentationParameter::LengthUnit, true); + registerParameter("offset_y", "Cell offset in Y", _offsetY, 0., SegmentationParameter::LengthUnit, true); + registerIdentifier("identifier_x", "Cell ID identifier for X", _xId, "x"); + registerIdentifier("identifier_y", "Cell ID identifier for Y", _yId, "y"); + registerParameter("stagger_keyword", "Volume ID identifier used for determining which volumes to stagger", _staggerKeyword, (std::string)"layer", SegmentationParameter::NoUnit, true); + + } + + /// Destructor + HexGrid::~HexGrid() { + } + + /// determine the position based on the cell ID + Vector3D HexGrid::position(const CellID& cID) const { + int layer=0; + if (_stagger) layer= _decoder->get(cID,_staggerKeyword); + + Vector3D cellPosition; + cellPosition.X = _decoder->get(cID,_xId )*1.5*_sideLength+_offsetX+_sideLength/2.; + cellPosition.Y = _decoder->get(cID,_yId )*std::sqrt(3)/2.*_sideLength+ _offsetY+_sideLength*std::sqrt(3)/2.; + if (_stagger==0) + cellPosition.X+=_sideLength; + else if (_stagger==1) + cellPosition.X+=(layer%3)*_sideLength; + else if (_stagger==2){ + switch (layer%4){ + case 0: + cellPosition.X-=0.75*_sideLength; + break; + case 1: + cellPosition.Y+=std::sqrt(3)/4*_sideLength; + break; + case 2: + cellPosition.Y-=std::sqrt(3)/4*_sideLength; + break; + case 3: + cellPosition.X+=0.75*_sideLength; + break; + } + } + return cellPosition; + } + + inline double positive_modulo(double i, double n) { + return std::fmod(std::fmod(i,n) + n,n); + } + + + /// determine the cell ID based on the position + CellID HexGrid::cellID(const Vector3D& localPosition, const Vector3D& /* globalPosition */, const VolumeID& vID) const { + CellID cID = vID ; + int layer=0; + if (_stagger) layer= _decoder->get(cID,_staggerKeyword); + + double x=localPosition.X-_offsetX; + double y=localPosition.Y-_offsetY; + if (_stagger==0) + x-=_sideLength; + else if (_stagger==1) + x-=(layer%3)*_sideLength; + else if (_stagger==2){ + switch (layer%4){ + case 0: + x+=0.75*_sideLength; + break; + case 1: + y-=std::sqrt(3)/4*_sideLength; + break; + case 2: + y+=std::sqrt(3)/4*_sideLength; + break; + case 3: + x-=0.75*_sideLength; + break; + } + } + + double a=positive_modulo(y/(std::sqrt(3)*_sideLength),1); + double b=positive_modulo(x/(3*_sideLength),1); + int ix = std::floor(x/(3*_sideLength/2.))+ + (b<0.5)*(-abs(a-.5)<(b-.5)*3)+(b>0.5)*(abs(a-.5)-.5<(b-1)*3); + int iy=std::floor(y/(std::sqrt(3)*_sideLength/2.)); + iy-=(ix+iy)&1; + + _decoder->set( cID,_xId, ix ); + _decoder->set( cID,_yId, iy ); + return cID ; + } + + std::vector HexGrid::cellDimensions(const CellID&) const { +#if __cplusplus >= 201103L + return {2*_sideLength, std::sqrt(3)*_sideLength}; +#else + std::vector cellDims(2,0.0); + cellDims[0] = 2*_sideLength; + cellDims[1] = std::sqrt(3)*_sideLength; + return cellDims; +#endif +} + + } /* namespace DDSegmentation */ +} /* namespace dd4hep */ + +DECLARE_SEGMENTATION(HexGrid, create_segmentation) diff --git a/DDEve/root7/WebDisplay.cpp b/DDEve/root7/WebDisplay.cpp index 27975f98f..57e835fbf 100644 --- a/DDEve/root7/WebDisplay.cpp +++ b/DDEve/root7/WebDisplay.cpp @@ -19,7 +19,11 @@ #include "ROOT/RDirectory.hxx" #if ROOT_VERSION_CODE >= ROOT_VERSION(6,27,00) #include "ROOT/RGeomViewer.hxx" -using GEOM_VIEWER = ROOT::Experimental::RGeomViewer; +# if ROOT_VERSION_CODE >= ROOT_VERSION(6,29,00) + using GEOM_VIEWER = ROOT::RGeomViewer; +# else + using GEOM_VIEWER = ROOT::Experimental::RGeomViewer; +# endif #else #include "ROOT/REveGeomViewer.hxx" using GEOM_VIEWER = ROOT::Experimental::REveGeomViewer; diff --git a/DDG4/edm4hep/Geant4Output2EDM4hep.cpp b/DDG4/edm4hep/Geant4Output2EDM4hep.cpp index 6d4acdcc2..9d9ed446d 100644 --- a/DDG4/edm4hep/Geant4Output2EDM4hep.cpp +++ b/DDG4/edm4hep/Geant4Output2EDM4hep.cpp @@ -505,7 +505,7 @@ void Geant4Output2EDM4hep::saveCollection(OutputContext& /*ctxt*/, G4VH //------------------------------------------------------------------- if( typeid( Geant4Tracker::Hit ) == coll->type().type() ){ // Create the hit container even if there are no entries! - auto& hits = m_trackerHits[colName] = edm4hep::SimTrackerHitCollection(); + auto& hits = m_trackerHits[colName]; for(unsigned i=0 ; i < nhits ; ++i){ auto sth = hits->create(); const Geant4Tracker::Hit* hit = coll->hit(i); @@ -536,8 +536,7 @@ void Geant4Output2EDM4hep::saveCollection(OutputContext& /*ctxt*/, G4VH Geant4Sensitive* sd = coll->sensitive(); int hit_creation_mode = sd->hitCreationMode(); // Create the hit container even if there are no entries! - auto& hits = m_calorimeterHits[colName] = - std::make_pair(edm4hep::SimCalorimeterHitCollection(), edm4hep::CaloHitContributionCollection()); + auto& hits = m_calorimeterHits[colName]; for(unsigned i=0 ; i < nhits ; ++i){ auto sch = hits.first->create(); const Geant4Calorimeter::Hit* hit = coll->hit(i); diff --git a/DDG4/hepmc/HepMC3FileReader.cpp b/DDG4/hepmc/HepMC3FileReader.cpp index b94897abe..d2711c817 100644 --- a/DDG4/hepmc/HepMC3FileReader.cpp +++ b/DDG4/hepmc/HepMC3FileReader.cpp @@ -130,11 +130,12 @@ HEPMC3FileReader::HEPMC3FileReader(const std::string& nam) m_reader = HepMC3::deduce_reader(nam); #if HEPMC3_VERSION_CODE >= 3002006 // to get the runInfo in the Ascii reader we have to force HepMC to read the first event - m_reader->skip(1); + HepMC3::GenEvent dummy; + m_reader->read_event(dummy); // then we get the run info (shared pointer) auto runInfo = m_reader->run_info(); - // and close the reader - m_reader->close(); + // and deallocate the reader + m_reader.reset(); // so we can open the file again from the start m_reader = HepMC3::deduce_reader(nam); // and set the run info object now diff --git a/DDG4/include/DDG4/Geant4FastSimShowerModel.h b/DDG4/include/DDG4/Geant4FastSimShowerModel.h index b158999b6..0c93e48d4 100644 --- a/DDG4/include/DDG4/Geant4FastSimShowerModel.h +++ b/DDG4/include/DDG4/Geant4FastSimShowerModel.h @@ -68,7 +68,7 @@ namespace dd4hep { ParticleConfig m_eMax { }; /// Property: Set maximum kinetic energy for particles to be killed ParticleConfig m_eKill { }; - /// Property: Set minmal kinetic energy for particles to trigger the model + /// Property: Set minimal kinetic energy for particles to trigger the model ParticleConfig m_eTriggerNames { }; /// Particle definitions for which this parametrization is applicable diff --git a/DDG4/include/DDG4/Geant4SensDetAction.h b/DDG4/include/DDG4/Geant4SensDetAction.h index a192bc366..c15040281 100644 --- a/DDG4/include/DDG4/Geant4SensDetAction.h +++ b/DDG4/include/DDG4/Geant4SensDetAction.h @@ -20,6 +20,7 @@ // Geant4 include files #include +#include // C/C++ include files #include @@ -28,7 +29,6 @@ class G4HCofThisEvent; class G4Step; class G4Event; -class G4VTouchable; class G4TouchableHistory; class G4VHitsCollection; class G4VReadOutGeometry; diff --git a/DDG4/include/DDG4/Geant4TouchableHandler.h b/DDG4/include/DDG4/Geant4TouchableHandler.h index 042f30405..0be5a58c1 100644 --- a/DDG4/include/DDG4/Geant4TouchableHandler.h +++ b/DDG4/include/DDG4/Geant4TouchableHandler.h @@ -13,13 +13,14 @@ #ifndef DDG4_GEANT4TOUCHABLEHANDLER_H #define DDG4_GEANT4TOUCHABLEHANDLER_H +#include + // C/C++ include files #include #include // Forward declarations class G4VPhysicalVolume; -class G4VTouchable; class G4Step; /// Namespace for the AIDA detector description toolkit diff --git a/DDG4/include/DDG4/Geant4VolumeManager.h b/DDG4/include/DDG4/Geant4VolumeManager.h index 6cbee9517..02027ad3e 100644 --- a/DDG4/include/DDG4/Geant4VolumeManager.h +++ b/DDG4/include/DDG4/Geant4VolumeManager.h @@ -18,8 +18,8 @@ #include #include +#include // Geant4 forward declarations -class G4VTouchable; class G4VPhysicalVolume; diff --git a/DDG4/python/DDSim/Helper/Gun.py b/DDG4/python/DDSim/Helper/Gun.py index 608b41f7c..c3cfb7cf7 100644 --- a/DDG4/python/DDSim/Helper/Gun.py +++ b/DDG4/python/DDSim/Helper/Gun.py @@ -35,7 +35,7 @@ def __init__(self): self.momentumMin = 0 * GeV self._momentumMax_EXTRA = {'help': "Maximal momentum when using distribution (default = 0.0)"} self.momentumMax = 10 * GeV - self._energy_EXTRA = {'help': "The kinetic energy for the particle gun.\n\n" + self._energy_EXTRA = {'help': "Total energy (including mass) for the particle gun.\n\n" "If not None, it will overwrite the setting of momentumMin and momentumMax"} self.energy = None diff --git a/DDG4/python/DDSim/Helper/Meta.py b/DDG4/python/DDSim/Helper/Meta.py index 7b1e2f2e9..45b406da8 100644 --- a/DDG4/python/DDSim/Helper/Meta.py +++ b/DDG4/python/DDSim/Helper/Meta.py @@ -100,6 +100,9 @@ def addParametersToRunHeader(sim): # add User import getpass - runHeader["User"] = getpass.getuser() + try: + runHeader["User"] = getpass.getuser() + except KeyError: + runHeader["User"] = str(os.getuid()) return runHeader diff --git a/DDParsers/include/Evaluator/Evaluator.h b/DDParsers/include/Evaluator/Evaluator.h index c8a331fa8..4dfa6b30f 100644 --- a/DDParsers/include/Evaluator/Evaluator.h +++ b/DDParsers/include/Evaluator/Evaluator.h @@ -56,10 +56,10 @@ namespace dd4hep { WARNING_EXISTING_VARIABLE, /**< Redefinition of existing variable */ WARNING_EXISTING_FUNCTION, /**< Redefinition of existing function */ WARNING_BLANK_STRING, /**< Empty input string */ - ERROR_NOT_A_NAME, /**< Not allowed sysmbol in the name of variable or function */ - ERROR_SYNTAX_ERROR, /**< Systax error */ + ERROR_NOT_A_NAME, /**< Not allowed symbol in the name of variable or function */ + ERROR_SYNTAX_ERROR, /**< Syntax error */ ERROR_UNPAIRED_PARENTHESIS, /**< Unpaired parenthesis */ - ERROR_UNEXPECTED_SYMBOL, /**< Unexpected sysbol */ + ERROR_UNEXPECTED_SYMBOL, /**< Unexpected symbol */ ERROR_UNKNOWN_VARIABLE, /**< Non-existing variable */ ERROR_UNKNOWN_FUNCTION, /**< Non-existing function */ ERROR_EMPTY_PARAMETER, /**< Function call has empty parameter */ diff --git a/DDParsers/src/Evaluator/Evaluator.cpp b/DDParsers/src/Evaluator/Evaluator.cpp index 5beb6626c..070b2fe0c 100644 --- a/DDParsers/src/Evaluator/Evaluator.cpp +++ b/DDParsers/src/Evaluator/Evaluator.cpp @@ -545,7 +545,7 @@ static int engine(char const* begin, char const* end, double & result, iWhat = SyntaxTable[iPrev][iCur]; iPrev = iCur; switch (iWhat) { - case 0: // systax error + case 0: // syntax error EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer ); case 1: // operand: number, variable, function EVAL_STATUS = operand(pointer, end, value, pointer, dictionary); diff --git a/DDTest/python/userSteeringFile.PY b/DDTest/python/userSteeringFile.PY index e21e6e66c..11a8eee6e 100644 --- a/DDTest/python/userSteeringFile.PY +++ b/DDTest/python/userSteeringFile.PY @@ -211,7 +211,7 @@ SIM.gun.direction = (0, 0, 1) ## SIM.gun.distribution = None -## The kinetic energy for the particle gun. +## Total energy (including mass) for the particle gun. ## ## If not None, it will overwrite the setting of momentumMin and momentumMax SIM.gun.energy = None diff --git a/UtilityApps/src/dumpBfield.cpp b/UtilityApps/src/dumpBfield.cpp index 39d8fb65a..1b582c2d3 100644 --- a/UtilityApps/src/dumpBfield.cpp +++ b/UtilityApps/src/dumpBfield.cpp @@ -29,8 +29,9 @@ using namespace dd4hep::detail; static int invoke_dump_B_field(int argc, char** argv ){ if( argc != 8 ) { - std::cout << " usage: dumpBfield compact.xml x y z dx dy dz [in cm]" << std::endl - << " will dump the B-field in volume [-x:x,-y:y,-z,z] with steps [dx,dy,dz] " + std::cout << " usage: dumpBfield compact.xml xmin[:xmax] ymin[:ymax] zmin[:zmax] dx dy dz [in cm]" << std::endl + << " will dump the B-field in volume (xmin:xmax, ymin:ymax, zmin:zmax) with steps (dx,dy,dz). All values are in cm." + << " If a single value is given for a range, symmetric boundaries are used" << std::endl ; exit(1) ; @@ -41,12 +42,56 @@ static int invoke_dump_B_field(int argc, char** argv ){ std::stringstream sstr ; sstr << argv[2] << " " << argv[3] << " " << argv[4] << " " << argv[5] << " " << argv[6] << " " << argv[7] ; - float xRange , yRange , zRange , dx , dy, dz ; - sstr >> xRange >> yRange >> zRange >> dx >> dy >> dz; + std::string RangeX , RangeY , RangeZ; + float dx , dy, dz ; - xRange *= dd4hep::cm; - yRange *= dd4hep::cm; - zRange *= dd4hep::cm; + sstr >> RangeX >> RangeY >> RangeZ >> dx >> dy >> dz; + + size_t colon_posX = RangeX.find(':'); + size_t colon_posY = RangeY.find(':'); + size_t colon_posZ = RangeZ.find(':'); + + float minX=0, maxX=0, minY=0, maxY=0, minZ=0, maxZ=0; + + if( colon_posX == std::string::npos ) { + std::cout << "X Interval not specified as xmin:xmax" << std::endl + << " setting xmin = -xmax " << std::endl; + maxX = std::stof( RangeX ); + minX = -maxX; + } + else { + minX = std::stof( RangeX.substr(0, colon_posX) ); + maxX = std::stof( RangeX.substr(colon_posX+1) ); + } + + if( colon_posY == std::string::npos ) { + std::cout << "Y Interval not specified as ymin:ymax" << std::endl + << " setting ymin = -ymax " << std::endl; + maxY = std::stof( RangeY ); + minY = -maxY; + } + else { + minY = std::stof( RangeY.substr(0, colon_posY) ); + maxY = std::stof( RangeY.substr(colon_posY+1) ); + } + +if( colon_posZ == std::string::npos ) { + std::cout << "Z Interval not specified as zmin:zmax" << std::endl + << " setting zmin = -zmax " << std::endl; + maxZ = std::stof( RangeZ ); + minZ = -maxZ; + } + else { + minZ = std::stof( RangeZ.substr(0, colon_posZ) ); + maxZ = std::stof( RangeZ.substr(colon_posZ+1) ); + } + + minX *= dd4hep::cm; + maxX *= dd4hep::cm; + minY *= dd4hep::cm; + maxY *= dd4hep::cm; + minZ *= dd4hep::cm; + maxZ *= dd4hep::cm; dx *= dd4hep::cm; dy *= dd4hep::cm; dz *= dd4hep::cm; @@ -57,9 +102,9 @@ static int invoke_dump_B_field(int argc, char** argv ){ printf("#######################################################################################################\n"); printf(" x[cm] y[cm] z[cm] Bx[Tesla] By[Tesla] Bz[Tesla] \n"); - for( float x = -xRange ; x <=xRange ; x += dx ){ - for( float y = -yRange ; y <=yRange ; y += dy ){ - for( float z = -zRange ; z <=zRange ; z += dz ){ + for( float x = minX ; x <= maxX ; x += dx ){ + for( float y = minY ; y <= maxY ; y += dy ){ + for( float z = minZ ; z <= maxZ ; z += dz ){ double posV[3] = { x, y, z } ; double bfieldV[3] ; diff --git a/cmake/DD4hepBuild.cmake b/cmake/DD4hepBuild.cmake index ab12d75a7..bcd3407f7 100644 --- a/cmake/DD4hepBuild.cmake +++ b/cmake/DD4hepBuild.cmake @@ -826,7 +826,11 @@ MACRO(DD4HEP_SETUP_GEANT4_TARGETS) if(Geant4_builtin_clhep_FOUND) dd4hep_debug("Using Geant4 internal CLHEP") - ADD_LIBRARY(CLHEP::CLHEP INTERFACE IMPORTED GLOBAL) + if(TARGET CLHEP::CLHEP) + message(WARNING "CLHEP::CLHEP already exists, this may cause problems if there are two different installations of CLHEP, one from Geant4 and one external") + else() + ADD_LIBRARY(CLHEP::CLHEP INTERFACE IMPORTED GLOBAL) + endif() SET_TARGET_PROPERTIES(CLHEP::CLHEP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${Geant4_INCLUDE_DIRS}" diff --git a/examples/ClientTests/compact/IncludePlugins.xml b/examples/ClientTests/compact/IncludePlugins.xml index b527abfb0..08a00248b 100644 --- a/examples/ClientTests/compact/IncludePlugins.xml +++ b/examples/ClientTests/compact/IncludePlugins.xml @@ -42,6 +42,10 @@ + + + + diff --git a/examples/ClientTests/compact/visTest.xml b/examples/ClientTests/compact/visTest.xml new file mode 100644 index 000000000..0fb65e56b --- /dev/null +++ b/examples/ClientTests/compact/visTest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/ClientTests/compact/visTestEx.xml b/examples/ClientTests/compact/visTestEx.xml new file mode 100644 index 000000000..b6995e3b7 --- /dev/null +++ b/examples/ClientTests/compact/visTestEx.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/ClientTests/scripts/SiliconBlockGFlash.py b/examples/ClientTests/scripts/SiliconBlockGFlash.py index 732150184..a07c331a4 100644 --- a/examples/ClientTests/scripts/SiliconBlockGFlash.py +++ b/examples/ClientTests/scripts/SiliconBlockGFlash.py @@ -100,6 +100,7 @@ def run(): model.Enable = True # Energy boundaries are optional: Units are GeV model.Emin = {'e+': 0.1 * GeV, 'e-': 0.1 * GeV} + model.Emax = {'e+': 100 * GeV, 'e-': 100 * GeV} model.Ekill = {'e+': 0.1 * MeV, 'e-': 0.1 * MeV} model.enableUI() seq.adopt(model) diff --git a/examples/ClientTests/scripts/visTest.C b/examples/ClientTests/scripts/visTest.C new file mode 100644 index 000000000..d9ddce226 --- /dev/null +++ b/examples/ClientTests/scripts/visTest.C @@ -0,0 +1,110 @@ +#include "TROOT.h" +#include "TColor.h" +#include "TGeoCone.h" +#include "TGeoMatrix.h" +#include "TGeoManager.h" +#include "TGeoElement.h" +#include "TGeoMaterial.h" + +#include + + +class Test { +public: + TGeoManager* m_manager = nullptr; + TGeoMaterial* m_vacuum = nullptr; + TGeoMedium* m_air = nullptr; + + TGeoBBox* m_worldShape = nullptr; + TGeoVolume* m_world = nullptr; + + struct Cone { + TGeoMaterial* material = nullptr; + TGeoMedium* medium = nullptr; + TGeoConeSeg* shape = nullptr; + TGeoVolume* volume = nullptr; + TGeoNode* place = nullptr; + void set_color(const char* typ, Float_t alpha, Float_t red, Float_t green, Float_t blue) { + Int_t col = TColor::GetColor(red, green, blue); + TColor* color = gROOT->GetColor(col); + if ( !color ) { + ::printf("+++ %s Failed to allocate Color: r:%02X g:%02X b:%02X\n", + typ, int(red*255.), int(green*255.), int(blue*255)); + } + char text[64]; + ::snprintf(text, sizeof(text), "%p", this); + TColor* colortr = new TColor(gROOT->GetListOfColors()->GetLast()+1, + color->GetRed(), color->GetGreen(), color->GetBlue(), text, alpha); + //colortr->SetAlpha(alpha); + + ::printf("Plot cone %s (col: %d) with transparency %8.3f r:%02X g:%02X b:%02X\n", + typ, col, (1.0-alpha)*100, int(red*255.), int(green*255.), int(blue*255)); + + /// Propagate values to the volume: + int col_num = color->GetNumber(); + int col_tr_num = colortr->GetNumber(); + volume->SetVisibility(kTRUE); + volume->SetVisContainers(kTRUE); + volume->SetVisDaughters(kTRUE); + volume->SetLineWidth(10); + volume->SetFillStyle(1001); + volume->ResetTransparency((1.0-alpha)*100); + volume->SetLineStyle(1); + + /// Set line color + volume->SetLineColor(col_num); + /// Set fill color + volume->SetFillColor(col_tr_num); + } + } cone1, cone2; + +public: + Test() { + } + virtual ~Test() { + } + void build(int version); +}; + +void Test::build(int version) { + m_manager = new TGeoManager("geom","Tube test"); + m_vacuum = new TGeoMaterial("vacuum", 0, 0, 0); + m_air = new TGeoMedium("Vacuum", 0, m_vacuum); + + m_worldShape = new TGeoBBox("WorldBox", 100, 100, 100); + m_world = new TGeoVolume("World", m_worldShape, m_air); + + cone1.material = new TGeoMaterial("Fe1", 55.845, 26, 7.87); + cone1.medium = new TGeoMedium("Iron1", 1, cone1.material); + cone1.shape = new TGeoConeSeg("Cone1Shape", 40, 0e0, 20e0, 0e0, 20e0, 0e0, 360e0); + cone1.volume = new TGeoVolume("Cone1", cone1.shape, cone1.medium); + cone1.set_color("Cone1", + version ? 0.1 : 0.9, + version ? 1e0 : 0e0, + 0e0, + version ? 0e0 : 1e0); + m_world->AddNode(cone1.volume, 1, new TGeoTranslation(-30, -30, 0)); + + cone2.material = version ? new TGeoMaterial("Fe2", 55.845, 26, 7.87) : cone1.material; + cone2.medium = version ? new TGeoMedium("Iron2", 1, cone2.material) : cone1.medium; + cone2.shape = new TGeoConeSeg("Cone2Shape", 40, 0e0, 20e0, 0e0, 20e0, 0e0, 360e0); + cone2.volume = new TGeoVolume("Cone2", cone2.shape, cone2.medium); + cone2.set_color("Cone2", + version ? 0.9 : 0.1, + version ? 0e0 : 0.9, + 0e0, + version ? 0.9 : 0e0); + m_world->AddNode(cone2.volume, 1, new TGeoTranslation(30, 30, 0)); + + m_manager->SetTopVolume(m_world); + m_manager->SetTopVisible(0); + + m_manager->GetTopVolume()->Draw("ogl"); +} + + +Test* visTest(int version=0) { + Test* obj = new Test(); + obj->build(version); + return obj; +} diff --git a/examples/DDCAD/CMakeLists.txt b/examples/DDCAD/CMakeLists.txt index 91f2d8a2f..0d9e38ec7 100644 --- a/examples/DDCAD/CMakeLists.txt +++ b/examples/DDCAD/CMakeLists.txt @@ -72,7 +72,7 @@ endforeach() # # Multi-shape tests # Not working: OBJ_spider -list(APPEND DDCAD_Tests_MV COB_dwarf MS3D_jeep) +list(APPEND DDCAD_Tests_MV COB_dwarf MS3D_jeep RelativePath) foreach (test ${DDCAD_Tests_MV}) dd4hep_add_test_reg( DDCAD_Check_Shape_${test} COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_DDCAD.sh" diff --git a/examples/DDCAD/compact/Check_Shape_RelativePath.xml b/examples/DDCAD/compact/Check_Shape_RelativePath.xml new file mode 100644 index 000000000..39b1627b2 --- /dev/null +++ b/examples/DDCAD/compact/Check_Shape_RelativePath.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + +