Forked from
atlas / athena
130760 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ExtParameterisedVolumeBuilder.cxx 25.73 KiB
/*
Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
*/
#include "ExtParameterisedVolumeBuilder.h"
#include "Geo2G4AssemblyFactory.h"
#include "Geo2G4AssemblyVolume.h"
#include "Geo2G4LVFactory.h"
#include "Geo2G4STParameterisation.h"
#include "G4LogicalVolume.hh"
#include "G4PVPlacement.hh"
#include "G4ReflectionFactory.hh"
#include "G4VPVParameterisation.hh"
#include "G4PVParameterised.hh"
#include "G4AffineTransform.hh"
#include "G4UnitsTable.hh"
#include "G4LogicalVolume.hh"
#include "G4VSolid.hh"
#include "G4SubtractionSolid.hh"
#include "G4PhysicalVolumeStore.hh"
#include "globals.hh"
#include "SimHelpers/ServiceAccessor.h"
#include "GeoModelKernel/GeoAccessVolAndSTAction.h"
#include "GeoModelKernel/GeoVolumeCursor.h"
#include "GeoModelKernel/GeoMaterial.h"
#include "GeoModelKernel/GeoLogVol.h"
#include "GeoModelKernel/GeoSerialTransformer.h"
#include "GeoModelInterfaces/StoredMaterialManager.h"
#include "AthenaBaseComps/AthMsgStreamMacros.h"
#include "StoreGate/StoreGateSvc.h"
#include <iostream>
ExtParameterisedVolumeBuilder::ExtParameterisedVolumeBuilder(std::string n):
VolumeBuilder(n),
m_getMatEther(true),
m_matEther(0),m_matHypUr(0),m_msg(n)
{
}
//stolen from G4bool G4PVPlacement::CheckOverlaps, but revised so we can tell what it overlaps with...
//returns 0 if no overlap, overwise returns overlapping volume pointer...and whether it's with the mother...
G4VPhysicalVolume* check_overlap(G4VPhysicalVolume *me, int &mom){
int res = 1000;//number of points to check per volume!
mom=-1;//will return whether it is the mom that is overlapping or not...
G4VSolid* solid = me->GetLogicalVolume()->GetSolid();
G4LogicalVolume* motherLog = me->GetMotherLogical();
//std::cout<<"check_overlap"<<std::endl;
if (!motherLog) { return 0; }
G4VSolid* motherSolid = motherLog->GetSolid();
// Create the transformation from daughter to mother
G4AffineTransform Tm( me->GetRotation(), me->GetTranslation() );
std::cout<<"check_overlap for "<<me->GetName()<<" with "<<res<<" points"<<std::endl;
for (G4int n=0; n<res; n++)
{
// Generate a random point on the solid's surface
G4ThreeVector point = solid->GetPointOnSurface();
// Transform the generated point to the mother's coordinate system
G4ThreeVector mp = Tm.TransformPoint(point);
// Checking overlaps with the mother volume
if (motherSolid->Inside(mp)==kOutside)
{
G4double distin = motherSolid->DistanceToIn(mp);
if (distin>0)
{
// std::ostringstream message;
// message << "Overlap with mother volume !" << G4endl
// << " Overlap is detected for volume "
// << me->GetName() << G4endl
// << " with its mother volume "
// << motherLog->GetName() << G4endl
// << " at mother local point " << mp << ", "
// << "overlapping by at least: "
// << G4BestUnit(distin, "Length");
//G4Exception("G4PVPlacement::CheckOverlaps()","GeomVol1002", JustWarning, message);
mom=1;
return 0;//motherLog;
}
}
// Checking overlaps with each 'sister' volume
for (G4int i=0; i<motherLog->GetNoDaughters(); i++)
{
G4VPhysicalVolume* daughter = motherLog->GetDaughter(i);
if (daughter == me) { continue; }
// Create the transformation for daughter volume and transform point
G4AffineTransform Td( daughter->GetRotation(),
daughter->GetTranslation() );
G4ThreeVector md = Td.Inverse().TransformPoint(mp);
G4VSolid* daughterSolid = daughter->GetLogicalVolume()->GetSolid();
if (daughterSolid->Inside(md)==kInside)
{
G4double distout = daughterSolid->DistanceToOut(md);
if (distout>0)
{
// std::ostringstream message;
// message << "Overlap with volume already placed !" << G4endl
// << " Overlap is detected for volume "
// << me->GetName() << G4endl
// << " with " << daughter->GetName() << " volume's"
// << G4endl
// << " local point " << md << ", "
// << "overlapping by at least: "
// << G4BestUnit(distout,"Length");
// G4Exception("G4PVPlacement::CheckOverlaps()",
// "GeomVol1002", JustWarning, message);
mom=0;
return daughter;
}
}
// Now checking that 'sister' volume is not totally included and
// overlapping. Do it only once, for the first point generated
if (n==0)
{
// Generate a single point on the surface of the 'sister' volume
// and verify that the point is NOT inside the current volume
G4ThreeVector dPoint = daughterSolid->GetPointOnSurface();
// Transform the generated point to the mother's coordinate system
// and finally to current volume's coordinate system
G4ThreeVector mp2 = Td.TransformPoint(dPoint);
G4ThreeVector msi = Tm.Inverse().TransformPoint(mp2);
if (solid->Inside(msi)==kInside)
{
// std::ostringstream message;
// message << "Overlap with volume already placed !" << G4endl
// << " Overlap is detected for volume "
// << me->GetName() << G4endl
// << " apparently fully encapsulating volume "
// << daughter->GetName() << G4endl
// << " at the same level !";
// G4Exception("G4PVPlacement::CheckOverlaps()",
// "GeomVol1002", JustWarning, message);
mom=2;
return daughter;
}
}
}
}
return 0;//no overlap!
}
G4LogicalVolume* ExtParameterisedVolumeBuilder::Build(const PVConstLink theGeoPhysVolume, OpticalVolumesMap* optical_volumes) const
{
MsgStream log(msgSvc(),GetKey());
PVConstLink theGeoPhysChild;
const GeoSerialTransformer* serialTransformerChild=0;
G4LogicalVolume* theG4LogChild;
unsigned int numChildNodes; // number of child nodes (PV and ST)
bool descend; // flag to continue geo tree navigation
bool serialExists = false; // flag for existence of ST among childs
std::string nameChild;
if(m_getMatEther) getMatEther();
static Geo2G4LVFactory LVFactory;
G4LogicalVolume* theG4LogVolume = LVFactory.Build(theGeoPhysVolume,descend);
if(!descend) return theG4LogVolume;
numChildNodes = theGeoPhysVolume->getNChildVolAndST();
// *****************************************************************
// **
// ** If m_ST2Param flag is set:
// ** Check if there's any serial transformer among child volumes
// **
// *****************************************************************
if(m_paramOn)
for(size_t counter1=0; counter1<numChildNodes; counter1++)
{
GeoAccessVolAndSTAction actionVolAndST(counter1);
theGeoPhysVolume->exec(&actionVolAndST);
if((serialTransformerChild=actionVolAndST.getSerialTransformer()))
{
nameChild = actionVolAndST.getName();
serialExists = true;
break;
}
}
// ***************************************************************************
// ** Next steps:
// **
// ** 1. If ST exists and numChildNodes==1, translate ST to G4 ST
// **
// ** 2. If ST exists and numChildNodes !=1, print information message and
// ** translate ST to single placements as well as all other child volumes
// **
// ** 3. There's no ST - ok, nothing special ...
// **
// ***************************************************************************
if(serialExists && (numChildNodes==1))
{
theGeoPhysChild = serialTransformerChild->getVolume();
// Build the child
if(!(theG4LogChild = Build(theGeoPhysChild,optical_volumes))) return 0;
if (nameChild == "ANON") nameChild=theG4LogChild->GetName();
nameChild += "_Param";
Geo2G4STParameterisation* stParameterisation = new Geo2G4STParameterisation(serialTransformerChild->getFunction(),
serialTransformerChild->getNCopies());
G4VPhysicalVolume* pvParametrised __attribute__ ((unused)) = new G4PVParameterised(nameChild,
theG4LogChild,
theG4LogVolume,
kUndefined,
serialTransformerChild->getNCopies(),
stParameterisation);
}
else
{
if(serialExists)
{
std::string volName = theGeoPhysVolume->getLogVol()->getName();
PrintSTInfo(volName);
}
GeoVolumeCursor av(theGeoPhysVolume);
while (!av.atEnd())
{
int id = 16969;
// Get child phys volume
theGeoPhysChild = av.getVolume();
// Get its transform
G4Transform3D theG4Position(av.getTransform());
Query<int> Qint = av.getId();
if(Qint.isValid()) id = Qint;
if(m_matEther == theGeoPhysChild->getLogVol()->getMaterial())
{
Geo2G4AssemblyVolume* assembly = BuildAssembly(theGeoPhysChild);
if(Qint.isValid())
assembly->MakeImprint(theG4LogVolume,theG4Position,id);
else
assembly->MakeImprint(theG4LogVolume,theG4Position);
}
else if(m_matHypUr == theGeoPhysChild->getLogVol()->getMaterial())
{
Geo2G4AssemblyVolume* assembly = BuildAssembly(theGeoPhysChild);
if(Qint.isValid())
assembly->MakeImprint(theG4LogVolume,theG4Position,id,true);
else
assembly->MakeImprint(theG4LogVolume,theG4Position,0,true);
}
else
{
nameChild = av.getName();
// Build the child
if(!(theG4LogChild = Build(theGeoPhysChild,optical_volumes))) return 0;
if (nameChild == "ANON") nameChild=theG4LogChild->GetName();
log << MSG::DEBUG << "ACH655 Placing child: "<<nameChild<<"["<<id<<"]"<<" in mother "<<theG4LogVolume->GetName()<<endmsg;
bool surfcheck=true; //whether to check for overlaps
bool doplace=true;
if ("TRT::MainRadiatorA"==nameChild && 16969==id) surfcheck=true;
if ("TRT::ThinRadiatorA"==nameChild && 16969==id) surfcheck=true;
if ("TRT::InnerSupportA"==nameChild && 16969==id) surfcheck=true;
if ("TRT::OuterSupportA"==nameChild && 16969==id) surfcheck=true;
if ("TRT::MiddleRadiatorA"==nameChild && 16969==id) surfcheck=true;
//if ("TRT::Straw"==nameChild) doplace=false;//don't build straws for now
//if ("TRT::StrawPlane"==nameChild && id!=2) doplace=false;//only build one strawplane for now
if (std::string(nameChild).find("LAr:")!=std::string::npos) surfcheck=false;
if (std::string(nameChild).find("Tile:")!=std::string::npos) surfcheck=false;
if (std::string(nameChild).find("DriftTube")!=std::string::npos) surfcheck=false;
if (std::string(nameChild).find("Muon:")!=std::string::npos) surfcheck=false;
if (std::string(theG4LogVolume->GetName()).find("Muon:")!=std::string::npos) surfcheck=false;//or if the mom is muon
if (std::string(nameChild).find("Pixel:")!=std::string::npos) surfcheck=false;
if (std::string(nameChild).find("SCT:")!=std::string::npos) surfcheck=false;
if (std::string(theG4LogVolume->GetName()).find("SCT:")!=std::string::npos) surfcheck=false;//or if the mom is sct
if (std::string(nameChild).find("_cut")!=std::string::npos) {
doplace=false;//don't add again for now, if we already cut it
log<<MSG::WARNING<<"Why is something that was cut already now being placed again?"<<endmsg;
}
bool dosurfcheckfuringplacement=false;//to run the printout in G4 for surfcheck placements
if (doplace) {
G4PhysicalVolumesPair pvPair = G4ReflectionFactory::Instance()->Place(theG4Position,
nameChild,
theG4LogChild,
theG4LogVolume,
false,
id,
surfcheck&&dosurfcheckfuringplacement);
static int trytofixoverlaps=-1;
if (trytofixoverlaps<0) {//just check it once...
char* pTRY; pTRY=getenv("HAAS_TryToFixOverlaps");
if (pTRY!=NULL) trytofixoverlaps=atoi(pTRY); else trytofixoverlaps=0;
log<<MSG::INFO<<"Try to fix overlaps: "<<trytofixoverlaps<<endmsg;
}
static int docheckoverlaps=-1;
if (docheckoverlaps<0) {//just check it once...
char* pTRY; pTRY=getenv("HAAS_CheckOverlaps");
if (pTRY!=NULL) docheckoverlaps=atoi(pTRY); else docheckoverlaps=0;
log<<MSG::INFO<<"Check for overlaps: "<<docheckoverlaps<<endmsg;
}
while (surfcheck){//keep looping until we break out...
bool triedtofix=false;
int mom=-2; G4VPhysicalVolume* other = 0; if (docheckoverlaps||trytofixoverlaps) {other=check_overlap(pvPair.first,mom);}
if (other){
log<<MSG::INFO<<"ACH649 : "<<other->GetName()<<" is overlapping "<<pvPair.first->GetName()<<" and mom is "<<mom<<endmsg;
if (!trytofixoverlaps){
static int ci = 0; std::string cis; std::stringstream cisout;
cisout<<"_cut"; cisout << ++ci; cis = cisout.str();//keep track of increasing cut N
other->SetName(other->GetName()+cis);
pvPair.first->SetName(pvPair.first->GetName()+cis);
std::cout<<"Now have "<<pvPair.first->GetName()<<" and "<<other->GetName()<<std::endl;
break;//
}
}
else {
break;//no overlaps
}
if (other&&trytofixoverlaps){
//do something to try to fix the overlap!
if (0==mom){
static int ci = 0; std::string cis; std::stringstream cisout;
cisout<<"_cut"; cisout << ++ci; cis = cisout.str();//keep track of increasing cut N
//easiest case, overlaping sisters within the same mother
//first make the new solid, via subtraction
G4RotationMatrix *myrot=new G4RotationMatrix();//initially Identity
if (other->GetRotation()) (*myrot)= *(other->GetRotation());//make sure it's not null
(*myrot)*=pvPair.first->GetObjectRotationValue();//straw rot * inverse support rot?
G4SubtractionSolid* cutout = new G4SubtractionSolid(pvPair.first->GetName()+cis, //TRT::InnerSupportB_cut5
pvPair.first->GetLogicalVolume()->GetSolid(), //TRT::InnerSupportB solid
other->GetLogicalVolume()->GetSolid(), //TRT::StrawPlane solid
myrot,//made just above
other->GetTranslation() - pvPair.first->GetTranslation() //straw - support
);
log<<MSG::INFO<<"ACH544 Replacing "<<pvPair.first->GetName()<<" volume of size "
<<pvPair.first->GetLogicalVolume()->GetSolid()->GetCubicVolume()
<<" with cutout volume "<<cutout->GetCubicVolume()<<endmsg;
//then we copy the logical volume, since it will have a different (cutout) solid
G4LogicalVolume *lv=pvPair.first->GetLogicalVolume();
std::cout<<"old name is "<<lv->GetName()<<" and cis is "<<cis<<std::endl;
G4LogicalVolume *lvnew = new G4LogicalVolume(cutout, lv->GetMaterial(),
lv->GetName()+cis, lv->GetFieldManager(), lv->GetSensitiveDetector(), lv->GetUserLimits() );
//copy the daughters of the old volume into the new volume
for (int d=0; d<lv->GetNoDaughters(); ++d){
lvnew->AddDaughter(lv->GetDaughter(d));
}
//really we should copy the daughters too, and then do daughter->SetMotherLogical(pvPair.first->GetLogicalVolume()); !!!
//TODO...
log<<MSG::INFO<<"New LogicalVolume "<<lvnew->GetName()<<" has "<<lvnew->GetNoDaughters()<<" daughters"<<endmsg;
//remove the old and make a new PhysicalVolume
G4String newvolname = pvPair.first->GetName()+cis;
pvPair.first->SetName(pvPair.first->GetName()+"_old");
G4PhysicalVolumeStore::DeRegister(pvPair.first);
delete pvPair.first;//!!!
G4PhysicalVolumesPair pvPair2 = G4ReflectionFactory::Instance()->Place(theG4Position,
newvolname,
lvnew,
theG4LogVolume,
false,
id,
true);//surfcheck&&dosurfcheckfuringplacement);
other->SetName(other->GetName()+cis);
if (pvPair2.first) std::cout<<"Now have first volume "<<pvPair2.first->GetName()<<" and "<<other->GetName()<<std::endl;
if (pvPair2.second) std::cout<<"Now have second volume "<<pvPair2.first->GetName()<<" and "<<other->GetName()<<std::endl;
triedtofix=true;
pvPair.first=pvPair2.first;//for the next time through the while loop checking for more overlaps...
}
else if (2==mom){
//a sister is totally inside me?
}
else {
log<<MSG::ERROR<<" How can mom be "<<mom<<" here ???"<<endmsg;
}
//
}//other
else if (mom==1 && trytofixoverlaps){
log<<MSG::WARNING<<"ACH649 : overlapping pvPair first with mother (not fixing yet), "
<<pvPair.first->GetName()<<" and mom is "<<mom<<endmsg;
}
if (pvPair.second){
mom=-2;
other = check_overlap(pvPair.second,mom);
if (other){
log<<MSG::WARNING<<"ACH649 : "<<other->GetName()<<" is overlapping pvPair second (not fixing yet), "
<<pvPair.second->GetName()<<" and mom is "<<mom<<endmsg;
}
else if (mom==1){
log<<MSG::WARNING<<"ACH649 : overlapping pvPair second (not fixing yet), "
<<pvPair.second->GetName()<<" and mom is "<<mom<<endmsg;
}
}
if (triedtofix){
int mom2=-2; G4VPhysicalVolume* other2 = check_overlap(pvPair.first,mom2);//recheck!
if (other2){
log<<MSG::INFO<<"ACH644 : "<<other2->GetName()<<" is still overlapping "<<pvPair.first->GetName()<<" and mom2 is "<<mom2<<endmsg;
//try again...
}
else if (mom2==1){
log<<MSG::WARNING<<"ACH644 : overlapping pvPair first with mother STILL "<<pvPair.first->GetName()<<" and mom2 is "<<mom2<<endmsg;
break;//not fixing it yet...
}
else{
log<<MSG::INFO<<"ACH644 : no overlaps for "<<pvPair.first->GetName()<<" now and mom2 is "<<mom2<<endmsg;
break;//good jorb!
}
}
}//while surfcheck
// if GeoModel volume is optical store it in the map
if(optical_volumes!=0)
{
const GeoOpticalPhysVol* opticalGeoPhysChild =
dynamic_cast < const GeoOpticalPhysVol* >(theGeoPhysChild.operator->());
if(opticalGeoPhysChild)
(*optical_volumes)[opticalGeoPhysChild] = pvPair.first;
}
}//doplace
}
av.next();
}
}
return theG4LogVolume;
}
Geo2G4AssemblyVolume* ExtParameterisedVolumeBuilder::BuildAssembly(PVConstLink pv) const
{
PVConstLink theGeoPhysChild;
G4LogicalVolume* theG4LogChild = 0;
Geo2G4AssemblyVolume* theG4AssemblyChild = 0;
bool descend; // flag to continue geo tree navigation
if(m_getMatEther) getMatEther();
static Geo2G4AssemblyFactory AssemblyFactory;
Geo2G4AssemblyVolume* assemblyVolume = AssemblyFactory.Build(pv,descend);
if(!descend) return assemblyVolume;
// Loop over child volumes and add them to the Geo2G4AssemblyVolume
GeoVolumeCursor av(pv);
while (!av.atEnd())
{
theGeoPhysChild = av.getVolume();
std::string nameChild = av.getName();
std::string strVolume = std::string("Volume ") + nameChild + " ("
+ theGeoPhysChild->getLogVol()->getName() + ")";
// Check if it is an assembly
if(m_matEther == theGeoPhysChild->getLogVol()->getMaterial() ||
m_matHypUr == theGeoPhysChild->getLogVol()->getMaterial() )
{
// Build the child assembly
if(!(theG4AssemblyChild = BuildAssembly(theGeoPhysChild))) return 0;
// Get its transform
G4Transform3D theG4Position(av.getTransform());
assemblyVolume->AddPlacedAssembly(theG4AssemblyChild,theG4Position);
}
else
{
Query<int> Qint = av.getId();
// Build the child
if(!(theG4LogChild = Build(theGeoPhysChild))) return 0;
// Get its transform
G4Transform3D theG4Position(av.getTransform());
int placedID = 0;
if(Qint.isValid()) placedID = Qint;
std::string placedName = nameChild=="ANON" ? "" : nameChild;
assemblyVolume->AddPlacedVolume(theG4LogChild,theG4Position,placedID,placedName);
}
av.next();
}
return assemblyVolume;
}
void ExtParameterisedVolumeBuilder::PrintSTInfo(std::string volume) const
{
ATH_MSG_INFO ( "**********************************************" );
ATH_MSG_INFO ( "** " );
ATH_MSG_INFO ( "** The Volume " << volume );
ATH_MSG_INFO ( "** Has children of two different types" );
ATH_MSG_INFO ( "** PeoPhysVolume and GeoSerialTransformer" );
ATH_MSG_INFO ( "** In this case GeoSerialTransformer will be " );
ATH_MSG_INFO ( "** translated into G4 placement but not in " );
ATH_MSG_INFO ( "** G4Parameterisation" );
ATH_MSG_INFO ( "** " );
ATH_MSG_INFO ( "********************************************** " );
}
void ExtParameterisedVolumeBuilder::getMatEther() const
{
StoreGateSvc* pDetStore=0;
ISvcLocator* svcLocator = Gaudi::svcLocator();
if(svcLocator->service("DetectorStore",pDetStore).isFailure()) {
ATH_MSG_ERROR ( "ExtParameterisedVolumeBuilder: Unable to access Detector Store" );
}
else
{
DataHandle<StoredMaterialManager> theMaterialManager;
if(pDetStore->retrieve(theMaterialManager, "MATERIALS").isFailure()) {
ATH_MSG_ERROR ( "ExtParameterisedVolumeBuilder: Unable to access Material Manager" );
}
else {
m_matEther = theMaterialManager->getMaterial("special::Ether");
m_matHypUr = theMaterialManager->getMaterial("special::HyperUranium");
}
}
m_getMatEther = false;
}