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

Last change on this file was 1347, checked in by garnier, 14 years ago

geant4 tag 9.4

File size: 18.7 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.83 2010/10/14 16:19:40 gcosmo Exp $
28// GEANT4 tag $Name: gdml-V09-03-09 $
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   axis = divisionvol->GetDivisionAxis();
70
71   G4String unitString("mm");
72   G4String axisString("kUndefined");
73   if (axis==kXAxis) { axisString = "kXAxis"; }
74   else if (axis==kYAxis) { axisString = "kYAxis"; }
75   else if (axis==kZAxis) { axisString = "kZAxis"; }
76   else if (axis==kRho)   { axisString = "kRho";     }
77   else if (axis==kPhi)   { axisString = "kPhi"; unitString = "rad"; }
78
79   const G4String name
80         = GenerateName(divisionvol->GetName(),divisionvol);
81   const G4String volumeref
82         = GenerateName(divisionvol->GetLogicalVolume()->GetName(),
83                        divisionvol->GetLogicalVolume());
84
85   xercesc::DOMElement* divisionvolElement = NewElement("divisionvol");
86   divisionvolElement->setAttributeNode(NewAttribute("axis",axisString));
87   divisionvolElement->setAttributeNode(NewAttribute("number",number));
88   divisionvolElement->setAttributeNode(NewAttribute("width",width));
89   divisionvolElement->setAttributeNode(NewAttribute("offset",offset));
90   divisionvolElement->setAttributeNode(NewAttribute("unit",unitString));
91   xercesc::DOMElement* volumerefElement = NewElement("volumeref");
92   volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
93   divisionvolElement->appendChild(volumerefElement);
94   volumeElement->appendChild(divisionvolElement);
95}
96
97void G4GDMLWriteStructure::PhysvolWrite(xercesc::DOMElement* volumeElement,
98                                        const G4VPhysicalVolume* const physvol,
99                                        const G4Transform3D& T,
100                                        const G4String& ModuleName)
101{
102   HepGeom::Scale3D scale;
103   HepGeom::Rotate3D rotate;
104   HepGeom::Translate3D translate;
105
106   T.getDecomposition(scale,rotate,translate);
107
108   const G4ThreeVector scl(scale(0,0),scale(1,1),scale(2,2));
109   const G4ThreeVector rot = GetAngles(rotate.getRotation());
110   const G4ThreeVector pos = T.getTranslation();
111
112   const G4String name = GenerateName(physvol->GetName(),physvol);
113
114   xercesc::DOMElement* physvolElement = NewElement("physvol");
115   physvolElement->setAttributeNode(NewAttribute("name",name));
116   volumeElement->appendChild(physvolElement);
117
118   const G4String volumeref
119         = GenerateName(physvol->GetLogicalVolume()->GetName(),
120                        physvol->GetLogicalVolume());
121
122   if (ModuleName.empty())
123   {
124      xercesc::DOMElement* volumerefElement = NewElement("volumeref");
125      volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
126      physvolElement->appendChild(volumerefElement);
127   }
128   else
129   {
130      xercesc::DOMElement* fileElement = NewElement("file");
131      fileElement->setAttributeNode(NewAttribute("name",ModuleName));
132      fileElement->setAttributeNode(NewAttribute("volname",volumeref));
133      physvolElement->appendChild(fileElement);
134   }
135
136   if (std::fabs(pos.x()) > kLinearPrecision
137    || std::fabs(pos.y()) > kLinearPrecision
138    || std::fabs(pos.z()) > kLinearPrecision)
139   {
140     PositionWrite(physvolElement,name+"_pos",pos);
141   }
142   if (std::fabs(rot.x()) > kAngularPrecision
143    || std::fabs(rot.y()) > kAngularPrecision
144    || std::fabs(rot.z()) > kAngularPrecision)
145   {
146     RotationWrite(physvolElement,name+"_rot",rot);
147   }
148   if (std::fabs(scl.x()-1.0) > kRelativePrecision
149    || std::fabs(scl.y()-1.0) > kRelativePrecision
150    || std::fabs(scl.z()-1.0) > kRelativePrecision)
151   {
152     ScaleWrite(physvolElement,name+"_scl",scl);
153   }
154}
155
156void G4GDMLWriteStructure::ReplicavolWrite(xercesc::DOMElement* volumeElement,
157                                     const G4VPhysicalVolume* const replicavol)
158{
159   EAxis axis = kUndefined;
160   G4int number = 0;
161   G4double width = 0.0;
162   G4double offset = 0.0;
163   G4bool consuming = false;
164   G4String unitString("mm");
165
166   replicavol->GetReplicationData(axis,number,width,offset,consuming);
167
168   const G4String volumeref
169         = GenerateName(replicavol->GetLogicalVolume()->GetName(),
170                        replicavol->GetLogicalVolume());
171
172   xercesc::DOMElement* replicavolElement = NewElement("replicavol");
173   replicavolElement->setAttributeNode(NewAttribute("number",number));
174   xercesc::DOMElement* volumerefElement = NewElement("volumeref");
175   volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
176   replicavolElement->appendChild(volumerefElement);
177   xercesc::DOMElement* replicateElement = NewElement("replicate_along_axis");
178   replicavolElement->appendChild(replicateElement);
179
180   xercesc::DOMElement* dirElement = NewElement("direction");
181   if(axis==kXAxis)
182     { dirElement->setAttributeNode(NewAttribute("x","1")); }
183   else if(axis==kYAxis)
184     { dirElement->setAttributeNode(NewAttribute("y","1")); }
185   else if(axis==kZAxis)
186     { dirElement->setAttributeNode(NewAttribute("z","1")); }
187   else if(axis==kRho)
188     { dirElement->setAttributeNode(NewAttribute("rho","1")); }
189   else if(axis==kPhi)
190     { dirElement->setAttributeNode(NewAttribute("phi","1"));
191       unitString="rad"; }
192   replicateElement->appendChild(dirElement);
193
194   xercesc::DOMElement* widthElement = NewElement("width");
195   widthElement->setAttributeNode(NewAttribute("value",width));
196   widthElement->setAttributeNode(NewAttribute("unit",unitString));
197   replicateElement->appendChild(widthElement);
198
199   xercesc::DOMElement* offsetElement = NewElement("offset");
200   offsetElement->setAttributeNode(NewAttribute("value",offset));
201   offsetElement->setAttributeNode(NewAttribute("unit",unitString));
202   replicateElement->appendChild(offsetElement);
203
204   volumeElement->appendChild(replicavolElement);
205}
206
207void G4GDMLWriteStructure::
208BorderSurfaceCache(const G4LogicalBorderSurface* const bsurf)
209{
210   if (!bsurf)  { return; }
211
212   const G4SurfaceProperty* psurf = bsurf->GetSurfaceProperty();
213
214   // Generate the new element for border-surface
215   //
216   xercesc::DOMElement* borderElement = NewElement("bordersurface");
217   borderElement->setAttributeNode(NewAttribute("name", bsurf->GetName()));
218   borderElement->setAttributeNode(NewAttribute("surfaceproperty",
219                                                psurf->GetName()));
220
221   const G4String volumeref1 = GenerateName(bsurf->GetVolume1()->GetName(),
222                                            bsurf->GetVolume1());
223   const G4String volumeref2 = GenerateName(bsurf->GetVolume2()->GetName(),
224                                            bsurf->GetVolume2());
225   xercesc::DOMElement* volumerefElement1 = NewElement("physvolref");
226   xercesc::DOMElement* volumerefElement2 = NewElement("physvolref");
227   volumerefElement1->setAttributeNode(NewAttribute("ref",volumeref1));
228   volumerefElement2->setAttributeNode(NewAttribute("ref",volumeref2));
229   borderElement->appendChild(volumerefElement1);
230   borderElement->appendChild(volumerefElement2);
231
232   if (FindOpticalSurface(psurf))
233   {
234     const G4OpticalSurface* opsurf =
235       dynamic_cast<const G4OpticalSurface*>(psurf);
236     if (!opsurf)
237     {
238       G4Exception("G4GDMLWriteStructure::BorderSurfaceCache()",
239                   "InvalidSetup", FatalException, "No optical surface found!");
240       return;
241     }
242     OpticalSurfaceWrite(solidsElement, opsurf);
243   }
244
245   borderElementVec.push_back(borderElement);
246}
247
248void G4GDMLWriteStructure::
249SkinSurfaceCache(const G4LogicalSkinSurface* const ssurf)
250{
251   if (!ssurf)  { return; }
252
253   const G4SurfaceProperty* psurf = ssurf->GetSurfaceProperty();
254
255   // Generate the new element for border-surface
256   //
257   xercesc::DOMElement* skinElement = NewElement("skinsurface");
258   skinElement->setAttributeNode(NewAttribute("name", ssurf->GetName()));
259   skinElement->setAttributeNode(NewAttribute("surfaceproperty",
260                                              psurf->GetName()));
261
262   const G4String volumeref = GenerateName(ssurf->GetLogicalVolume()->GetName(),
263                                           ssurf->GetLogicalVolume());
264   xercesc::DOMElement* volumerefElement = NewElement("volumeref");
265   volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
266   skinElement->appendChild(volumerefElement);
267
268   if (FindOpticalSurface(psurf))
269   {
270     const G4OpticalSurface* opsurf =
271       dynamic_cast<const G4OpticalSurface*>(psurf);
272     if (!opsurf)
273     {
274       G4Exception("G4GDMLWriteStructure::SkinSurfaceCache()",
275                   "InvalidSetup", FatalException, "No optical surface found!");
276       return;
277     }
278     OpticalSurfaceWrite(solidsElement, opsurf);
279   }
280
281   skinElementVec.push_back(skinElement);
282}
283
284G4bool G4GDMLWriteStructure::FindOpticalSurface(const G4SurfaceProperty* psurf)
285{
286   const G4OpticalSurface* osurf = dynamic_cast<const G4OpticalSurface*>(psurf);
287   std::vector<const G4OpticalSurface*>::const_iterator pos;
288   pos = std::find(opt_vec.begin(), opt_vec.end(), osurf);
289   if (pos != opt_vec.end()) { return false; }  // item already created!
290
291   opt_vec.push_back(osurf);              // cache it for future reference
292   return true;
293}
294
295const G4LogicalSkinSurface*
296G4GDMLWriteStructure::GetSkinSurface(const G4LogicalVolume* const lvol)
297{
298  G4LogicalSkinSurface* surf = 0;
299  G4int nsurf = G4LogicalSkinSurface::GetNumberOfSkinSurfaces();
300  if (nsurf)
301  {
302    const G4LogicalSkinSurfaceTable* stable =
303          G4LogicalSkinSurface::GetSurfaceTable();
304    std::vector<G4LogicalSkinSurface*>::const_iterator pos;
305    for (pos = stable->begin(); pos != stable->end(); pos++)
306    {
307      if (lvol == (*pos)->GetLogicalVolume())
308      {
309        surf = *pos; break;
310      }
311    }
312  }
313  return surf;
314}
315
316const G4LogicalBorderSurface*
317G4GDMLWriteStructure::GetBorderSurface(const G4VPhysicalVolume* const pvol)
318{
319  G4LogicalBorderSurface* surf = 0;
320  G4int nsurf = G4LogicalBorderSurface::GetNumberOfBorderSurfaces();
321  if (nsurf)
322  {
323    const G4LogicalBorderSurfaceTable* btable =
324          G4LogicalBorderSurface::GetSurfaceTable();
325    std::vector<G4LogicalBorderSurface*>::const_iterator pos;
326    for (pos = btable->begin(); pos != btable->end(); pos++)
327    {
328      if (pvol == (*pos)->GetVolume1())  // just the first in the couple
329      {                                  // is enough
330        surf = *pos; break;
331      }
332    }
333  }
334  return surf;
335}
336
337void G4GDMLWriteStructure::SurfacesWrite()
338{
339   G4cout << "G4GDML: Writing surfaces..." << G4endl;
340
341   std::vector<xercesc::DOMElement*>::const_iterator pos;
342   for (pos = skinElementVec.begin(); pos != skinElementVec.end(); pos++)
343   {
344     structureElement->appendChild(*pos);
345   }
346   for (pos = borderElementVec.begin(); pos != borderElementVec.end(); pos++)
347   {
348     structureElement->appendChild(*pos);
349   }
350}
351
352void G4GDMLWriteStructure::StructureWrite(xercesc::DOMElement* gdmlElement)
353{
354   G4cout << "G4GDML: Writing structure..." << G4endl;
355
356   structureElement = NewElement("structure");
357   gdmlElement->appendChild(structureElement);
358}
359
360G4Transform3D G4GDMLWriteStructure::
361TraverseVolumeTree(const G4LogicalVolume* const volumePtr, const G4int depth)
362{
363   if (VolumeMap().find(volumePtr) != VolumeMap().end())
364   {
365     return VolumeMap()[volumePtr]; // Volume is already processed
366   }
367
368   G4VSolid* solidPtr = volumePtr->GetSolid();
369   G4Transform3D R,invR;
370   G4int trans=0;
371
372   while (true) // Solve possible displacement/reflection
373   {            // of the referenced solid!
374      if (trans>maxTransforms)
375      {
376        G4String ErrorMessage = "Referenced solid in volume '"
377                              + volumePtr->GetName()
378                              + "' was displaced/reflected too many times!";
379        G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
380                    "InvalidSetup", FatalException, ErrorMessage);
381      }
382
383      if (G4ReflectedSolid* refl = dynamic_cast<G4ReflectedSolid*>(solidPtr))
384      {
385         R = R*refl->GetTransform3D();
386         solidPtr = refl->GetConstituentMovedSolid();
387         trans++;
388         continue;
389      }
390
391      if (G4DisplacedSolid* disp = dynamic_cast<G4DisplacedSolid*>(solidPtr))
392      {
393         R = R*G4Transform3D(disp->GetObjectRotation(),
394                             disp->GetObjectTranslation());
395         solidPtr = disp->GetConstituentMovedSolid();
396         trans++;
397         continue;
398      }
399
400      break;
401   }
402
403   // Only compute the inverse when necessary!
404   //
405   if (trans>0) { invR = R.inverse(); }
406
407   const G4String name
408         = GenerateName(volumePtr->GetName(),volumePtr);
409   const G4String materialref
410         = GenerateName(volumePtr->GetMaterial()->GetName(),
411                        volumePtr->GetMaterial());
412   const G4String solidref
413         = GenerateName(solidPtr->GetName(),solidPtr);
414
415   xercesc::DOMElement* volumeElement = NewElement("volume");
416   volumeElement->setAttributeNode(NewAttribute("name",name));
417   xercesc::DOMElement* materialrefElement = NewElement("materialref");
418   materialrefElement->setAttributeNode(NewAttribute("ref",materialref));
419   volumeElement->appendChild(materialrefElement);
420   xercesc::DOMElement* solidrefElement = NewElement("solidref");
421   solidrefElement->setAttributeNode(NewAttribute("ref",solidref));
422   volumeElement->appendChild(solidrefElement);
423
424   const G4int daughterCount = volumePtr->GetNoDaughters();
425
426   for (G4int i=0;i<daughterCount;i++)   // Traverse all the children!
427   {
428      const G4VPhysicalVolume* const physvol = volumePtr->GetDaughter(i);
429      const G4String ModuleName = Modularize(physvol,depth);
430
431      G4Transform3D daughterR;
432
433      if (ModuleName.empty())   // Check if subtree requested to be
434      {                         // a separate module!
435         daughterR = TraverseVolumeTree(physvol->GetLogicalVolume(),depth+1);
436      }
437      else
438      {   
439         G4GDMLWriteStructure writer;
440         daughterR = writer.Write(ModuleName,physvol->GetLogicalVolume(),
441                                  SchemaLocation,depth+1);
442      }
443
444      if (const G4PVDivision* const divisionvol
445         = dynamic_cast<const G4PVDivision*>(physvol)) // Is it division?
446      {
447         if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
448         {
449            G4String ErrorMessage = "Division volume in '"
450                                  + name
451                                  + "' can not be related to reflected solid!";
452            G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
453                        "InvalidSetup", FatalException, ErrorMessage);
454         }
455         DivisionvolWrite(volumeElement,divisionvol); 
456      } else 
457      if (physvol->IsParameterised())   // Is it a paramvol?
458      {
459         if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
460         {
461            G4String ErrorMessage = "Parameterised volume in '"
462                                  + name
463                                  + "' can not be related to reflected solid!";
464            G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
465                        "InvalidSetup", FatalException, ErrorMessage);
466         }
467         ParamvolWrite(volumeElement,physvol);
468      } else
469      if (physvol->IsReplicated())   // Is it a replicavol?
470      {
471         if (!G4Transform3D::Identity.isNear(invR*daughterR,kRelativePrecision))
472         {
473            G4String ErrorMessage = "Replica volume in '"
474                                  + name
475                                  + "' can not be related to reflected solid!";
476            G4Exception("G4GDMLWriteStructure::TraverseVolumeTree()",
477                        "InvalidSetup", FatalException, ErrorMessage);
478         }
479         ReplicavolWrite(volumeElement,physvol); 
480      }
481      else   // Is it a physvol?
482      {
483         G4RotationMatrix rot;
484
485         if (physvol->GetFrameRotation() != 0)
486         {
487           rot = *(physvol->GetFrameRotation());
488         }
489         G4Transform3D P(rot,physvol->GetObjectTranslation());
490         PhysvolWrite(volumeElement,physvol,invR*P*daughterR,ModuleName);
491      }
492      BorderSurfaceCache(GetBorderSurface(physvol));
493   }
494
495   structureElement->appendChild(volumeElement);
496     // Append the volume AFTER traversing the children so that
497     // the order of volumes will be correct!
498
499   VolumeMap()[volumePtr] = R;
500
501   AddExtension(volumeElement, volumePtr);
502     // Add any possible user defined extension attached to a volume
503
504   AddMaterial(volumePtr->GetMaterial());
505     // Add the involved materials and solids!
506
507   AddSolid(solidPtr);
508
509   SkinSurfaceCache(GetSkinSurface(volumePtr));
510
511   return R;
512}
Note: See TracBrowser for help on using the repository browser.