G4GDMLWriteStructure.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id$
00028 //
00029 // class G4GDMLWriteStructure Implementation
00030 //
00031 // Original author: Zoltan Torzsok, November 2007
00032 //
00033 // --------------------------------------------------------------------
00034 
00035 #include "G4GDMLWriteStructure.hh"
00036 
00037 #include "G4Material.hh"
00038 #include "G4ReflectedSolid.hh"
00039 #include "G4DisplacedSolid.hh"
00040 #include "G4LogicalVolumeStore.hh"
00041 #include "G4PhysicalVolumeStore.hh"
00042 #include "G4PVDivision.hh"
00043 #include "G4PVReplica.hh"
00044 #include "G4OpticalSurface.hh"
00045 #include "G4LogicalSkinSurface.hh"
00046 #include "G4LogicalBorderSurface.hh"
00047 
00048 G4GDMLWriteStructure::G4GDMLWriteStructure()
00049   : G4GDMLWriteParamvol()
00050 {
00051 }
00052 
00053 G4GDMLWriteStructure::~G4GDMLWriteStructure()
00054 {
00055 }
00056 
00057 void
00058 G4GDMLWriteStructure::DivisionvolWrite(xercesc::DOMElement* volumeElement,
00059                                        const G4PVDivision* const divisionvol)
00060 {
00061    EAxis axis = kUndefined;
00062    G4int number = 0;
00063    G4double width = 0.0;
00064    G4double offset = 0.0;
00065    G4bool consuming = false;
00066 
00067    divisionvol->GetReplicationData(axis,number,width,offset,consuming);
00068    axis = divisionvol->GetDivisionAxis();
00069 
00070    G4String unitString("mm");
00071    G4String axisString("kUndefined");
00072    if (axis==kXAxis) { axisString = "kXAxis"; }
00073    else if (axis==kYAxis) { axisString = "kYAxis"; }
00074    else if (axis==kZAxis) { axisString = "kZAxis"; }
00075    else if (axis==kRho)   { axisString = "kRho";     }
00076    else if (axis==kPhi)   { axisString = "kPhi"; unitString = "rad"; }
00077 
00078    const G4String name
00079          = GenerateName(divisionvol->GetName(),divisionvol);
00080    const G4String volumeref
00081          = GenerateName(divisionvol->GetLogicalVolume()->GetName(),
00082                         divisionvol->GetLogicalVolume());
00083 
00084    xercesc::DOMElement* divisionvolElement = NewElement("divisionvol");
00085    divisionvolElement->setAttributeNode(NewAttribute("axis",axisString));
00086    divisionvolElement->setAttributeNode(NewAttribute("number",number));
00087    divisionvolElement->setAttributeNode(NewAttribute("width",width));
00088    divisionvolElement->setAttributeNode(NewAttribute("offset",offset));
00089    divisionvolElement->setAttributeNode(NewAttribute("unit",unitString));
00090    xercesc::DOMElement* volumerefElement = NewElement("volumeref");
00091    volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
00092    divisionvolElement->appendChild(volumerefElement);
00093    volumeElement->appendChild(divisionvolElement);
00094 }
00095 
00096 void G4GDMLWriteStructure::PhysvolWrite(xercesc::DOMElement* volumeElement,
00097                                         const G4VPhysicalVolume* const physvol,
00098                                         const G4Transform3D& T,
00099                                         const G4String& ModuleName)
00100 {
00101    HepGeom::Scale3D scale;
00102    HepGeom::Rotate3D rotate;
00103    HepGeom::Translate3D translate;
00104 
00105    T.getDecomposition(scale,rotate,translate);
00106 
00107    const G4ThreeVector scl(scale(0,0),scale(1,1),scale(2,2));
00108    const G4ThreeVector rot = GetAngles(rotate.getRotation());
00109    const G4ThreeVector pos = T.getTranslation();
00110 
00111    const G4String name = GenerateName(physvol->GetName(),physvol);
00112 
00113    xercesc::DOMElement* physvolElement = NewElement("physvol");
00114    physvolElement->setAttributeNode(NewAttribute("name",name));
00115    volumeElement->appendChild(physvolElement);
00116 
00117    const G4String volumeref
00118          = GenerateName(physvol->GetLogicalVolume()->GetName(),
00119                         physvol->GetLogicalVolume());
00120 
00121    if (ModuleName.empty())
00122    {
00123       xercesc::DOMElement* volumerefElement = NewElement("volumeref");
00124       volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
00125       physvolElement->appendChild(volumerefElement);
00126    }
00127    else
00128    {
00129       xercesc::DOMElement* fileElement = NewElement("file");
00130       fileElement->setAttributeNode(NewAttribute("name",ModuleName));
00131       fileElement->setAttributeNode(NewAttribute("volname",volumeref));
00132       physvolElement->appendChild(fileElement);
00133    }
00134 
00135    if (std::fabs(pos.x()) > kLinearPrecision
00136     || std::fabs(pos.y()) > kLinearPrecision
00137     || std::fabs(pos.z()) > kLinearPrecision)
00138    {
00139      PositionWrite(physvolElement,name+"_pos",pos);
00140    }
00141    if (std::fabs(rot.x()) > kAngularPrecision
00142     || std::fabs(rot.y()) > kAngularPrecision
00143     || std::fabs(rot.z()) > kAngularPrecision)
00144    {
00145      RotationWrite(physvolElement,name+"_rot",rot);
00146    }
00147    if (std::fabs(scl.x()-1.0) > kRelativePrecision
00148     || std::fabs(scl.y()-1.0) > kRelativePrecision
00149     || std::fabs(scl.z()-1.0) > kRelativePrecision)
00150    {
00151      ScaleWrite(physvolElement,name+"_scl",scl);
00152    }
00153 }
00154 
00155 void G4GDMLWriteStructure::ReplicavolWrite(xercesc::DOMElement* volumeElement,
00156                                      const G4VPhysicalVolume* const replicavol)
00157 {
00158    EAxis axis = kUndefined;
00159    G4int number = 0;
00160    G4double width = 0.0;
00161    G4double offset = 0.0;
00162    G4bool consuming = false;
00163    G4String unitString("mm");
00164 
00165    replicavol->GetReplicationData(axis,number,width,offset,consuming);
00166 
00167    const G4String volumeref
00168          = GenerateName(replicavol->GetLogicalVolume()->GetName(),
00169                         replicavol->GetLogicalVolume());
00170 
00171    xercesc::DOMElement* replicavolElement = NewElement("replicavol");
00172    replicavolElement->setAttributeNode(NewAttribute("number",number));
00173    xercesc::DOMElement* volumerefElement = NewElement("volumeref");
00174    volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
00175    replicavolElement->appendChild(volumerefElement);
00176    xercesc::DOMElement* replicateElement = NewElement("replicate_along_axis");
00177    replicavolElement->appendChild(replicateElement);
00178 
00179    xercesc::DOMElement* dirElement = NewElement("direction");
00180    if(axis==kXAxis)
00181      { dirElement->setAttributeNode(NewAttribute("x","1")); }
00182    else if(axis==kYAxis)
00183      { dirElement->setAttributeNode(NewAttribute("y","1")); }
00184    else if(axis==kZAxis)
00185      { dirElement->setAttributeNode(NewAttribute("z","1")); }
00186    else if(axis==kRho)
00187      { dirElement->setAttributeNode(NewAttribute("rho","1")); }
00188    else if(axis==kPhi)
00189      { dirElement->setAttributeNode(NewAttribute("phi","1"));
00190        unitString="rad"; }
00191    replicateElement->appendChild(dirElement);
00192 
00193    xercesc::DOMElement* widthElement = NewElement("width");
00194    widthElement->setAttributeNode(NewAttribute("value",width));
00195    widthElement->setAttributeNode(NewAttribute("unit",unitString));
00196    replicateElement->appendChild(widthElement);
00197 
00198    xercesc::DOMElement* offsetElement = NewElement("offset");
00199    offsetElement->setAttributeNode(NewAttribute("value",offset));
00200    offsetElement->setAttributeNode(NewAttribute("unit",unitString));
00201    replicateElement->appendChild(offsetElement);
00202 
00203    volumeElement->appendChild(replicavolElement);
00204 }
00205 
00206 void G4GDMLWriteStructure::
00207 BorderSurfaceCache(const G4LogicalBorderSurface* const bsurf)
00208 {
00209    if (!bsurf)  { return; }
00210 
00211    const G4SurfaceProperty* psurf = bsurf->GetSurfaceProperty();
00212 
00213    // Generate the new element for border-surface
00214    //
00215    xercesc::DOMElement* borderElement = NewElement("bordersurface");
00216    borderElement->setAttributeNode(NewAttribute("name", bsurf->GetName()));
00217    borderElement->setAttributeNode(NewAttribute("surfaceproperty",
00218                                                 psurf->GetName()));
00219 
00220    const G4String volumeref1 = GenerateName(bsurf->GetVolume1()->GetName(),
00221                                             bsurf->GetVolume1());
00222    const G4String volumeref2 = GenerateName(bsurf->GetVolume2()->GetName(),
00223                                             bsurf->GetVolume2());
00224    xercesc::DOMElement* volumerefElement1 = NewElement("physvolref");
00225    xercesc::DOMElement* volumerefElement2 = NewElement("physvolref");
00226    volumerefElement1->setAttributeNode(NewAttribute("ref",volumeref1));
00227    volumerefElement2->setAttributeNode(NewAttribute("ref",volumeref2));
00228    borderElement->appendChild(volumerefElement1);
00229    borderElement->appendChild(volumerefElement2);
00230 
00231    if (FindOpticalSurface(psurf))
00232    {
00233      const G4OpticalSurface* opsurf =
00234        dynamic_cast<const G4OpticalSurface*>(psurf);
00235      if (!opsurf)
00236      {
00237        G4Exception("G4GDMLWriteStructure::BorderSurfaceCache()",
00238                    "InvalidSetup", FatalException, "No optical surface found!");
00239        return;
00240      }
00241      OpticalSurfaceWrite(solidsElement, opsurf);
00242    }
00243 
00244    borderElementVec.push_back(borderElement);
00245 }
00246 
00247 void G4GDMLWriteStructure::
00248 SkinSurfaceCache(const G4LogicalSkinSurface* const ssurf)
00249 {
00250    if (!ssurf)  { return; }
00251 
00252    const G4SurfaceProperty* psurf = ssurf->GetSurfaceProperty();
00253 
00254    // Generate the new element for border-surface
00255    //
00256    xercesc::DOMElement* skinElement = NewElement("skinsurface");
00257    skinElement->setAttributeNode(NewAttribute("name", ssurf->GetName()));
00258    skinElement->setAttributeNode(NewAttribute("surfaceproperty",
00259                                               psurf->GetName()));
00260 
00261    const G4String volumeref = GenerateName(ssurf->GetLogicalVolume()->GetName(),
00262                                            ssurf->GetLogicalVolume());
00263    xercesc::DOMElement* volumerefElement = NewElement("volumeref");
00264    volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
00265    skinElement->appendChild(volumerefElement);
00266 
00267    if (FindOpticalSurface(psurf))
00268    {
00269      const G4OpticalSurface* opsurf =
00270        dynamic_cast<const G4OpticalSurface*>(psurf);
00271      if (!opsurf)
00272      {
00273        G4Exception("G4GDMLWriteStructure::SkinSurfaceCache()",
00274                    "InvalidSetup", FatalException, "No optical surface found!");
00275        return;
00276      }
00277      OpticalSurfaceWrite(solidsElement, opsurf);
00278    }
00279 
00280    skinElementVec.push_back(skinElement);
00281 }
00282 
00283 G4bool G4GDMLWriteStructure::FindOpticalSurface(const G4SurfaceProperty* psurf)
00284 {
00285    const G4OpticalSurface* osurf = dynamic_cast<const G4OpticalSurface*>(psurf);
00286    std::vector<const G4OpticalSurface*>::const_iterator pos;
00287    pos = std::find(opt_vec.begin(), opt_vec.end(), osurf);
00288    if (pos != opt_vec.end()) { return false; }  // item already created!
00289 
00290    opt_vec.push_back(osurf);              // cache it for future reference
00291    return true;
00292 }
00293 
00294 const G4LogicalSkinSurface*
00295 G4GDMLWriteStructure::GetSkinSurface(const G4LogicalVolume* const lvol)
00296 {
00297   G4LogicalSkinSurface* surf = 0;
00298   G4int nsurf = G4LogicalSkinSurface::GetNumberOfSkinSurfaces();
00299   if (nsurf)
00300   {
00301     const G4LogicalSkinSurfaceTable* stable =
00302           G4LogicalSkinSurface::GetSurfaceTable();
00303     std::vector<G4LogicalSkinSurface*>::const_iterator pos;
00304     for (pos = stable->begin(); pos != stable->end(); pos++)
00305     {
00306       if (lvol == (*pos)->GetLogicalVolume())
00307       {
00308         surf = *pos; break;
00309       }
00310     }
00311   }
00312   return surf;
00313 }
00314 
00315 const G4LogicalBorderSurface*
00316 G4GDMLWriteStructure::GetBorderSurface(const G4VPhysicalVolume* const pvol)
00317 {
00318   G4LogicalBorderSurface* surf = 0;
00319   G4int nsurf = G4LogicalBorderSurface::GetNumberOfBorderSurfaces();
00320   if (nsurf)
00321   {
00322     const G4LogicalBorderSurfaceTable* btable =
00323           G4LogicalBorderSurface::GetSurfaceTable();
00324     std::vector<G4LogicalBorderSurface*>::const_iterator pos;
00325     for (pos = btable->begin(); pos != btable->end(); pos++)
00326     {
00327       if (pvol == (*pos)->GetVolume1())  // just the first in the couple 
00328       {                                  // is enough
00329         surf = *pos; break;
00330       }
00331     }
00332   }
00333   return surf;
00334 }
00335 
00336 void G4GDMLWriteStructure::SurfacesWrite()
00337 {
00338    G4cout << "G4GDML: Writing surfaces..." << G4endl;
00339 
00340    std::vector<xercesc::DOMElement*>::const_iterator pos;
00341    for (pos = skinElementVec.begin(); pos != skinElementVec.end(); pos++)
00342    {
00343      structureElement->appendChild(*pos);
00344    }
00345    for (pos = borderElementVec.begin(); pos != borderElementVec.end(); pos++)
00346    {
00347      structureElement->appendChild(*pos);
00348    }
00349 }
00350 
00351 void G4GDMLWriteStructure::StructureWrite(xercesc::DOMElement* gdmlElement)
00352 {
00353    G4cout << "G4GDML: Writing structure..." << G4endl;
00354 
00355    structureElement = NewElement("structure");
00356    gdmlElement->appendChild(structureElement);
00357 }
00358 
00359 G4Transform3D G4GDMLWriteStructure::
00360 TraverseVolumeTree(const G4LogicalVolume* const volumePtr, const G4int depth)
00361 {
00362    if (VolumeMap().find(volumePtr) != VolumeMap().end())
00363    {
00364      return VolumeMap()[volumePtr]; // Volume is already processed
00365    }
00366 
00367    G4VSolid* solidPtr = volumePtr->GetSolid();
00368    G4Transform3D R,invR;
00369    G4int trans=0;
00370 
00371    while (true) // Solve possible displacement/reflection
00372    {            // of the referenced solid!
00373       if (trans>maxTransforms)
00374       {
00375         G4String ErrorMessage = "Referenced solid in volume '"
00376                               + volumePtr->GetName()
00377                               + "' was displaced/reflected too many times!";
00378         G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
00379                     "InvalidSetup", FatalException, ErrorMessage);
00380       }
00381 
00382       if (G4ReflectedSolid* refl = dynamic_cast<G4ReflectedSolid*>(solidPtr))
00383       {
00384          R = R*refl->GetTransform3D();
00385          solidPtr = refl->GetConstituentMovedSolid();
00386          trans++;
00387          continue;
00388       }
00389 
00390       if (G4DisplacedSolid* disp = dynamic_cast<G4DisplacedSolid*>(solidPtr))
00391       {
00392          R = R*G4Transform3D(disp->GetObjectRotation(),
00393                              disp->GetObjectTranslation());
00394          solidPtr = disp->GetConstituentMovedSolid();
00395          trans++;
00396          continue;
00397       }
00398 
00399       break;
00400    }
00401 
00402    // Only compute the inverse when necessary!
00403    //
00404    if (trans>0) { invR = R.inverse(); }
00405 
00406    const G4String name
00407          = GenerateName(volumePtr->GetName(),volumePtr);
00408    const G4String materialref
00409          = GenerateName(volumePtr->GetMaterial()->GetName(),
00410                         volumePtr->GetMaterial());
00411    const G4String solidref
00412          = GenerateName(solidPtr->GetName(),solidPtr);
00413 
00414    xercesc::DOMElement* volumeElement = NewElement("volume");
00415    volumeElement->setAttributeNode(NewAttribute("name",name));
00416    xercesc::DOMElement* materialrefElement = NewElement("materialref");
00417    materialrefElement->setAttributeNode(NewAttribute("ref",materialref));
00418    volumeElement->appendChild(materialrefElement);
00419    xercesc::DOMElement* solidrefElement = NewElement("solidref");
00420    solidrefElement->setAttributeNode(NewAttribute("ref",solidref));
00421    volumeElement->appendChild(solidrefElement);
00422 
00423    const G4int daughterCount = volumePtr->GetNoDaughters();
00424 
00425    for (G4int i=0;i<daughterCount;i++)   // Traverse all the children!
00426    {
00427       const G4VPhysicalVolume* const physvol = volumePtr->GetDaughter(i);
00428       const G4String ModuleName = Modularize(physvol,depth);
00429 
00430       G4Transform3D daughterR;
00431 
00432       if (ModuleName.empty())   // Check if subtree requested to be 
00433       {                         // a separate module!
00434          daughterR = TraverseVolumeTree(physvol->GetLogicalVolume(),depth+1);
00435       }
00436       else
00437       {   
00438          G4GDMLWriteStructure writer;
00439          daughterR = writer.Write(ModuleName,physvol->GetLogicalVolume(),
00440                                   SchemaLocation,depth+1);
00441       }
00442 
00443       if (const G4PVDivision* const divisionvol
00444          = dynamic_cast<const G4PVDivision*>(physvol)) // Is it division?
00445       {
00446          if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
00447          {
00448             G4String ErrorMessage = "Division volume in '"
00449                                   + name
00450                                   + "' can not be related to reflected solid!";
00451             G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
00452                         "InvalidSetup", FatalException, ErrorMessage);
00453          }
00454          DivisionvolWrite(volumeElement,divisionvol); 
00455       } else 
00456       if (physvol->IsParameterised())   // Is it a paramvol?
00457       {
00458          if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
00459          {
00460             G4String ErrorMessage = "Parameterised volume in '"
00461                                   + name
00462                                   + "' can not be related to reflected solid!";
00463             G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
00464                         "InvalidSetup", FatalException, ErrorMessage);
00465          }
00466          ParamvolWrite(volumeElement,physvol);
00467       } else
00468       if (physvol->IsReplicated())   // Is it a replicavol?
00469       {
00470          if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
00471          {
00472             G4String ErrorMessage = "Replica volume in '"
00473                                   + name
00474                                   + "' can not be related to reflected solid!";
00475             G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
00476                         "InvalidSetup", FatalException, ErrorMessage);
00477          }
00478          ReplicavolWrite(volumeElement,physvol); 
00479       }
00480       else   // Is it a physvol?
00481       {
00482          G4RotationMatrix rot;
00483 
00484          if (physvol->GetFrameRotation() != 0)
00485          {
00486            rot = *(physvol->GetFrameRotation());
00487          }
00488          G4Transform3D P(rot,physvol->GetObjectTranslation());
00489          PhysvolWrite(volumeElement,physvol,invR*P*daughterR,ModuleName);
00490       }
00491       BorderSurfaceCache(GetBorderSurface(physvol));
00492    }
00493 
00494    structureElement->appendChild(volumeElement);
00495      // Append the volume AFTER traversing the children so that
00496      // the order of volumes will be correct!
00497 
00498    VolumeMap()[volumePtr] = R;
00499 
00500    AddExtension(volumeElement, volumePtr);
00501      // Add any possible user defined extension attached to a volume
00502 
00503    AddMaterial(volumePtr->GetMaterial());
00504      // Add the involved materials and solids!
00505 
00506    AddSolid(solidPtr);
00507 
00508    SkinSurfaceCache(GetSkinSurface(volumePtr));
00509 
00510    return R;
00511 }

Generated on Mon May 27 17:48:20 2013 for Geant4 by  doxygen 1.4.7