source: trunk/source/persistency/gdml/src/G4GDMLWriteStructure.cc @ 1243

Last change on this file since 1243 was 1228, checked in by garnier, 14 years ago

update geant4.9.3 tag

File size: 18.2 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer                                           *
4// *                                                                  *
5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7// * conditions of the Geant4 Software License,  included in the file *
8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9// * include a list of copyright holders.                             *
10// *                                                                  *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work  make  any representation or  warranty, express or implied, *
14// * regarding  this  software system or assume any liability for its *
15// * use.  Please see the license in the file  LICENSE  and URL above *
16// * for the full disclaimer and the limitation of liability.         *
17// *                                                                  *
18// * This  code  implementation is the result of  the  scientific and *
19// * technical work of the GEANT4 collaboration.                      *
20// * By using,  copying,  modifying or  distributing the software (or *
21// * any work based  on the software)  you  agree  to acknowledge its *
22// * use  in  resulting  scientific  publications,  and indicate your *
23// * acceptance of all terms of the Geant4 Software license.          *
24// ********************************************************************
25//
26//
27// $Id: G4GDMLWriteStructure.cc,v 1.80 2009/04/24 15:34:20 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-03 $
29//
30// class G4GDMLWriteStructure Implementation
31//
32// Original author: Zoltan Torzsok, November 2007
33//
34// --------------------------------------------------------------------
35
36#include "G4GDMLWriteStructure.hh"
37
38#include "G4Material.hh"
39#include "G4ReflectedSolid.hh"
40#include "G4DisplacedSolid.hh"
41#include "G4LogicalVolumeStore.hh"
42#include "G4PhysicalVolumeStore.hh"
43#include "G4PVDivision.hh"
44#include "G4PVReplica.hh"
45#include "G4OpticalSurface.hh"
46#include "G4LogicalSkinSurface.hh"
47#include "G4LogicalBorderSurface.hh"
48
49G4GDMLWriteStructure::G4GDMLWriteStructure()
50  : G4GDMLWriteParamvol()
51{
52}
53
54G4GDMLWriteStructure::~G4GDMLWriteStructure()
55{
56}
57
58void
59G4GDMLWriteStructure::DivisionvolWrite(xercesc::DOMElement* volumeElement,
60                                       const G4PVDivision* const divisionvol)
61{
62   EAxis axis = kUndefined;
63   G4int number = 0;
64   G4double width = 0.0;
65   G4double offset = 0.0;
66   G4bool consuming = false;
67
68   divisionvol->GetReplicationData(axis,number,width,offset,consuming);
69
70   G4String unitString("mm");
71   G4String axisString("kUndefined");
72   if (axis==kXAxis) { axisString = "kXAxis"; }
73   else if (axis==kYAxis) { axisString = "kYAxis"; }
74   else if (axis==kZAxis) { axisString = "kZAxis"; }
75   else if (axis==kRho)   { axisString = "kRho";     }
76   else if (axis==kPhi)   { axisString = "kPhi"; unitString = "degree"; }
77
78   const G4String name
79         = GenerateName(divisionvol->GetName(),divisionvol);
80   const G4String volumeref
81         = GenerateName(divisionvol->GetLogicalVolume()->GetName(),
82                        divisionvol->GetLogicalVolume());
83
84   xercesc::DOMElement* divisionvolElement = NewElement("divisionvol");
85   divisionvolElement->setAttributeNode(NewAttribute("axis",axisString));
86   divisionvolElement->setAttributeNode(NewAttribute("number",number));
87   divisionvolElement->setAttributeNode(NewAttribute("width",width));
88   divisionvolElement->setAttributeNode(NewAttribute("offset",offset));
89   divisionvolElement->setAttributeNode(NewAttribute("unit",unitString));
90   xercesc::DOMElement* volumerefElement = NewElement("volumeref");
91   volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
92   divisionvolElement->appendChild(volumerefElement);
93   volumeElement->appendChild(divisionvolElement);
94}
95
96void G4GDMLWriteStructure::PhysvolWrite(xercesc::DOMElement* volumeElement,
97                                        const G4VPhysicalVolume* const physvol,
98                                        const G4Transform3D& T,
99                                        const G4String& ModuleName)
100{
101   HepGeom::Scale3D scale;
102   HepGeom::Rotate3D rotate;
103   HepGeom::Translate3D translate;
104
105   T.getDecomposition(scale,rotate,translate);
106
107   const G4ThreeVector scl(scale(0,0),scale(1,1),scale(2,2));
108   const G4ThreeVector rot = GetAngles(rotate.getRotation());
109   const G4ThreeVector pos = T.getTranslation();
110
111   const G4String name = GenerateName(physvol->GetName(),physvol);
112
113   xercesc::DOMElement* physvolElement = NewElement("physvol");
114   physvolElement->setAttributeNode(NewAttribute("name",name));
115   volumeElement->appendChild(physvolElement);
116
117   const G4String volumeref
118         = GenerateName(physvol->GetLogicalVolume()->GetName(),
119                        physvol->GetLogicalVolume());
120
121   if (ModuleName.empty())
122   {
123      xercesc::DOMElement* volumerefElement = NewElement("volumeref");
124      volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
125      physvolElement->appendChild(volumerefElement);
126   }
127   else
128   {
129      xercesc::DOMElement* fileElement = NewElement("file");
130      fileElement->setAttributeNode(NewAttribute("name",ModuleName));
131      fileElement->setAttributeNode(NewAttribute("volname",volumeref));
132      physvolElement->appendChild(fileElement);
133   }
134
135   if (std::fabs(pos.x()) > kLinearPrecision
136    || std::fabs(pos.y()) > kLinearPrecision
137    || std::fabs(pos.z()) > kLinearPrecision)
138   {
139     PositionWrite(physvolElement,name+"_pos",pos);
140   }
141   if (std::fabs(rot.x()) > kAngularPrecision
142    || std::fabs(rot.y()) > kAngularPrecision
143    || std::fabs(rot.z()) > kAngularPrecision)
144   {
145     RotationWrite(physvolElement,name+"_rot",rot);
146   }
147   if (std::fabs(scl.x()-1.0) > kRelativePrecision
148    || std::fabs(scl.y()-1.0) > kRelativePrecision
149    || std::fabs(scl.z()-1.0) > kRelativePrecision)
150   {
151     ScaleWrite(physvolElement,name+"_scl",scl);
152   }
153}
154
155void G4GDMLWriteStructure::ReplicavolWrite(xercesc::DOMElement* volumeElement,
156                                     const G4VPhysicalVolume* const replicavol)
157{
158   EAxis axis = kUndefined;
159   G4int number = 0;
160   G4double width = 0.0;
161   G4double offset = 0.0;
162   G4bool consuming = false;
163   G4String unitString("mm");
164
165   replicavol->GetReplicationData(axis,number,width,offset,consuming);
166
167   const G4String volumeref
168         = GenerateName(replicavol->GetLogicalVolume()->GetName(),
169                        replicavol->GetLogicalVolume());
170
171   xercesc::DOMElement* replicavolElement = NewElement("replicavol");
172   replicavolElement->setAttributeNode(NewAttribute("number",number));
173   xercesc::DOMElement* volumerefElement = NewElement("volumeref");
174   volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
175   replicavolElement->appendChild(volumerefElement);
176   xercesc::DOMElement* replicateElement = NewElement("replicate_along_axis");
177   replicavolElement->appendChild(replicateElement);
178
179   xercesc::DOMElement* dirElement = NewElement("direction");
180   if(axis==kXAxis)
181     { dirElement->setAttributeNode(NewAttribute("x","1")); }
182   else if(axis==kYAxis)
183     { dirElement->setAttributeNode(NewAttribute("y","1")); }
184   else if(axis==kZAxis)
185     { dirElement->setAttributeNode(NewAttribute("z","1")); }
186   else if(axis==kRho)
187     { dirElement->setAttributeNode(NewAttribute("rho","1")); }
188   else if(axis==kPhi)
189     { dirElement->setAttributeNode(NewAttribute("phi","1")); }
190   replicateElement->appendChild(dirElement);
191
192   xercesc::DOMElement* widthElement = NewElement("width");
193   widthElement->setAttributeNode(NewAttribute("value",width));
194   widthElement->setAttributeNode(NewAttribute("unit",unitString));
195   replicateElement->appendChild(widthElement);
196
197   xercesc::DOMElement* offsetElement = NewElement("offset");
198   offsetElement->setAttributeNode(NewAttribute("value",offset));
199   offsetElement->setAttributeNode(NewAttribute("unit",unitString));
200   replicateElement->appendChild(offsetElement);
201
202   volumeElement->appendChild(replicavolElement);
203}
204
205void G4GDMLWriteStructure::
206BorderSurfaceCache(const G4LogicalBorderSurface* const bsurf)
207{
208   if (!bsurf)  { return; }
209
210   const G4SurfaceProperty* psurf = bsurf->GetSurfaceProperty();
211
212   // Generate the new element for border-surface
213   //
214   xercesc::DOMElement* borderElement = NewElement("bordersurface");
215   borderElement->setAttributeNode(NewAttribute("name", bsurf->GetName()));
216   borderElement->setAttributeNode(NewAttribute("surfaceproperty",
217                                                psurf->GetName()));
218
219   const G4String volumeref1 = GenerateName(bsurf->GetVolume1()->GetName(),
220                                            bsurf->GetVolume1());
221   const G4String volumeref2 = GenerateName(bsurf->GetVolume2()->GetName(),
222                                            bsurf->GetVolume2());
223   xercesc::DOMElement* volumerefElement1 = NewElement("physvolref");
224   xercesc::DOMElement* volumerefElement2 = NewElement("physvolref");
225   volumerefElement1->setAttributeNode(NewAttribute("ref",volumeref1));
226   volumerefElement2->setAttributeNode(NewAttribute("ref",volumeref2));
227   borderElement->appendChild(volumerefElement1);
228   borderElement->appendChild(volumerefElement2);
229
230   if (FindOpticalSurface(psurf))
231   {
232     OpticalSurfaceWrite(solidsElement,
233                         dynamic_cast<const G4OpticalSurface*>(psurf));
234   }
235
236   borderElementVec.push_back(borderElement);
237}
238
239void G4GDMLWriteStructure::
240SkinSurfaceCache(const G4LogicalSkinSurface* const ssurf)
241{
242   if (!ssurf)  { return; }
243
244   const G4SurfaceProperty* psurf = ssurf->GetSurfaceProperty();
245
246   // Generate the new element for border-surface
247   //
248   xercesc::DOMElement* skinElement = NewElement("skinsurface");
249   skinElement->setAttributeNode(NewAttribute("name", ssurf->GetName()));
250   skinElement->setAttributeNode(NewAttribute("surfaceproperty",
251                                              psurf->GetName()));
252
253   const G4String volumeref = GenerateName(ssurf->GetLogicalVolume()->GetName(),
254                                           ssurf->GetLogicalVolume());
255   xercesc::DOMElement* volumerefElement = NewElement("volumeref");
256   volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
257   skinElement->appendChild(volumerefElement);
258
259   if (FindOpticalSurface(psurf))
260   {
261     OpticalSurfaceWrite(solidsElement,
262                         dynamic_cast<const G4OpticalSurface*>(psurf));
263   }
264
265   skinElementVec.push_back(skinElement);
266}
267
268G4bool G4GDMLWriteStructure::FindOpticalSurface(const G4SurfaceProperty* psurf)
269{
270   const G4OpticalSurface* osurf = dynamic_cast<const G4OpticalSurface*>(psurf);
271   std::vector<const G4OpticalSurface*>::const_iterator pos;
272   pos = std::find(opt_vec.begin(), opt_vec.end(), osurf);
273   if (pos != opt_vec.end()) { return false; }  // item already created!
274
275   opt_vec.push_back(osurf);              // cache it for future reference
276   return true;
277}
278
279const G4LogicalSkinSurface*
280G4GDMLWriteStructure::GetSkinSurface(const G4LogicalVolume* const lvol)
281{
282  G4LogicalSkinSurface* surf = 0;
283  G4int nsurf = G4LogicalSkinSurface::GetNumberOfSkinSurfaces();
284  if (nsurf)
285  {
286    const G4LogicalSkinSurfaceTable* stable =
287          G4LogicalSkinSurface::GetSurfaceTable();
288    std::vector<G4LogicalSkinSurface*>::const_iterator pos;
289    for (pos = stable->begin(); pos != stable->end(); pos++)
290    {
291      if (lvol == (*pos)->GetLogicalVolume())
292      {
293        surf = *pos; break;
294      }
295    }
296  }
297  return surf;
298}
299
300const G4LogicalBorderSurface*
301G4GDMLWriteStructure::GetBorderSurface(const G4VPhysicalVolume* const pvol)
302{
303  G4LogicalBorderSurface* surf = 0;
304  G4int nsurf = G4LogicalBorderSurface::GetNumberOfBorderSurfaces();
305  if (nsurf)
306  {
307    const G4LogicalBorderSurfaceTable* btable =
308          G4LogicalBorderSurface::GetSurfaceTable();
309    std::vector<G4LogicalBorderSurface*>::const_iterator pos;
310    for (pos = btable->begin(); pos != btable->end(); pos++)
311    {
312      if (pvol == (*pos)->GetVolume1())  // just the first in the couple
313      {                                  // is enough
314        surf = *pos; break;
315      }
316    }
317  }
318  return surf;
319}
320
321void G4GDMLWriteStructure::SurfacesWrite()
322{
323   G4cout << "G4GDML: Writing surfaces..." << G4endl;
324
325   std::vector<xercesc::DOMElement*>::const_iterator pos;
326   for (pos = skinElementVec.begin(); pos != skinElementVec.end(); pos++)
327   {
328     structureElement->appendChild(*pos);
329   }
330   for (pos = borderElementVec.begin(); pos != borderElementVec.end(); pos++)
331   {
332     structureElement->appendChild(*pos);
333   }
334}
335
336void G4GDMLWriteStructure::StructureWrite(xercesc::DOMElement* gdmlElement)
337{
338   G4cout << "G4GDML: Writing structure..." << G4endl;
339
340   structureElement = NewElement("structure");
341   gdmlElement->appendChild(structureElement);
342}
343
344G4Transform3D G4GDMLWriteStructure::
345TraverseVolumeTree(const G4LogicalVolume* const volumePtr, const G4int depth)
346{
347   if (VolumeMap().find(volumePtr) != VolumeMap().end())
348   {
349     return VolumeMap()[volumePtr]; // Volume is already processed
350   }
351
352   G4VSolid* solidPtr = volumePtr->GetSolid();
353   G4Transform3D R,invR;
354   G4int trans=0;
355
356   while (true) // Solve possible displacement/reflection
357   {            // of the referenced solid!
358      if (trans>maxTransforms)
359      {
360        G4String ErrorMessage = "Referenced solid in volume '"
361                              + volumePtr->GetName()
362                              + "' was displaced/reflected too many times!";
363        G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
364                    "InvalidSetup", FatalException, ErrorMessage);
365      }
366
367      if (G4ReflectedSolid* refl = dynamic_cast<G4ReflectedSolid*>(solidPtr))
368      {
369         R = R*refl->GetTransform3D();
370         solidPtr = refl->GetConstituentMovedSolid();
371         trans++;
372         continue;
373      }
374
375      if (G4DisplacedSolid* disp = dynamic_cast<G4DisplacedSolid*>(solidPtr))
376      {
377         R = R*G4Transform3D(disp->GetObjectRotation(),
378                             disp->GetObjectTranslation());
379         solidPtr = disp->GetConstituentMovedSolid();
380         trans++;
381         continue;
382      }
383
384      break;
385   }
386
387   // Only compute the inverse when necessary!
388   //
389   if (trans>0) { invR = R.inverse(); }
390
391   const G4String name
392         = GenerateName(volumePtr->GetName(),volumePtr);
393   const G4String materialref
394         = GenerateName(volumePtr->GetMaterial()->GetName(),
395                        volumePtr->GetMaterial());
396   const G4String solidref
397         = GenerateName(solidPtr->GetName(),solidPtr);
398
399   xercesc::DOMElement* volumeElement = NewElement("volume");
400   volumeElement->setAttributeNode(NewAttribute("name",name));
401   xercesc::DOMElement* materialrefElement = NewElement("materialref");
402   materialrefElement->setAttributeNode(NewAttribute("ref",materialref));
403   volumeElement->appendChild(materialrefElement);
404   xercesc::DOMElement* solidrefElement = NewElement("solidref");
405   solidrefElement->setAttributeNode(NewAttribute("ref",solidref));
406   volumeElement->appendChild(solidrefElement);
407
408   const G4int daughterCount = volumePtr->GetNoDaughters();
409
410   for (G4int i=0;i<daughterCount;i++)   // Traverse all the children!
411   {
412      const G4VPhysicalVolume* const physvol = volumePtr->GetDaughter(i);
413      const G4String ModuleName = Modularize(physvol,depth);
414
415      G4Transform3D daughterR;
416
417      if (ModuleName.empty())   // Check if subtree requested to be
418      {                         // a separate module!
419         daughterR = TraverseVolumeTree(physvol->GetLogicalVolume(),depth+1);
420      }
421      else
422      {   
423         G4GDMLWriteStructure writer;
424         daughterR = writer.Write(ModuleName,physvol->GetLogicalVolume(),
425                                  SchemaLocation,depth+1);
426      }
427
428      if (const G4PVDivision* const divisionvol
429         = dynamic_cast<const G4PVDivision*>(physvol)) // Is it division?
430      {
431         if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
432         {
433            G4String ErrorMessage = "Division volume in '"
434                                  + name
435                                  + "' can not be related to reflected solid!";
436            G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
437                        "InvalidSetup", FatalException, ErrorMessage);
438         }
439         DivisionvolWrite(volumeElement,divisionvol); 
440      } else 
441      if (physvol->IsParameterised())   // Is it a paramvol?
442      {
443         if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
444         {
445            G4String ErrorMessage = "Parameterised volume in '"
446                                  + name
447                                  + "' can not be related to reflected solid!";
448            G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
449                        "InvalidSetup", FatalException, ErrorMessage);
450         }
451         ParamvolWrite(volumeElement,physvol);
452      } else
453      if (physvol->IsReplicated())   // Is it a replicavol?
454      {
455         if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
456         {
457            G4String ErrorMessage = "Replica volume in '"
458                                  + name
459                                  + "' can not be related to reflected solid!";
460            G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
461                        "InvalidSetup", FatalException, ErrorMessage);
462         }
463         ReplicavolWrite(volumeElement,physvol); 
464      }
465      else   // Is it a physvol?
466      {
467         G4RotationMatrix rot;
468
469         if (physvol->GetFrameRotation() != 0)
470         {
471           rot = *(physvol->GetFrameRotation());
472         }
473         G4Transform3D P(rot,physvol->GetObjectTranslation());
474         PhysvolWrite(volumeElement,physvol,invR*P*daughterR,ModuleName);
475      }
476      BorderSurfaceCache(GetBorderSurface(physvol));
477   }
478
479   structureElement->appendChild(volumeElement);
480     // Append the volume AFTER traversing the children so that
481     // the order of volumes will be correct!
482
483   VolumeMap()[volumePtr] = R;
484
485   AddExtension(volumeElement, volumePtr);
486     // Add any possible user defined extension attached to a volume
487
488   AddMaterial(volumePtr->GetMaterial());
489     // Add the involved materials and solids!
490
491   AddSolid(solidPtr);
492
493   SkinSurfaceCache(GetSkinSurface(volumePtr));
494
495   return R;
496}
Note: See TracBrowser for help on using the repository browser.