// // ******************************************************************** // * 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 G4ReflectionFactory Implementation // // Decomposition of a general transformation // that can include reflection in a "reflection-free" transformation: // // x(inM') = TG*x(inM) TG - general transformation // = T*(R*x(inM)) T - "reflection-free" transformation // = T* x(inReflM) // // Daughters transformation: // When a volume V containing daughter D with transformation TD // is placed in mother M with a general tranformation TGV, // the TGV is decomposed, // new reflected volume ReflV containing a new daughter ReflD // with reflected transformation ReflTD is created: // // x(inV) = TD * x(inD); // x(inM) = TGV * x(inV) // = TV * R * x(inV) // = TV * R * TD * x(inD) // = TV * R*TD*R-1 * R*x(inD) // = TV * ReflTD * x(inReflD) // // Author: Ivana Hrivnacova (IN2P3/IJCLab Orsay), 16 October 2001 // -------------------------------------------------------------------- #include "G4ReflectionFactory.hh" #include "G4ReflectedSolid.hh" #include "G4Region.hh" #include "G4LogicalVolume.hh" #include "G4PVPlacement.hh" #include "G4PVReplica.hh" #include "G4VPVDivisionFactory.hh" #include "G4GeometryTolerance.hh" G4ThreadLocal G4ReflectionFactory* G4ReflectionFactory::fInstance = nullptr; const G4String G4ReflectionFactory::fDefaultNameExtension = "_refl"; const G4Scale3D G4ReflectionFactory::fScale = G4ScaleZ3D(-1.0); //_____________________________________________________________________________ G4ReflectionFactory* G4ReflectionFactory::Instance() { // Static singleton access method. // --- if (fInstance == nullptr) { fInstance = new G4ReflectionFactory(); } return fInstance; } //_____________________________________________________________________________ G4ReflectionFactory::G4ReflectionFactory() : fNameExtension(fDefaultNameExtension) { // Protected singleton constructor. // --- fScalePrecision = 10. * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); fInstance = this; } //_____________________________________________________________________________ G4ReflectionFactory::~G4ReflectionFactory() { delete fInstance; } // // public methods // //_____________________________________________________________________________ G4PhysicalVolumesPair G4ReflectionFactory::Place( const G4Transform3D& transform3D, const G4String& name, G4LogicalVolume* LV, G4LogicalVolume* motherLV, G4bool isMany, G4int copyNo, G4bool surfCheck) { // Evaluates the passed transformation; if it contains reflection // it performs its decomposition, creates new reflected solid and // logical volume (or retrieves them from a map if the reflected // objects were already created), transforms the daughters (if present) // and place it in the given mother. // The result is a pair of physical volumes; // the second physical volume is a placement in a reflected mother // - or nullptr if mother LV was not reflected. // --- if (fVerboseLevel>0) { G4cout << "Place " << name << " lv " << LV << " " << LV->GetName() << G4endl; } // decompose transformation G4Scale3D scale; G4Rotate3D rotation; G4Translate3D translation; transform3D.getDecomposition(scale, rotation, translation); G4Transform3D pureTransform3D = translation * rotation; //PrintTransform(transform3D); //PrintTransform(pureTransform3D); // check that scale correspond to fScale // CheckScale(scale); // // reflection IS NOT present in transform3D // if (!IsReflection(scale)) { if (fVerboseLevel>0) { G4cout << "Scale positive" << G4endl; } G4VPhysicalVolume* pv1 = new G4PVPlacement(pureTransform3D, LV, name, motherLV, isMany, copyNo, surfCheck); G4VPhysicalVolume* pv2 = nullptr; if (G4LogicalVolume* reflMotherLV = GetReflectedLV(motherLV)) { // if mother was reflected // reflect this LV and place it in reflected mother pv2 = new G4PVPlacement(fScale * (pureTransform3D * fScale.inverse()), ReflectLV(LV, surfCheck), name, reflMotherLV, isMany, copyNo, surfCheck); } return {pv1, pv2}; } // // reflection IS present in transform3D // if (fVerboseLevel>0) { G4cout << "scale negative" << G4endl; } G4VPhysicalVolume* pv1 = new G4PVPlacement(pureTransform3D, ReflectLV(LV, surfCheck), name, motherLV, isMany, copyNo, surfCheck); G4VPhysicalVolume* pv2 = nullptr; if (G4LogicalVolume* reflMotherLV = GetReflectedLV(motherLV)) { // if mother was reflected // place the refLV consituent in reflected mother pv2 = new G4PVPlacement(fScale * (pureTransform3D * fScale.inverse()), LV, name, reflMotherLV, isMany, copyNo, surfCheck); } return {pv1, pv2}; } //_____________________________________________________________________________ G4PhysicalVolumesPair G4ReflectionFactory::Replicate(const G4String& name, G4LogicalVolume* LV, G4LogicalVolume* motherLV, EAxis axis, G4int nofReplicas, G4double width, G4double offset) { // Creates replica in given mother. // The result is a pair of physical volumes; // the second physical volume is a replica in a reflected mother // - or nullptr if mother LV was not reflected. // --- if (fVerboseLevel>0) { G4cout << "Replicate " << name << " lv " << LV << " " << LV->GetName() << G4endl; } G4VPhysicalVolume* pv1 = new G4PVReplica(name, LV, motherLV, axis, nofReplicas, width, offset); G4VPhysicalVolume* pv2 = nullptr; if (G4LogicalVolume* reflMotherLV = GetReflectedLV(motherLV)) { // if mother was reflected // reflect the LV and replicate it in reflected mother pv2 = new G4PVReplica(name, ReflectLV(LV), reflMotherLV, axis, nofReplicas, width, offset); } return {pv1, pv2}; } //_____________________________________________________________________________ G4PhysicalVolumesPair G4ReflectionFactory::Divide(const G4String& name, G4LogicalVolume* LV, G4LogicalVolume* motherLV, EAxis axis, G4int nofDivisions, G4double width, G4double offset) { // Creates division in the given mother. // The result is a pair of physical volumes; // the second physical volume is a division in a reflected mother // or nullptr if mother LV was not reflected. // --- if (fVerboseLevel>0) { G4cout << "Divide " << name << " lv " << LV << " " << LV->GetName() << G4endl; } G4VPVDivisionFactory* divisionFactory = GetPVDivisionFactory(); G4VPhysicalVolume* pv1 = divisionFactory ->CreatePVDivision(name, LV, motherLV, axis, nofDivisions, width, offset); G4VPhysicalVolume* pv2 = nullptr; if (G4LogicalVolume* reflMotherLV = GetReflectedLV(motherLV)) { // if mother was reflected // reflect the LV and replicate it in reflected mother pv2 = divisionFactory->CreatePVDivision(name, ReflectLV(LV), reflMotherLV, axis, nofDivisions, width, offset); } return {pv1, pv2}; } //_____________________________________________________________________________ G4PhysicalVolumesPair G4ReflectionFactory::Divide(const G4String& name, G4LogicalVolume* LV, G4LogicalVolume* motherLV, EAxis axis, G4int nofDivisions, G4double offset) { // Creates division in the given mother. // The result is a pair of physical volumes; // the second physical volume is a division in a reflected mother // or nullptr if mother LV was not reflected. // --- if (fVerboseLevel>0) { G4cout << "Divide " << name << " lv " << LV << " " << LV->GetName() << G4endl; } G4VPVDivisionFactory* divisionFactory = GetPVDivisionFactory(); G4VPhysicalVolume* pv1 = divisionFactory ->CreatePVDivision(name, LV, motherLV, axis, nofDivisions, offset); G4VPhysicalVolume* pv2 = nullptr; if (G4LogicalVolume* reflMotherLV = GetReflectedLV(motherLV)) { // if mother was reflected // reflect the LV and replicate it in reflected mother pv2 = divisionFactory->CreatePVDivision(name, ReflectLV(LV), reflMotherLV, axis, nofDivisions, offset); } return {pv1, pv2}; } //_____________________________________________________________________________ G4PhysicalVolumesPair G4ReflectionFactory::Divide(const G4String& name, G4LogicalVolume* LV, G4LogicalVolume* motherLV, EAxis axis, G4double width, G4double offset) { // Creates division in the given mother. // The result is a pair of physical volumes; // the second physical volume is a division in a reflected mother // or nullptr if mother LV was not reflected. // --- if (fVerboseLevel>0) { G4cout << "Divide " << name << " lv " << LV << " " << LV->GetName() << G4endl; } G4VPVDivisionFactory* divisionFactory = GetPVDivisionFactory(); G4VPhysicalVolume* pv1 = divisionFactory -> CreatePVDivision(name, LV, motherLV, axis, width, offset); G4VPhysicalVolume* pv2 = nullptr; if (G4LogicalVolume* reflMotherLV = GetReflectedLV(motherLV)) { // if mother was reflected // reflect the LV and replicate it in reflected mother pv2 = divisionFactory->CreatePVDivision(name, ReflectLV(LV), reflMotherLV, axis, width, offset); } return {pv1, pv2}; } // // private methods // //_____________________________________________________________________________ G4LogicalVolume* G4ReflectionFactory::ReflectLV(G4LogicalVolume* LV, G4bool surfCheck) { // Gets/creates the reflected solid and logical volume // and copies + transforms LV daughters. // --- G4LogicalVolume* refLV = GetReflectedLV(LV); if (refLV == nullptr) { // create new (reflected) objects // refLV = CreateReflectedLV(LV); // process daughters // ReflectDaughters(LV, refLV, surfCheck); // check if to be set as root region // if (LV->IsRootRegion()) { LV->GetRegion()->AddRootLogicalVolume(refLV); } } return refLV; } //_____________________________________________________________________________ G4LogicalVolume* G4ReflectionFactory::CreateReflectedLV(G4LogicalVolume* LV) { // Creates the reflected solid and logical volume // and add the logical volumes pair in the maps. // --- // consistency check // if (fReflectedLVMap.find(LV) != fReflectedLVMap.cend()) { std::ostringstream message; message << "Invalid reflection for volume: " << LV->GetName() << G4endl << "Cannot be applied to a volume already reflected !"; G4Exception("G4ReflectionFactory::CreateReflectedLV()", "GeomVol0002", FatalException, message); } G4VSolid* refSolid = new G4ReflectedSolid(LV->GetSolid()->GetName() + fNameExtension, LV->GetSolid(), fScale); auto refLV = new G4LogicalVolume(refSolid, LV->GetMaterial(), LV->GetName() + fNameExtension, LV->GetFieldManager(), LV->GetSensitiveDetector(), LV->GetUserLimits()); if (LV->GetVisAttributes() != nullptr) { refLV->SetVisAttributes(*LV->GetVisAttributes()); // vis-attributes } refLV->SetBiasWeight(LV->GetBiasWeight()); // biasing weight if (LV->IsRegion()) { refLV->SetRegion(LV->GetRegion()); // set a region in case } fConstituentLVMap[LV] = refLV; fReflectedLVMap[refLV] = LV; return refLV; } //_____________________________________________________________________________ void G4ReflectionFactory::ReflectDaughters(G4LogicalVolume* LV, G4LogicalVolume* refLV, G4bool surfCheck) { // Reflects daughters recursively. // --- if (fVerboseLevel>0) { G4cout << "G4ReflectionFactory::ReflectDaughters(): " << LV->GetNoDaughters() << " of " << LV->GetName() << G4endl; } for (std::size_t i=0; iGetNoDaughters(); ++i) { G4VPhysicalVolume* dPV = LV->GetDaughter((G4int)i); if (!dPV->IsReplicated()) { ReflectPVPlacement(dPV, refLV, surfCheck); } else if (dPV->GetParameterisation() == nullptr) { ReflectPVReplica(dPV, refLV); } else if ((G4VPVDivisionFactory::Instance() != nullptr) && G4VPVDivisionFactory::Instance()->IsPVDivision(dPV)) { ReflectPVDivision(dPV, refLV); } else { ReflectPVParameterised(dPV, refLV, surfCheck); } } } //_____________________________________________________________________________ void G4ReflectionFactory::ReflectPVPlacement(G4VPhysicalVolume* dPV, G4LogicalVolume* refLV, G4bool surfCheck) { // Copies and transforms daughter of PVPlacement type of // a constituent volume into a reflected volume. // --- G4LogicalVolume* dLV = dPV->GetLogicalVolume(); // update daughter transformation // G4Transform3D dt(dPV->GetObjectRotationValue(), dPV->GetObjectTranslation()); dt = fScale * (dt * fScale.inverse()); G4LogicalVolume* refDLV; if (fVerboseLevel>0) { G4cout << "Daughter: " << dPV << " " << dLV->GetName(); } if (!IsReflected(dLV)) { if (fVerboseLevel>0) { G4cout << " will be reflected." << G4endl; } // get reflected volume if already created refDLV = GetReflectedLV(dLV); if (refDLV == nullptr) { // create new daughter solid and logical volume // refDLV = CreateReflectedLV(dLV); // recursive call // ReflectDaughters(dLV, refDLV, surfCheck); } // create new daughter physical volume // with updated transformation new G4PVPlacement(dt, refDLV, dPV->GetName(), refLV, dPV->IsMany(), dPV->GetCopyNo(), surfCheck); } else { if (fVerboseLevel>0) { G4cout << " will be reconstitued." << G4endl; } refDLV = GetConstituentLV(dLV); new G4PVPlacement(dt, refDLV, dPV->GetName(), refLV, dPV->IsMany(), dPV->GetCopyNo(), surfCheck); } } //_____________________________________________________________________________ void G4ReflectionFactory::ReflectPVReplica(G4VPhysicalVolume* dPV, G4LogicalVolume* refLV) { // Copies and transforms daughter of PVReplica type of // a constituent volume into a reflected volume. // --- G4LogicalVolume* dLV = dPV->GetLogicalVolume(); // get replication data // EAxis axis; G4int nofReplicas; G4double width; G4double offset; G4bool consuming; dPV->GetReplicationData(axis, nofReplicas, width, offset, consuming); G4LogicalVolume* refDLV; if (fVerboseLevel>0) { G4cout << "Daughter: " << dPV << " " << dLV->GetName(); } if (!IsReflected(dLV)) { if (fVerboseLevel>0) { G4cout << " will be reflected." << G4endl; } // get reflected volume if already created // refDLV = GetReflectedLV(dLV); if (refDLV == nullptr) { // create new daughter solid and logical volume // refDLV = CreateReflectedLV(dLV); // recursive call // ReflectDaughters(dLV, refDLV); } // create new daughter replica // new G4PVReplica(dPV->GetName(), refDLV, refLV, axis, nofReplicas, width, offset); } else { if (fVerboseLevel>0) { G4cout << " will be reconstitued." << G4endl; } refDLV = GetConstituentLV(dLV); new G4PVReplica(dPV->GetName(), refDLV, refLV, axis, nofReplicas, width, offset); } } //_____________________________________________________________________________ void G4ReflectionFactory::ReflectPVDivision(G4VPhysicalVolume* dPV, G4LogicalVolume* refLV) { // Copies and transforms daughter of PVDivision type of // a constituent volume into a reflected volume. // --- G4VPVDivisionFactory* divisionFactory = GetPVDivisionFactory(); G4LogicalVolume* dLV = dPV->GetLogicalVolume(); // get parameterisation data // G4VPVParameterisation* param = dPV->GetParameterisation(); G4LogicalVolume* refDLV; if (fVerboseLevel>0) { G4cout << "Daughter: " << dPV << " " << dLV->GetName(); } if (!IsReflected(dLV)) { if (fVerboseLevel>0) { G4cout << " will be reflected." << G4endl; } // get reflected volume if already created // refDLV = GetReflectedLV(dLV); if (refDLV == nullptr) { // create new daughter solid and logical volume // refDLV = CreateReflectedLV(dLV); // recursive call // ReflectDaughters(dLV, refDLV); } // create new daughter replica // divisionFactory->CreatePVDivision(dPV->GetName(), refDLV, refLV, param); } else { if (fVerboseLevel>0) { G4cout << " will be reconstitued." << G4endl; } refDLV = GetConstituentLV(dLV); divisionFactory->CreatePVDivision(dPV->GetName(), refDLV, refLV, param); } } //_____________________________________________________________________________ void G4ReflectionFactory::ReflectPVParameterised(G4VPhysicalVolume* dPV, G4LogicalVolume*, G4bool) { // Not implemented. // Should copy and transform daughter of G4PVParameterised type of // a constituent volume into a reflected volume. // --- std::ostringstream message; message << "Not yet implemented. Volume: " << dPV->GetName() << G4endl << "Reflection of parameterised volumes is not yet implemented."; G4Exception("G4ReflectionFactory::ReflectPVParameterised()", "GeomVol0001", FatalException, message); } //_____________________________________________________________________________ G4LogicalVolume* G4ReflectionFactory::GetConstituentLV(G4LogicalVolume* reflLV) const { // Returns the consituent volume of the given reflected volume, // nullptr if the given reflected volume was not found. // --- auto it = fReflectedLVMap.find(reflLV); if (it == fReflectedLVMap.cend()) { return nullptr; } return (*it).second; } //_____________________________________________________________________________ G4LogicalVolume* G4ReflectionFactory::GetReflectedLV(G4LogicalVolume* lv) const { // Returns the reflected volume of the given consituent volume, // nullptr if the given volume was not reflected. // --- auto it = fConstituentLVMap.find(lv); if (it == fConstituentLVMap.cend()) { return nullptr; } return (*it).second; } //_____________________________________________________________________________ G4bool G4ReflectionFactory::IsConstituent(G4LogicalVolume* lv) const { // Returns true if the given volume has been already reflected // (is in the map of constituent volumes). // --- return (fConstituentLVMap.find(lv) != fConstituentLVMap.cend()); } //_____________________________________________________________________________ G4bool G4ReflectionFactory::IsReflected(G4LogicalVolume* lv) const { // Returns true if the given volume is a reflected volume // (is in the map reflected volumes). // --- return (fReflectedLVMap.find(lv) != fReflectedLVMap.cend()); } //_____________________________________________________________________________ G4bool G4ReflectionFactory::IsReflection(const G4Scale3D& scale) const { // Returns true if the scale is negative, false otherwise. // --- return scale(0,0)*scale(1,1)*scale(2,2) < 0.; } //_____________________________________________________________________________ const G4ReflectedVolumesMap& G4ReflectionFactory::GetReflectedVolumesMap() const { return fReflectedLVMap; } //_____________________________________________________________________________ void G4ReflectionFactory::Clean() { fConstituentLVMap.clear(); fReflectedLVMap.clear(); } //_____________________________________________________________________________ void G4ReflectionFactory::PrintConstituentLVMap() const { // temporary - for debugging purpose // --- for (const auto & it : fConstituentLVMap) { G4cout << "lv: " << it.first << " lv_refl: " << it.second << G4endl; } G4cout << G4endl; } //_____________________________________________________________________________ void G4ReflectionFactory::CheckScale(const G4Scale3D& scale) const { // Check if scale correspond to fScale, // if not give exception. // --- if (!IsReflection(scale)) { return; } G4double diff = 0.; for (auto i=0; i<4; ++i) { for (auto j=0; j<4; ++j) { diff += std::abs(scale(i,j) - fScale(i,j)); } } if (diff > fScalePrecision) { std::ostringstream message; message << "Unexpected scale in input !" << G4endl << " Difference: " << diff; G4Exception("G4ReflectionFactory::CheckScale()", "GeomVol0002", FatalException, message); } } //_____________________________________________________________________________ G4VPVDivisionFactory* G4ReflectionFactory::GetPVDivisionFactory() const { // Returns the G4PVDivisionFactory instance if it exists, // otherwise gives exception // --- G4VPVDivisionFactory* divisionFactory = G4VPVDivisionFactory::Instance(); if (divisionFactory == nullptr) { std::ostringstream message; message << "A concrete G4PVDivisionFactory instantiated is required !" << G4endl << " It has been requested to reflect divided volumes." << G4endl << " In this case, it is required to instantiate a concrete" << G4endl << " factory G4PVDivisionFactory in your program -before-" << G4endl << " executing the reflection !"; G4Exception("G4ReflectionFactory::GetPVDivisionFactory()", "GeomVol0002", FatalException, message); } return divisionFactory; } //_____________________________________________________________________________ void G4ReflectionFactory::SetScalePrecision(G4double scaleValue) { fScalePrecision = scaleValue; } //_____________________________________________________________________________ G4double G4ReflectionFactory::GetScalePrecision() const { return fScalePrecision; } //_____________________________________________________________________________ void G4ReflectionFactory::SetVerboseLevel(G4int verboseLevel) { fVerboseLevel = verboseLevel; } //_____________________________________________________________________________ G4int G4ReflectionFactory::GetVerboseLevel() const { return fVerboseLevel; } //_____________________________________________________________________________ void G4ReflectionFactory::SetVolumesNameExtension(const G4String& nameExtension) { fNameExtension = nameExtension; } //_____________________________________________________________________________ const G4String& G4ReflectionFactory::GetVolumesNameExtension() const { return fNameExtension; }