// // ******************************************************************** // * 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. * // ******************************************************************** // // // $Id: G4ReflectionFactory.cc,v 1.10 2010/04/13 07:19:01 gcosmo Exp $ // GEANT4 tag $Name: geant4-09-04-beta-01 $ // // // 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, 16.10.2001 (Ivana.Hrivnacova@cern.ch) // -------------------------------------------------------------------- #include "G4ReflectionFactory.hh" #include "G4ReflectedSolid.hh" #include "G4Region.hh" #include "G4LogicalVolume.hh" #include "G4PVPlacement.hh" #include "G4PVReplica.hh" #include "G4VPVDivisionFactory.hh" #include "G4GeometryTolerance.hh" G4ReflectionFactory* G4ReflectionFactory::fInstance = 0; const G4String G4ReflectionFactory::fDefaultNameExtension = "_refl"; const G4Scale3D G4ReflectionFactory::fScale = G4ScaleZ3D(-1.0); //_____________________________________________________________________________ G4ReflectionFactory* G4ReflectionFactory::Instance() { // Static singleton access method. // --- if (!fInstance) { fInstance = new G4ReflectionFactory(); } return fInstance; } //_____________________________________________________________________________ G4ReflectionFactory::G4ReflectionFactory() : fVerboseLevel(0), 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 0 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 = 0; 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 G4PhysicalVolumesPair(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 = 0; 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 G4PhysicalVolumesPair(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 0 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 = 0; 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 G4PhysicalVolumesPair(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 0 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 = 0; 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 G4PhysicalVolumesPair(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 0 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 = 0; 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 G4PhysicalVolumesPair(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 0 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 = 0; 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 G4PhysicalVolumesPair(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) { // 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.end()) { G4cerr << "ERROR - G4ReflectionFactory::CreateReflectedLV(..): " << LV->GetName() << G4endl << " Cannot be applied to an already reflected volume !" << G4endl; G4Exception("G4ReflectionFactory::CreateReflectedLV(..)", "NotApplicable", FatalException, "Cannot be applied to a volume already reflected."); } G4VSolid* refSolid = new G4ReflectedSolid(LV->GetSolid()->GetName() + fNameExtension, LV->GetSolid(), fScale); G4LogicalVolume* refLV = new G4LogicalVolume(refSolid, LV->GetMaterial(), LV->GetName() + fNameExtension, LV->GetFieldManager(), LV->GetSensitiveDetector(), LV->GetUserLimits()); 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 (G4int i=0; iGetNoDaughters(); i++) { G4VPhysicalVolume* dPV = LV->GetDaughter(i); if (! dPV->IsReplicated()) { ReflectPVPlacement(dPV, refLV, surfCheck); } else if (! dPV->GetParameterisation()) { ReflectPVReplica(dPV, refLV); } else if (G4VPVDivisionFactory::Instance() && 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) { // 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) { // 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) { // 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 PVReplica type of // a constituent volume into a reflected volume. // --- G4cerr << "ERROR - G4ReflectionFactory::ReflectPVParameterised(...): " << dPV->GetName() << G4endl << " Reflection of parameterised volumes " << "is not yet implemented." << G4endl; G4Exception("G4ReflectionFactory::ReflectPVParameterised(...)", "NotImplemented", FatalException, "Sorry, not yet implemented."); } //_____________________________________________________________________________ G4LogicalVolume* G4ReflectionFactory::GetConstituentLV(G4LogicalVolume* reflLV) const { // Returns the consituent volume of the given reflected volume, // 0 if the given reflected volume was not found. // --- LogicalVolumesMapIterator it = fReflectedLVMap.find(reflLV); if (it == fReflectedLVMap.end()) return 0; return (*it).second; } //_____________________________________________________________________________ G4LogicalVolume* G4ReflectionFactory::GetReflectedLV(G4LogicalVolume* lv) const { // Returns the reflected volume of the given consituent volume, // 0 if the given volume was not reflected. // --- LogicalVolumesMapIterator it = fConstituentLVMap.find(lv); if (it == fConstituentLVMap.end()) return 0; 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.end()); } //_____________________________________________________________________________ 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.end()); } //_____________________________________________________________________________ G4bool G4ReflectionFactory::IsReflection(const G4Scale3D& scale) const { // Returns true if the scale is negative, false otherwise. // --- if (scale(0,0)*scale(1,1)*scale(2,2) < 0.) return true; else return false; } //_____________________________________________________________________________ const G4ReflectedVolumesMap& G4ReflectionFactory::GetReflectedVolumesMap() const { return fReflectedLVMap; } //_____________________________________________________________________________ void G4ReflectionFactory::Reset() { fConstituentLVMap.~map(); fReflectedLVMap.~map(); } //_____________________________________________________________________________ void G4ReflectionFactory::PrintConstituentLVMap() { // temporary - for debugging purpose // --- LogicalVolumesMapIterator it; for (it = fConstituentLVMap.begin(); it != fConstituentLVMap.end(); it++) { 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 (G4int i=0; i<4; i++) for (G4int j=0; j<4; j++) diff += std::abs(scale(i,j) - fScale(i,j)); if (diff > fScalePrecision) { G4cerr << "ERROR - G4ReflectionFactory::CheckScale(..)" << G4endl << " Unexpected scale. Difference: " << diff << G4endl; G4Exception("G4ReflectionFactory::CheckScale(..)", "WrongArgumentValue", FatalException, "Unexpected scale in input !"); } } //_____________________________________________________________________________ G4VPVDivisionFactory* G4ReflectionFactory::GetPVDivisionFactory() const { // Returns the G4PVDivisionFactory instance if it exists, // otherwise gives exception // --- G4VPVDivisionFactory* divisionFactory = G4VPVDivisionFactory::Instance(); if (!divisionFactory) { G4cerr << "ERROR - G4ReflectionFactory::GetPVDivisionFactory()" << 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 !" << G4endl; G4Exception("G4ReflectionFactory::GetPVDivisionFactory()", "WrongSetup", FatalException, "A concrete G4PVDivisionFactory instantiated is required !"); } 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; } /* // placement with decomposed transformation G4VPhysicalVolume* pv1 = new G4PVPlacement(new G4RotationMatrix(rotation.getRotation().inverse()), translation.getTranslation(), refLV, name, motherLV, isMany, copyNo); */