11 #include "GeoModelKernel/GeoShape.h"
12 #include "GeoModelKernel/GeoBox.h"
13 #include "GeoModelKernel/GeoTube.h"
14 #include "GeoModelKernel/GeoTubs.h"
15 #include "GeoModelKernel/GeoTrd.h"
16 #include "GeoModelKernel/GeoPcon.h"
17 #include "GeoModelKernel/GeoPgon.h"
18 #include "GeoModelKernel/GeoPara.h"
19 #include "GeoModelKernel/GeoTrap.h"
20 #include "GeoModelKernel/GeoCons.h"
21 #include "GeoModelKernel/GeoSimplePolygonBrep.h"
22 #include "GeoModelKernel/GeoTessellatedSolid.h"
23 #include "GeoModelKernel/GeoEllipticalTube.h"
24 #include "GeoModelKernel/GeoTorus.h"
25 #include "GeoModelKernel/GeoGenericTrap.h"
26 #include "GeoModelKernel/GeoShapeShift.h"
27 #include "GeoModelKernel/GeoShapeUnion.h"
28 #include "GeoModelKernel/GeoShapeIntersection.h"
29 #include "GeoModelKernel/GeoUnidentifiedShape.h"
30 #include "GeoModelKernel/GeoShapeSubtraction.h"
33 #include "GaudiKernel/ISvcLocator.h"
34 #include "GaudiKernel/Bootstrap.h"
47 #include "G4VSolid.hh"
51 #include "G4Polycone.hh"
53 #include "G4Polyhedra.hh"
56 #include "G4UnionSolid.hh"
57 #include "G4DisplacedSolid.hh"
58 #include "G4IntersectionSolid.hh"
59 #include "G4SubtractionSolid.hh"
60 #include "G4ExtrudedSolid.hh"
61 #include "G4TessellatedSolid.hh"
62 #include "G4EllipticalTube.hh"
64 #include "G4TriangularFacet.hh"
65 #include "G4QuadrangularFacet.hh"
66 #include "G4GenericTrap.hh"
75 typedef std::map<const GeoShape*, G4VSolid*, std::less<const GeoShape*> >
shapesMap;
76 typedef std::map<std::string, G4VSolid*,std::less<std::string> >
customSolidMap;
148 m_detStore(
"StoreGateSvc/DetectorStore",
"Geo2G4SolidFactory" )
154 G4VSolid* theSolid(
nullptr);
158 if(sharedShapes.find(geoShape)!=sharedShapes.end())
159 return sharedShapes[geoShape];
162 G4VSolid* solidA(
nullptr);
163 G4VSolid* solidB(
nullptr);
167 std::string
n = std::move(
name);
172 if(geoShape->typeID() == GeoBox::getClassTypeID() )
174 const GeoBox* theBox =
dynamic_cast<const GeoBox*
> (geoShape);
175 if (
nullptr==theBox)
throw std::runtime_error(
"TypeID did not match cast for box");
176 if (
n.empty())
n=
"G4Box";
177 if (theBox->getXHalfLength()<=0.){
ATH_MSG_WARNING(
"Box " <<
n <<
" has an x side of " << theBox->getXHalfLength() <<
" - using std::abs.");}
178 if (theBox->getYHalfLength()<=0.){
ATH_MSG_WARNING(
"Box " <<
n <<
" has an y side of " << theBox->getYHalfLength() <<
" - using std::abs.");}
179 if (theBox->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Box " <<
n <<
" has an z side of " << theBox->getZHalfLength() <<
" - using std::abs.");}
180 theSolid =
new G4Box(
n,
181 std::abs(theBox->getXHalfLength()),
182 std::abs(theBox->getYHalfLength()),
183 std::abs(theBox->getZHalfLength()));
188 else if(geoShape->typeID() == GeoTube::getClassTypeID() )
190 const GeoTube* theTube =
dynamic_cast<const GeoTube*
> (geoShape);
191 if (
nullptr==theTube)
throw std::runtime_error(
"TypeID did not match cast for tube");
192 if (
n.empty())
n=
"G4Tube";
193 if (theTube->getRMax()<=0.){
ATH_MSG_WARNING(
"Tube " <<
n <<
" has a max radius of " << theTube->getRMax() <<
" - using std::abs.");}
194 if (theTube->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Tube " <<
n <<
" has a z half length of " << theTube->getZHalfLength() <<
" - using std::abs.");}
195 if (theTube->getRMax()<theTube->getRMin()){
ATH_MSG_WARNING(
"Tube " <<
n <<
" has a max radius of " << theTube->getRMax() <<
" and a min radius of " << theTube->getRMin());}
196 theSolid =
new G4Tubs(
n,
198 std::abs(theTube->getRMax()),
199 std::abs(theTube->getZHalfLength()),
205 else if(geoShape->typeID() == GeoTubs::getClassTypeID() )
207 const GeoTubs* theTubs =
dynamic_cast<const GeoTubs*
> (geoShape);
208 if (
nullptr==theTubs)
throw std::runtime_error(
"TypeID did not match cast for tubs");
209 if (
n.empty())
n=
"G4Tubs";
210 if (theTubs->getRMin()<0.){
ATH_MSG_WARNING(
"Tubs " <<
n <<
" has a min radius of " << theTubs->getRMax());}
211 if (theTubs->getRMax()<=0.){
ATH_MSG_WARNING(
"Tubs " <<
n <<
" has a max radius of " << theTubs->getRMax() <<
" - using std::abs.");}
212 if (theTubs->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Tubs " <<
n <<
" has a half length of " << theTubs->getZHalfLength() <<
" - using std::abs.");}
213 if (theTubs->getRMax()<theTubs->getRMin()){
ATH_MSG_WARNING(
"Tubs " <<
n <<
" has a max radius of " << theTubs->getRMax() <<
" and a min radius of " << theTubs->getRMin());}
214 if (theTubs->getDPhi()<=0.){
ATH_MSG_WARNING(
"Tubs " <<
n <<
" has a dPhi of " << theTubs->getDPhi());}
215 theSolid =
new G4Tubs(
n,
217 std::abs(theTubs->getRMax()),
218 std::abs(theTubs->getZHalfLength()),
225 else if(geoShape->typeID() == GeoTrd::getClassTypeID() )
227 const GeoTrd* theTrd =
dynamic_cast<const GeoTrd*
> (geoShape);
228 if (
nullptr==theTrd)
throw std::runtime_error(
"TypeID did not match cast for trd");
229 if (
n.empty())
n=
"G4Trd";
230 if (theTrd->getXHalfLength1()<0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has a x half length 1 of " << theTrd->getXHalfLength1() <<
" - using std::abs.");}
231 if (theTrd->getXHalfLength2()<0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has a x half length 2 of " << theTrd->getXHalfLength2() <<
" - using std::abs.");}
232 if (theTrd->getYHalfLength1()<0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has a y half length 1 of " << theTrd->getYHalfLength1() <<
" - using std::abs.");}
233 if (theTrd->getYHalfLength2()<0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has a y half length 2 of " << theTrd->getYHalfLength2() <<
" - using std::abs.");}
234 if (theTrd->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has a z half length of " << theTrd->getZHalfLength() <<
" - using std::abs.");}
235 if (theTrd->getXHalfLength1()<=0. && theTrd->getXHalfLength2()<=0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has an x half length 1 of " << theTrd->getXHalfLength1()
236 <<
" and an x half length 2 of " << theTrd->getXHalfLength2() <<
" - using std::abs.");}
237 if (theTrd->getYHalfLength1()<=0. && theTrd->getYHalfLength2()<=0.){
ATH_MSG_WARNING(
"Trd " <<
n <<
" has a y half length 1 of " << theTrd->getYHalfLength1()
238 <<
" and a y half length 2 of " << theTrd->getYHalfLength2() <<
" - using std::abs.");}
239 theSolid =
new G4Trd(
n,
240 std::abs(theTrd->getXHalfLength1()),
241 std::abs(theTrd->getXHalfLength2()),
242 std::abs(theTrd->getYHalfLength1()),
243 std::abs(theTrd->getYHalfLength2()),
244 std::abs(theTrd->getZHalfLength()));
249 else if(geoShape->typeID() == GeoPcon::getClassTypeID())
251 const GeoPcon* thePcon =
dynamic_cast<const GeoPcon*
>(geoShape);
252 if (
nullptr==thePcon)
throw std::runtime_error(
"TypeID did not match cast for pcon");
253 if (
n.empty())
n=
"G4Polycone";
254 nPlanes =
static_cast<int>(thePcon->getNPlanes());
256 auto zPlane = std::make_unique<double[]>(nPlanes);
257 auto rInner = std::make_unique<double[]>(nPlanes);
258 auto rOuter = std::make_unique<double[]>(nPlanes);
259 for (
unsigned int index=0; index<static_cast<unsigned int>(nPlanes);
index++)
265 if (rOuter[
index]<=0.){
266 ATH_MSG_WARNING(
"PCon " <<
n <<
" has an outer radius of " << rOuter[
index] <<
" for slice " <<
index <<
" of " << nPlanes <<
" - using std::abs.");
271 theSolid =
new G4Polycone(
n,
282 else if(geoShape->typeID() == GeoCons::getClassTypeID())
284 const GeoCons* theCons =
dynamic_cast<const GeoCons*
>(geoShape);
285 if (
nullptr==theCons)
throw std::runtime_error(
"TypeID did not match cast for cons");
286 if (
n.empty())
n=
"G4Cons";
287 if (theCons->getRMax1()<0.){
ATH_MSG_WARNING(
"Cons " <<
n <<
" has a max radius 1 of " << theCons->getRMax1() <<
" - will use std::abs.");}
288 if (theCons->getRMax2()<0.){
ATH_MSG_WARNING(
"Cons " <<
n <<
" has a max radius 2 of " << theCons->getRMax2() <<
" - will use std::abs.");}
289 if (theCons->getRMin1()<0.){
ATH_MSG_WARNING(
"Cons " <<
n <<
" has a min radius 1 of " << theCons->getRMin1());}
290 if (theCons->getRMin2()<0.){
ATH_MSG_WARNING(
"Cons " <<
n <<
" has a min radius 2 of " << theCons->getRMin2());}
291 if (theCons->getDZ()<=0){
ATH_MSG_WARNING(
"Cons " <<
n <<
" has a DZ of " << theCons->getDZ() <<
" - will use std::abs.");}
292 if (theCons->getRMax1()<=0. && theCons->getRMax2()<=0.){
ATH_MSG_WARNING(
"Cons " <<
n <<
" has a max radius 1 of " << theCons->getRMax1()
293 <<
" and a max radius 2 of " << theCons->getRMax2() <<
" - will use std::abs.");}
294 theSolid =
new G4Cons(
n,
296 std::abs(theCons->getRMax1()),
298 std::abs(theCons->getRMax2()),
299 std::abs(theCons->getDZ()),
306 else if(geoShape->typeID() == GeoPara::getClassTypeID())
308 const GeoPara* thePara =
dynamic_cast<const GeoPara*
>(geoShape);
309 if (
nullptr==thePara)
throw std::runtime_error(
"TypeID did not match cast for para");
310 if (
n.empty())
n=
"G4Para";
311 if (thePara->getXHalfLength()<=0.){
ATH_MSG_WARNING(
"Para " <<
n <<
" has an x side of " << thePara->getXHalfLength() <<
" - using std::abs.");}
312 if (thePara->getYHalfLength()<=0.){
ATH_MSG_WARNING(
"Para " <<
n <<
" has an y side of " << thePara->getYHalfLength() <<
" - using std::abs.");}
313 if (thePara->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Para " <<
n <<
" has an z side of " << thePara->getZHalfLength() <<
" - using std::abs.");}
314 theSolid =
new G4Para(
n,
315 std::abs(thePara->getXHalfLength()),
316 std::abs(thePara->getYHalfLength()),
317 std::abs(thePara->getZHalfLength()),
325 else if(geoShape->typeID() == GeoPgon::getClassTypeID())
327 const GeoPgon* thePgon =
dynamic_cast<const GeoPgon*
>(geoShape);
328 if (
nullptr==thePgon)
throw std::runtime_error(
"TypeID did not match cast for pgon");
329 if (
n.empty())
n=
"G4Polyhedra";
330 nPlanes =
static_cast<int>(thePgon->getNPlanes());
332 auto zPlane = std::make_unique<double[]>(nPlanes);
333 auto rInner = std::make_unique<double[]>(nPlanes);
334 auto rOuter = std::make_unique<double[]>(nPlanes);
335 double alpha = thePgon->getDPhi()/(2*thePgon->getNSides());
336 for (
unsigned int index=0; index<static_cast<unsigned int>(nPlanes);
index++)
342 if (rOuter[
index]<=0.){
343 ATH_MSG_WARNING(
"Pgon " <<
n <<
" has an outer radius of " << rOuter[
index] <<
" for slice " <<
index <<
" of " << nPlanes <<
" - using std::abs.");
348 theSolid =
new G4Polyhedra(
n,
351 thePgon->getNSides(),
360 else if(geoShape->typeID() == GeoTrap::getClassTypeID())
362 const GeoTrap* theTrap =
dynamic_cast<const GeoTrap*
>(geoShape);
363 if (
nullptr==theTrap)
throw std::runtime_error(
"TypeID did not match cast for trap");
364 if (
n.empty())
n=
"G4Trap";
365 if (theTrap->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Trap " <<
n <<
" has an z side of " << theTrap->getZHalfLength() <<
" - using std::abs.");}
366 theSolid =
new G4Trap(
n,
367 std::abs(theTrap->getZHalfLength()),
371 theTrap->getDxdyndzn(),
372 theTrap->getDxdypdzn(),
373 theTrap->getAngleydzn(),
375 theTrap->getDxdyndzp(),
376 theTrap->getDxdypdzp(),
377 theTrap->getAngleydzp());
382 else if(geoShape->typeID() == GeoSimplePolygonBrep::getClassTypeID())
384 const GeoSimplePolygonBrep* theBrep =
dynamic_cast<const GeoSimplePolygonBrep*
>(geoShape);
385 if (
nullptr==theBrep)
throw std::runtime_error(
"TypeID did not match cast for brep");
386 if (
n.empty())
n=
"G4ExtrudedSolid";
387 double dz = theBrep->getDZ();
390 G4TwoVector off(0,0);
391 std::vector<G4TwoVector> polygon;
395 polygon.push_back(G4TwoVector(theBrep->getXVertex(
nVertices-1-
i),theBrep->getYVertex(
nVertices-1-
i)));
397 theSolid =
new G4ExtrudedSolid(
n,polygon,dz,off,1,off,1);
402 else if(geoShape->typeID() == GeoTessellatedSolid::getClassTypeID())
404 const GeoTessellatedSolid* theTessellated =
dynamic_cast<const GeoTessellatedSolid*
>(geoShape);
405 if (
nullptr==theTessellated)
throw std::runtime_error(
"TypeID did not match cast for tessellated solid");
406 if(
n.empty())
n=
"G4TessellatedSolid";
408 G4TessellatedSolid* g4Tessellated =
new G4TessellatedSolid(
n);
409 for(
size_t i=0;
i<theTessellated->getNumberOfFacets(); ++
i) {
410 GeoFacet* geoFacet = theTessellated->getFacet(
i);
411 G4FacetVertexType
vertexType = (geoFacet->getVertexType()==GeoFacet::ABSOLUTE? ABSOLUTE : RELATIVE);
412 G4VFacet* g4Facet(
nullptr);
413 if(geoFacet->getNumberOfVertices()==3)
425 g4Tessellated->AddFacet(g4Facet);
427 g4Tessellated->SetSolidClosed(
true);
428 theSolid = g4Tessellated;
433 else if(geoShape->typeID() == GeoEllipticalTube::getClassTypeID())
435 const GeoEllipticalTube* theEltube =
dynamic_cast<const GeoEllipticalTube*
>(geoShape);
436 if (
nullptr==theEltube)
throw std::runtime_error(
"TypeID did not match cast for elliptical tube");
437 if (
n.empty())
n=
"G4EllipticalTube";
439 if (theEltube->getXHalfLength()<=0.){
ATH_MSG_WARNING(
"Eltube " <<
n <<
" has an x side of " << theEltube->getXHalfLength() <<
" - using std::abs.");}
440 if (theEltube->getYHalfLength()<=0.){
ATH_MSG_WARNING(
"Eltube " <<
n <<
" has an y side of " << theEltube->getYHalfLength() <<
" - using std::abs.");}
441 if (theEltube->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"Eltube " <<
n <<
" has an z side of " << theEltube->getZHalfLength() <<
" - using std::abs.");}
442 G4EllipticalTube* g4Eltube =
new G4EllipticalTube(
n
443 ,std::abs(theEltube->getXHalfLength())
444 ,std::abs(theEltube->getYHalfLength())
445 ,std::abs(theEltube->getZHalfLength()));
451 else if(geoShape->typeID() == GeoTorus::getClassTypeID() ) {
452 const GeoTorus* theTorus =
dynamic_cast<const GeoTorus*
> (geoShape);
453 if (
nullptr==theTorus)
throw std::runtime_error(
"TypeID did not match cast for torus");
454 if (
n.empty())
n=
"G4Torus";
456 theSolid =
new G4Torus(
n,
461 theTorus->getDPhi());
466 else if(geoShape->typeID() == GeoGenericTrap::getClassTypeID()) {
467 const GeoGenericTrap* theGenTrap =
dynamic_cast<const GeoGenericTrap*
>(geoShape);
468 if (
nullptr==theGenTrap)
throw std::runtime_error(
"TypeID did not match cast for generic trap");
469 if (
n.empty())
n=
"G4GenericTrap";
470 if (theGenTrap->getZHalfLength()<=0.){
ATH_MSG_WARNING(
"GenTrap " <<
n <<
" has an z side of " << theGenTrap->getZHalfLength() <<
" - using std::abs.");}
473 std::vector<CLHEP::Hep2Vector> clhepVertices;
474 clhepVertices.reserve(theGenTrap->getVertices().size());
476 clhepVertices.push_back(CLHEP::Hep2Vector(geoVertex.x(),geoVertex.y()));
479 G4GenericTrap* g4GenTrap =
new G4GenericTrap(
n
480 ,std::abs(theGenTrap->getZHalfLength())
482 theSolid = g4GenTrap;
491 else if (geoShape->typeID() == GeoShapeShift::getClassTypeID() )
493 const GeoShapeShift* theShapeShift =
dynamic_cast<const GeoShapeShift*
> (geoShape);
494 if (
nullptr==theShapeShift)
throw std::runtime_error(
"TypeID did not match cast for shape shift");
495 if (
n.empty())
n=
"DisplacedSolid";
496 G4VSolid * undisplacedSolid = Build(theShapeShift->getOp());
502 else if (geoShape->typeID() == GeoShapeUnion::getClassTypeID() )
504 const GeoShapeUnion* theUnion =
dynamic_cast<const GeoShapeUnion*
> (geoShape);
505 if (
nullptr==theUnion)
throw std::runtime_error(
"TypeID did not match cast for union");
506 if (
n.empty())
n=
"Union";
507 solidA = Build(theUnion->getOpA());
508 solidB = Build(theUnion->getOpB());
509 theSolid =
new G4UnionSolid(
n, solidA, solidB);
514 else if (geoShape->typeID() == GeoShapeIntersection::getClassTypeID() )
516 const GeoShapeIntersection* theIntersection =
dynamic_cast<const GeoShapeIntersection*
>(geoShape);
517 if (
nullptr==theIntersection)
throw std::runtime_error(
"TypeID did not match cast for intersection");
518 if (
n.empty())
n=
"Intersection";
519 solidA = Build(theIntersection->getOpA());
520 solidB = Build(theIntersection->getOpB());
521 theSolid =
new G4IntersectionSolid(
n, solidA, solidB);
526 else if (geoShape->typeID() == GeoShapeSubtraction::getClassTypeID() )
528 const GeoShapeSubtraction* theSubtraction =
dynamic_cast<const GeoShapeSubtraction*
>(geoShape);
529 if (
nullptr==theSubtraction)
throw std::runtime_error(
"TypeID did not match cast for subtraction");
530 if (
n.empty())
n=
"Subtraction";
531 solidA = Build(theSubtraction->getOpA());
532 solidB = Build(theSubtraction->getOpB());
533 theSolid =
new G4SubtractionSolid(
n, solidA, solidB);
538 else if(geoShape->typeID() == GeoUnidentifiedShape::getClassTypeID())
540 const GeoUnidentifiedShape* customShape =
dynamic_cast<const GeoUnidentifiedShape*
> (geoShape);
541 if (
nullptr==customShape)
throw std::runtime_error(
"TypeID did not match cast for custom shape");
542 if (customShape->name()==
"LArCustomShape") {
546 ISvcLocator* svcLocator = Gaudi::svcLocator();
548 SmartIF<IGeoModelSvc> geoModel{svcLocator->service (
"GeoModelSvc")};
551 "Geo2G4SolidFactory",
"AccessGeoModel", FatalException,
552 "Build cannot access GeoModelSvc");
554 SmartIF<IGeoDbTagSvc> geoDbTagSvc{svcLocator->service (
"GeoDbTagSvc")};
555 if ( !geoDbTagSvc ) {
557 "Geo2G4SolidFactory",
"AccessDbTagSvc", FatalException,
558 "Build cannot access DbTagSvc");
561 SmartIF<IRDBAccessSvc> pAccessSvc{svcLocator->service(geoDbTagSvc->getParamSvcName())};
564 "Geo2G4SolidFactory",
"AccessAccessSvc", FatalException,
565 "Build cannot access AccessSvc");
572 std::string customName = customShape->asciiData();
573 customSolidMap::const_iterator
it = customSolids.find(customName);
574 if(
it!=customSolids.end())
575 theSolid =
it->second;
579 if(customName.find(
"Slice") != std::string::npos){
580 theSolid = createLArWheelSliceSolid(customShape,emecData);
582 theSolid = createLArWheelSolid(customName, s_lwsTypes.at(customName) ,emecData);
584 if (
nullptr == theSolid ) {
585 std::string
error = std::string(
"Can't create LArWheelSolid for name ") + customName +
" in Geo2G4SolidFactory::Build";
586 throw std::runtime_error(
error);
589 if(theSolid !=
nullptr) customSolids[customName] = theSolid;
598 ATH_MSG_FATAL(
"Sorry this solid is not yet implemented... ");
604 sharedShapes[geoShape] = theSolid;
610 int zside = lwsdef.second;
616 if ( m_detStore->record(theLWS_p,
name).isFailure() ) {
617 ATH_MSG_WARNING(
"Can't store proxy for LArWheelSolid to the DetectorStore");
629 if(m_detStore->record(theLWS_p, theLWS->GetName()).isFailure()){
630 ATH_MSG_WARNING(
"Can't store proxy for LArWheelSolid to the DetectorStore");