Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /DD4hep/DDCore/src/plugins/DetectorChecksum.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework includes
0015 #include <DD4hep/Plugins.h>
0016 #include <DD4hep/Printout.h>
0017 #include <DD4hep/FieldTypes.h>
0018 #include <DD4hep/DetectorTools.h>
0019 #include <DD4hep/MatrixHelpers.h>
0020 #include <DD4hep/AlignmentData.h>
0021 #include <DD4hep/DetFactoryHelper.h>
0022 #include <DD4hep/detail/ObjectsInterna.h>
0023 #include <DD4hep/detail/DetectorInterna.h>
0024 #include "DetectorChecksum.h"
0025 
0026 // ROOT includes
0027 #include <TROOT.h>
0028 #include <TClass.h>
0029 #include <TColor.h>
0030 #include <TGeoBoolNode.h>
0031 #include <TGeoSystemOfUnits.h>
0032 
0033 // C/C++ include files
0034 #include <iostream>
0035 #include <sstream>
0036 #include <fstream>
0037 #include <iomanip>
0038 #include <cfloat>
0039 #include <cfenv>
0040 
0041 using namespace dd4hep;
0042 using DetectorChecksum = dd4hep::detail::DetectorChecksum;
0043 
0044 namespace {
0045   
0046   bool is_volume(const TGeoVolume* volume)  {
0047     Volume v(volume);
0048     return v.data() != 0;
0049   }
0050   inline double check_null(double d)   {
0051     if ( fabs(d) < 1e-12 )
0052       return 0e0;
0053     else
0054       return d;
0055   }
0056   template <typename O, typename C, typename F> void handle(const O* o, const C& c, F pmf) {
0057     for (typename C::const_iterator i = c.begin(); i != c.end(); ++i) {
0058       (o->*pmf)(*i);
0059     }
0060   }
0061   template <typename T>
0062   void _do_output(const std::string& title, bool reorder, bool with_file, bool have_hash, const T& container)   {
0063     std::ofstream out;
0064     std::string tit = title + ":";
0065     char delim = have_hash ? '\'' : ' ';
0066     std::string fname = title + "s.txt";
0067 
0068     if ( with_file )  {
0069       out.open(fname, std::ios::out);
0070     }
0071     if ( reorder )   {
0072       std::map<DetectorChecksum::hash_t, const DetectorChecksum::entry_t*> m;
0073       for(const auto& e : container)
0074         m.emplace(e.second.hash, &e.second);
0075 
0076       for(const auto& e : m)   {
0077         auto data = format(nullptr, "+++ %-12s0x%016lx %c%s%c",
0078                            tit.c_str(), e.second->hash, delim, have_hash ? e.second->data.c_str() : "", delim);
0079         printout(ALWAYS, "DetectorChecksum", data.c_str());
0080         if ( with_file ) out << data << std::endl;
0081       }
0082       return;
0083     }
0084     for(const auto& e : container)   {
0085       auto data = format(nullptr, "+++ %-12s0x%016lx %c%s%c",
0086                          tit.c_str(), e.second.hash, delim, have_hash ? e.second.data.c_str() : "", delim);
0087       printout(ALWAYS, "DetectorChecksum", data.c_str());
0088       if ( with_file ) out << data << std::endl;
0089     }
0090   }
0091   template <typename T>
0092   void _do_output_name(const std::string& title, bool reorder, bool with_file, bool have_hash, const T& container)   {
0093     std::ofstream out;
0094     std::string tit = title + ":";
0095     char delim = have_hash ? '\'' : ' ';
0096     std::string fname = title + "s.txt";
0097 
0098     if ( with_file )  {
0099       out.open(fname, std::ios::out);
0100     }
0101     if ( reorder )   {
0102       std::map<DetectorChecksum::hash_t, const DetectorChecksum::entry_t*> m;
0103       std::map<DetectorChecksum::hash_t, typename T::key_type> v;
0104       for(const auto& e : container)  {
0105         v.emplace(e.second.hash, e.first);
0106         m.emplace(e.second.hash, &e.second);
0107       }
0108       for(const auto& e : m)   {
0109         auto data = format(nullptr, "+++ %-12s0x%016lx %-32s %c%s%c",
0110                            tit.c_str(), e.second->hash, v[e.first].name(),
0111                            delim, have_hash ? e.second->data.c_str() : "", delim);
0112         printout(ALWAYS, "DetectorChecksum", data.c_str());
0113         if ( with_file ) out << data << std::endl;
0114       }
0115       return;
0116     }
0117     for(const auto& e : container)   {
0118       auto data = format(nullptr, "+++ %-12s0x%016lx %-32s %c%s%c",
0119                          tit.c_str(), e.second.hash, e.first.name(),
0120                          delim, have_hash ? e.second.data.c_str() : "", delim);
0121       printout(ALWAYS, "DetectorChecksum", data.c_str());
0122       if ( with_file ) out << data << std::endl;
0123     }
0124   }
0125 }
0126 
0127 /// Initializing Constructor
0128 DetectorChecksum::DetectorChecksum(Detector& description)
0129   : m_detDesc(description), m_dataPtr(0) {
0130 }
0131 
0132 DetectorChecksum::~DetectorChecksum() {
0133   if (m_dataPtr)
0134     delete m_dataPtr;
0135   m_dataPtr = 0;
0136 }
0137 
0138 template <typename T> std::string DetectorChecksum::refName(T handle)  const  {
0139   std::string nam = handle->GetName();
0140   std::size_t idx = nam.find("_0x");
0141   if ( idx == std::string::npos ) return nam;
0142   return nam.substr(0, idx);
0143 }
0144 
0145 template <> std::string DetectorChecksum::refName(Segmentation handle)  const  {
0146   std::string nam = handle->name();
0147   std::size_t idx = nam.find("_0x");
0148   if ( idx == std::string::npos ) return nam;
0149   return nam.substr(0, idx);
0150 }
0151 
0152 template <typename T> std::string DetectorChecksum::attr_name(T handle)  const  {
0153   std::string n = " name=\"" + refName(handle)+"\"";
0154   return n;
0155 }
0156 
0157 std::stringstream DetectorChecksum::logger()   const    {
0158   std::stringstream log;
0159   log.setf(std::ios::fixed, std::ios::floatfield);
0160   log << std::setprecision(precision);
0161   return log;
0162 }
0163 
0164 DetectorChecksum::entry_t DetectorChecksum::make_entry(std::stringstream& log)   const {
0165   std::string data(log.str());
0166   hash_t hash_value = hash64(data.c_str(), data.length());
0167   if ( have_hash_strings )
0168     return { hash_value, std::move(data) };
0169   return { hash_value, std::string("") };
0170 }
0171 
0172 void DetectorChecksum::configure()   {
0173   m_len_unit = _toDouble(m_len_unit_nam);
0174   m_ang_unit = _toDouble(m_ang_unit_nam)/_toDouble("deg/rad");
0175   m_ene_unit = _toDouble(m_ene_unit_nam);
0176   m_densunit = _toDouble(m_densunit_nam)/_toDouble("g/cm3");  // g/cm3  is always internal unit of TGeo
0177   m_atomunit = _toDouble(m_atomunit_nam)/_toDouble("g/mole"); // g/mole is always internal unit of TGeo
0178   if ( debug > 1 )   {
0179     printout(INFO,"DetectorChecksum","+++ Float precision: %d", precision);
0180     printout(INFO,"DetectorChecksum","+++ Unit of length:  %-12s -> conversion factor: %f", m_len_unit_nam.c_str(), m_len_unit);
0181     printout(INFO,"DetectorChecksum","+++ Unit of angle:   %-12s -> conversion factor: %f", m_ang_unit_nam.c_str(), m_ang_unit);
0182     printout(INFO,"DetectorChecksum","+++ Unit of energy:  %-12s -> conversion factor: %f", m_ene_unit_nam.c_str(), m_ene_unit);
0183     printout(INFO,"DetectorChecksum","+++ Unit of density: %-12s -> conversion factor: %f", m_densunit_nam.c_str(), m_densunit);
0184     printout(INFO,"DetectorChecksum","+++ Unit of density: %-12s -> conversion factor: %f", m_atomunit_nam.c_str(), m_atomunit);
0185   }
0186 }
0187 
0188 /// Dump element in GDML format to output stream
0189 const DetectorChecksum::entry_t& DetectorChecksum::handleElement(Atom element) const {
0190   auto& geo = data().mapOfElements;
0191   auto  iel = geo.find(element);
0192   if ( iel == geo.end() )   {
0193     if ( element->HasIsotopes() )   {
0194       except("DetectorChecksum","%s: Atoms with isotopes not implemented", element.name());
0195     }
0196     else   {
0197       std::stringstream log = logger();
0198       log << "<element"         << attr_name(element)
0199           << " Z=\""            << element->Z()   << "\""
0200           << " formula=\""      << element.name() << "\""
0201           << ">" << newline
0202           << " <atom unit=\""   << m_atomunit_nam 
0203           << "\" value=\""      << std::scientific << element->A()/m_atomunit << "\"/>" << newline
0204           << "</element>";
0205       iel = geo.emplace(element, make_entry(log) ).first;
0206     }
0207   }
0208   return iel->second;
0209 }
0210 
0211 /// Dump material in GDML format to output stream
0212 const DetectorChecksum::entry_t& DetectorChecksum::handleMaterial(Material medium) const {
0213   auto& geo = data().mapOfMaterials;
0214   auto  ima = geo.find(medium);
0215   if ( ima == geo.end() )   {
0216     std::stringstream log = logger();
0217     auto* mat = medium->GetMaterial();
0218     log << "<material"   << attr_name(medium) << "\"/>" << newline;
0219     if ( mat->IsMixture() )   {
0220       std::map<std::string, double>  elts;
0221       TGeoMixture* mix = (TGeoMixture*)mat;
0222       int count_elts = mix->GetNelements();
0223       for ( Int_t idx = 0; idx < count_elts; idx++ )
0224         elts[refName(mix->GetElement(idx))] = mix->GetWmixt()[idx];
0225       log << " <elements count=\""<< count_elts << "\">" << newline;
0226       for( const auto& w : elts )
0227         log << " <fraction ref=\"" << w.first << "\" n=\"" << w.second << "\">" << newline;
0228       log << " </elements>" << newline;
0229     }
0230     else   {
0231       log << " A=\""          << mat->GetA()                  << "\""
0232           << " Z=\""          << mat->GetZ()                  << "\">" << newline
0233           << " <element=\""   << refName(mat->GetElement())   << "\"/>" << newline
0234           << " <atom unit=\"" << m_atomunit_nam << "\" value=\"" << mat->GetA()/m_atomunit << "\"/>" << newline;
0235     }
0236     log << " <D unit=\"" << m_densunit_nam << "\" value=\"" << mat->GetDensity()/m_densunit << "\"/>" << newline;
0237     log << "</material>";
0238     ima = geo.emplace(medium, make_entry(log)).first;
0239   }
0240   return ima->second;
0241 }
0242 
0243 /// Dump solid in GDML format to output stream
0244 const DetectorChecksum::entry_t& DetectorChecksum::handleSolid(Solid solid) const {
0245   auto& geo = data().mapOfSolids;
0246   auto  iso = geo.find(solid);
0247   if ( iso == geo.end() )   {
0248     const TGeoShape* shape = solid.ptr();
0249     auto  log = logger();
0250 
0251     if ( !shape )  {
0252       log << "<shape type=\"INVALID\"></shape>)";
0253       iso = geo.emplace(solid, make_entry(log)).first;
0254       return iso->second;
0255     }
0256 
0257     // NOTE: We cannot use the name when creating the hash!
0258     // The name is artificially assigned and contains the shape pointer.
0259     // This causes havoc.
0260     TClass*     cl  = shape->IsA();
0261     std::string nam = "";//attr_name(solid);
0262     if ( cl == TGeoBBox::Class() )   {
0263       TGeoBBox* sh = (TGeoBBox*) shape;
0264       log << "<box" << nam
0265           << " lunit=\"" << m_len_unit_nam << "\""
0266           << " x=\"" << 2.0*sh->GetDX()/m_len_unit << "\""
0267           << " y=\"" << 2.0*sh->GetDY()/m_len_unit << "\""
0268           << " z=\"" << 2.0*sh->GetDZ()/m_len_unit << "\""
0269           << "/>";
0270     }
0271     else if ( cl == TGeoHalfSpace::Class() ) {
0272       TGeoHalfSpace* sh = (TGeoHalfSpace*)(const_cast<TGeoShape*>(shape));
0273       const auto& pnt = sh->GetPoint();
0274       const auto& nrm = sh->GetNorm();
0275       log << "<halfspace" << nam
0276           << " lunit=\"" << m_len_unit_nam << "\">" << newline
0277           << " <point x=\""        << pnt[0]/m_len_unit << "\""
0278           << " y=\""               << pnt[1]/m_len_unit << "\""
0279           << " z=\""               << pnt[2]/m_len_unit << "\"/>" << newline
0280           << " <normal x=\""       << nrm[0]/m_len_unit << "\""
0281           << " y=\""               << nrm[1]/m_len_unit << "\""
0282           << " z=\""               << nrm[2]/m_len_unit << "\"/>" << newline
0283           << "</halfspace>";
0284     }
0285     else if ( cl == TGeoTube::Class() || cl == TGeoTubeSeg::Class() ) {
0286       const TGeoTube* sh = (const TGeoTube*) shape;
0287       log << "<tube" << nam
0288           << " lunit=\""    << m_len_unit_nam           << "\""
0289           << " aunit=\""    << m_ang_unit_nam           << "\""
0290           << " rmin=\""     << check_null(sh->GetRmin()/m_len_unit) << "\""
0291           << " rmax=\""     << check_null(sh->GetRmax()/m_len_unit) << "\""
0292           << " dz=\""       << check_null(2*sh->GetDz()/m_len_unit) << "\""
0293           << " startphi=\"" << 0.0                 << "\""
0294           << " deltaphi=\"" << 360.0/m_ang_unit         << "\""
0295           << "/>";
0296     }
0297     else if ( cl == TGeoTubeSeg::Class() ) {
0298       const TGeoTubeSeg* sh = (const TGeoTubeSeg*) shape;
0299       log << "<tube" << nam
0300           << " lunit=\""    << m_len_unit_nam             << "\""
0301           << " aunit=\""    << m_ang_unit_nam             << "\""
0302           << " rmin=\""     << check_null(sh->GetRmin()/m_len_unit) << "\""
0303           << " rmax=\""     << check_null(sh->GetRmax()/m_len_unit) << "\""
0304           << " dz=\""       << check_null(2*sh->GetDz()/m_len_unit) << "\""
0305           << " startphi=\"" << sh->GetPhi1()/m_ang_unit   << "\""
0306           << " deltaphi=\"" << (sh->GetPhi2() - sh->GetPhi1())/m_ang_unit << "\""
0307           << "/>";
0308     }
0309     else if ( cl == TGeoCtub::Class() ) {
0310       const TGeoCtub* sh = (const TGeoCtub*) shape;
0311       const Double_t* hi = sh->GetNhigh();
0312       const Double_t* lo = sh->GetNlow();
0313       log << "<cutTube" << nam
0314           << " lunit=\""    << m_len_unit_nam             << "\""
0315           << " aunit=\""    << m_ang_unit_nam             << "\""
0316           << " rmin=\""     << sh->GetRmin()/m_len_unit   << "\""
0317           << " rmax=\""     << sh->GetRmax()/m_len_unit   << "\""
0318           << " dz=\""       << 2*sh->GetDz()/m_len_unit   << "\""
0319           << " startphi=\"" << sh->GetPhi1()/m_ang_unit   << "\""
0320           << " deltaphi=\"" << (sh->GetPhi2() - sh->GetPhi1())/m_ang_unit << "\""
0321           << " lowX=\""     << lo[0]/m_len_unit           << "\""
0322           << " lowY=\""     << lo[1]/m_len_unit           << "\""
0323           << " lowZ=\""     << lo[2]/m_len_unit           << "\""
0324           << " highX=\""    << hi[0]/m_len_unit           << "\""
0325           << " highY=\""    << hi[1]/m_len_unit           << "\""
0326           << " highZ=\""    << hi[2]/m_len_unit           << "\""
0327           << "/>";
0328     }
0329     else if ( cl == TGeoEltu::Class() ) {
0330       const TGeoEltu* sh = (const TGeoEltu*) shape;
0331       log << "<eltube" << nam
0332           << " lunit=\""  << m_len_unit_nam             << "\""
0333           << " dx=\""     << sh->GetA()/m_len_unit      << "\""
0334           << " dy=\""     << sh->GetB()/m_len_unit      << "\""
0335           << " dz=\""     << sh->GetDz()/m_len_unit     << "\""
0336           << "/>";
0337     }
0338     else if ( cl == TGeoTrd1::Class() ) {
0339       const TGeoTrd1* sh = (const TGeoTrd1*) shape;
0340       log << "<trd" << nam
0341           << " lunit=\""  << m_len_unit_nam             << "\""
0342           << " x1=\""     << 2*check_null(sh->GetDx1()/m_len_unit)  << "\""
0343           << " x2=\""     << 2*check_null(sh->GetDx2()/m_len_unit)  << "\""
0344           << " y1=\""     << 2*check_null(sh->GetDy()/m_len_unit)   << "\""
0345           << " y2=\""     << 2*check_null(sh->GetDy()/m_len_unit)   << "\""
0346           << " z=\""      << 2*check_null(sh->GetDz()/m_len_unit)   << "\""
0347           << "/>";
0348     }
0349     else if ( cl == TGeoTrd2::Class() ) {
0350       const TGeoTrd2* sh = (const TGeoTrd2*) shape;
0351       log << "<trd" << nam
0352           << " lunit=\""  << m_len_unit_nam             << "\""
0353           << " x1=\""     << 2*check_null(sh->GetDx1()/m_len_unit)  << "\""
0354           << " x2=\""     << 2*check_null(sh->GetDx2()/m_len_unit)  << "\""
0355           << " y1=\""     << 2*check_null(sh->GetDy1()/m_len_unit)  << "\""
0356           << " y2=\""     << 2*check_null(sh->GetDy2()/m_len_unit)  << "\""
0357           << " z=\""      << 2*check_null(sh->GetDz()/m_len_unit)   << "\""
0358           << "/>";
0359     }
0360     else if ( cl == TGeoTrap::Class() )   {
0361       const TGeoTrap* sh = (const TGeoTrap*) shape;
0362       log << "<trap" << nam
0363           << " lunit=\""  << m_len_unit_nam             << "\""
0364           << " aunit=\""  << m_ang_unit_nam             << "\""
0365           << " z=\""      << check_null(2*sh->GetDz()/m_len_unit)   << "\""
0366           << " theta=\""  << check_null(sh->GetTheta()/m_ang_unit)  << "\""
0367           << " phi=\""    << check_null(sh->GetPhi()/m_ang_unit)    << "\""
0368           << " x1=\""     << check_null(2*sh->GetBl1()/m_len_unit)  << "\""
0369           << " x2=\""     << check_null(2*sh->GetTl1()/m_len_unit)  << "\""
0370           << " x3=\""     << check_null(2*sh->GetBl2()/m_len_unit)  << "\""
0371           << " x4=\""     << check_null(2*sh->GetTl2()/m_len_unit)  << "\""
0372           << " y1=\""     << check_null(2*sh->GetH1()/m_len_unit)   << "\""
0373           << " y2=\""     << check_null(2*sh->GetH2()/m_len_unit)   << "\""
0374           << " alpha1=\"" << check_null(sh->GetAlpha1()/m_ang_unit) << "\""
0375           << " alpha2=\"" << check_null(sh->GetAlpha2()/m_ang_unit) << "\""
0376           << "/>";
0377     }
0378     else if ( cl == TGeoHype::Class() )   {
0379       const TGeoHype* sh = (const TGeoHype*) shape;
0380       log << "<hype" << nam
0381           << " lunit=\""  << m_len_unit_nam             << "\""
0382           << " aunit=\""  << m_ang_unit_nam             << "\""
0383           << " rmin=\""   << check_null(sh->GetRmin()/m_len_unit)   << "\""
0384           << " rmax=\""   << check_null(sh->GetRmax()/m_len_unit)   << "\""
0385           << " inst=\""   << check_null(sh->GetStIn()/m_ang_unit)   << "\""
0386           << " outst=\""  << check_null(sh->GetStOut()/m_ang_unit)  << "\""
0387           << " z=\""      << check_null(2*sh->GetDz()/m_len_unit)   << "\""
0388           << "/>";
0389     }
0390     else if ( cl == TGeoPgon::Class() )   {
0391       const TGeoPgon* sh = (const TGeoPgon*) shape;
0392       log << "<polyhedra" << nam
0393           << " lunit=\""  << m_len_unit_nam             << "\""
0394           << " aunit=\""  << m_ang_unit_nam             << "\""
0395           << " startphi=\"" << check_null(sh->GetPhi1()/m_ang_unit) << "\""
0396           << " deltaphi=\"" << check_null(sh->GetDphi()/m_ang_unit) << "\""
0397           << " numsides=\"" << sh->GetNedges()     << "\">" << newline;
0398       for(int i=0, n=sh->GetNz(); i<n; ++i)  {
0399         log << " <zplane z=\"" << check_null(sh->GetZ(i)/m_len_unit) 
0400             << "\" rmin=\"" << check_null(sh->GetRmin(i)/m_len_unit) << "\""
0401             << "\" rmax=\"" << check_null(sh->GetRmax(i)/m_len_unit) << "\"/>" << newline;
0402       }
0403       log << "</polyhedra>";
0404     }
0405     else if ( cl == TGeoPcon::Class() )  {
0406       const TGeoPcon* sh = (const TGeoPcon*) shape;
0407       log << "<polycone" << nam
0408           << " lunit=\""  << m_len_unit_nam             << "\""
0409           << " aunit=\""  << m_ang_unit_nam             << "\""
0410           << " startphi=\"" << check_null(sh->GetPhi1()/m_ang_unit) << "\""
0411           << " deltaphi=\"" << check_null(sh->GetDphi()/m_ang_unit) << "\">" << newline;
0412       for(int i=0, n=sh->GetNz(); i<n; ++i)  {
0413         log << " <zplane z=\"" << check_null(sh->GetZ(i)/m_len_unit) 
0414             << "\" rmin=\"" << check_null(sh->GetRmin(i)/m_len_unit) << "\""
0415             << "\" rmax=\"" << check_null(sh->GetRmax(i)/m_len_unit) << "\"/>" << newline;
0416       }
0417       log << "</polycone>";
0418     }
0419     else if ( cl == TGeoCone::Class() )  {
0420       const TGeoCone* sh = (const TGeoCone*) shape;
0421       log << "<cone" << nam
0422           << " lunit=\""  << m_len_unit_nam             << "\""
0423           << " aunit=\""  << m_ang_unit_nam             << "\""
0424           << " rmin1=\""  << check_null(sh->GetRmin1()/m_len_unit)  << "\""
0425           << " rmin2=\""  << check_null(sh->GetRmin2()/m_len_unit)  << "\""
0426           << " rmax1=\""  << check_null(sh->GetRmax1()/m_len_unit)  << "\""
0427           << " rmax2=\""  << check_null(sh->GetRmax2()/m_len_unit)  << "\""
0428           << " z=\""      << check_null(sh->GetDz()/m_len_unit)     << "\""
0429           << " startphi=\"" << 0.0/m_ang_unit           << "\""
0430           << " deltaphi=\"" << 360.0/m_ang_unit         << "\""
0431           << "/>";
0432     }
0433     else if ( cl == TGeoConeSeg::Class() )  {
0434       const TGeoConeSeg* sh = (const TGeoConeSeg*) shape;
0435       log << "<cone" << nam
0436           << " lunit=\""  << m_len_unit_nam             << "\""
0437           << " aunit=\""  << m_ang_unit_nam             << "\""
0438           << " rmin1=\""  << check_null(sh->GetRmin1()/m_len_unit)  << "\""
0439           << " rmin2=\""  << check_null(sh->GetRmin2()/m_len_unit)  << "\""
0440           << " rmax1=\""  << check_null(sh->GetRmax1()/m_len_unit)  << "\""
0441           << " rmax2=\""  << check_null(sh->GetRmax2()/m_len_unit)  << "\""
0442           << " z=\""      << check_null(sh->GetDz()/m_len_unit)     << "\""
0443           << " startphi=\"" << check_null(sh->GetPhi1()/m_ang_unit) << "\""
0444           << " deltaphi=\"" << check_null((sh->GetPhi1()-sh->GetPhi1())/m_ang_unit) << "\""
0445           << "/>";
0446     }
0447     else if ( cl == TGeoParaboloid::Class() )  {
0448       const TGeoParaboloid* sh = (const TGeoParaboloid*) shape;
0449       log << "<paraboloid" << nam
0450           << " lunit=\""  << m_len_unit_nam             << "\""
0451           << " rlo=\""    << sh->GetRlo()/m_len_unit    << "\""
0452           << " rhi=\""    << sh->GetRhi()/m_len_unit    << "\""
0453           << " z=\""      << sh->GetDz()/m_len_unit     << "\""
0454           << "/>";
0455     }
0456     else if ( cl == TGeoSphere::Class() )   {
0457       const TGeoSphere* sh = (const TGeoSphere*) shape;
0458       log << "<sphere" << nam
0459           << " lunit=\""  << m_len_unit_nam             << "\""
0460           << " aunit=\""  << m_ang_unit_nam             << "\""
0461           << " rmin=\""   << sh->GetRmin()/m_len_unit   << "\""
0462           << " rmax=\""   << sh->GetRmax()/m_len_unit   << "\""
0463           << " startphi=\""   << sh->GetPhi1()/m_ang_unit << "\""
0464           << " deltaphi=\""   << (sh->GetPhi1()-sh->GetPhi1())/m_ang_unit << "\""
0465           << " starttheta=\"" << sh->GetTheta1()/m_ang_unit << "\""
0466           << " deltatheta=\"" << (sh->GetTheta1()-sh->GetTheta1())/m_ang_unit << "\""
0467           << "/>";
0468     }
0469     else if ( cl == TGeoTorus::Class() )   {
0470       const TGeoTorus* sh = (const TGeoTorus*) shape;
0471       log << "<torus" << nam
0472           << " lunit=\""  << m_len_unit_nam             << "\""
0473           << " aunit=\""  << m_ang_unit_nam             << "\""
0474           << " rtor=\""   << sh->GetR()/m_len_unit      << "\""
0475           << " rmin=\""   << sh->GetRmin()/m_len_unit   << "\""
0476           << " rmax=\""   << sh->GetRmax()/m_len_unit   << "\""
0477           << " startphi=\""   << sh->GetPhi1()/m_ang_unit << "\""
0478           << " deltaphi=\""   << sh->GetDphi()/m_ang_unit << "\""
0479           << "/>";
0480     }
0481     else if ( cl == TGeoArb8::Class() )   {
0482       TGeoArb8* sh = (TGeoArb8*) shape;
0483       const Double_t* v = sh->GetVertices();
0484       log << "<arb8" << nam
0485           << " v1x=\""    << v[0]/m_len_unit            << "\""
0486           << " v1y=\""    << v[1]/m_len_unit            << "\""
0487           << " v2x=\""    << v[2]/m_len_unit            << "\""
0488           << " v2y=\""    << v[3]/m_len_unit            << "\""
0489           << " v3x=\""    << v[4]/m_len_unit            << "\""
0490           << " v3y=\""    << v[5]/m_len_unit            << "\""
0491           << " v4x=\""    << v[6]/m_len_unit            << "\""
0492           << " v4y=\""    << v[7]/m_len_unit            << "\""
0493           << " v5x=\""    << v[8]/m_len_unit            << "\""
0494           << " v5y=\""    << v[9]/m_len_unit            << "\""
0495           << " v6x=\""    << v[10]/m_len_unit           << "\""
0496           << " v6y=\""    << v[11]/m_len_unit           << "\""
0497           << " v7x=\""    << v[12]/m_len_unit           << "\""
0498           << " v7y=\""    << v[13]/m_len_unit           << "\""
0499           << " v8x=\""    << v[14]/m_len_unit           << "\""
0500           << " v8y=\""    << v[15]/m_len_unit           << "\""
0501           << " dz=\""     << sh->GetDz()/m_len_unit     << "\""
0502           << "/>";
0503     }
0504     else if ( cl == TGeoXtru::Class() )   {
0505       const TGeoXtru* sh = (const TGeoXtru*) shape;
0506       log << "<xtru" << nam << ">" << newline;
0507       for (int i = 0; i < sh->GetNvert(); i++) {
0508         log << " <twoDimVertex x=\"" << sh->GetX(i)/m_len_unit << "\""
0509             << "\" y=\"" << sh->GetY(i)/m_len_unit << "\"/>" << newline;
0510       }
0511       for (int i = 0; i < sh->GetNz(); i++) {
0512         log << " <section zOrder=\"" << i << "\""
0513             << " scalingFactor=\"" << sh->GetScale(i) << "\""
0514             << " zPosition=\"" << sh->GetZ(i)/m_len_unit << "\""
0515             << " xOffset=\""   << sh->GetXOffset(i)/m_len_unit << "\""
0516             << " yOffset=\""   << sh->GetYOffset(i)/m_len_unit << "\"/>" << newline;
0517       }
0518       log << "</xtru>";
0519     }
0520     else if (shape->IsA() == TGeoCompositeShape::Class() )   {
0521       const TGeoCompositeShape* sh  = (const TGeoCompositeShape*)shape;
0522       const TGeoBoolNode* boolean   = sh->GetBoolNode();
0523       const TGeoShape*    left      = boolean->GetLeftShape();
0524       const TGeoShape*    right     = boolean->GetRightShape();
0525       const TGeoMatrix*   mat_left  = boolean->GetLeftMatrix();
0526       const TGeoMatrix*   mat_right = boolean->GetRightMatrix();
0527       std::string         str_oper;
0528 
0529       TGeoBoolNode::EGeoBoolType oper = boolean->GetBooleanOperator();
0530       if (oper == TGeoBoolNode::kGeoSubtraction)
0531         str_oper = "subtraction";
0532       else if (oper == TGeoBoolNode::kGeoUnion)
0533         str_oper = "union";
0534       else if (oper == TGeoBoolNode::kGeoIntersection)
0535         str_oper = "intersection";
0536 
0537       if ( left->IsA() == TGeoScaledShape::Class() && right->IsA() == TGeoBBox::Class() )   {
0538         const auto* scaled = (TGeoScaledShape*)left;
0539         const auto* sphere = (TGeoSphere*)scaled->GetShape();
0540         const auto* box    = (TGeoBBox*)right;
0541         if ( scaled->IsA() == TGeoSphere::Class() && oper == TGeoBoolNode::kGeoIntersection )   {
0542           Double_t sx    = scaled->GetScale()->GetScale()[0];
0543           Double_t sy    = scaled->GetScale()->GetScale()[1];
0544           Double_t ax    = sx * sphere->GetRmax();
0545           Double_t by    = sy * sphere->GetRmax();
0546           Double_t cz    = sphere->GetRmax();
0547           Double_t dz    = box->GetDZ();
0548           Double_t zorig = box->GetOrigin()[2];
0549           Double_t zcut2 = dz + zorig;
0550           Double_t zcut1 = 2 * zorig - zcut2;
0551           log << "<ellipsoid" << nam
0552               << " lunit=\""  << m_len_unit_nam     << "\""
0553               << " ax=\""     << ax/m_len_unit      << "\""
0554               << " by=\""     << by/m_len_unit      << "\""
0555               << " cz=\""     << cz/m_len_unit      << "\""
0556               << " zcut1=\""  << zcut1/m_len_unit   << "\""
0557               << " zcut2=\""  << zcut2/m_len_unit   << "\"/>";
0558           iso = geo.emplace(solid, make_entry(log)).first;
0559           return iso->second;
0560         }
0561       }
0562       // The name cannot be used. We hence use the full hash code
0563       // for the left and right side shapes!
0564       const entry_t&  ent_left  = handleSolid(Solid(left));
0565       const entry_t&  ent_right = handleSolid(Solid(right));
0566       const entry_t&  ent_pos_left = handlePosition(mat_left);
0567       const entry_t&  ent_rot_left = handleRotation(mat_left);
0568       const entry_t&  ent_pos_right = handlePosition(mat_right);
0569       const entry_t&  ent_rot_right = handleRotation(mat_right);
0570       log << "<" << str_oper << nam
0571           << " lunit=\"" << m_len_unit_nam << "\""
0572           << " aunit=\"" << m_ang_unit_nam << "\">" << newline
0573           << " <first ref=\"" << (void*)ent_left.hash << "\""  << ">" << newline
0574           << "  " << ent_pos_left.hash << newline
0575           << "  " << ent_rot_left.hash << newline
0576           << " </first>" << newline
0577           << " <second ref=\"" << (void*)ent_right.hash << "\"" << ">" << newline
0578           << "  " << ent_pos_right.hash << newline
0579           << "  " << ent_rot_right.hash << newline
0580           << " </second>" << newline
0581           << "</" << str_oper << ">";
0582     }
0583     else if ( shape->IsA() == TGeoScaledShape::Class() )   {
0584       const TGeoScaledShape* sh  = (TGeoScaledShape*)shape;
0585       const TGeoShape*       org = sh->GetShape();
0586       const double*          scl = sh->GetScale()->GetScale();
0587       log << "<scaled_shape" << nam
0588           << " sx=\"" << scl[0] << "\""
0589           << " sy=\"" << scl[1] << "\""
0590           << " sz=\"" << scl[2] << "\">" << newline
0591           << "  " << handleSolid(Solid(org)).hash << newline
0592           << "</scaled_shape>";
0593     }
0594     else if ( shape->IsA() == TGeoShapeAssembly::Class() )   {
0595       log << "<shape_assembly " << nam << "\"/>";
0596     }
0597     else if ( shape->IsA() == TGeoTessellated::Class() )  {
0598       if ( hash_meshes )   {
0599         const TGeoTessellated* sh  = (TGeoTessellated*)shape;
0600         log << "<define>" << newline;
0601         if ( sh->IsClosedBody() == false ) {
0602           except("DetectorChecksum","+++ TGeoTessellated volume is not closed: %s", solid.name());
0603         }
0604         for (int ivertex = 0; ivertex < sh->GetNvertices(); ivertex++)  {
0605           // Note: const_cast since TGeoTessellated::GetVertex not marked const in ROOT <= 6.28
0606           const auto& vtx = const_cast<TGeoTessellated*>(sh)->GetVertex(ivertex);
0607           log << "<position name\"" << nam << "_v" << ivertex
0608               << " lunit=\"" << m_len_unit_nam << "\""
0609               << " x=\"" << vtx.x()/m_len_unit << "\""
0610               << " y=\"" << vtx.y()/m_len_unit << "\""
0611               << " z=\"" << vtx.z()/m_len_unit << "\""
0612               << "/>" << newline;
0613         }
0614         log << "</define>" << newline;
0615         log << "<tessellated name=\"" << nam << "\">" << newline;
0616         for (int ifacet = 0; ifacet < sh->GetNfacets(); ifacet++)  {
0617           // Note: const_cast since TGeoTessellated::GetFacet not marked const in ROOT <= 6.28
0618           const auto& facet = const_cast<TGeoTessellated*>(sh)->GetFacet(ifacet);
0619           if ( facet.GetNvert() == 3 ) {
0620             log << "<triangular";
0621           }
0622           else if ( facet.GetNvert() == 4 ) {
0623             log << "<quadrangular";
0624           }
0625           else {
0626             except("DetectorChecksum","+++ TGeoTessellated volume with unsupported number of vertices: %s", solid.name());
0627           }
0628           for (int ivertex = 0; ivertex < facet.GetNvert(); ivertex++) {
0629 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,31,1)
0630             auto vertexIndex = facet[ivertex];
0631 #else
0632             auto vertexIndex = facet.GetVertexIndex(ivertex);
0633 #endif
0634             log << " vertex" << ivertex + 1 << "=\"" << nam << "_v" << vertexIndex << "\"";
0635           }
0636           log << " type=\"ABSOLUTE\"/>" << newline;
0637         }
0638         log << "</tessellated>" << newline;
0639       }
0640       else {
0641         log << "<tessellated></tessellated>" << newline;
0642       }
0643     }
0644     else   {
0645       except("DetectorChecksum","+++ Unknown shape: %s", solid.name());
0646     }
0647     auto ins = geo.emplace(solid, make_entry(log));
0648     if ( !ins.second )   {
0649       except("DetectorChecksum", "+++ FAILED to register shape: %s", solid.name());
0650     }
0651     iso = ins.first;
0652   }
0653   return iso->second;
0654 }
0655 
0656 /// Convert the Position into the corresponding Xml object(s).
0657 const DetectorChecksum::entry_t& DetectorChecksum::handlePosition(const TGeoMatrix* trafo) const {
0658   auto& geo = data().mapOfPositions;
0659   auto  ipo = geo.find(trafo);
0660   if ( ipo == geo.end() )    {
0661     const double* tr = trafo->GetTranslation();
0662     std::stringstream log = logger();
0663     log << "<position"
0664         << " unit=\"" << m_len_unit_nam << "\""
0665         << " x=\"" << check_null(tr[0]/m_len_unit)  << "\""
0666         << " y=\"" << check_null(tr[1]/m_len_unit)  << "\""
0667         << " z=\"" << check_null(tr[2]/m_len_unit)  << "\"";
0668     log << "/>";
0669     ipo = geo.emplace(trafo, make_entry(log)).first;
0670   }
0671   return ipo->second;
0672 }
0673 
0674 /// Convert the Rotation into the corresponding Xml object(s).
0675 const DetectorChecksum::entry_t& DetectorChecksum::handleRotation(const TGeoMatrix* trafo) const {
0676   auto& geo = data().mapOfRotations;
0677   auto  iro = geo.find(trafo);
0678   if ( iro == geo.end() )    {
0679     XYZAngles rot = detail::matrix::_xyzAngles(trafo->GetRotationMatrix());
0680     std::stringstream log = logger();
0681     log << "<rotation"
0682         << " unit=\"" << m_ang_unit_nam  << "\""
0683         << " x=\"" << check_null(rot.X()/m_ang_unit) << "\""
0684         << " y=\"" << check_null(rot.Y()/m_ang_unit) << "\""
0685         << " z=\"" << check_null(rot.Z()/m_ang_unit) << "\""
0686         << "/>";
0687     iro = geo.emplace(trafo, make_entry(log)).first;
0688   }
0689   return iro->second;
0690 }
0691 
0692 /// Convert the geometry visualisation attributes to the corresponding Detector object(s).
0693 const DetectorChecksum::entry_t& DetectorChecksum::handleVis(VisAttr attr) const {
0694   auto& geo = data().mapOfVis;
0695   auto  ivi = geo.find(attr);
0696   if ( ivi == geo.end() ) {
0697     std::stringstream log = logger();
0698     float red = 0, green = 0, blue = 0;
0699     int style = attr.lineStyle();
0700     int draw  = attr.drawingStyle();
0701     attr.rgb(red, green, blue);
0702 
0703     log << "<vis"
0704         << " name=\""           << attr.name()          << "\""
0705         << " visible=\""        << attr.visible()       << "\""
0706         << " show_daughters=\"" << attr.showDaughters() << "\"";
0707     if (style == VisAttr::SOLID)
0708       log << " line_style=\"unbroken\"";
0709     else if (style == VisAttr::DASHED)
0710       log << " line_style=\"broken\"";
0711     if (draw == VisAttr::SOLID)
0712       log << " line_style=\"solid\"";
0713     else if (draw == VisAttr::WIREFRAME)
0714       log << " line_style=\"wireframe\"";
0715     log << "<color"
0716         << " alpha=\"" << attr.alpha()
0717         << " R=\""     << red    << "\""
0718         << " B=\""     << blue   << "\""
0719         << " G=\""     << green  << "\"/>" << newline;
0720     log << "</vis>";
0721     ivi = geo.emplace(attr, make_entry(log)).first;
0722   }
0723   return ivi->second;
0724 }
0725 
0726 /// Convert the geometry type region into the corresponding Detector object(s).
0727 const DetectorChecksum::entry_t& DetectorChecksum::handleRegion(Region region) const {
0728   auto& geo = data().mapOfRegions;
0729   auto  ire = geo.find(region);
0730   if ( ire == geo.end() )   {
0731     std::stringstream log = logger();
0732     log << "<region name=\""       << region.name() << "\""
0733         << " store_secondaries=\"" << (region.storeSecondaries() ? 1 : 0) << "\""
0734         << " cut=\""               << region.cut() << "\""
0735         << " eunit=\""             << m_ene_unit_nam << "\""
0736         << " lunit=\""             << m_len_unit_nam << "\""
0737         << "/>";
0738     ire = geo.emplace(region, make_entry(log)).first;
0739   }
0740   return ire->second;
0741 }
0742 
0743 /// Convert the geometry type LimitSet into the corresponding Detector object(s)
0744 const DetectorChecksum::entry_t& DetectorChecksum::handleLimitSet(LimitSet lim) const {
0745   auto& geo = data().mapOfLimits;
0746   auto  ili = geo.find(lim);
0747   if ( ili == geo.end() )    {
0748     std::stringstream log = logger();
0749     const std::set<Limit>& obj = lim.limits();
0750     log << "<limitset name=\""     << lim.name() << "\">" << newline;
0751     for (const auto& limit : obj)  {
0752       log << "<limit name=\""      << limit.name   << "\""
0753           << "  unit=\""           << limit.unit   << "\""
0754           << "  value=\""          << limit.value  << "\""
0755           << " particles=\""       << limit.particles << "\""
0756           << "/>" << newline;
0757     }
0758     log << "</limitSet>";
0759     ili = geo.emplace(lim, make_entry(log)).first;
0760   }
0761   return ili->second;
0762 }
0763 
0764 const DetectorChecksum::entry_t& DetectorChecksum::handleAlignment(Alignment alignment)  const  {
0765   auto& geo = data().mapOfAlignments;
0766   auto  ial = geo.find(alignment);
0767   if ( ial == geo.end() ) {
0768     std::stringstream log = logger();
0769     const auto& data = alignment.data();
0770     double x, y, z;
0771     data.delta.pivot.GetComponents(x, y, z);
0772     log << "<nominal>" << newline;
0773     log << "<translation"
0774         << " unit=\""  << m_len_unit_nam << "\""
0775         << " x=\""     << data.delta.translation.X()/m_len_unit  << "\""
0776         << " y=\""     << data.delta.translation.Y()/m_len_unit  << "\""
0777         << " z=\""     << data.delta.translation.Z()/m_len_unit  << "\"/>" << newline;
0778     log << "<pivot"
0779         << " unit=\""  << m_len_unit_nam << "\""
0780         << " x=\""     << x / m_len_unit << "\""
0781         << " y=\""     << y / m_len_unit << "\""
0782         << " z=\""     << z / m_len_unit << "\"/>" << newline;
0783     log << "<rotation"
0784         << " unit=\""  << m_len_unit_nam << "\""
0785         << " theta=\"" << data.delta.rotation.Theta()/m_ang_unit  << "\""
0786         << " phi=\""   << data.delta.rotation.Phi()/m_len_unit  << "\""
0787         << " psi=\""   << data.delta.rotation.Psi()/m_len_unit  << "\"/>" << newline;
0788     log << "</nominal>";
0789     ial = geo.emplace(alignment, make_entry(log)).first;
0790   }
0791   return ial->second;
0792 }
0793 
0794 /// Dump logical volume in GDML format to output stream
0795 void DetectorChecksum::collectVolume(Volume volume) const {
0796   Volume v(volume);
0797   if ( is_volume(volume) )     {
0798     Region            reg = v.region();
0799     LimitSet          lim = v.limitSet();
0800     VisAttr           vis = v.visAttributes();
0801     SensitiveDetector det = v.sensitiveDetector();
0802     if ( lim.isValid() ) handleLimitSet(lim);
0803     if ( reg.isValid() ) handleRegion(reg);
0804     if ( vis.isValid() ) handleVis(vis);
0805     if ( det.isValid() ) handleSensitive(det);
0806   }
0807   else {
0808     printout(WARNING,"DetectorChecksum","++ CollectVolume: Skip volume: %s",volume.name());
0809   }
0810 }
0811 
0812 /// Dump logical volume in GDML format to output stream
0813 const DetectorChecksum::entry_t& DetectorChecksum::handleVolume(Volume volume) const {
0814   auto& geo = data().mapOfVolumes;
0815   auto  ivo = geo.find(volume);
0816   if ( ivo == geo.end() ) {
0817     const TGeoVolume* v = volume;
0818     std::string       tag;
0819     std::string       sol;
0820     std::string       nam = attr_name(v);
0821     std::stringstream log = logger();
0822     TGeoShape*  sh  = v->GetShape();
0823     if ( !sh )
0824       throw std::runtime_error("DetectorChecksum: No solid present for volume:" + nam);
0825 
0826     if (v->IsAssembly()) {
0827       const auto& solid_ent = handleSolid(sh);
0828       tag = "assembly";
0829       log << "<" << tag << nam
0830           << " solid=\""         << refName(sh)           << "\""
0831           << " solid_hash=\""    << (void*)solid_ent.hash << "\"";
0832     }
0833     else {
0834       TGeoMedium*   med = v->GetMedium();
0835       if ( !med )
0836         throw std::runtime_error("DetectorChecksum: No material present for volume:" + nam);
0837       const auto& solid_ent = handleSolid(sh);
0838       tag = "volume";
0839       log << "<" << tag << nam
0840           << " material=\""      << refName(med)          << "\""
0841           << " solid=\""         << refName(sh)           << "\""
0842           << " solid_hash=\""    << (void*)solid_ent.hash << "\"";
0843     }
0844     collectVolume(volume);
0845     auto reg = volume.region();
0846     auto lim = volume.limitSet();
0847     auto vis = volume.visAttributes();
0848     auto det = volume.sensitiveDetector();
0849     if ( lim.isValid() )
0850       log << " limits=\""    << refName(lim) << "\"";
0851     if ( reg.isValid() )
0852       log << " region=\""    << refName(reg) << "\"";
0853     if ( vis.isValid() )
0854       log << " vis=\""       << refName(vis) << "\"";
0855     if ( det.isValid() )
0856       log << " sensitive=\"" << refName(det) << "\"";
0857     const TObjArray* dau = const_cast<TGeoVolume*>(v)->GetNodes();
0858     if (dau && dau->GetEntries() > 0) {
0859       log << ">" << newline;
0860       for (Int_t i = 0, n_dau = dau->GetEntries(); i < n_dau; ++i) {
0861         TGeoNode* node = reinterpret_cast<TGeoNode*>(dau->At(i));
0862         const auto& ent = handlePlacement(node);
0863         log << " <physvol name=\"" << refName(node) << " hash=\"" << (void*)ent.hash << "\"/>" << newline;
0864       }
0865       log << "</" << tag << ">";
0866     }
0867     else   {
0868       log << "/>";
0869     }
0870     auto ins = geo.emplace(volume, make_entry(log));
0871     if ( !ins.second )   {
0872       except("DetectorChecksum", "+++ FAILED to register volume: %s", volume.name());
0873     }
0874     ivo = ins.first;
0875   }
0876   return ivo->second;
0877 }
0878 
0879 /// Dump volume placement in GDML format to output stream
0880 const DetectorChecksum::entry_t& DetectorChecksum::handlePlacement(PlacedVolume node) const {
0881   auto& geo = data().mapOfPlacements;
0882   auto  ipl = geo.find(node);
0883   if ( ipl == geo.end() ) {
0884     TGeoMatrix* matrix = node->GetMatrix();
0885     TGeoVolume* volume = node->GetVolume();
0886     const auto& vol_ent = handleVolume(volume);
0887     std::stringstream  log = logger();
0888     log << "<physvol" << attr_name(node)
0889         << " volume=\"" << refName(volume) << "\"";
0890     log << " volume_hash=\"" << (void*)vol_ent.hash << "\"";
0891     log << ">" << newline;
0892     if ( matrix )   {
0893       log << " " << handlePosition(matrix).hash << newline;
0894       //log << " " << _to_hex(handlePosition(matrix).hash) << newline;
0895       if ( matrix->IsRotation() )  {
0896         log << " " << handleRotation(matrix).hash << newline;
0897         //log << " " << _to_hex(handleRotation(matrix).hash) << newline;
0898       }
0899     }
0900     if ( node.data() )   {
0901       const auto& ids = node.volIDs();
0902       for (const auto& vid : ids )
0903         log << " <physvolid"
0904             << " name=\""  << vid.first  << "\""
0905             << " value=\"" << vid.second << "\""
0906             << "/>" << newline;
0907     }
0908     log << "</physvol>";
0909     ipl = geo.emplace(node, make_entry(log)).first;
0910   }
0911   return ipl->second;
0912 }
0913 
0914 const DetectorChecksum::entry_t& DetectorChecksum::handleDetElement(DetElement det)  const  {
0915   auto& geo = data().mapOfDetElements;
0916   auto  dit = geo.find(det);
0917   if ( dit == geo.end() )   {
0918     std::stringstream log = logger();
0919     const auto& place = handlePlacement(det.placement());
0920     const auto& par = det.parent().isValid() ? handleDetElement(det.parent()) : empty_entry;
0921     log << "<detelement"
0922         << " name=\""          << det.name()        << "\""
0923         << " id=\""            << det.id()          << "\""
0924         << " type=\""          << det.type()        << "\""
0925         << " key=\""           << det.key()         << "\""
0926         << " parent=\""        << (void*)par.hash   << "\""
0927         << " flag=\""          << det.typeFlag()    << "\""
0928         << " combineHits=\""   << det.combineHits() << "\""
0929         << " placement=\""     << (void*)place.hash << "\""
0930         << "/>";
0931     dit = geo.emplace(det, make_entry(log)).first;
0932   }
0933   return dit->second;
0934 }
0935 
0936 /// Convert the geometry type SensitiveDetector into the corresponding Detector object(s).
0937 const DetectorChecksum::entry_t& DetectorChecksum::handleSensitive(SensitiveDetector sd) const {
0938   if ( sd.isValid() )   {
0939     auto& geo = data().mapOfSensDets;
0940     auto  isi = geo.find(sd);
0941     if ( isi == geo.end() ) {
0942       std::stringstream log = logger();
0943       log << "<sensitive_detector"
0944           << " name=\""            << refName(sd)                  << "\""
0945           << " type=\""            << sd.type()                    << "\""
0946           << " ecut=\""            << sd.energyCutoff()/m_ene_unit << "\""
0947           << " eunit=\""           << m_ene_unit_nam               << "\""
0948           << " hits_collection=\"" << sd.hitsCollection()          << "\""
0949           << " combine_hits=\""    << sd.combineHits()             << "\"";
0950       Readout ro = sd.readout();
0951       if ( ro.isValid() ) {
0952         const auto& ro_ent = handleIdSpec(ro.idSpec());
0953         log << " iddescriptor=\"" << (void*)ro_ent.hash            << "\"";
0954         const auto& seg_ent = handleSegmentation(ro.segmentation());
0955         log << " segmentation=\"" << (void*)seg_ent.hash           << "\"";
0956       }
0957       log << "/>";
0958       isi = geo.emplace(sd, make_entry(log)).first;
0959     }
0960     return isi->second;
0961   }
0962   return empty_entry;
0963 }
0964 
0965 /// Convert the segmentation of a SensitiveDetector into the corresponding Detector object
0966 const DetectorChecksum::entry_t& DetectorChecksum::handleSegmentation(Segmentation seg) const {
0967   if (seg.isValid()) {
0968     auto& geo = data().mapOfSegmentations;
0969     auto  ise = geo.find(seg);
0970     if ( ise == geo.end() ) {
0971       using param_t = DDSegmentation::SegmentationParameter;
0972       std::stringstream log = logger();
0973       const auto& p = seg.parameters();
0974       log << "<segmentation" << attr_name(seg)
0975           << " type=\"" << seg.type() << "\">" << newline;
0976       log << " <parameters>" << newline;
0977       for ( const auto& v : p )  {
0978         log << "  <parameter";
0979         log << " name=\"" << v->name() << "\""
0980             << " type=\"" << v->type() << "\"";
0981         if ( v->unitType() == param_t::LengthUnit )
0982           log << " value=\"" << _toDouble(v->value())/m_len_unit << "\""
0983               << " unit=\""  << m_len_unit_nam << "\"";
0984         else if ( v->unitType() == param_t::AngleUnit )
0985           log << " value=\"" << _toDouble(v->value())/m_ang_unit << "\""
0986               << " unit=\""  << m_ang_unit_nam << "\"";
0987         else
0988           log << " value=\"" << v->value() << "\"";
0989         log << "/>" << newline;
0990       }
0991       log << " </parameters>" << newline;
0992       log << "</segmentation>";
0993       ise = geo.emplace(seg, make_entry(log)).first;
0994     }
0995     return ise->second;
0996   }
0997   return empty_entry;
0998 }
0999 
1000 /// Convert the geometry id dictionary entry to the corresponding Xml object(s).
1001 const DetectorChecksum::entry_t& DetectorChecksum::handleIdSpec(IDDescriptor id_spec) const {
1002   if ( id_spec.isValid() )   {
1003     auto& geo = data().mapOfIdSpecs;
1004     auto  iid = geo.find(id_spec);
1005     if ( iid == geo.end() ) {
1006       const IDDescriptor::FieldMap& fm = id_spec.fields();
1007       std::stringstream log = logger();
1008       log << "<id name=\"" << refName(id_spec) << "\">" << newline;
1009       for (const auto& i : fm )  {
1010         const BitFieldElement* f = i.second;
1011         log << " <idfield label=\"" << f->name()       << "\""
1012             << " signed=\""         << true_false(f->isSigned()) << "\""
1013             << " length=\""         << f->width()      << "\""
1014             << " start=\""          << f->offset()     << "\"/>" << newline;
1015       }
1016       log << "</id>";
1017       iid = geo.emplace(id_spec, make_entry(log)).first;
1018     }
1019     return iid->second;
1020   }
1021   return empty_entry;
1022 }
1023 
1024 /// Convert the electric or magnetic fields into the corresponding Xml object(s).
1025 const DetectorChecksum::entry_t& DetectorChecksum::handleField(OverlayedField f) const {
1026   auto& geo = data().mapOfFields;
1027   auto  ifd = geo.find(f);
1028   if ( ifd == geo.end() ) {
1029     std::string type = f->GetTitle();
1030     std::stringstream log = logger();
1031     log << "<field name=\"" << f->GetName() << "\" type=\"" << f->GetTitle() << "\">";
1032 #if 0
1033     field = xml_elt_t(geo.doc, Unicode(type));
1034     field.setAttr(_U(name), f->GetName());
1035     fld = PluginService::Create<NamedObject*>(type + "_Convert2Detector", &m_detDesc, &field, &fld);
1036     printout(ALWAYS,"DetectorChecksum","++ %s electromagnetic field:%s of type %s",
1037              (fld.isValid() ? "Converted" : "FAILED    to convert "), f->GetName(), type.c_str());
1038     if (!fld.isValid()) {
1039       PluginDebug dbg;
1040       PluginService::Create<NamedObject*>(type + "_Convert2Detector", &m_detDesc, &field, &fld);
1041       throw std::runtime_error("Failed to locate plugin to convert electromagnetic field:"
1042                                + std::string(f->GetName()) + " of type " + type + ". "
1043                                + dbg.missingFactory(type));
1044     }
1045 #endif
1046     log << "</field>";
1047     ifd = geo.emplace(f, make_entry(log)).first;
1048   }
1049   return ifd->second;
1050 }
1051 
1052 /// Add header information in Detector format
1053 const DetectorChecksum::entry_t& DetectorChecksum::handleHeader() const {
1054   GeometryInfo& geo = data();
1055   Header hdr = m_detDesc.header();
1056   if ( hdr.isValid() && 0 == geo.header.hash )  {
1057     std::stringstream log = logger();
1058     log << "<header name=\"" << hdr.name() << "\">"
1059         << "<autor name=\""  << hdr.author() << "\"/>"
1060         << "<generator version=\"" << hdr.version() << "\"" << " url=\"" << hdr.url() << "\"/>"
1061         << "<comment>" << hdr.comment() << "</comment>"
1062         << "</header>";
1063     geo.header = make_entry(log);
1064     return geo.header;
1065   }
1066   printout(WARNING,"DetectorChecksum","+++ No Detector header information availible from the geometry description.");
1067   return empty_entry;
1068 }
1069 
1070 void DetectorChecksum::collect_det_elements(DetElement top)  const  {
1071   auto& geo = data().mapOfDetElements;
1072   auto it = geo.find(top);
1073   if ( it == geo.end() )    {
1074     handleDetElement(top);
1075     handlePlacement(top.placement());
1076     for( const auto& c : top.children() )   {
1077       collect_det_elements(c.second);
1078     }
1079   }
1080 }
1081 
1082 /// Create geometry conversion
1083 void DetectorChecksum::analyzeDetector(DetElement top)      {
1084   Detector& description = m_detDesc;
1085   if (!top.isValid()) {
1086     throw std::runtime_error("Attempt to call analyzeDetector with an invalid geometry!");
1087   }
1088   GeometryInfo& geo = *(m_dataPtr = new GeometryInfo);
1089   m_data->clear();
1090   handleHeader();
1091   collect_det_elements(top);
1092   for (const auto& fld : description.fields() )
1093     handleField(fld.second);
1094   if ( debug > 1 )   {
1095     printout(ALWAYS, "DetectorChecksum", "++ ==> Computing checksum for tree: %s", top.path().c_str());
1096     printout(ALWAYS, "DetectorChecksum", "++ Handled %ld materials.",      geo.mapOfMaterials.size());
1097     printout(ALWAYS, "DetectorChecksum", "++ Handled %ld solids.",         geo.mapOfSolids.size());
1098     printout(ALWAYS, "DetectorChecksum", "++ Handled %ld volumes.",        geo.mapOfVolumes.size());
1099     printout(ALWAYS, "DetectorChecksum", "++ Handled %ld vis.attributes.", geo.mapOfVis.size());
1100     printout(ALWAYS, "DetectorChecksum", "++ Handled %ld fields.",         geo.mapOfFields.size());
1101   }
1102 }
1103 
1104 std::vector<PlacedVolume> _get_path(PlacedVolume node, const std::set<PlacedVolume>& match)   {
1105   if ( match.end() == match.find(node) )   {
1106     const TObjArray* dau = node.volume()->GetNodes();
1107     for (Int_t i = 0, n_dau = dau->GetEntries(); i < n_dau; ++i) {
1108       TGeoNode* n = reinterpret_cast<TGeoNode*>(dau->At(i));
1109       auto cont = _get_path(n, match);
1110       if ( !cont.empty() )   {
1111         cont.emplace_back(node);
1112         return cont;
1113       }
1114     }
1115     return { };
1116   }
1117   return { node };
1118 }
1119 
1120 void DetectorChecksum::hash_debug(const std::string& prefix, const entry_t& ent, int flg)  const   {
1121   if ( debug > 2 )    {
1122     if ( flg == 1 )    {
1123       debug_hash << std::setw(16) << std::left << prefix << "." << ent.data << std::endl;
1124       return;
1125     }
1126     debug_hash << std::setw(16) << std::left << (prefix+".hash64:  ") << (void*)ent.hash << std::endl;
1127     if ( debug > 3 )    {
1128       debug_hash << std::setw(16) << std::left << prefix << ": |" << ent.data << "|" << std::endl;
1129     }
1130   }
1131 }
1132 
1133 void DetectorChecksum::checksumDetElement(int lvl, DetElement det, hashes_t& hashes, bool recursive)  const  {
1134   auto& dat = data();
1135   auto& geo = dat.mapOfDetElements;
1136   auto it = geo.find(det);
1137   if ( it != geo.end() )    {
1138     std::set<PlacedVolume> child_places;
1139     std::set<PlacedVolume> hashed_places;
1140     auto det_pv = det.placement();
1141     std::size_t hash_idx_de = hashes.size();
1142 
1143     /// Hash DetElement and placement
1144     hashes.push_back(it->second.hash);
1145     hash_debug(det.name(), it->second);
1146     std::size_t hash_idx_ro  = hashes.size();
1147     std::size_t hash_idx_id  = 0;
1148     std::size_t hash_idx_seg = 0;
1149     if ( hash_readout )   {
1150       SensitiveDetector sd = m_detDesc.sensitiveDetector(det.name());
1151       if ( sd.isValid() )   {
1152         Readout ro = sd.readout();
1153         const auto& sens_ent = handleSensitive(sd);
1154         hashes.push_back(sens_ent.hash);
1155         hash_debug(" .sensitive", sens_ent);
1156         if ( ro.isValid() ) {
1157           const auto& id_ent = handleIdSpec(ro.idSpec());
1158           const auto& seg_ent = handleSegmentation(ro.segmentation());
1159 
1160           hash_idx_id = hashes.size();
1161           hashes.push_back(id_ent.hash);
1162           hash_idx_seg = hashes.size();
1163           hashes.push_back(seg_ent.hash);
1164 
1165           hash_debug(" .iddesc",  id_ent);
1166           hash_debug(" .readout", seg_ent);
1167         }
1168       }
1169     }
1170 
1171     std::size_t hash_idx_pv = hashes.size();
1172     checksumPlacement(det_pv, hashes, false);
1173     for ( const auto& c : det.children() )
1174       child_places.emplace(c.second.placement());
1175 
1176     /// Hash all daughters with a DetElement child (but excluding the child)
1177     /// Note: We only take into account the placements to the next DetElement (if any)
1178     /// On the fly we remember all placements already taken into account!
1179     std::size_t hash_idx_daughters = hashes.size();
1180     for( const auto& pv : child_places )   {
1181       auto chain = _get_path(pv, child_places);
1182       for( std::size_t i=0; i < chain.size()-1; ++i )   {
1183         checksumPlacement(chain[i], hashes, false);
1184         hashed_places.insert(chain[i]);
1185       }
1186       if ( !chain.empty() ) hashed_places.insert(chain[chain.size()-1]);
1187     }
1188     /// Now hash all daughter volumes, which are not linked to a DetElement
1189     /// in the structural hierarchy.
1190     const TObjArray* dau = det_pv.volume()->GetNodes();
1191     if (dau && dau->GetEntries() > 0) {
1192       for (Int_t i = 0, n_dau = dau->GetEntries(); i < n_dau; ++i) {
1193         PlacedVolume pv = reinterpret_cast<TGeoNode*>(dau->At(i));
1194         if ( hashed_places.find(pv) == hashed_places.end() )  {
1195           checksumPlacement(det_pv, hashes, true);
1196         }
1197       }
1198     }
1199 
1200     /// Finally: Hash recursively the structural children
1201     std::size_t hash_idx_children = hashes.size();
1202     if ( recursive )   {
1203       for ( const auto& c : det.children() )
1204         checksumDetElement(lvl+1, c.second, hashes, recursive);
1205     }
1206 
1207     /// All done: Some debugging printout
1208     if ( debug > 0 || lvl <= max_level )  {
1209       std::stringstream str;
1210       hash_t code = detail::hash64(&hashes[hash_idx_de], (hash_idx_ro-hash_idx_de)*sizeof(hash_t));
1211       str << "+++ " << std::setw(4) << std::left << lvl
1212           << " " << std::setw(36) << std::left << det.name() << " de"
1213           << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1214       code = detail::hash64(&hashes[hash_idx_pv], sizeof(hash_t));
1215       str << " " << std::setfill(' ') << std::setw(9) << std::left << "+place"
1216           << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1217       code = detail::hash64(&hashes[hash_idx_daughters], (hash_idx_children-hash_idx_daughters)*sizeof(hash_t));
1218       if ( !(child_places.empty() && hashed_places.empty()) )
1219         str << " " << std::setfill(' ') << std::setw(10) << std::left << "+daughters"
1220             << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1221       code = detail::hash64(&hashes[hash_idx_children], (hashes.size()-hash_idx_children)*sizeof(hash_t));
1222       if ( !det.children().empty() )
1223         str << " " << std::setfill(' ') << std::setw(9) << std::left << "+children"
1224             << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1225       std::cout << str.str() << std::endl;
1226       if ( hash_idx_pv-hash_idx_ro > 0 )  {
1227         str.str("");
1228         str << std::setfill(' ') << "+++ " << std::setw(4) << std::left << lvl
1229             << " " << std::setw(56) << std::left << " ";
1230         code = detail::hash64(&hashes[hash_idx_ro], (hash_idx_pv-hash_idx_ro)*sizeof(hash_t));
1231         str << " " << std::setfill(' ') << std::setw(9) << std::left << "+readout"
1232             << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1233         if ( hash_idx_id > 0 )  {
1234           code = detail::hash64(&hashes[hash_idx_id], sizeof(hash_t));
1235           str << " " << std::setfill(' ') << std::setw(10) << std::left << "+iddesc"
1236               << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1237         }
1238         if ( hash_idx_seg > 0 )  {
1239           code = detail::hash64(&hashes[hash_idx_seg], sizeof(hash_t));
1240           str << " " << std::setfill(' ') << std::setw(9) << std::left << "+segment"
1241               << " " << std::setfill('0') << std::setw(16) << std::hex << code;
1242         }
1243         std::cout << str.str() << std::endl;
1244       }
1245       if ( lvl == 0 )   {
1246         str.str("");
1247         code = detail::hash64(&hashes[0], hashes.size()*sizeof(hash_t));
1248         str << std::setfill(' ') << "+++ " << std::setw(4) << std::left << lvl
1249             << " " << std::setw(39) << std::left << "Combined hash code"
1250             << " " << std::setfill('0') << std::setw(16) << std::hex << code
1251             << "  (" << std::dec << hashes.size() << " sub-codes)";
1252         std::cout << str.str() << std::endl;
1253       }
1254     }
1255     return;
1256   }
1257   except("DetectorChecksum","ERROR: Cannot checksum invalid DetElement");
1258 }
1259 
1260 void DetectorChecksum::checksumPlacement(PlacedVolume pv, hashes_t& hashes, bool recursive)  const  {
1261   handlePlacement(pv);
1262   auto& geo = data().mapOfPlacements;
1263   auto it = geo.find(pv);
1264   if ( it != geo.end() )    {
1265     Volume v = pv.volume();
1266     const auto& vol = handleVolume(v);
1267     entry_t name_entry {0, pv.name()};
1268 
1269     hash_debug(" .place.name", name_entry, 1);
1270     hash_debug(" .place", it->second);
1271     hashes.push_back(it->second.hash);
1272     hashes.push_back(vol.hash);
1273     hash_debug(" .place.vol", vol);
1274     if ( !v.isAssembly() )  {
1275       const auto& mat = handleMaterial(v.material());
1276       hashes.push_back(mat.hash);
1277       hash_debug(" .place.mat", mat);
1278     }
1279     if ( recursive )   {
1280       const TObjArray* dau = v->GetNodes();
1281       if (dau && dau->GetEntries() > 0)   {
1282         for (Int_t i = 0, n_dau = dau->GetEntries(); i < n_dau; ++i) {
1283           PlacedVolume node = reinterpret_cast<TGeoNode*>(dau->At(i));
1284           checksumPlacement(node, hashes, recursive);
1285         }
1286       }
1287     }
1288     return;
1289   }
1290   except("DetectorChecksum","ERROR: Cannot checksum invalid PlacedVolume");
1291 }
1292 
1293 /// Dump elements used in this apparatus
1294 void DetectorChecksum::dump_elements()   const   {
1295   _do_output_name("Element", reorder, write_files, debug>1 && have_hash_strings, data().mapOfElements);
1296 }
1297 
1298 /// Dump materials used in this apparatus
1299 void DetectorChecksum::dump_materials()   const   {
1300   _do_output_name("Material", reorder, write_files, debug>1 && have_hash_strings, data().mapOfMaterials);
1301 }
1302 
1303 /// Dump solids used in this apparatus
1304 void DetectorChecksum::dump_solids()   const   {
1305   _do_output_name("Solid", reorder, write_files, debug>1 && have_hash_strings, data().mapOfSolids);
1306 }
1307 
1308 /// Dump positions used in this apparatus
1309 void DetectorChecksum::dump_positions()   const   {
1310   _do_output("Position", reorder, write_files, have_hash_strings, data().mapOfPositions);
1311 }
1312 
1313 /// Dump rotations used in this apparatus
1314 void DetectorChecksum::dump_rotations()   const   {
1315   _do_output("Rotation", reorder, write_files, have_hash_strings, data().mapOfRotations);
1316 }
1317 
1318 /// Dump volumes used in this apparatus
1319 void DetectorChecksum::dump_volumes()   const   {
1320   _do_output_name("Volume", reorder, write_files, debug>1 && have_hash_strings, data().mapOfVolumes);
1321 }
1322 
1323 /// Dump placements used in this apparatus
1324 void DetectorChecksum::dump_placements()   const   {
1325   _do_output_name("Placement", reorder, write_files, debug>1 && have_hash_strings, data().mapOfPlacements);
1326 }
1327 
1328 /// Dump iddescriptors used in this apparatus
1329 void DetectorChecksum::dump_iddescriptors()   const   {
1330   _do_output_name("ID desc", reorder, write_files, debug>1 && have_hash_strings, data().mapOfIdSpecs);
1331 }
1332 
1333 /// Dump segmentations used in this apparatus
1334 void DetectorChecksum::dump_segmentations()   const   {
1335   _do_output_name("Segment", reorder, write_files, debug>1 && have_hash_strings, data().mapOfSegmentations);
1336 }
1337 
1338 /// Dump sensitives used in this apparatus
1339 void DetectorChecksum::dump_sensitives()   const   {
1340   _do_output_name("Sens.Det", reorder, write_files, debug>0 && have_hash_strings, data().mapOfSensDets);
1341 }
1342 
1343 /// Dump detelements used in this apparatus
1344 void DetectorChecksum::dump_detelements()   const   {
1345   const auto& geo = data().mapOfDetElements;
1346   for(const auto& e : geo)   {
1347     DetElement de = e.first;
1348     printout(ALWAYS, "DetectorChecksum",   "+++ Detelement: 0x%016lx  %-32s  %s",
1349              e.second.hash, de.name(), debug > 2 ? ("\n"+e.second.data).c_str() : "");
1350     if ( de.path() == "/world" )   {
1351       PlacedVolume pv  = de.placement();
1352       Volume       vol = pv.volume();
1353       Solid        sol = vol.solid();
1354       const auto&   es = handleSolid(sol);
1355       const auto&   ev = handleVolume(vol);
1356       const auto&   ep = handlePlacement(pv);
1357 
1358       printout(ALWAYS, "DetectorChecksum", "    Solid:      0x%016lx  %-32s  %s",
1359                es.hash, sol.name(), debug > 2 ? ("\n"+es.data).c_str() : "");
1360       printout(ALWAYS, "DetectorChecksum", "    Volume:     0x%016lx  %-32s  %s",
1361                ev.hash, vol.name(), debug > 2 ? ("\n"+ev.data).c_str() : "");
1362       printout(ALWAYS, "DetectorChecksum", "    Placement:  0x%016lx  %-32s  %s",
1363                ep.hash, pv.name(),  debug > 2 ? ("\n"+ep.data).c_str() : "");
1364     }
1365   }
1366 }
1367 
1368 static long create_checksum(Detector& description, int argc, char** argv) {
1369   std::vector<std::string> detectors;
1370   int precision = 6, newline = 1, level = 1, meshes = 0, readout = 0, debug = 0;
1371   int dump_elements = 0, dump_materials = 0, dump_solids = 0, dump_volumes = 0;
1372   int dump_placements = 0, dump_detelements = 0, dump_sensitives = 0;
1373   int dump_iddesc = 0, dump_segmentations = 0, dump_pos = 0;
1374   int dump_rot = 0;
1375   int have_hash_strings = 0, reorder = 0, write_files = 0;
1376   std::string len_unit, ang_unit, ene_unit, dens_unit, atom_unit;
1377 
1378   for(int i = 0; i < argc && argv[i]; ++i)  {
1379     if ( 0 == ::strncmp("-detector",argv[i],4) && (i+1)<argc )
1380       detectors.emplace_back(argv[++i]);
1381     else if ( 0 == ::strncmp("-precision",argv[i],4) && (i+1)<argc )
1382       precision = ::atol(argv[++i]);
1383     else if ( 0 == ::strncmp("-length_unit",argv[i],10) && (i+1)<argc )
1384       len_unit = argv[++i];
1385     else if ( 0 == ::strncmp("-angle_unit",argv[i],10) && (i+1)<argc )
1386       ang_unit = argv[++i];
1387     else if ( 0 == ::strncmp("-energy_unit",argv[i],10) && (i+1)<argc )
1388       ene_unit = argv[++i];
1389     else if ( 0 == ::strncmp("-density_unit",argv[i],10) && (i+1)<argc )
1390       dens_unit = argv[++i];
1391     else if ( 0 == ::strncmp("-atomic_unit",argv[i],10) && (i+1)<argc )
1392       atom_unit = argv[++i];
1393     else if ( 0 == ::strncmp("-level", argv[i],5) && (i+1)<argc )
1394       level = ::atol(argv[++i]);
1395     else if ( 0 == ::strncmp("-debug", argv[i],5) && (i+1)<argc )
1396       debug = ::atol(argv[++i]);
1397     else if ( 0 == ::strncmp("+newline",argv[i],5) )
1398       newline = 0;
1399     else if ( 0 == ::strncmp("-meshes",argv[i],5) )
1400       meshes = 1;
1401     else if ( 0 == ::strncmp("-readout",argv[i],5) )
1402       readout = 1;
1403     else if ( 0 == ::strncmp("-dump_elements",argv[i],10) )
1404       dump_elements = 1;
1405     else if ( 0 == ::strncmp("-dump_materials",argv[i],10) )
1406       dump_materials = 1;
1407     else if ( 0 == ::strncmp("-dump_solids",argv[i],10) )
1408       dump_solids = 1;
1409     else if ( 0 == ::strncmp("-dump_volumes",argv[i],10) )
1410       dump_volumes = 1;
1411     else if ( 0 == ::strncmp("-dump_positions",argv[i],12) )
1412       dump_pos = 1;
1413     else if ( 0 == ::strncmp("-dump_rotations",argv[i],12) )
1414       dump_rot = 1;
1415     else if ( 0 == ::strncmp("-dump_placements",argv[i],10) )
1416       dump_placements = 1;
1417     else if ( 0 == ::strncmp("-dump_detelements",argv[i],10) )
1418       dump_detelements = 1;
1419     else if ( 0 == ::strncmp("-dump_sensitives",argv[i],10) )
1420       dump_sensitives = 1;
1421     else if ( 0 == ::strncmp("-dump_segmentations",argv[i],10) )
1422       dump_segmentations = 1;
1423     else if ( 0 == ::strncmp("-dump_iddescriptors",argv[i],10) )
1424       dump_iddesc = 1;
1425     else if ( 0 == ::strncmp("-write_files",argv[i],8) )
1426      write_files = 1;
1427     else if ( 0 == ::strncmp("-reorder",argv[i],6) )
1428       reorder = 1;
1429     else if ( 0 == ::strncmp("-keep_hashes",argv[i],8) )
1430       have_hash_strings = 1;
1431     else  {
1432       std::cout <<
1433         "Usage: -plugin DD4hepDetectorChecksum -arg [-arg]                             \n\n"
1434         "     -detector <string>     Top level DetElement path. Default: '/world'        \n"
1435         "     -meshes                also hash the detector's meshed solids              \n"
1436         "                            (may be sensitive to changes due to rounding)       \n"
1437         "                            default: false                                      \n"
1438         "     -readout               also hash the detector's readout properties         \n"
1439         "                            (sensitive det, id desc, segmentation)              \n"
1440         "                            default: false                                      \n"
1441         "     -keep_hash             keep the hash strings (not only hash codes.         \n"
1442         "                            Useful for debugging and -dump_<x> options.         \n"
1443         "     -precsision <digits>   Set floating point precision after comma            \n"
1444         "                            for the checsum calculation.                        \n"
1445         "                                                                                \n"
1446         "   Debugging: Dump individual hash codes (debug>=1)                             \n"
1447         "   Debugging: and the hashed string (debug>2)                                   \n"
1448         "     -dump_elements         Dump hashes of used elements                        \n"
1449         "     -dump_materials        Dump hashes of used materials                       \n"
1450         "     -dump_solids           Dump hashes of used solids                          \n"
1451         "     -dump_volumes          Dump hashes of used volumes                         \n"
1452         "     -dump_positions        Dump hashes of used positions                       \n"
1453         "     -dump_rotations        Dump hashes of used rotations                       \n"
1454         "     -dump_placements       Dump hashes of used placements                      \n"
1455         "     -dump_detelements      Dump hashes of used detelements                     \n"
1456         "     -dump_sensitive        Dump hashes of sensitive detectors                  \n"
1457         "     -dump_iddescriptors    Dump hashes of ID descriptors                       \n"
1458         "     -dump_segmentations    Dump hashes of readout segmentations                \n"
1459         "     -write_files           Write a file for each category dumped (debugging).  \n"
1460         "                            File name is <item>.txt (aka. Positions.txt etc.    \n"
1461         "     -reorder               Reorder dump containers according to hash.          \n"
1462         "                                                                                \n"
1463         "   Modify units in the created hash strings (deprecated):                       \n"
1464         "     -length_unit  <value>  Unit of length  as literal. default: mm             \n"
1465         "     -angle_unit   <value>  Unit of angle   as literal. default: deg            \n"
1466         "     -energy_unit  <value>  Unit of energy  as literal. default: GeV            \n"
1467         "     -density_unit <value>  Unit of density as literal. default: g/cm3          \n"
1468         "     -atomic_unit <value>   Unit of atomic weight as literal. default: g/mole   \n"
1469         "                                                                                \n"
1470         "     -debug <number>        Steer additional debug printouts (gets verbose)     \n"
1471         "     -help                  Print this help output                            \n\n"
1472         "     Arguments given: " << arguments(argc, argv) << std::endl << std::flush;
1473       ::exit(EINVAL);
1474     }
1475   }
1476   DetectorChecksum wr(description);
1477   DetElement de = description.world();
1478   wr.precision = precision;
1479   if ( !len_unit.empty()  ) wr.m_len_unit_nam = std::move(len_unit);
1480   if ( !ang_unit.empty()  ) wr.m_ang_unit_nam = std::move(ang_unit);
1481   if ( !ene_unit.empty()  ) wr.m_ene_unit_nam = std::move(ene_unit);
1482   if ( !dens_unit.empty() ) wr.m_densunit_nam = std::move(dens_unit);
1483   if ( !atom_unit.empty() ) wr.m_atomunit_nam = std::move(atom_unit);
1484   if ( newline ) wr.newline = "\n";
1485   wr.have_hash_strings = have_hash_strings;
1486   wr.write_files  = write_files;
1487   wr.reorder      = reorder;
1488   wr.hash_meshes  = meshes;
1489   wr.hash_readout = readout;
1490   wr.max_level    = level;
1491   wr.debug        = debug;
1492   wr.configure();
1493 
1494   bool make_dump = false;
1495   if ( dump_elements   || dump_materials  || dump_solids || 
1496        dump_volumes    || dump_placements || dump_detelements ||
1497        dump_sensitives || dump_iddesc     || dump_segmentations ||
1498        dump_pos        || dump_rot )
1499   {
1500     make_dump = true;
1501     wr.debug = 1;
1502   }
1503   int round = std::fegetround();
1504   std::fesetround(FE_TONEAREST);
1505   printout(INFO,"DetectorChecksum","+++ Rounding mode: %d new: %d", round, std::fegetround());
1506 
1507   DetectorChecksum::hashes_t hash_vec;
1508   DetectorChecksum::hash_t checksum = 0;
1509   if ( !detectors.empty() )  {
1510     for (const auto& det : detectors )   {
1511       de = detail::tools::findElement(description,det);
1512       wr.analyzeDetector(de);
1513       hash_vec.clear();
1514       wr.checksumDetElement(0, de, hash_vec, true);
1515       if ( wr.debug > 2 )   {
1516         std::cout << wr.debug_hash.str() << std::endl;
1517         wr.debug_hash.str("");
1518       }
1519       checksum = detail::hash64(&hash_vec[0], hash_vec.size()*sizeof(DetectorChecksum::hash_t));
1520       printout(ALWAYS,"DetectorChecksum","+++ Checksum for %s 0x%016lx",
1521                de.path().c_str(), checksum);
1522       if ( make_dump ) goto MakeDump;
1523     }
1524     return 1;
1525   }
1526   
1527 
1528   wr.analyzeDetector(de);
1529   hash_vec.push_back(wr.handleHeader().hash);
1530   wr.checksumDetElement(0, description.world(), hash_vec, true);
1531   checksum = detail::hash64(&hash_vec[0], hash_vec.size()*sizeof(DetectorChecksum::hash_t));
1532   if ( wr.debug > 2 ) std::cout << wr.debug_hash.str() << std::endl;
1533   printout(ALWAYS,"DetectorChecksum","+++ Checksum for %s 0x%016lx",
1534            de.path().c_str(), checksum);
1535 
1536  MakeDump:
1537   if ( make_dump )   {
1538     wr.debug = debug;
1539     if ( dump_elements      ) wr.dump_elements();
1540     if ( dump_materials     ) wr.dump_materials();
1541     if ( dump_pos           ) wr.dump_positions();
1542     if ( dump_rot           ) wr.dump_rotations();
1543     if ( dump_solids        ) wr.dump_solids();
1544     if ( dump_volumes       ) wr.dump_volumes();
1545     if ( dump_placements    ) wr.dump_placements();
1546     if ( dump_sensitives    ) wr.dump_sensitives();
1547     if ( dump_segmentations ) wr.dump_segmentations();
1548     if ( dump_iddesc        ) wr.dump_iddescriptors();
1549     if ( dump_detelements   ) wr.dump_detelements();
1550   }
1551   return 1;
1552 }
1553 
1554 DECLARE_APPLY(DD4hepDetectorChecksum, create_checksum)