Files
geant4/source/geometry/volumes/src/G4PVReplica.cc
T
2025-12-05 08:54:02 +01:00

402 lines
14 KiB
C++

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Class G4PVReplica Implementation
//
// Original author: Paul Kent (CERN), 29 July 1995 - First non-stub version
// - G.Cosmo, A.Dotti (CERN), 13 January 2013 - Modified for MT thread-safety
// ----------------------------------------------------------------------
#include "G4PVReplica.hh"
#include "G4LogicalVolume.hh"
// ----------------------------------------------------------------------
G4PVRManager G4PVReplica::subInstanceManager;
// Helping in the use of the class G4PVRManager.
#define G4MT_copyNo ((subInstanceManager.offset[instanceID]).fcopyNo)
// This macro changes the references to fields that are now encapsulated
// in the class G4ReplicaData.
// ----------------------------------------------------------------------
G4PVReplica::G4PVReplica( const G4String& pName,
G4LogicalVolume* pLogical,
G4VPhysicalVolume* pMother,
const EAxis pAxis,
const G4int nReplicas,
const G4double width,
const G4double offset )
: G4VPhysicalVolume(nullptr, G4ThreeVector(), pName, pLogical, pMother)
{
instanceID = subInstanceManager.CreateSubInstance();
if ((pMother == nullptr) || (pMother->GetLogicalVolume() == nullptr))
{
std::ostringstream message;
message << "NULL pointer specified as mother volume." << G4endl
<< "The world volume cannot be sliced or parameterised !";
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
G4LogicalVolume* motherLogical = pMother->GetLogicalVolume();
if (pLogical == motherLogical)
{
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, "Cannot place a volume inside itself!");
return;
}
SetMotherLogical(motherLogical);
motherLogical->AddDaughter(this);
if (motherLogical->GetNoDaughters() != 1)
{
std::ostringstream message;
message << "Replica or parameterised volume must be the only daughter !"
<< G4endl
<< " Mother physical volume: " << pMother->GetName() << G4endl
<< " Replicated volume: " << pName;
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
CheckAndSetParameters (pAxis, nReplicas, width, offset);
}
// ----------------------------------------------------------------------
G4PVReplica::G4PVReplica( const G4String& pName,
G4LogicalVolume* pLogical,
G4LogicalVolume* pMotherLogical,
const EAxis pAxis,
const G4int nReplicas,
const G4double width,
const G4double offset )
: G4VPhysicalVolume(nullptr, G4ThreeVector(), pName, pLogical, nullptr)
{
instanceID = subInstanceManager.CreateSubInstance();
if (pMotherLogical == nullptr)
{
std::ostringstream message;
message << "NULL pointer specified as mother volume for "
<< pName << ".";
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
if (pLogical == pMotherLogical)
{
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, "Cannot place a volume inside itself!");
return;
}
pMotherLogical->AddDaughter(this);
SetMotherLogical(pMotherLogical);
if (pMotherLogical->GetNoDaughters() != 1)
{
std::ostringstream message;
message << "Replica or parameterised volume must be the only daughter !"
<< G4endl
<< " Mother logical volume: " << pMotherLogical->GetName()
<< G4endl
<< " Replicated volume: " << pName;
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
CheckAndSetParameters (pAxis, nReplicas, width, offset);
}
// ----------------------------------------------------------------------
G4PVReplica::G4PVReplica( const G4String& pName,
G4int nReplicas,
EAxis pAxis,
G4LogicalVolume* pLogical,
G4LogicalVolume* pMotherLogical )
: G4VPhysicalVolume(nullptr, G4ThreeVector(), pName, pLogical, nullptr)
{
// Constructor for derived type(s)
// Does not set mother volume or register this one in mother volume
// ( To allow the correct type to be found in mother->AddDaughter )
instanceID = subInstanceManager.CreateSubInstance();
if (pMotherLogical == nullptr)
{
std::ostringstream message;
message << "NULL pointer specified as mother volume for "
<< pName << ".";
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
if (pLogical == pMotherLogical)
{
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, "Cannot place a volume inside itself!");
return;
}
CheckOnlyDaughter(pMotherLogical);
/***
if (pMotherLogical->GetNoDaughters() != 0)
{
std::ostringstream message;
message << "Replica or parameterised volume must be the only daughter !"
<< G4endl
<< " Mother logical volume: " << pMotherLogical->GetName()
<< G4endl
<< " Replicated volume: " << pName;
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
**/
CheckAndSetParameters (pAxis, nReplicas, 0.0, 0.0);
}
// ----------------------------------------------------------------------
void G4PVReplica::CheckOnlyDaughter(G4LogicalVolume* pMotherLogical)
{
if (pMotherLogical->GetNoDaughters() != 0)
{
std::ostringstream message;
message << "Replica or parameterised volume must be the only daughter !"
<< G4endl
<< " Mother logical volume: " << pMotherLogical->GetName()
<< G4endl
<< " Replicated volume: " << this->GetName() << G4endl
<< " Existing 'sister': " << pMotherLogical->GetDaughter(0)
->GetName();
G4Exception("G4PVReplica::G4PVReplica()", "GeomVol0002",
FatalException, message);
return;
}
}
// ----------------------------------------------------------------------
void G4PVReplica::CheckAndSetParameters( const EAxis pAxis,
const G4int nReplicas,
const G4double width,
const G4double offset)
{
if (nReplicas<1)
{
G4Exception("G4PVReplica::CheckAndSetParameters()", "GeomVol0002",
FatalException, "Illegal number of replicas.");
}
fnReplicas=nReplicas;
if (width<0)
{
G4Exception("G4PVReplica::CheckAndSetParameters()", "GeomVol0002",
FatalException, "Width must be positive.");
}
fwidth = width;
foffset = offset;
faxis = pAxis;
// Create rotation matrix for phi axis case & check axis is valid
//
G4RotationMatrix* pRMat = nullptr;
switch (faxis)
{
case kPhi:
pRMat = new G4RotationMatrix();
if (pRMat == nullptr)
{
G4Exception("G4PVReplica::CheckAndSetParameters()", "GeomVol0003",
FatalException, "Rotation matrix allocation failed.");
}
SetRotation(pRMat);
break;
case kRho:
case kXAxis:
case kYAxis:
case kZAxis:
case kUndefined:
break;
default:
G4Exception("G4PVReplica::CheckAndSetParameters()", "GeomVol0002",
FatalException, "Unknown axis of replication.");
break;
}
}
// ----------------------------------------------------------------------
G4PVReplica::G4PVReplica( __void__& a )
: G4VPhysicalVolume(a), faxis(kZAxis), fnReplicas(0), fwidth(0.), foffset(0.)
{
instanceID = subInstanceManager.CreateSubInstance();
}
// ----------------------------------------------------------------------
G4bool G4PVReplica::IsMany() const
{
return false;
}
// ----------------------------------------------------------------------
G4int G4PVReplica::GetCopyNo() const
{
return G4MT_copyNo;
}
// ----------------------------------------------------------------------
void G4PVReplica::SetCopyNo(G4int newCopyNo)
{
G4MT_copyNo = newCopyNo;
}
// ----------------------------------------------------------------------
G4bool G4PVReplica::IsReplicated() const
{
return true;
}
// ----------------------------------------------------------------------
G4bool G4PVReplica::IsParameterised() const
{
return false;
}
// ----------------------------------------------------------------------
G4VPVParameterisation* G4PVReplica::GetParameterisation() const
{
return nullptr;
}
// ----------------------------------------------------------------------
G4int G4PVReplica::GetMultiplicity() const
{
return fnReplicas;
}
// ----------------------------------------------------------------------
EVolume G4PVReplica::VolumeType() const
{
return kReplica;
}
// ----------------------------------------------------------------------
void G4PVReplica::GetReplicationData( EAxis& axis,
G4int& nReplicas,
G4double& width,
G4double& offset,
G4bool& consuming ) const
{
axis = faxis;
nReplicas = fnReplicas;
width = fwidth;
offset = foffset;
consuming = true;
}
// ----------------------------------------------------------------------
G4bool G4PVReplica::IsRegularStructure() const
{
return (fRegularVolsId != 0);
}
// ----------------------------------------------------------------------
G4int G4PVReplica::GetRegularStructureId() const
{
return fRegularVolsId;
}
// ----------------------------------------------------------------------
void G4PVReplica::SetRegularStructureId( G4int code )
{
fRegularVolsId = code;
}
// ----------------------------------------------------------------------
// Returns the private data instance manager.
//
const G4PVRManager& G4PVReplica::GetSubInstanceManager()
{
return subInstanceManager;
}
// ----------------------------------------------------------------------
// This method is similar to the constructor. It is used by each worker
// thread to achieve the same effect as that of the master thread exept
// to register the new created instance. This method is invoked explicitly.
// It does not create a new G4PVReplica instance. It only assigns the value
// for the fields encapsulated by the class G4ReplicaData.
//
void G4PVReplica::InitialiseWorker(G4PVReplica* pMasterObject)
{
G4VPhysicalVolume::InitialiseWorker( pMasterObject, nullptr, G4ThreeVector());
subInstanceManager.SlaveCopySubInstanceArray();
G4MT_copyNo = -1;
// This call causes "self-assignment" of the input parameters
// Issue reported by DRD since TerminateWorker() below can be called
// at the same time by another thread.
// What we need here is the split-class component of CheckAndSetParameters()
// funciton copied here.
// Create rotation matrix for phi axis case & check axis is valid
//
G4RotationMatrix* pRMat = nullptr;
switch (faxis)
{
case kPhi:
pRMat = new G4RotationMatrix();
if (pRMat == nullptr)
{
G4Exception("G4PVReplica::InitialiseWorker(...)", "GeomVol0003",
FatalException, "Rotation matrix allocation failed.");
}
SetRotation(pRMat);
break;
case kRho:
case kXAxis:
case kYAxis:
case kZAxis:
case kUndefined:
break;
default:
G4Exception("G4PVReplica::InitialiseWorker(...)", "GeomVol0002",
FatalException, "Unknown axis of replication.");
break;
}
}
// ----------------------------------------------------------------------
// This method is similar to the destructor. It is used by each worker
// thread to achieve the partial effect as that of the master thread.
// For G4PVReplica instances, it destroys the rotation matrix.
//
void G4PVReplica::TerminateWorker(G4PVReplica* /*pMasterObject*/)
{
if ( faxis==kPhi )
{
delete GetRotation();
}
}