Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GeoGeometry.cxx

Go to the documentation of this file.
00001 
00002 //
00003 // GeoGeometry
00004 //
00005 // GeoGeometry is single geometry constructed using the TGeoManager
00006 //
00007 // Author:  S. Kasahara 11/03
00008 //
00009 // Based on R. Hatcher's UgliGeometry/UgliGeometry class.
00011 
00012 #include <iostream>
00013 #include <cassert>
00014 #include <math.h>
00015 #include <set>
00016 using namespace std;
00017 
00018 #include <TGeoManager.h>
00019 #include <TGeoMatrix.h>
00020 #include <TGeoNode.h>
00021 #include <TGeoBBox.h>
00022 #include <TGeoArb8.h>
00023 #include <TList.h>
00024 
00025 #include "Conventions/Munits.h"
00026 #include "Conventions/MinosMaterial.h"
00027 #include "Util/UtilString.h"
00028 #include "GeoGeometry/Geo.h"
00029 #include "GeoGeometry/GeoGeometry.h"
00030 #include "GeoGeometry/GeoMediumMap.h"
00031 #include "GeoGeometry/GeoScintPlnVolume.h"
00032 #include "GeoGeometry/GeoSteelPlnVolume.h"
00033 #include "GeoGeometry/GeoStripVolume.h"
00034 #include "GeoGeometry/GeoScintMdlVolume.h"
00035 #include "GeoGeometry/GeoStripNode.h"
00036 #include "GeoGeometry/GeoScintMdlNode.h"
00037 #include "GeoGeometry/GeoScintPlnNode.h"
00038 #include "GeoGeometry/GeoSteelPlnNode.h"
00039 #include "GeoGeometry/GeoMedium.h"
00040 #include "UgliGeometry/UgliDbiTables.h"
00041 #include "UgliGeometry/UgliDbiStructHash.h"
00042 #include "MessageService/MsgService.h"
00043 #include "Plex/PlexVetoShieldHack.h"
00044 
00045 ClassImp(GeoGeometry)
00046 
00047 CVSID("$Id: GeoGeometry.cxx,v 1.87 2008/01/09 06:38:11 schubert Exp $");
00048 
00049 //_____________________________________________________________________________
00050 GeoGeometry::GeoGeometry() : fVldRange(),fAppType(Geo::kRecons),
00051                 fScale(1),fHallPath(""),fGeoManager(0),fGeoShield(),
00052                 fIsSwimMedia(false),fMediumMap(0),fRot45(0),fRot315(0) {
00053   // Default constructor, used for i/o
00054 
00055   MSG("Geo",Msg::kDebug) << "GeoGeometry def ctor @ " << this << endl;
00056 
00057   UpdateGlobalManager(); // this is okay, because fGeoManager ptr stored
00058 
00059   // fScale has been set before this step
00060   for ( int ism = 0; ism < 2; ism++ ) { 
00061      fSMZMin[ism] = +999.*fScale; 
00062      fSMZMax[ism] = -999.*fScale; 
00063   }
00064 
00065 }
00066 
00067 //_____________________________________________________________________________
00068 GeoGeometry::GeoGeometry(const VldContext &vldc, Geo::EAppType apptype) : 
00069   fVldRange(),fAppType(apptype),fScale(1),fHallPath(""),
00070   fGeoManager(0),fGeoShield(this),fIsSwimMedia(false),fMediumMap(0),
00071   fRot45(0),fRot315(0) {
00072   // Normal constructor
00073   // Geometry is built for application type Geo::kRecons by default.
00074   // The application type determines the units the geometry will be built
00075   // in.  The default apptype = Geo::kRecons will build the geometry in
00076   // Minos standard units of meters.  Specifying apptype = Geo::kVMC will
00077   // build the geometry in TVirtualMC standard units of cm.
00078   
00079   MSG("Geo",Msg::kDebug) << "GeoGeometry normal ctor @ " << this << endl;
00080 
00081   UpdateGlobalManager(); // set gGeoManager to null before building new 
00082 
00083   MSG("Geo",Msg::kInfo) << "GeoGeometry build for validity " 
00084                         << vldc << "." << endl;
00085   
00086   // Silence TGeoManager info messages
00087   Int_t saveErrorIgnoreLevel = gErrorIgnoreLevel;
00088   gErrorIgnoreLevel = kWarning;
00089   
00090   //MsgStream* msgeo = MsgService::Instance() -> GetStream("Geo");
00091   //msgeo -> SetLogLevel(Msg::kVerbose);
00092   
00093   fScale = Geo::GetScale(apptype);
00094 
00095   // fScale must be set before this step
00096   for ( int ism = 0; ism < 2; ism++ ) { 
00097      fSMZMin[ism] = +999.*fScale; 
00098      fSMZMax[ism] = -999.*fScale; 
00099   }
00100 
00101   fGeoManager = new TGeoManager(vldc.AsString("s1ac-"),"a MINOS geometry");
00102   UpdateGlobalManager(); // set gGeoManager to fGeoManager
00103 
00104   fMediumMap = new GeoMediumMap(this,vldc);
00105   
00106   // Build all materials and detector geometry
00107   this -> BuildAll(vldc);
00108   
00109   fGeoManager->CloseGeometry();
00110 
00111   TGeoVolume* volume = fGeoManager->GetTopVolume();
00112   UpdateNodeMatrices(volume);
00113   // Invoke CdTop to position back to top (MARS) volume.
00114   fGeoManager->CdTop();
00115   
00116   //this -> DumpVolume("MARS");
00117   
00118   fGeoManager->SetVisLevel(4);
00119   fGeoManager->SetVisOption(0);
00120 
00121   MSG("Geo",Msg::kInfo) << "GeoGeometry build complete." << endl;
00122   gErrorIgnoreLevel = saveErrorIgnoreLevel;
00123 
00124 }
00125 
00126 //_____________________________________________________________________________
00127 GeoGeometry::~GeoGeometry() {
00128   // delete all the owned sub-objects
00129 
00130   MSG("Geo",Msg::kDebug) << "GeoGeometry dtor @ " << this << endl;
00131 
00132   UpdateGlobalManager();
00133 
00134   fPlaneMap.clear();
00135   if ( fMediumMap ) delete fMediumMap; fMediumMap = 0;
00136   
00137   if ( fGeoManager ) {
00138     delete fGeoManager; fGeoManager = 0;
00139   }
00140  
00141   UpdateGlobalManager(); // set gGeoManager to null to avoid further use
00142   
00143 }
00144 
00145 //_____________________________________________________________________________
00146 void GeoGeometry::Draw(Option_t* volname) {
00147   // Public. Draw this geometry from volume volname (default "HALL")
00148 
00149   UpdateGlobalManager();
00150 
00151   std::string volnamestr(volname);
00152   if (volnamestr.empty()) volnamestr = "HALL"; 
00153    
00154   MSG("Geo",Msg::kInfo) << "GeoGeometry::Draw() from top volume " 
00155                         << volnamestr.empty() << "." << endl;
00156 
00157   if ( !fGeoManager ) {
00158     MSG("Geo",Msg::kWarning) << "Null fGeoManager" << endl;
00159     return;
00160   }
00161   
00162   TGeoVolume* topVol = fGeoManager -> GetVolume(volnamestr.c_str());
00163   if ( !topVol ) {
00164     MSG("Geo",Msg::kWarning) << "No volume of name " << volnamestr.c_str() 
00165                              << endl;
00166     return;
00167   }
00168   //fGeoManager->SetTopVisible();
00169   topVol -> SetVisContainers();
00170   topVol -> Draw();
00171    
00172 }
00173 
00174 //_____________________________________________________________________________
00175 void GeoGeometry::DumpVolume(std::string volname, std::string preface) const {
00176   // Print information about volume down through all daughter nodes
00177 
00178   UpdateGlobalManager();
00179 
00180   TGeoVolume* volume = fGeoManager->GetVolume(volname.c_str());
00181   if ( !volume ) {
00182     cout << "No volume of name \"" << volname.c_str() << "\"!" << endl;
00183     return;
00184   }
00185   
00186   cout << preface.c_str() << "Volume " << volume->GetName() << ", shape:" 
00187        << endl;
00188   cout << preface.c_str();
00189   volume->GetShape()->InspectShape();
00190   
00191   Int_t ndaughter = volume -> GetNdaughters();
00192   if ( ndaughter > 0 ) 
00193     cout << preface.c_str() << ndaughter << " daughter nodes:" << endl;
00194   else
00195     cout << preface.c_str() << "No daughter nodes." << endl;
00196   
00197   for ( int id = 0; id < ndaughter; id++ ) {
00198     TGeoNode* daughternode = volume->GetNode(id);
00199     cout << preface.c_str() << "  " << id << ")" << daughternode->GetName() 
00200          << endl;
00201     cout << preface.c_str() << "  ";
00202     daughternode->GetMatrix()->Print();
00203     TGeoVolume* daughtervol = daughternode->GetVolume();
00204     this -> DumpVolume(daughtervol->GetName(),preface+"  ");
00205   }
00206   
00207 }
00208 
00209 //_____________________________________________________________________________
00210 std::string GeoGeometry::GetGeoCompatibleName(std::string name) {
00211   // Public Static method to return acceptable node or volume name
00212   // Symbol "/" is replaced with "f" to avoid conflict with "/" used in paths
00213   // Symbol "-" is replaced with "h" to avoid conflict with "-" used in
00214   // composite shapes. 
00215 
00216   std::string okayname = name;
00217   // Name cannot include "/" because of ambiguity with "/" used in
00218   // path to nodes. Replace "/" with "f".
00219   unsigned int ipos = okayname.find("/");
00220   while ( ipos != std::string::npos ) {
00221     okayname.replace(ipos,1,"f");
00222     ipos = okayname.find("/");
00223   }
00224 
00225   // Name cannot include "-" because of ambiguity with "-" used in
00226   // composite shapes. Replace "-" with "h".
00227   ipos = okayname.find("-");
00228   while ( ipos != std::string::npos ) {
00229     okayname.replace(ipos,1,"h");
00230     ipos = okayname.find("-");
00231   }
00232   
00233   return okayname; 
00234 }
00235 
00236 //_____________________________________________________________________________
00237 TVector3 GeoGeometry::GetHallExtentMin() const {
00238   // Purpose:: Return the min (x,y,z) of the detector hall in global
00239   // (MARS) coordinates.
00240 
00241   UpdateGlobalManager();
00242   
00243   gGeoManager -> cd(fHallPath.c_str());
00244   TGeoNode* hallNode = gGeoManager->GetCurrentNode();
00245   TGeoVolume* hallVol = hallNode->GetVolume();
00246 
00247   TGeoBBox* hallBox = dynamic_cast<TGeoBBox*>(hallVol->GetShape());
00248   
00249   Double_t lxyz[3] = {-(hallBox->GetDX()),-(hallBox->GetDY()),
00250                       -(hallBox->GetDZ())};
00251   Double_t gxyz[3] = {0};
00252 
00253   gGeoManager->LocalToMaster(lxyz,gxyz);
00254   
00255   return TVector3(gxyz[0],gxyz[1],gxyz[2]);
00256 
00257 }
00258 
00259 //_____________________________________________________________________________
00260 TVector3 GeoGeometry::GetHallExtentMax() const {
00261   // Purpose:: Return the max (x,y,z) of the detector hall in global
00262   // (MARS) coordinates.
00263 
00264   UpdateGlobalManager();
00265   
00266   gGeoManager -> cd(fHallPath.c_str());
00267   TGeoNode* hallNode = gGeoManager->GetCurrentNode();
00268   TGeoVolume* hallVol = hallNode->GetVolume();
00269 
00270   TGeoBBox* hallBox = dynamic_cast<TGeoBBox*>(hallVol->GetShape());
00271   
00272   Double_t lxyz[3] = {+(hallBox->GetDX()),+(hallBox->GetDY()),
00273                       +(hallBox->GetDZ())};
00274   Double_t gxyz[3] = {0};
00275   
00276   gGeoManager->LocalToMaster(lxyz,gxyz);
00277   
00278   return TVector3(gxyz[0],gxyz[1],gxyz[2]);
00279 
00280 }
00281 
00282 //_____________________________________________________________________________
00283 GeoSteelPlnNode* GeoGeometry::GetNearestSteelPlnNode(Double_t z) const {
00284   // Public. Purpose:: Retrieve the nearest steel node for a given z
00285 
00286   UpdateGlobalManager();
00287 
00288   MSG("Geo",Msg::kDebug) << "GeoGeometry::GetNearestSteelPlnNode to z " 
00289                          << z << "." << endl;
00290   assert(fGeoManager);
00291 
00292   const std::map<Float_t,GeoSteelPlnNode*>& stnodemap = GetSteelPlnNodeMap();
00293 
00294   // Steel planes in map are all in main detector block
00295   // Ordering of planes is lo to hi
00296   std::map<Float_t,GeoSteelPlnNode*>::const_iterator steelplnItr;
00297   
00298   // Lower bound returns steel plane with z value greater than or equal to key
00299   steelplnItr = stnodemap.lower_bound(z);
00300   GeoSteelPlnNode* loplnNode = 0;
00301   Double_t         loplnz0   = -9999.;
00302   GeoSteelPlnNode* hiplnNode = 0;
00303   Double_t         hiplnz0   = -9999.;
00304   if ( steelplnItr != stnodemap.end() ) {
00305     hiplnNode = steelplnItr->second;
00306     hiplnz0   = steelplnItr->first;
00307   }
00308   if ( steelplnItr != stnodemap.begin() ) {
00309     steelplnItr--;
00310     loplnNode = steelplnItr->second;
00311     loplnz0   = steelplnItr->first;
00312   }
00313   if ( hiplnNode == 0 ) return loplnNode;
00314   else if ( loplnNode == 0 ) return hiplnNode;
00315   
00316   // Bracketed by two planes, determine which is closer
00317   // avoid additional (slow) coordinate transformations by using
00318   // information stored in the map
00319   return ( TMath::Abs(z-loplnz0) < TMath::Abs(z-hiplnz0) ) ? loplnNode : hiplnNode;
00320 
00321 
00322 }
00323 
00324 //_____________________________________________________________________________
00325 PlexPlaneId GeoGeometry::GetPlaneIdFromZ(Double_t z) const {
00326   // Purpose:: Retrieve detector plane corresponding to the first
00327   // plane in the main detector block with a back face (high-z side)
00328   // "downstream" of z (greater than z).  The exception is that if z 
00329   // is greater than back face of highest-z plane in detector, return 
00330   // plexplaneid of last plane, even though this plane's high-z face is 
00331   // not downstream of z.  This behavior is that used in UgliGeometry. 
00332   // Use PlexPlaneId::IsValid() to determine validity of returned PlexPlaneId.
00333   // Will only return invalid plexplaneid if no planes in main detector
00334   // block.  
00335  
00336   UpdateGlobalManager();
00337   
00338   MSG("Geo",Msg::kDebug) << "GeoGeometry::GetPlaneIdFromZ " << z << "."<< endl;
00339   assert(fGeoManager);
00340 
00341   PlexPlaneId defplex;  // default plex is invalid
00342   
00343   PlaneMapConstItr plnItr;
00344   // Move through the plane map from low to high z
00345   Double_t xyz_global[3] = {0,0,z};
00346   Double_t xyz_local[3] = {0};
00347       
00348   // fPlaneMap has scint & steel planes 
00349   for ( plnItr = fPlaneMap.begin();  plnItr != fPlaneMap.end(); ++plnItr) {
00350     if ( (plnItr->first).IsVetoShield() ) continue; // No shield
00351     GeoPlnNode* plnNode = dynamic_cast<GeoPlnNode*>(plnItr -> second);
00352     plnNode->GlobalToLocal(xyz_global,xyz_local);
00353     Float_t dz  = dynamic_cast<TGeoBBox*>(plnNode->GetVolume()->GetShape())
00354                   ->GetDZ();
00355     if ( xyz_local[2] < dz ) {
00356       return plnItr->first;
00357     }
00358     defplex = plnItr->first; // default plex is highest-z pln in main block
00359   }
00360 
00361   return defplex;
00362 
00363 }
00364 
00365 //_____________________________________________________________________________
00366 const vector<GeoPlnNode*>& GeoGeometry::GetPlnNodePtrVector() const {
00367   // Public. Purpose:: Return collection of ptrs for all pln nodes in detector
00368 
00369   MSG("Geo",Msg::kDebug) << "GetPlnNodePtrVector" << endl;
00370 
00371   UpdateGlobalManager();
00372 
00373   if ( fPlnNodes.empty() ) {
00374     PlaneMapConstItr plnItr;
00375     for ( plnItr = fPlaneMap.begin(); plnItr != fPlaneMap.end(); ++plnItr) {
00376       GeoPlnNode* plnNode = plnItr->second;
00377       fPlnNodes.push_back(plnNode);
00378     }
00379   }
00380   
00381   return fPlnNodes;
00382 
00383 }
00384 
00385 //_____________________________________________________________________________
00386 GeoScintPlnNode* GeoGeometry::GetScintPlnNode(PlexPlaneId planeid) const {
00387   // Public. Purpose:: Retrieve the node for a particular plane
00388 
00389   MSG("Geo",Msg::kDebug) << "GetScintPlnNode for plane " << planeid.AsString() 
00390                          << endl;
00391 
00392   UpdateGlobalManager();
00393 
00394   GeoScintPlnNode* plnnode = 0;
00395   if ( planeid.IsSteel() ) {
00396     MSG("Geo",Msg::kWarning) 
00397       << "GetScintPlnNode called with steel plane id " 
00398       << planeid.AsString() << endl;
00399     return 0;
00400   }
00401   
00402   PlaneMapConstItr citr = fPlaneMap.find(planeid);
00403   if ( citr != fPlaneMap.end() ) {
00404     plnnode = dynamic_cast<GeoScintPlnNode*>(citr->second);
00405   }
00406   
00407   return plnnode;
00408 
00409 }
00410 
00411 //_____________________________________________________________________________
00412 const vector<GeoScintPlnNode*>& GeoGeometry::GetScintPlnNodePtrVector() const {
00413   // Purpose:: Return collection of ptrs for all scint pln nodes in detector
00414 
00415   MSG("Geo",Msg::kDebug) << "GetScintPlnNodePtrVector" << endl;
00416 
00417   UpdateGlobalManager();
00418 
00419   if ( fScintPlnNodes.empty() ) {
00420     PlaneMapConstItr plnItr;
00421     for ( plnItr = fPlaneMap.begin(); plnItr != fPlaneMap.end(); ++plnItr ){
00422       if ( !(plnItr->first).IsSteel() ) {
00423         fScintPlnNodes.push_back(
00424                               dynamic_cast<GeoScintPlnNode*>(plnItr->second));
00425       }
00426     }
00427   }
00428 
00429   return fScintPlnNodes;
00430 
00431 }
00432 
00433 //_____________________________________________________________________________
00434 GeoSteelPlnNode* GeoGeometry::GetSteelPlnNode(PlexPlaneId planeid) const {
00435   // Public. Purpose:: Retrieve the node for a particular plane
00436 
00437   MSG("Geo",Msg::kDebug) << "GetSteelPlnNode for plane " << planeid.AsString() 
00438                          << endl;
00439 
00440   UpdateGlobalManager();
00441 
00442   GeoSteelPlnNode* plnnode = 0;
00443   if ( !planeid.IsSteel() ) {
00444     MSG("Geo",Msg::kWarning) 
00445       << "GetSteelPlnNode called with non steel plane id " 
00446       << planeid.AsString() << endl;
00447     return 0;
00448   }
00449   
00450   PlaneMapConstItr citr = fPlaneMap.find(planeid);
00451   if ( citr != fPlaneMap.end() ) {
00452     plnnode = dynamic_cast<GeoSteelPlnNode*>(citr->second);
00453   }
00454   
00455   return plnnode;
00456 
00457 }
00458 
00459 //_____________________________________________________________________________
00460 const vector<GeoSteelPlnNode*>& GeoGeometry::GetSteelPlnNodePtrVector() const {
00461   // Public. Purpose:: Return collection of ptrs for all steel pln nodes 
00462   // in detector
00463 
00464   MSG("Geo",Msg::kDebug) << "GetSteelPlnNodePtrVector" << endl;
00465 
00466   UpdateGlobalManager();
00467 
00468   if ( fSteelPlnNodes.empty() ) {
00469     PlaneMapConstItr plnItr;
00470     for ( plnItr = fPlaneMap.begin(); plnItr != fPlaneMap.end(); ++plnItr ){
00471       if ( (plnItr->first).IsSteel() ) {
00472         fSteelPlnNodes.push_back(
00473                               dynamic_cast<GeoSteelPlnNode*>(plnItr->second));
00474       }
00475     }
00476   }
00477   
00478   return fSteelPlnNodes;
00479 
00480 }
00481 
00482 //_____________________________________________________________________________
00483 const std::map<Float_t,GeoSteelPlnNode*>& GeoGeometry::GetSteelPlnNodeMap() 
00484                                                                      const {
00485   // Public. Purpose:: Return collection of ptrs for all steel pln nodes 
00486   // in main body of detector, key'ed by z-position. 
00487 
00488   MSG("Geo",Msg::kDebug) << "GetSteelPlnNodeMap" << endl;
00489 
00490   UpdateGlobalManager();
00491   
00492   if ( fSteelPlnNodeMap.empty() ) {
00493     PlaneMapConstItr plnItr;
00494     for ( plnItr = fPlaneMap.begin(); plnItr != fPlaneMap.end(); plnItr++ ){
00495       if ( (plnItr->first).IsSteel() && !(plnItr->first).IsVetoShield()) {
00496         fSteelPlnNodeMap.insert(make_pair(plnItr->second->GetZ0(),
00497                              dynamic_cast<GeoSteelPlnNode*>(plnItr->second)));
00498       }
00499     }
00500   }
00501   
00502   return fSteelPlnNodeMap;
00503 
00504 }
00505 
00506 //_____________________________________________________________________________
00507 GeoStripNode* GeoGeometry::GetStripNode(const PlexStripEndId& seid) const {
00508   // Public. Purpose:: Retrieve the node for a particular strip
00509  
00510   MSG("Geo",Msg::kDebug) << "GetStripNode for strip "  << seid.AsString() 
00511                          << endl;
00512 
00513   UpdateGlobalManager();
00514 
00515   GeoStripNode* stripnode = 0;
00516 
00517   // Retrieve the plane node and then the strip node
00518   GeoScintPlnNode* planenode = this -> GetScintPlnNode(seid);
00519   if ( planenode ) {
00520     stripnode = planenode -> GetStripNode(seid);
00521   }
00522 
00523   return stripnode;
00524 
00525 }
00526 
00527 //_____________________________________________________________________________
00528 void GeoGeometry::GetTransverseExtent(PlaneView::PlaneView_t view,
00529                                       Double_t& tmin, Double_t& tmax) const {
00530   // Public. Purpose: Retrieve transverse extent of detector
00531   // based on detector type and form.  These values are currently hardwired
00532   // as in UgliGeometry::GetTransverseExtent
00533 
00534   MSG("Geo",Msg::kDebug) << "GetTransverseExtent for view "  
00535                          << PlaneView::AsString(view) << endl;
00536 
00537   UpdateGlobalManager();
00538 
00539   tmin = -999; tmax=-999;
00540 
00541   Detector::Detector_t detector 
00542     = (Detector::Detector_t)fVldRange.GetDetectorMask();
00543   
00544   switch (detector) {
00545   case Detector::kNear:
00546     switch (view ) {
00547     case PlaneView::kU:
00548       tmin = -2.10 * fScale;
00549       tmax = +2.75 * fScale;
00550       break;
00551     case PlaneView::kV:
00552       tmin = -2.75 * fScale;
00553       tmax = +2.10 * fScale;
00554       break;
00555     default:
00556       MSG("Geo",Msg::kError)
00557         << "GeoGeometry::GetTransverseExtent undefined for "
00558         << Detector::AsString(detector) << " view "
00559         << PlaneView::AsString(view) << endl;
00560       break;
00561     }
00562   case Detector::kFar:
00563     tmin = -4.0 * fScale;
00564     tmax = +4.0 * fScale;
00565     break;
00566   case Detector::kCalib:
00567     tmin = -0.5 * fScale;
00568     tmax = +0.5 * fScale;
00569     break;
00570   default:
00571     MSG("Geo",Msg::kError) 
00572       << "GeoGeometry::GetTransverseExtent undefined for "
00573       << Detector::AsString(detector) << endl;
00574     break;
00575   }
00576 
00577   Float_t fuzz = 0.5*Geo::kStripWidth*fScale;
00578   tmin = tmin - fuzz;
00579   tmax = tmax + fuzz;
00580   
00581   return;
00582     
00583 }
00584 
00585 //_____________________________________________________________________________
00586 void GeoGeometry::GetTransverseExtent(PlaneView::PlaneView_t view,
00587                                       Float_t& tmin, Float_t& tmax) const {
00588   // Public. Purpose: Retrieve transverse extent of detector in global (MARS)
00589   // coordinates.
00590 
00591   UpdateGlobalManager();
00592   
00593   Double_t tmind,tmaxd;
00594   GetTransverseExtent(view,tmind,tmaxd);
00595   tmin = (Float_t)tmind;
00596   tmax = (Float_t)tmaxd;
00597 
00598   return;
00599     
00600 }
00601 
00602 //_____________________________________________________________________________
00603 void GeoGeometry::GetZExtent(Double_t& zmin, Double_t& zmax, Int_t isup) const{
00604   // Public. Purpose: Retrieve zextent of specified isup supermodule in MARS
00605   // coordinates. If isup = -1 (default), returns zextent of entire detector.
00606  
00607   MSG("Geo",Msg::kDebug) << "GetZExtent for isup "  << isup << endl;
00608 
00609   UpdateGlobalManager();
00610  
00611   // The boundaries are calculated during geometry build 
00612   zmax =-999999;
00613   zmin =+999999; 
00614   if ( isup < 0 ) {
00615     zmin = fSMZMin[0];
00616     if ( fSMZMax[1] > 0 ) zmax = fSMZMax[1];
00617     else zmax = fSMZMax[0];
00618   }
00619   else if ( isup < 2 ) {
00620     zmin = fSMZMin[isup];
00621     zmax = fSMZMax[isup];
00622   }
00623   else {
00624     MSG("Geo",Msg::kWarning) << "GetZExtent failed. SuperModule "
00625                              << isup << " undefined." << endl;
00626   }
00627 
00628   return;
00629   
00630    
00631 }
00632 
00633 //_____________________________________________________________________________
00634 void GeoGeometry::GetZExtent(Float_t& zmin, Float_t& zmax, Int_t isup) const {
00635   // Public. Purpose:: Retrieve zextent of specified isup supermodule. If 
00636   // isup = -1 (default), returns zextent of entire detector.
00637 
00638   UpdateGlobalManager();
00639   
00640   Double_t zmind,zmaxd;
00641   GetZExtent(zmind,zmaxd,isup);
00642   zmin = (Float_t)zmind;
00643   zmax = (Float_t)zmaxd;
00644 
00645   return;
00646 }
00647 
00648 //_____________________________________________________________________________
00649 TGeoMedium* GeoGeometry::GetMedium(const char* name) const {
00650   // Public. Purpose:: Return ptr to medium of given name.  If geometry
00651   // is not closed, such that this method is being called during the
00652   // geometry build stage, will abort with fatal message if no medium
00653   // of given name is found.  Otherwise, will return null ptr if
00654   // medium not found.
00655   //  
00656 
00657   UpdateGlobalManager();
00658 
00659   TGeoMedium* medium = fGeoManager->GetMedium(name);
00660   if ( !medium && !(fGeoManager->IsClosed()) ) {
00661     MSG("Geo",Msg::kFatal) << "GeoGeometry::GetMedium did not find medium\n"
00662                            << name << " during geometry build stage. Abort."
00663                            << endl;
00664     abort();
00665   }
00666   
00667   return medium;
00668 
00669 }
00670 
00671 //_____________________________________________________________________________
00672 bool GeoGeometry::IsCompatible(const VldContext& vldc, 
00673                                Geo::EAppType apptype) const {
00674   // Public. Test if vldc and apptype are in range of this geometry
00675 
00676   UpdateGlobalManager();
00677 
00678   bool iscompatible = false;
00679   if ( fVldRange.IsCompatible(vldc) && fAppType == apptype ) 
00680                                              iscompatible = true;
00681   return iscompatible; 
00682 }
00683 
00684 //_____________________________________________________________________________
00685 void GeoGeometry::ls(Option_t* option) const {
00686   // Public. list components of this geometry
00687   // Argument: option string is a concatenated list of char options, where:
00688   //           "m" => print list materials
00689   //           "M" => print list of media.  Default won't print swim media
00690   //                  Override with configopt == "a", e.g. ls("Ma").
00691   //           "d" => print MediumMap detector components and associated 
00692   //                  mediums and swim methods 
00693   //           "v" => print list of volumes 
00694   //           "a" => configuration option "all".  If present, may toggle
00695   //                  on a greater dump of information.
00696   // Example: An option argument to specify listing of materials and mediums
00697   //          is "mM"
00698 
00699   UpdateGlobalManager();
00700   PrintHeader();
00701 
00702   TString opt = option;
00703   bool isAll = false;
00704   if ( opt.Contains("a") ) isAll = true;
00705   
00706   if (opt.Contains("m")) {
00707     // Can't use ls() for TGeoMaterial because not supported
00708     fGeoManager->GetListOfMaterials()->Print(); 
00709   }
00710   if (opt.Contains("M")) {
00711     // Can't use ls() or Print() for TGeoMedium because not supported
00712     GeoMedium::PrintHeader();  // print media table header
00713     TIter medItr(fGeoManager->GetListOfMedia());
00714     GeoMedium* medium = 0;  
00715     while ( ( medium = dynamic_cast<GeoMedium*>(medItr()) ) ) {
00716       if ( !isAll ) {
00717         std::string medName = medium->GetName();
00718         if ( medName.find("_SWIM") != std::string::npos ) continue;
00719       }
00720       medium -> Print();
00721     }
00722   }
00723   if (opt.Contains("d")) {
00724     // Print list of detector components and associated mediums and
00725     // swim methods
00726     GetMediumMap().Print();
00727   }
00728   if (opt.Contains("v")) {
00729     // Print list of volumes in this geometry
00730     TIter volItr(fGeoManager->GetListOfUVolumes());
00731     TGeoVolume* volume = 0;
00732     while ( ( volume = dynamic_cast<TGeoVolume*>(volItr()) ) ) {
00733       cout << setiosflags(ios::left) << setw(30) << volume->GetName() 
00734            << setw(30) << volume->GetMedium()->GetName()
00735            << endl;
00736     }
00737   }    
00738   
00739 }
00740 
00741 //_____________________________________________________________________________
00742 void GeoGeometry::Print(Option_t* option) const {
00743    // Public. Print something about this geometry (name + vldrange)
00744 
00745   UpdateGlobalManager();
00746 
00747   std::string stoption(option);
00748   if (stoption != "") DumpVolume(stoption);
00749   PrintHeader();
00750   
00751 }
00752 
00753 //_____________________________________________________________________________
00754 void GeoGeometry::PrintHeader(Option_t* /* option */) const {
00755   // Print header info (name + vldrange) about this geometry.
00756 
00757   cout << "GeoGeometry " << fGeoManager->GetName() << " " 
00758        << fGeoManager->GetTitle() << endl;
00759   cout << "Has " << CountRef() << " reference" << ((CountRef()==1)?"":"s")
00760        << " VldRange:" << fVldRange.AsString("acs-") << endl;
00761   
00762 }
00763 
00764 //_____________________________________________________________________________
00765 void GeoGeometry::SwitchMedia(bool toswim) {
00766   // Method to geometry to/from swim media to default media
00767   // Swim media are used during GeoSwimmer particle transport and
00768   // have a different set of physics process flags/energy threshold
00769   // cuts assigned to them when used with a concrete VMC.
00770 
00771   Int_t ntoadd = 0;
00772   Int_t nmedia = fGeoManager->GetListOfMedia()->GetSize();
00773   if ( toswim ) {
00774     if ( fIsSwimMedia ) return;  // already set up for swim media
00775     ntoadd = nmedia/2 - 1; // number to add to current medId to get swim twin  
00776   }
00777   else {
00778     if ( !fIsSwimMedia ) return; // already set up for default media
00779     ntoadd = -nmedia/2 - 1; // number to add to current medId to get def twin
00780   }
00781   
00782   TIter nextvol(fGeoManager->GetListOfVolumes());
00783   TGeoVolume* vol = 0;
00784   while ( ( vol = (TGeoVolume*)nextvol() ) ) {
00785     TGeoMedium* currentMed = vol -> GetMedium();
00786     Int_t twinMedId = currentMed->GetId() + ntoadd;
00787     TGeoMedium* twinMed = (TGeoMedium*)
00788                      (fGeoManager->GetListOfMedia()->At(twinMedId));
00789     vol -> SetMedium(twinMed);
00790   }
00791 
00792   fIsSwimMedia = toswim;
00793 
00794 }
00795 
00796 //_____________________________________________________________________________
00797 void GeoGeometry::BuildAll(const VldContext &vldc) {
00798   // Private.  Build materials & geometry
00799 
00800   UpdateGlobalManager();
00801 
00802   MSG("Geo",Msg::kDebug) << "GeoGeometry BuildAll " << endl;
00803   assert(fGeoManager);
00804 
00805   // Get the VldRange that fits this context
00806   BuildVldRange(vldc);
00807 
00808   // Build commonly used rotation matrices
00809   BuildRotations();
00810   
00811   // Build Detector Geometry
00812   BuildGeometry(vldc);
00813 
00814 }
00815 
00816 //_____________________________________________________________________________
00817 void GeoGeometry::BuildVldRange(const VldContext &vldc) {
00818   // Private. Build VldRange from VldContext
00819 
00820   UpdateGlobalManager();
00821 
00822   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildVldRange for VldContext " 
00823                          << vldc << endl;
00824   
00825   Detector::Detector_t det = vldc.GetDetector();
00826   bool isunknown = (Detector::kUnknown == det);
00827   const char* src = "DBI";
00828   Int_t detmask = Detector::FullMask();
00829   Int_t simmask = SimFlag::FullMask();
00830   if ( isunknown ) { 
00831     src = "Fake (unknown detector)";
00832     detmask = det;
00833     simmask = vldc.GetSimFlag();
00834   }
00835   
00836   // Start the VldRange covering all of time and then trim it down
00837   VldTimeStamp starttime = VldTimeStamp::GetBOT();
00838   VldTimeStamp endtime = VldTimeStamp::GetEOT();
00839   fVldRange = VldRange(detmask,simmask,starttime,endtime,src);
00840 
00841   // special return for unknown detector
00842   if (isunknown) return;
00843 
00844   DbiResultPtr<UgliDbiSteelPln> steelTbl(vldc);
00845   TrimVldRange("UgliDbiSteelPln",steelTbl.GetValidityRec());
00846 
00847   DbiResultPtr<UgliDbiScintPlnStruct> scintStructTbl(vldc);
00848   TrimVldRange("UgliDbiScintPlnStruct",scintStructTbl.GetValidityRec());
00849 
00850   DbiResultPtr<UgliDbiScintPln> scintTbl(vldc);
00851   TrimVldRange("UgliDbiScintPln",scintTbl.GetValidityRec());
00852 
00853   DbiResultPtr<UgliDbiScintMdlStruct> mdlStructTbl(vldc);
00854   TrimVldRange("UgliDbiScintMdlStruct",mdlStructTbl.GetValidityRec());
00855 
00856   DbiResultPtr<UgliDbiScintMdl> mdlTbl(vldc);
00857   TrimVldRange("UgliDbiScintMdl",mdlTbl.GetValidityRec());
00858 
00859   DbiResultPtr<UgliDbiStripStruct> stripStructTbl(vldc);
00860   TrimVldRange("UgliDbiStripStruct",stripStructTbl.GetValidityRec());
00861 
00862   DbiResultPtr<UgliDbiStrip> stripTbl(vldc);
00863   TrimVldRange("UgliDbiStrip",stripTbl.GetValidityRec());
00864   
00865   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildVldRange built VldRange " 
00866                          << fVldRange << endl;
00867   
00868 }
00869 
00870 //_____________________________________________________________________________
00871 void GeoGeometry::TrimVldRange(const char* tblName,
00872                                const DbiValidityRec* dbivrec) {
00873   // Private. Trim VldRange based on DbiValidityRec range info
00874 
00875   UpdateGlobalManager();
00876 
00877   if ( dbivrec ) {
00878     fVldRange.TrimTo(dbivrec->GetVldRange());
00879   }
00880   else {
00881     MSG("Geo",Msg::kWarning) << "No DbiValidityRec for table " << tblName 
00882                              << endl;
00883   }
00884   
00885 }
00886    
00887 //_____________________________________________________________________________
00888 void GeoGeometry::BuildRotations() {
00889   // Build commonly used rotation matrices
00890 
00891   // Rotation about the z-axis by +45 degrees
00892   fRot45 = new TGeoRotation("rot45",90,45,90,135,0,0);
00893   fRot45 -> RegisterYourself(); // do this so that it can be found later
00894 
00895 
00896   // Rotation about the z-axis by -45 degrees
00897   fRot315 = new TGeoRotation("rot315",90,315,90,45,0,0);
00898   fRot315 -> RegisterYourself(); // do this so that it can be found later
00899 
00900 }
00901 
00902 
00903 //_____________________________________________________________________________
00904 void GeoGeometry::BuildGeometry(const VldContext& vldc) {
00905   // Private. Build this geometry's hierarchy of nodes
00906 
00907   UpdateGlobalManager();
00908   
00909   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildGeometry" << endl;
00910   assert(fGeoManager);
00911 
00912   const GeoMediumMap& medMap = GetMediumMap();
00913   
00914   if (vldc.GetDetector() == Detector::kUnknown) {
00915     // build a minimalistic geometry
00916     TGeoVolume* volMARS = fGeoManager -> MakeBox("MARS",
00917                                    medMap.GetMedium(Geo::kMars),1.2,1.2,1.2);
00918     TGeoVolume* volLINR = fGeoManager -> MakeBox("LINR",
00919                                    medMap.GetMedium(Geo::kLinr),1.1,1.1,1.1);
00920     volMARS -> AddNode(volLINR,1,gGeoIdentity);
00921     TGeoVolume* volHALL = fGeoManager -> MakeBox("HALL",
00922                                    medMap.GetMedium(Geo::kHall),1.0,1.0,1.0);
00923     volLINR -> AddNode(volHALL,1,gGeoIdentity);
00924     fGeoManager -> SetTopVolume(volMARS);
00925     return;
00926   }
00927 
00928   const UgliDbiTables& ugliDbiTables = UgliDbiTables(vldc);
00929   const UgliDbiGeometry* ugliDbiGeo = ugliDbiTables.GetDbiGeometry();
00930   if (!ugliDbiGeo) {
00931     MSG("Geo",Msg::kFatal) 
00932        << "No UgliDbiGeometry for " << vldc << endl;
00933     abort();
00934   }
00935 
00936   // Start with the hall, this is the widest view stored in db 
00937   const Float_t* hmin = ugliDbiGeo->GetHallXYZMin();
00938   const Float_t* hmax = ugliDbiGeo->GetHallXYZMax();
00939 
00940   // For far detector, pad x-dimension because otherwise shield is cut-off
00941   Double_t xpad = 0.*fScale;
00942   if ( vldc.GetDetector() == Detector::kFar ) xpad = 0.02*fScale;
00943   // For near detector, pad y-dim by 1 cm because otherwise scint plane
00944   // polygon extrudes floor in imperfect geometry. Fix me.
00945   Double_t ypad = 0.*fScale;
00946   if ( vldc.GetDetector() == Detector::kNear ) ypad = 0.01*fScale;
00947   
00948   Double_t hminsc[3] = {hmin[0]*fScale,hmin[1]*fScale,hmin[2]*fScale};
00949   Double_t hmaxsc[3] = {hmax[0]*fScale,hmax[1]*fScale,hmax[2]*fScale};
00950 
00951   // x/y/zhsiz is half-width in each dimension of hall
00952   Double_t xhsiz = 0.5*(hmaxsc[0] - hminsc[0]) + xpad;
00953   Double_t yhsiz = 0.5*(hmaxsc[1] - hminsc[1]) + ypad;
00954   Double_t zhsiz = 0.5*(hmaxsc[2] - hminsc[2]);
00955 
00956   // x/y/z0hall is center of hall
00957   Double_t x0hall = 0.5*(hmaxsc[0] + hminsc[0]);
00958   Double_t y0hall = 0.5*(hmaxsc[1] + hminsc[1]);
00959   Double_t z0hall = 0.5*(hmaxsc[2] + hminsc[2]);
00960 
00961   MSG("Geo",Msg::kDebug) << "Hall halfwidths " << xhsiz << ","
00962                          << yhsiz << "," << zhsiz << " placed at "
00963                          << x0hall << "," << y0hall << "," << z0hall << endl;
00964   
00965 
00966   // Hall
00967   TGeoVolume* volHALL   = fGeoManager->MakeBox("HALL",
00968                              medMap.GetMedium(Geo::kHall),xhsiz,yhsiz,zhsiz);
00969   volHALL-> SetVisibility(kTRUE);
00970   volHALL-> SetLineColor(kGreen);
00971 
00972   // Liner pad is box with halfwidth dimensions equal
00973   // to the hall halfwidths + the liner thickness (1 m)
00974   Detector::Detector_t dettype = (Detector::Detector_t)vldc.GetDetector();
00975   const Double_t linerpad = 1.0*fScale; // thickness concrete liner (1 m)
00976   
00977   TGeoVolume* volLINR     = fGeoManager->MakeBox("LINR",
00978                                          medMap.GetMedium(Geo::kLinr),
00979                                          xhsiz+linerpad,yhsiz+linerpad,
00980                                          zhsiz+linerpad);
00981   volLINR-> SetVisibility(kTRUE);
00982   volLINR-> SetLineColor(kYellow);
00983 
00984   // Build MARS appropriate to detector type.
00985   TGeoVolume* volMARS = 0;
00986   switch ( dettype ) {
00987   case Detector::kFar:
00988     volMARS = BuildFarMARS();
00989     break;
00990   case Detector::kNear:
00991     volMARS = BuildNearMARS();
00992     break;
00993   default:
00994     // Rock shell default is
00995     // rock padding, minimum 5 m thick onto half hall dimensions
00996     const Double_t rockpad = 5.0*fScale; // thickness of considered rock (5 m)
00997     Double_t absxmax = TMath::Max(TMath::Abs(hminsc[0]-xpad),
00998                                   TMath::Abs(hmaxsc[0]+xpad));
00999     Double_t absymax = TMath::Max(TMath::Abs(hminsc[1]-ypad),
01000                                 TMath::Abs(hmaxsc[1]+ypad));
01001     Double_t abszmax = TMath::Max(TMath::Abs(hminsc[2]),
01002                                 TMath::Abs(hmaxsc[2]));
01003     volMARS = fGeoManager->MakeBox("MARS",medMap.GetMedium(Geo::kMars),
01004                                     absxmax+rockpad,
01005                                     absymax+rockpad,abszmax+rockpad);
01006     break;
01007   }
01008 
01009   volMARS -> SetVisibility(kTRUE);
01010   volMARS -> SetLineColor(kBlack); 
01011 
01012   // The top level volume MARS will be assigned node path "/MARS_1" by root
01013   fGeoManager -> SetTopVolume(volMARS);
01014   // GeoNodes are owned by the TGeoManager
01015   std::string nodename = "LINR_1";
01016   std::string globalpath = "/MARS_1/" + nodename;
01017   volMARS -> AddNode(volLINR,1,
01018                      new TGeoTranslation("LINR",x0hall,y0hall,z0hall));
01019    
01020   nodename = "HALL_1";
01021   globalpath += "/" + nodename;
01022   fHallPath = globalpath;
01023   volLINR -> AddNode(volHALL,1,gGeoIdentity);
01024 
01025   BuildDetector(vldc,volHALL);
01026   
01027 }
01028 
01029 //_____________________________________________________________________________
01030 void GeoGeometry::BuildDetector(const VldContext& vldc,
01031                                 TGeoVolume* hallVol) {
01032    // Private. Build this geometry's steel+scint planes + coil
01033 
01034   UpdateGlobalManager();
01035 
01036   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildDetector " << endl;
01037   assert(fGeoManager);
01038 
01039   DbiResultPtr<UgliDbiSteelPln> steelTbl(vldc);
01040 
01041   BuildPlanePairVolumes(vldc); // pre-build plane pair volumes
01042 
01043   // Build shield group volumes and install them as nodes in hall
01044   // and install shield plane pair nodes in group volumes
01045   if ( vldc.GetDetector() == Detector::kFar ) 
01046                              fGeoShield.BuildGroupNodes(hallVol);
01047   
01048   // Plane db positions are stored relative to mars so need
01049   // hall global position to recalculate
01050   // Translation taken from liner, since hall placed with identity
01051   // matrix relative to liner
01052   TGeoNode* linrNode = fGeoManager->GetVolume("MARS")->GetNode("LINR_1");
01053   const Double_t* h0 = linrNode -> GetMatrix() -> GetTranslation();
01054   
01055   Int_t plnMin[2] = {-1};
01056   Int_t plnMax[2] = {-1};
01057   Int_t nSM = GetSMPlaneLimits(vldc,plnMin,plnMax);
01058 
01059   std::string minPlaneName[2];
01060   std::string maxPlaneName[2];
01061   Int_t minPlane[2] = {9999,9999};
01062   Int_t maxPlane[2] = {-9999,-9999};
01063   
01064   // order construction by plane #, STL set will sort them
01065   std::set<PlexPlaneId> steelset;
01066   for (unsigned int irow=0; irow < steelTbl.GetNumRows(); ++irow) {
01067     const UgliDbiSteelPln* stRow = steelTbl.GetRow(irow);
01068     PlexPlaneId steelId = stRow -> GetPlaneId();
01069     steelset.insert(steelId);
01070   }
01071   
01072   std::set<PlexPlaneId>::const_iterator steelitr = steelset.begin();
01073   for ( ; steelitr != steelset.end() ; steelitr++) {
01074     PlexPlaneId steelId = *steelitr;
01075     const UgliDbiSteelPln* stRow = steelTbl.GetRowByIndex(steelId.GetPlane());
01076     if ( (vldc.GetDetector() ==  Detector::kFar && !steelId.IsVetoShield()) ) {
01077       // Dispatch some anomalies in the database
01078        if ( steelId.GetPlane() > 485 ) continue; // because db has 0-497
01079        // Skip planes that have intentionally been placed at unphysical
01080        // locations
01081        if ( TMath::Abs(stRow->GetX0() ) > 50. ) continue;
01082     }
01083 
01084     // This is used just for reporting info at end of build
01085     Int_t vsId = 0;
01086     std::string stName = GetGeoCompatibleName(steelId.AsString());
01087     if ( steelId.IsVetoShield() ) vsId = 1;
01088     if ( steelId.GetPlane() < minPlane[vsId] ) {
01089         minPlane[vsId] = steelId.GetPlane();
01090         minPlaneName[vsId] = stName;
01091     }
01092     if ( steelId.GetPlane() > maxPlane[vsId] ) {
01093         maxPlane[vsId] = steelId.GetPlane();
01094         maxPlaneName[vsId] = stName;
01095     }
01096     
01097     // Veto shield built separately
01098     if ( vldc.GetDetector() == Detector::kFar && steelId.IsVetoShield() ) 
01099                                                               continue;
01100     
01101     Double_t offxyz[3] = {h0[0],h0[1],h0[2]};
01102        
01103     // The pair volumes have been pre-built
01104     std::string pairName = GetGeoCompatibleName(steelId.AsString("b"));
01105     TGeoVolume* pairVol = fGeoManager -> GetVolume(pairName.c_str());
01106     if ( !pairVol ) {
01107       MSG("Geo",Msg::kFatal) 
01108          << "Unable to find pre-built pairvol for volume "
01109          << pairName.c_str() << endl;
01110       abort();
01111     }
01112     
01113     // Position pair bounding box 
01114     TGeoRotation* stRotMatrix = new TGeoRotation(pairName.c_str(),
01115                                 stRow->GetThetaDeg(0),stRow->GetPhiDeg(0),
01116                                 stRow->GetThetaDeg(1),stRow->GetPhiDeg(1),
01117                                 stRow->GetThetaDeg(2),stRow->GetPhiDeg(2));
01118     stRotMatrix -> RegisterYourself();
01119     
01120     // Plane DB translation is relative to MARS, move to SM or hall local 
01121     Float_t x0pair = (stRow->GetX0())*fScale - offxyz[0];
01122     Float_t y0pair = (stRow->GetY0())*fScale - offxyz[1];
01123 
01124     // If plane is first plane in supermodule than thickness of pair
01125     // box is just "Thickness".  If it's part of vetoshield, than 
01126     // thickness of pair box is just "TotalZ", else pair box thickness 
01127     // is set by distance from back face of
01128     // of current steel plane to back face of previous steel plane. z0pair
01129     // is defined as the position of the center of this pair box in z.
01130     Int_t planeno = steelId.GetPlane();
01131     Float_t z0pair = 0;
01132     if ( vldc.GetDetector() == Detector::kCalDet || steelId.IsVetoShield() ) 
01133       z0pair =(stRow->GetZBack()-0.5*(stRow->GetTotalZ()))*fScale - offxyz[2];
01134     else
01135       z0pair =(stRow->GetZBack()-0.5*(stRow->GetThickness()))*fScale-offxyz[2];
01136           
01137     if ( !steelId.IsVetoShield() ) {
01138       if ( planeno != plnMin[0] ) {
01139         if ( nSM == 1 || (nSM > 1 && planeno != plnMin[1]) ) {
01140           const UgliDbiSteelPln* stPrevRow = steelTbl.GetRowByIndex(planeno-1);
01141           z0pair = (stRow->GetZBack()-0.5*(stRow->GetZBack()
01142                                   -stPrevRow->GetZBack()))*fScale - offxyz[2];
01143         }
01144       }
01145     }
01146     
01147     TGeoCombiTrans* pairMatrix = new TGeoCombiTrans(pairName.c_str(),
01148                                     x0pair,y0pair,z0pair,stRotMatrix);
01149     MSG("Geo",Msg::kDebug) << "Placing plane pair " << pairName.c_str()
01150                            << " at " << x0pair << ","
01151                            << y0pair << "," << z0pair 
01152                            << "\n rotmatrix:(thetax/y/z,phix/y/z) (" 
01153                            << stRow->GetThetaDeg(0) << ","  
01154                            << stRow->GetPhiDeg(0) << "),("
01155                            << stRow->GetThetaDeg(1) << ","  
01156                            << stRow->GetPhiDeg(1) << "),("
01157                            << stRow->GetThetaDeg(2) << ","  
01158                            << stRow->GetPhiDeg(2) << ")"
01159                            << endl;
01160 
01161     // Place plane pairs directly in hall
01162     hallVol -> AddNode(pairVol,1,pairMatrix);
01163   } // end of loop over all plane db rows
01164 
01165 
01166   MSG("Geo",Msg::kInfo) << "GeoGeometry built detector planes "
01167                         << minPlaneName[0].c_str() << " to " 
01168                         << maxPlaneName[0].c_str() << "." << endl;
01169   if ( !minPlaneName[1].empty() ) {
01170     MSG("Geo",Msg::kInfo) << "GeoGeometry built shield planes "
01171                           << minPlaneName[1].c_str() << " to " 
01172                           << maxPlaneName[1].c_str() << "." << endl;
01173   }
01174   
01175   // Build outer coil after all planes are positioned so that detector
01176   // limits are known
01177   Detector::Detector_t dettype = (Detector::Detector_t)vldc.GetDetector();
01178   switch ( dettype ) {
01179   case Detector::kFar:
01180     BuildFarCoil(hallVol);
01181     break;
01182   case Detector::kNear:
01183     BuildNearCoil(hallVol);
01184     break;
01185   default:
01186     break;
01187   }
01188 
01189   return;
01190   
01191 }
01192 
01193 //_____________________________________________________________________________
01194 void GeoGeometry::BuildPlanePairVolumes(const VldContext& vldc) {
01195    // Private. Build this geometry's steel+scint plane pair volumes
01196 
01197   UpdateGlobalManager();
01198 
01199   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildPlanePairVolumes " << endl;
01200   assert(fGeoManager);
01201 
01202   const GeoMediumMap& medMap = GetMediumMap();
01203 
01204   DbiResultPtr<UgliDbiSteelPln> steelTbl(vldc);
01205   const UgliDbiTables& ugliDbiTables = UgliDbiTables(vldc);
01206 
01207   // Pre-build strip volumes
01208   BuildStripVolumes(vldc);
01209 
01210   Int_t plnMin[2] = {-1};
01211   Int_t plnMax[2] = {-1};
01212   Int_t nSM = GetSMPlaneLimits(vldc,plnMin,plnMax);
01213   
01214   // Build coil segment volume to be used for air gaps between scint & steel
01215   // planes.  This is built as TGeoVolumeMulti, and can be built once and
01216   // used to fill every air gap in detector.
01217   TGeoVolume* coilVol = BuildCoilAirGapVolume(vldc); 
01218   TGeoRotation* rot45 = GetRot45();
01219   Detector::Detector_t dettype = (Detector::Detector_t)vldc.GetDetector();
01220   
01221   for (unsigned int irow=0; irow < steelTbl.GetNumRows(); ++irow) {
01222 
01223     // Build steel and scint plane volumes first, then position so
01224     // that we know pair volume size.
01225 
01226     // Steel plane
01227     GeoSteelPlnVolume* stplnVolume = 0;
01228     const UgliDbiSteelPln* stRow = steelTbl.GetRow(irow);
01229     PlexPlaneId steelId = stRow -> GetPlaneId();
01230 
01231     std::string stName = GetGeoCompatibleName(steelId.AsString());
01232      
01233     if ( steelId.IsVetoShield() 
01234       && vldc.GetDetector() == Detector::kFar ) steelId =
01235       PlexVetoShieldHack::RenumberMuxToMdl(vldc,steelId);  // don't know why 
01236     else if ( steelId.GetPlane() > 485 ) continue; // because db has 0-497
01237     // Skip planes that have intentionally been placed at unphysical
01238     // locations
01239     if ( TMath::Abs(stRow->GetX0() ) > 50. ) continue;
01240     
01241     Double_t pairhalfx = 0;
01242     Double_t pairhalfy = 0;
01243 
01244     // If plane is first plane in supermodule, thickness of pair box is just
01245     // "Thickness", else pair box thickness is set by distance from back 
01246     // face of of current steel plane to back face of previous steel plane. 
01247     Int_t planeno = steelId.GetPlane();
01248     Double_t pairhalfz = 0;
01249     if ( vldc.GetDetector() == Detector::kCalDet || steelId.IsVetoShield() ) 
01250       pairhalfz = 0.5*(stRow->GetTotalZ())*fScale;
01251     else
01252       pairhalfz = 0.5*(stRow->GetThickness())*fScale;
01253     if ( !steelId.IsVetoShield() ) {
01254       if ( planeno != plnMin[0] ) {
01255         if ( nSM == 1 || (nSM > 1 && planeno != plnMin[1]) ) {
01256           const UgliDbiSteelPln* stPrevRow = steelTbl.GetRowByIndex(planeno-1);
01257           pairhalfz = 0.5*(stRow->GetZBack() - stPrevRow->GetZBack())*fScale;
01258         }
01259       }
01260     }
01261     
01262     if ( !steelId.IsVetoShield() ) {
01263       stplnVolume = new GeoSteelPlnVolume(this,steelId,
01264                                        stRow->GetThickness()*fScale);
01265       stplnVolume -> SetLineColor(kRed);
01266       stplnVolume -> SetVisibility(kTRUE);
01267 
01268       // Since we assume that pair is always placed at (x,y)=(0,0), need
01269       // to take into account bbox origin when determining pair dx,dy
01270       TGeoBBox* bbox = dynamic_cast<TGeoBBox*>(stplnVolume->GetShape());
01271       pairhalfx = bbox->GetDX() + TMath::Abs((bbox->GetOrigin())[0]);
01272       pairhalfy = bbox->GetDY() + TMath::Abs((bbox->GetOrigin())[1]);
01273     }
01274     
01275     // Scint plane
01276     GeoScintPlnVolume* scplnVolume = 0;
01277     const UgliDbiScintPln* scRow = 0;
01278     PlexPlaneId scintId = steelId;
01279     scintId.SetIsSteel(false);
01280     std::string scName = GetGeoCompatibleName(scintId.AsString());
01281     if ( PlaneCoverage::kNoActive != steelId.GetPlaneCoverage() && 
01282          PlaneCoverage::kUnknown  != steelId.GetPlaneCoverage() ) {
01283       scRow = ugliDbiTables.GetDbiScintPlnByIndex(scintId.GetPlane());
01284       MSG("Geo",Msg::kDebug) << "Build ScintPln " << scintId.AsString()
01285                              << " w/thickness " << scRow->GetThickness()*fScale
01286                              << endl;
01287 
01288       scplnVolume = new GeoScintPlnVolume(this,scintId,
01289                                           scRow->GetThickness()*fScale);
01290       scplnVolume -> SetVisibility(kFALSE); // deactivate when not debugging
01291       scplnVolume -> SetLineColor(kBlue);
01292 
01293       // This only works because scint planes are rotated in a way such that
01294       // width and height of bounding box don't change.
01295       TGeoBBox* bbox = dynamic_cast<TGeoBBox*>(scplnVolume->GetShape());
01296       pairhalfx = TMath::Max(pairhalfx,bbox->GetDX() 
01297                                      + TMath::Abs((bbox->GetOrigin())[0]));
01298       pairhalfy = TMath::Max(pairhalfy,bbox->GetDY() 
01299                                      + TMath::Abs((bbox->GetOrigin())[1]));
01300     }
01301     // avoid extension of near detector pair box into hall floor. Fix me.
01302     if ( vldc.GetDetector() == Detector::kNear ) pairhalfy = 2.91*fScale;
01303     
01304     // Build pair bounding box and position according to steel plane coords
01305     std::string pairName = GetGeoCompatibleName(steelId.AsString("b"));
01306     MSG("Geo",Msg::kDebug) << "Build PairBox " << pairName.c_str()
01307                            << " w/halfx,y,z " << pairhalfx << ","
01308                            << pairhalfy << "," << pairhalfz << "." << endl;
01309 
01310     Geo::EDetComponent detcomp = Geo::kPlnAirGap;
01311     if ( steelId.IsVetoShield() ) detcomp = Geo::kHall;
01312     TGeoVolume* pairVol = fGeoManager->MakeBox(pairName.c_str(),
01313                                              medMap.GetMedium(detcomp),
01314                                              pairhalfx,pairhalfy,pairhalfz);
01315     pairVol -> SetVisibility(kFALSE);
01316     pairVol -> VisibleDaughters(kTRUE);
01317 
01318     // Build 2 boxes representing air gaps.  "airgap0" is the gap between
01319     // the "front" (low-z face) of the scint plane in the current pair and the
01320     // "back" (high-z face) of the steel plane in the previous pair.
01321     // "airgap1" is the gap between the scint & steel plane in the current
01322     // pair.  The airgap coil segment will be added to each air gap.
01323     if ( !steelId.IsVetoShield() && coilVol ) {
01324       if ( planeno != plnMin[0] ) {
01325         if ( nSM == 1 || (nSM > 1 && planeno != plnMin[1]) ) {
01326           std::string airgap0 = pairName + "_air0";
01327           Double_t airgap0halfz = pairhalfz - 0.5*(stRow->GetTotalZ())*fScale;
01328           // totalz includes airgap even when scint pln not present? 
01329           // compensate for it here
01330           if ( !scplnVolume ) airgap0halfz 
01331                              = pairhalfz - 0.5*(stRow->GetThickness())*fScale;
01332           TGeoVolume* airgap0Vol = fGeoManager->MakeBox(airgap0.c_str(),
01333                                           medMap.GetMedium(Geo::kPlnAirGap),
01334                                           pairhalfx,pairhalfy,airgap0halfz);
01335           airgap0Vol -> SetVisibility(kFALSE);
01336           airgap0Vol -> VisibleDaughters(kTRUE);
01337           Double_t airgap0z0 = -pairhalfz + airgap0halfz;
01338           pairVol->AddNode(airgap0Vol,1,new TGeoTranslation(0.,0.,airgap0z0));
01339           if (dettype == Detector::kNear) airgap0Vol->AddNode(coilVol,1,rot45);
01340           else airgap0Vol -> AddNode(coilVol,1,gGeoIdentity);
01341         }
01342       }
01343       if ( scplnVolume ) {  // can't have airgap1 without active plane
01344         std::string airgap1 = pairName + "_air1";
01345         Double_t airgap1halfz = 0.5*(stRow->GetTotalZ()-stRow->GetThickness() 
01346                           - scRow->GetThickness())*fScale;
01347         TGeoVolume* airgap1Vol = fGeoManager->MakeBox(airgap1.c_str(),
01348                                      medMap.GetMedium(Geo::kPlnAirGap),
01349                                      pairhalfx,pairhalfy,airgap1halfz);
01350         airgap1Vol -> SetVisibility(kFALSE);
01351         airgap1Vol -> VisibleDaughters(kTRUE);
01352         Double_t airgap1z0 = pairhalfz-stRow->GetThickness()*fScale
01353                            - airgap1halfz;
01354         pairVol -> AddNode(airgap1Vol,1,new TGeoTranslation(0.,0.,airgap1z0));
01355 
01356         if ( dettype == Detector::kNear ) airgap1Vol->AddNode(coilVol,1,rot45);
01357         else airgap1Vol -> AddNode(coilVol,1,gGeoIdentity);
01358       }  
01359     }
01360     
01361     // Add to shield groups so as to be able to build bounding volume
01362     // default for caldet shield planes is still to place pair directly in hall
01363     std::string pairPath = fHallPath + "/" + pairName +"_1"; 
01364     if ( steelId.IsVetoShield() && vldc.GetDetector() == Detector::kFar ) { 
01365       GeoShield::EGroupType group=fGeoShield.AddVolume(pairVol,steelId,stRow);
01366       pairPath = fHallPath + "/" + GeoShield::AsString(group) + "_1/" + 
01367                  pairName+"_1";
01368     }
01369       
01370     int iSM = -1; // veto shield
01371     if ( !steelId.IsVetoShield() ) {
01372       iSM = 0;
01373       if ( nSM > 1 && steelId.GetPlane() > plnMax[0] ) iSM = 1;
01374     }
01375       
01376     if ( stplnVolume ) {
01377       // Place the steel plane within the pairVol
01378       std::string stplnNodeName = stName + "_1";
01379       std::string steelPlnPath = pairPath + "/" + stplnNodeName;
01380       double z0steel = pairhalfz - 0.5*(stRow->GetThickness())*fScale;
01381       MSG("Geo",Msg::kDebug) << "Placing steel pln at " << 0. << ","
01382                              << 0. << "," << z0steel << endl;
01383       GeoSteelPlnNode* stplnNode = new GeoSteelPlnNode(this,stplnVolume,
01384                           new TGeoTranslation(stName.c_str(),0.,0.,z0steel),
01385                           pairVol,steelPlnPath,stplnNodeName,steelId);
01386       
01387       // fSMZMin/Max in MARS coordinates
01388       if ( vldc.GetDetector() != Detector::kCalDet ) 
01389         fSMZMin[iSM] = TMath::Min(fSMZMin[iSM],(stRow->GetZBack()
01390                                   -stRow->GetThickness())*fScale);  
01391       else 
01392         fSMZMin[iSM] = TMath::Min(fSMZMin[iSM],(stRow->GetZBack()
01393                                   -stRow->GetTotalZ())*fScale);      
01394       fSMZMax[iSM] = TMath::Max(fSMZMax[iSM],(stRow->GetZBack())*fScale);
01395 
01396       // Insert steelplnNode in plane map
01397       fPlaneMap[steelId] = stplnNode;
01398     }
01399     
01400     if ( scplnVolume ) {
01401       // Place the scint plane within the pairVol
01402       Float_t x0pln = (scRow->GetX0RelSteel())*fScale;
01403       Float_t y0pln = (scRow->GetY0RelSteel())*fScale;
01404       Float_t z0pln = pairhalfz + 
01405                       (-stRow->GetTotalZ()+0.5*(scRow->GetThickness()))*fScale;
01406 
01407       // Rotation matrix relative to steel
01408       // (thetax,phix) = (90, 0+zrotrelsteel)
01409       // (thetay,phiy) = (90,90+zrotrelsteel)
01410       // (thetaz,phiz) = ( 0, 0)
01411       Double_t zrotrelsteel = scRow->GetZRotRelSteelDeg();
01412 
01413       MSG("Geo",Msg::kDebug) << "Placing scint pln at " << x0pln << ", "
01414                              << y0pln << "," << z0pln 
01415                              << " zrotrelsteel " << zrotrelsteel << endl;
01416         
01417       TGeoRotation* scRotMatrix = new TGeoRotation(scName.c_str(),90.,
01418                                   zrotrelsteel,90.,90.+zrotrelsteel,0.,0.);
01419       scRotMatrix -> RegisterYourself();
01420       
01421       TGeoCombiTrans* combiMatrix 
01422          = new TGeoCombiTrans(scName.c_str(),x0pln,y0pln,z0pln,scRotMatrix);
01423 
01424       std::string scplnNodeName = scName + "_1";
01425       std::string scintPlnPath = pairPath + "/" + scplnNodeName;
01426       GeoScintPlnNode* scplnNode 
01427           = new GeoScintPlnNode(this,scplnVolume,combiMatrix,pairVol,
01428                                 scintPlnPath,scplnNodeName,scintId);
01429     
01430       this -> BuildModules(ugliDbiTables, scplnNode);
01431 
01432       // Insert scint pln node in plane map
01433       fPlaneMap[scintId] = scplnNode;
01434 
01435     }
01436     
01437   } // end of loop over all plane db rows
01438 
01439   
01440   return;
01441   
01442 }
01443   
01444 //_____________________________________________________________________________
01445 Int_t GeoGeometry::GetSMPlaneLimits(const VldContext& vldc,
01446                                     Int_t* plnMin, Int_t* plnMax) {
01447   // Private, but could be public?
01448   // Determine Super Module plane limits for specified vldc.  
01449   // Returns number of super modules.  plnMin/Max[0] is filled for
01450   // supermodule 0 and plnMin/Max[1] for supermodule 1 if applicable.
01451 
01452   Detector::Detector_t dettype = vldc.GetDetector();
01453   Int_t nSM = 0;
01454   switch (dettype) {
01455   case Detector::kFar: 
01456     nSM = 2;
01457     plnMin[0] = 0;
01458     plnMax[0] = 248;
01459     plnMin[1] = 249;
01460     plnMax[1] = 485;
01461     break;
01462   case Detector::kNear:
01463     nSM = 1;
01464     plnMin[0] = 0;
01465     plnMax[0] = 281;
01466     break;
01467   case Detector::kCalDet:
01468     nSM = 1;
01469     plnMin[0] = 0;
01470     plnMax[0] = 60; // main detector block, 61-64 on floor
01471     break;
01472   default:
01473     MSG("Geo",Msg::kError) 
01474     << "GetSMPlaneLimits failed for unknown detector type\n"
01475     << Detector::AsString(dettype) << "." << endl;
01476   } // end of switch
01477 
01478   return nSM;
01479   
01480 }
01481 
01482 //_____________________________________________________________________________
01483 TGeoVolume* GeoGeometry::BuildFarMARS() {
01484   // Private. Build MARS appropriate for the far detector site.
01485 
01486   UpdateGlobalManager();
01487  
01488   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildFarMARS " << endl;
01489   assert(fGeoManager);
01490 
01491   const GeoMediumMap& medMap = GetMediumMap();
01492 
01493   // Dimensions of MARS should be db parameters?
01494   Float_t mars_halfx =  85.*fScale; //  85 m MARS half-x
01495   Float_t mars_halfy =  30.*fScale; //  30 m MARS half-y
01496   Float_t mars_halfz = 250.*fScale; // 250 m MARS half-z
01497   
01498   // Far detector rock medium is different than that of near
01499   TGeoVolume* volMARS = fGeoManager->MakeBox("MARS",
01500                                         medMap.GetMedium(Geo::kMars),
01501                                         mars_halfx,mars_halfy,mars_halfz);
01502 
01503   // Build shaft, tunnel, Soudan 2 cavern & ghost of S2 detector out of air 
01504   // and according to gminos dimensions, except as noted.
01505 
01506   Float_t shft_halfx =  1.*fScale; //  1 m shaft half-x
01507   Float_t shft_halfy = 30.*fScale; // 30 m shaft half-y == MARS half-y
01508   Float_t shft_halfz =  1.*fScale; //  1 m shaft half-z
01509   TGeoVolume* volSHFT = gGeoManager->MakeBox("SHFT",
01510                                              medMap.GetMedium(Geo::kHall),
01511                                              shft_halfx,shft_halfy,shft_halfz);
01512 
01513   // Shorten tunnel by 1 m from gminos dimensions to avoid overlap with LINR
01514   Float_t tunl_halfx =  2.*fScale; //  2 m tunnel half-x
01515   Float_t tunl_halfy =  2.*fScale; //  2 m tunnel half-y 
01516   Float_t tunl_halfz = 13.5*fScale; // 13.5 m tunnel half-z
01517   TGeoVolume* volTUNL = gGeoManager->MakeBox("TUNL",
01518                                             medMap.GetMedium(Geo::kHall),
01519                                             tunl_halfx,tunl_halfy,tunl_halfz);
01520 
01521   Float_t s2hl_halfx =  7.  *fScale; //  7    m S2 hall half-x
01522   Float_t s2hl_halfy =  5.65*fScale; //  5.65 m S2 hall half-y 
01523   Float_t s2hl_halfz = 35.  *fScale; // 35.   m S2 hall half-z
01524   TGeoVolume* volS2HL = gGeoManager->MakeBox("S2HL",
01525                                             medMap.GetMedium(Geo::kHall),
01526                                             s2hl_halfx,s2hl_halfy,s2hl_halfz);
01527 
01528   // The ghost of the S2 detector size is adjusted from that in gminos to 
01529   // be more realistic, but it doesn't matter of course because it's not there!
01530   Float_t s2dt_halfx =  4. *fScale; // 4   m S2 detector half-x
01531   Float_t s2dt_halfy =  2.7*fScale; // 2.7 m S2 detector half-y (4.5, gminos) 
01532   Float_t s2dt_halfz =  7.5*fScale; // 7.5 m S2 detector half-z 
01533   TGeoVolume* volS2DT = gGeoManager->MakeBox("S2DT",
01534                                             medMap.GetMedium(Geo::kHall),
01535                                             s2dt_halfx,s2dt_halfy,s2dt_halfz);
01536   volS2HL -> AddNode(volS2DT,1,
01537                      new TGeoTranslation(0*fScale,-1.15*fScale,-23.5*fScale));
01538 
01539 
01540   volMARS -> AddNode(volSHFT,1,
01541                      new TGeoTranslation(-5.*fScale,0.*fScale,98.18*fScale));
01542   volMARS -> AddNode(volTUNL,1,
01543                      new TGeoTranslation(-5.*fScale,-4.1*fScale,83.68*fScale));
01544   TGeoRotation* s2rot = new TGeoRotation("s2rot",64,0,90,90,26,180);
01545   s2rot -> RegisterYourself();
01546   volMARS -> AddNode(volS2HL,1,
01547                      new TGeoCombiTrans(36.*fScale,-0.45*fScale,61.68*fScale,
01548                                         s2rot));
01549 
01550   return volMARS;
01551 
01552 }
01553 
01554 //_____________________________________________________________________________
01555 TGeoVolume* GeoGeometry::BuildNearMARS() {
01556   // Private. Build MARS appropriate for the near detector site.
01557 
01558   UpdateGlobalManager();
01559  
01560   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildNearMARS " << endl;
01561   assert(fGeoManager);
01562 
01563   const GeoMediumMap& medMap = GetMediumMap();
01564 
01565   // Dimensions of MARS should be db parameters?
01566   Float_t mars_halfx =  85.*fScale; //  85 m MARS half-x
01567   Float_t mars_halfy =  30.*fScale; //  30 m MARS half-y
01568   Float_t mars_halfz = 250.*fScale; // 250 m MARS half-z
01569   
01570   // Near detector rock medium is different than that of far 
01571   TGeoVolume* volMARS = fGeoManager->MakeBox("MARS",
01572                                            medMap.GetMedium(Geo::kMars),
01573                                            mars_halfx,mars_halfy,mars_halfz);
01574 
01575   return volMARS;
01576 
01577 }
01578 
01579 //_____________________________________________________________________________
01580 void GeoGeometry::BuildNearCoil(TGeoVolume* hallVol) {
01581   // Private. Build the near detector coil. Fix me.  
01582   // x0,y0 is coil hole center in hall coordinates (assumed constant
01583   // over all planes).
01584 
01585   UpdateGlobalManager();
01586  
01587   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildNearCoil " << endl;
01588   assert(fGeoManager);
01589 
01590   const GeoMediumMap& medMap = GetMediumMap();
01591 
01592   // The dimensions of the coil should be extracted from the db
01593   Float_t shalfx  = Geo::kNeckRad*fScale; // steel 
01594   Float_t shalfy  = shalfx; // steel
01595   Float_t ahalfx  = Geo::kThroatRad*fScale; // air
01596   Float_t ahalfy  = ahalfx; // air
01597   Float_t alhalfx = Geo::kCoilRad*fScale; // aluminum
01598   Float_t alhalfy = alhalfx; // aluminum
01599  
01600   // Build coil along z-direction, extends to ends of super module
01601   Float_t zmin,zmax;
01602   GetZExtent(zmin,zmax,-1); // returned in MARS coordinates
01603   // Convert to HALL coordinates
01604   TGeoNode* linrNode = fGeoManager->GetVolume("MARS")->GetNode("LINR_1");
01605   const Double_t* h0 = linrNode -> GetMatrix() -> GetTranslation();
01606   zmin -= h0[2];
01607   zmax -= h0[2];
01608   Float_t x0 = -h0[0];
01609   Float_t y0 = -h0[1];
01610   
01611   Float_t zcoillen = zmax - zmin;
01612   TGeoVolume* BUS0 = fGeoManager->MakeBox("BUS0",
01613                                            medMap.GetMedium(Geo::kRCShaft),
01614                                            shalfx,shalfy,0.5*zcoillen);
01615   BUS0 -> SetLineColor(14);  // gray  
01616   BUS0 -> SetVisibility(kTRUE);
01617 
01618   TGeoVolume* BUA0 = fGeoManager->MakeBox("BUA0",
01619                                            medMap.GetMedium(Geo::kRCAir),
01620                                            ahalfx,ahalfy,0.5*zcoillen);
01621   BUA0 -> SetLineColor(14);  
01622   BUA0 -> SetVisibility(kTRUE);
01623   BUS0 -> AddNode(BUA0,1,gGeoIdentity);
01624 
01625   TGeoVolume* BUC0 = fGeoManager->MakeBox("BUC0",
01626                                            medMap.GetMedium(Geo::kRCCoil),
01627                                            alhalfx,alhalfy,0.5*zcoillen);
01628   BUC0 -> SetLineColor(14);  
01629   BUC0 -> SetVisibility(kTRUE);
01630   BUA0 -> AddNode(BUC0,1,gGeoIdentity);
01631 
01632   // Rotate first, then translate
01633   TGeoRotation *rot45 = GetRot45();
01634   Float_t zcoil = (zmin+zmax)/2.;
01635 
01636   // Place return coil in hall
01637   Float_t steelhalfy = 1.9*fScale; // 1.9 m halfwidth in y direction
01638   Float_t xcoil = x0 - steelhalfy;
01639   Float_t ycoil = y0 - steelhalfy;
01640   // overlap because it overlaps pair plane volumes. Fix me.
01641   hallVol -> AddNodeOverlap(BUS0,2,
01642                             new TGeoCombiTrans(xcoil,ycoil,zcoil,rot45)); 
01643 
01644   // Along xy face
01645   Float_t cos45 = 0.707107;
01646   Float_t coillenxy = steelhalfy/cos45 + 2.*shalfx;
01647   TGeoVolume* BUSXY = fGeoManager->MakeBox("BUSXY",
01648                                             medMap.GetMedium(Geo::kRCShaft),
01649                                             shalfx,0.5*coillenxy,shalfy);
01650   BUSXY -> SetLineColor(14);  // gray  
01651   BUSXY -> SetVisibility(kTRUE);
01652   TGeoVolume* BUAXY = fGeoManager->MakeBox("BUAXY",
01653                                             medMap.GetMedium(Geo::kRCAir),
01654                                             ahalfx,0.5*coillenxy,ahalfy);
01655   BUAXY -> SetLineColor(14);  
01656   BUAXY -> SetVisibility(kTRUE);
01657   BUSXY -> AddNode(BUAXY,1,gGeoIdentity);
01658 
01659   TGeoVolume* BUCXY = fGeoManager->MakeBox("BUCXY",
01660                                             medMap.GetMedium(Geo::kRCCoil),
01661                                             alhalfx,0.5*coillenxy,alhalfy);
01662   BUCXY -> SetLineColor(14);  
01663   BUCXY -> SetVisibility(kTRUE);
01664   BUAXY -> AddNode(BUCXY,1,gGeoIdentity);
01665 
01666   // Will be rotated and then translated
01667   TGeoRotation* rotneg45 = GetRot315();
01668   xcoil = x0 - (0.5*coillenxy - shalfx)*cos45;
01669   ycoil = y0 - (0.5*coillenxy - shalfy)*cos45;
01670   zcoil = zmin - shalfy;
01671   hallVol -> AddNode(BUSXY,1,new TGeoCombiTrans(xcoil,ycoil,zcoil,rotneg45));  
01672 
01673   zcoil = zmax + shalfy;
01674   hallVol -> AddNode(BUSXY,2,new TGeoCombiTrans(xcoil,ycoil,zcoil,rotneg45));  
01675 
01676   return;
01677 
01678 }
01679 
01680 //_____________________________________________________________________________
01681 void GeoGeometry::BuildFarCoil(TGeoVolume* hallVol) {
01682   // Private. Build the far detector coil outside of the detector.  
01683   // x0,y0 is coil hole center in HALL coordinates (assumed constant
01684   // over all planes).
01685 
01686   UpdateGlobalManager();
01687  
01688   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildFarCoil " << endl;
01689   assert(fGeoManager);
01690 
01691   const GeoMediumMap& medMap = GetMediumMap();
01692 
01693   // These dimensions/etc. of the coil should be in the db, but for now
01694   // use hardwired values
01695 
01696   // Nomenclature (BUS) is chosen to match that of gminos
01697   // BUSn is the center of the coil made up of medium FARCOIL
01698   // In the convention used here, n = supermodule number
01699 
01700   Float_t sRad = Geo::kCoilRad*fScale; // coil radius 
01701 
01702   Float_t halfhally = dynamic_cast<TGeoBBox*>(hallVol -> GetShape())->GetDY();
01703   
01704   // SM0 coil along z-direction of detector, ends at supermodule ends
01705   // return coil lies on floor
01706   Float_t zmin0,zmax0;
01707   GetZExtent(zmin0,zmax0,0);
01708   // Convert to HALL coordinates
01709   TGeoNode* linrNode = fGeoManager->GetVolume("MARS")->GetNode("LINR_1");
01710   const Double_t* h0 = linrNode -> GetMatrix() -> GetTranslation();
01711   zmin0 -= h0[2];
01712   zmax0 -= h0[2];
01713   Float_t x0 = -h0[0];
01714   Float_t y0 = -h0[1];
01715 
01716   // Per specification from J. Nelson received 8/1/2006, model return
01717   // coil lying along far detector floor as box of halfx 0.225 m and
01718   // halfy 0.05 m.
01719   Float_t retcoilhalfx = 0.225*fScale;
01720   Float_t retcoilhalfy = 0.05*fScale;
01721 
01722   Float_t zcoillen0 = zmax0-zmin0;
01723   TGeoVolume* BUS0=fGeoManager->MakeBox("BUS0",medMap.GetMedium(Geo::kRCCoil),
01724                                       retcoilhalfx,retcoilhalfy,0.5*zcoillen0);
01725   BUS0 -> SetLineColor(42); // tan  
01726   BUS0 -> SetVisibility(kTRUE);
01727 
01728   // Place SM0 return coil in hall
01729   Float_t z0 = 0.5*(zmin0 + zmax0);
01730   hallVol -> AddNode(BUS0,1,new TGeoTranslation("BUS0",x0,
01731                                            -halfhally+retcoilhalfy,z0));
01732   
01733   // SM1 coil along z-direction of detector, ends at supermodule ends
01734   Float_t zmin1,zmax1;
01735   GetZExtent(zmin1,zmax1,1);
01736   // Convert to HALL coordinates
01737   zmin1 -= h0[2];
01738   zmax1 -= h0[2];
01739 
01740   Float_t zcoillen1 = zmax1-zmin1;
01741   TGeoVolume* BUS1=fGeoManager->MakeBox("BUS1",medMap.GetMedium(Geo::kRCCoil),
01742                                       retcoilhalfx,retcoilhalfy,0.5*zcoillen1);
01743   BUS1 -> SetLineColor(42);  // tan  
01744   BUS1 -> SetVisibility(kTRUE);
01745 
01746   // Place SM1 return coil in hall
01747   Float_t z1 = 0.5*(zmin1 + zmax1);
01748   hallVol -> AddNode(BUS1,1,new TGeoTranslation("BUS1",x0,
01749                                                 -halfhally+retcoilhalfy,z1));
01750 
01751   // Build coil volume on xy faces
01752   // Dimensions for horse's tail are roughly those received from J. Nelson 
01753   // correspondence of 8/1/2006, but y-length of bottom section is adjusted to 
01754   // actual distance to floor, and top & mid-sections are trapezoids 
01755   // instead of boxes, dimension in z has been squeezed to fit the supermodule
01756   // gap...
01757   Float_t ycoillen = y0+halfhally+sRad; // top of coil to floor
01758 
01759   // gap between bottom section of tail & plane. Adjust to fit avail region.
01760   Float_t zbotgap = 0.10*fScale; 
01761   // Define bounding box to contain tail 
01762   Float_t xhalftail = 0.40*fScale;
01763   Float_t yhalftail = 0.5*ycoillen;
01764   Float_t zhalftail = 0.5*(zbotgap+0.4*fScale);
01765   TGeoVolume* BUXY = fGeoManager->MakeBox("BUXY",medMap.GetMedium(Geo::kRCAir),
01766                                            xhalftail,yhalftail,zhalftail);
01767   BUXY -> SetLineColor(14); // gray bounding box, invisible by default 
01768   BUXY -> SetVisibility(kFALSE);
01769 
01770   // Horse's tail bounding box is placed at 4 end planes, rotating &
01771   // translating as necessary
01772   // rotFlip defines a 180 rotation
01773   TGeoRotation *rotFlip = new TGeoRotation("BUXY",90,180,90,90,180,0);
01774   rotFlip -> RegisterYourself();
01775   
01776   Float_t xcoil = x0;
01777   Float_t ycoil = y0 + sRad - ycoillen/2.;
01778   hallVol -> AddNode(BUXY,1,new TGeoTranslation("BUXY_1",xcoil,ycoil,
01779                      zmin0-zhalftail));
01780   hallVol -> AddNode(BUXY,2,new TGeoCombiTrans("BUXY_2",xcoil,ycoil,
01781                      zmax0+zhalftail,rotFlip));
01782   hallVol -> AddNode(BUXY,3,new TGeoTranslation("BUXY_3",xcoil,ycoil,
01783                      zmin1-zhalftail));
01784   hallVol -> AddNode(BUXY,4,new TGeoCombiTrans("BUXY_4",xcoil,ycoil,
01785                      zmax1+zhalftail,rotFlip));
01786 
01787   // Now build the inserts for the coil tail bounding box
01788   // Top section is a trapezoid
01789   Float_t yhalftop = 0.5*0.53*fScale;
01790   Float_t zhalftop = 0.10*fScale;
01791   Float_t xhalfloy = 0.2825*fScale;
01792   Float_t xhalfhiy = 0.12*fScale;
01793   TGeoTrap* bxyTopShp = new TGeoTrap("BXYTOP",zhalftop,0.,0.,
01794                                      yhalftop,xhalfloy,xhalfhiy,0.,
01795                                      yhalftop,xhalfloy,xhalfhiy,0.);
01796   TGeoVolume* BXYTOP = new TGeoVolume("BXYTOP",bxyTopShp,
01797                                        medMap.GetMedium(Geo::kRCCoil));
01798   BXYTOP -> SetLineColor(42);  // tan
01799   BXYTOP -> SetVisibility(kTRUE);
01800   BUXY -> AddNode(BXYTOP,1,new TGeoTranslation(0.,yhalftail-sRad-yhalftop,
01801                                               -zhalftail+zhalftop));
01802   
01803 
01804   // Middle section is a trapezoid that skews towards the face of the
01805   // steel plane with decreasing y
01806   Float_t yhalfmid = 0.5*0.85*fScale;
01807   TGeoArb8* bxyMidShp = new TGeoArb8(yhalfmid);
01808   bxyMidShp -> SetVertex(0,-0.4*fScale,0.05*fScale);
01809   bxyMidShp -> SetVertex(1,-0.4*fScale,0.15*fScale);
01810   bxyMidShp -> SetVertex(2,0.4*fScale,0.15*fScale);
01811   bxyMidShp -> SetVertex(3,0.4*fScale,0.05*fScale);
01812   bxyMidShp -> SetVertex(4,-0.2825*fScale,-0.25*fScale);
01813   bxyMidShp -> SetVertex(5,-0.2825*fScale,-0.05*fScale);
01814   bxyMidShp -> SetVertex(6,0.2825*fScale,-0.05*fScale);
01815   bxyMidShp -> SetVertex(7,0.2825*fScale,-0.25*fScale);
01816   
01817   TGeoVolume* BXYMID = new TGeoVolume("BXYMID",bxyMidShp,
01818                                        medMap.GetMedium(Geo::kRCCoil));
01819   BXYMID -> SetLineColor(42); // tan
01820   BXYMID -> SetVisibility(kTRUE);
01821 
01822   TGeoRotation *rotMid = new TGeoRotation("BXYMid",90,0,0,0,90,90);
01823   rotMid -> RegisterYourself();
01824   BUXY -> AddNode(BXYMID,1,new TGeoCombiTrans("BXYMID",0.,
01825                   yhalftail-sRad-2.*yhalftop-yhalfmid,0.,rotMid));
01826 
01827   // Bottom section is a box that extends to floor
01828   Float_t xhalfbot = 0.4*fScale;
01829   Float_t yhalfbot = 0.5*(ycoillen-sRad-2.*yhalftop-2.*yhalfmid);
01830   Float_t zhalfbot = 0.05*fScale;
01831   
01832   TGeoVolume* BXYBOT = fGeoManager -> MakeBox("BXYBOT",
01833                                                medMap.GetMedium(Geo::kRCCoil),
01834                                                xhalfbot,yhalfbot,zhalfbot);
01835   BXYBOT -> SetLineColor(42); // tan
01836   BXYBOT -> SetVisibility(kTRUE);
01837   BUXY -> AddNode(BXYBOT,1,new TGeoTranslation(0.,-yhalftail+yhalfbot,
01838                                                zhalftail-zbotgap-zhalfbot));
01839   
01840   // Return coil along floor that extends outside of detector
01841   TGeoVolume* BXYRET = fGeoManager -> MakeBox("BXYRET",
01842                                medMap.GetMedium(Geo::kRCCoil),
01843                                retcoilhalfx,retcoilhalfy,0.5*zbotgap);
01844   BXYRET -> SetLineColor(42);  // tan
01845   BXYRET -> SetVisibility(kTRUE);
01846   BUXY -> AddNode(BXYRET,1,new TGeoTranslation(0.,-yhalftail+retcoilhalfy,
01847                                                zhalftail-0.5*zbotgap));
01848 
01849   // Segment of coil tube that extends out beyond detector
01850   TGeoVolume* BXYSTB = fGeoManager -> MakeTube("BXYSTB",
01851                                                 medMap.GetMedium(Geo::kRCCoil),
01852                                                 0.,sRad,zhalftail);
01853   BXYSTB -> SetLineColor(42);  // tan
01854   BXYSTB -> SetVisibility(kTRUE);
01855   BUXY -> AddNodeOverlap(BXYSTB,1,new TGeoTranslation(0.,yhalftail-sRad,0.));
01856                                    
01857   return;
01858 
01859 }
01860 
01861 //_____________________________________________________________________________
01862 void GeoGeometry::BuildModules(const UgliDbiTables& ugliDbiTables,
01863                                GeoScintPlnNode* plnNode) {
01864   // Private. Purpose: Build the modules as part of the scintillator plane
01865   
01866   UpdateGlobalManager();
01867   
01868   assert(fGeoManager);
01869 
01870   const PlexPlaneId& plexPlaneId = plnNode -> GetPlexPlaneId();
01871   MSG("Geo",Msg::kDebug) <<"GeoGeometry::BuildModules for scint pln  " 
01872                          << plnNode->GetName() << endl;
01873 
01874   // Global path to plane node. Used to build module global path.
01875   std::string plnPath = plnNode->GetGlobalPath();
01876 
01877   // ScintPlnStruct used to retrieve number of modules in plane  
01878   UgliDbiStructHash planestructhash(plexPlaneId);
01879   const UgliDbiScintPlnStruct* plnStruct = ugliDbiTables.fScintPlnStructTbl
01880         .GetRowByIndex(planestructhash.HashAsPlane());
01881   Int_t nmodules = plnStruct -> GetNModules();
01882   
01883   // Loop over all modules in plane
01884   for ( int imod = 0; imod < nmodules; imod++ ) {
01885     // For each module
01886     PlexScintMdlId plexModuleId(plexPlaneId,imod);
01887 
01888     std::string mdlName = GetGeoCompatibleName(plexModuleId.AsString());
01889     
01890     // Build the module volume
01891     // Ideally could just build one module of each type but alignment varies
01892     // tpos and this may cause slight size variations
01893     // So for now generate one mdl volume per module
01894     GeoScintMdlVolume* mdlVol = new GeoScintMdlVolume(this,plexModuleId,
01895                                                       ugliDbiTables);
01896  
01897     // Build the node and place it in the plane
01898     // Establish the rotational & translational matrix for the module
01899     const UgliDbiScintMdl* scModule 
01900       = ugliDbiTables.GetDbiScintMdlById(plexModuleId);
01901     Float_t tposMod = (scModule -> GetTPosRelPln())*fScale;
01902     Float_t lposMod = (scModule -> GetLPosRelPln())*fScale;
01903     Float_t zrotMod = scModule -> GetZRotRelPlnDeg(); 
01904  
01905     TGeoRotation* modRotMatrix = new TGeoRotation(mdlName.c_str(), 90.,zrotMod,
01906                                                   90.,90.+zrotMod,0.,0.);
01907     modRotMatrix -> RegisterYourself();
01908 
01909     TGeoCombiTrans* combiMatrix = new TGeoCombiTrans(mdlName.c_str(),
01910                                      lposMod,tposMod,0.,modRotMatrix);
01911     std::string mdlNodeName = mdlName + "_1";
01912 
01913     MSG("Geo",Msg::kVerbose) << "Mdl node " << mdlNodeName.c_str() 
01914                              << "tpos, lpos, zrot(deg) rel pln " 
01915                              << tposMod << "," << lposMod << "," << zrotMod 
01916                              << endl;
01917     
01918     GeoScintMdlNode* mdlNode = new GeoScintMdlNode(this,mdlVol,combiMatrix,
01919                                                    plnNode,mdlNodeName,
01920                                                    plexModuleId,
01921                                           scModule->GetClearLenEast()*fScale,
01922                                           scModule->GetClearLenWest()*fScale,
01923                                           scModule->GetWlsLenEast()*fScale,
01924                                           scModule->GetWlsLenWest()*fScale);
01925 
01926     // Add strips to module node
01927     BuildStrips(ugliDbiTables,mdlNode);
01928 
01929   }
01930   
01931 }
01932   
01933 //_____________________________________________________________________________
01934 void GeoGeometry::BuildStrips(const UgliDbiTables& ugliDbiTables,
01935                               GeoScintMdlNode* mdlNode) {
01936   // Purpose:: Build this planes's scint strips and add them as nodes to the
01937   // det plane volume
01938   // This method should be moved to GeoScintPlnVolume
01939 
01940   UpdateGlobalManager();
01941   assert(fGeoManager);
01942  
01943   PlexScintMdlId plexModuleId = mdlNode->GetPlexScintMdlId();
01944   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildStrips for module " 
01945                          << mdlNode->GetName() << endl;
01946   
01947   // Determine lo,hi strip in plane
01948   UgliDbiStructHash modulestructhash(plexModuleId);
01949   const UgliDbiScintMdlStruct* scModuleStruct 
01950        = ugliDbiTables.fScintMdlStructTbl
01951         .GetRowByIndex(modulestructhash.HashAsScintMdl());
01952   Int_t lostrip = scModuleStruct -> GetFirstStrip();
01953   Int_t histrip = scModuleStruct -> GetLastStrip();
01954 
01955   for ( int istp = lostrip; istp <= histrip; istp++ ) {
01956     // For each strip in module
01957     PlexStripEndId seid(plexModuleId,istp);
01958     std::string stpName = GetGeoCompatibleName(seid.AsString());
01959 
01960     MSG("Geo",Msg::kVerbose)  << "Strip " << istp << " name " 
01961                               << stpName.c_str() << endl;
01962     const UgliDbiStrip* scStrip = ugliDbiTables.GetDbiStripById(seid);
01963 
01964     // The strip volumes have been pre-built
01965     std::string stpVolName = GetGeoCompatibleName(seid.AsString("s"));
01966     TGeoVolume* stpVol = fGeoManager -> GetVolume(stpVolName.c_str());
01967     if ( !stpVol ) {
01968       MSG("Geo",Msg::kFatal) 
01969          << "Unable to find pre-built stripvol for volume "
01970          << stpName.c_str() << " shape name " 
01971          << stpVolName.c_str() << endl;
01972       abort();
01973     } 
01974 
01975     // Build the node and place it in the plane
01976     Float_t tposStp = (scStrip -> GetTPosRelMdl())*fScale;
01977     Float_t lposStp = (scStrip -> GetLPosRelMdl())*fScale;
01978     Float_t zrotStp = scStrip -> GetZRotRelMdlDeg();
01979     MSG("Geo",Msg::kVerbose) << "tpos, lpos, zrot(deg) rel to module " 
01980                              << tposStp << ", " << lposStp << ", " 
01981                              << zrotStp << endl;
01982 
01983     std::string stpNodeName = stpVolName+"_1";
01984 
01985     TGeoRotation* stpRotMatrix = new TGeoRotation(stpNodeName.c_str(), 90.,
01986                                        zrotStp,90.,90.+zrotStp,0.,0.);
01987     stpRotMatrix -> RegisterYourself();
01988     TGeoCombiTrans* combiMatrix 
01989      = new TGeoCombiTrans(stpNodeName.c_str(),lposStp,tposStp,0.,stpRotMatrix);
01990 
01991     new GeoStripNode(this,stpVol,combiMatrix,mdlNode,stpNodeName,seid);
01992 
01993   }
01994 
01995   return;
01996   
01997 }
01998 
01999 //__________________________________________________________________________ 
02000 void GeoGeometry::BuildStripVolumes(const VldContext& vldc) {
02001   // pre-build set of strip volumes for this vldc.  strip volumes will be 
02002   // placed appropriately in module volumes as nodes when planes are 
02003   // constructed.
02004 
02005   UpdateGlobalManager();
02006 
02007   MSG("Geo",Msg::kDebug) << "GeoGeometry::BuildStripVolumes " << endl;
02008   assert(fGeoManager);
02009 
02010   DbiResultPtr<UgliDbiStripStruct> stripTbl(vldc);
02011   Detector::Detector_t dettype = vldc.GetDetector();
02012   
02013   for ( unsigned int irow = 0; irow < stripTbl.GetNumRows(); irow++ ) {
02014     const UgliDbiStripStruct* sRow = stripTbl.GetRow(irow);
02015     string stpName = GetGeoCompatibleName(sRow -> GetShapeName());
02016     PlaneView::PlaneView_t plnview = sRow->GetPlaneView();
02017     bool isVetoShield = false;
02018     if ( dettype == Detector::kFar ) {
02019       if ( plnview != PlaneView::kU && plnview != PlaneView::kV ) 
02020         isVetoShield = true;
02021     }
02022     else if ( dettype == Detector::kCalDet ) {
02023       if ( plnview != PlaneView::kX && plnview != PlaneView::kY )
02024         isVetoShield = true;
02025     }
02026     
02027     // Volumes will self-register with fGeoManager
02028     Float_t totallen = (sRow->GetTotalLen())*fScale;
02029     Float_t leneastpart = (sRow->GetLenEastPart())*fScale;
02030     Float_t lenwestpart = (sRow->GetLenWestPart())*fScale;
02031     // Clean up some caldet database crud
02032     if ( totallen < 1.E-4*fScale ) continue;
02033     if ( leneastpart < 1.E-4*fScale ) leneastpart = totallen;
02034     if ( lenwestpart < 1.E-4*fScale ) lenwestpart = totallen;
02035     
02036     new GeoStripVolume(this,stpName.c_str(),totallen,leneastpart,lenwestpart,
02037                                        (sRow->GetWlsLenEast())*fScale, 
02038                                        (sRow->GetWlsLenWest())*fScale, 
02039                                        (sRow->GetWlsLenBypass())*fScale,
02040                                        isVetoShield);
02041   } 
02042 
02043 }
02044 
02045 //_____________________________________________________________________________
02046 void GeoGeometry::UpdateNodeMatrices(TGeoVolume* volume) {
02047   // Private method. Loop through all GeoNodes in geometry starting at volume 
02048   // and construct global matrices for use in local to global (MARS) 
02049   // coordinates
02050 
02051   UpdateGlobalManager();
02052   if (!volume) {
02053     MSG("Geo",Msg::kFatal) << "UpdateNodeMatrices called with null volume ptr "
02054                            << endl;
02055     abort();
02056   }
02057   
02058   Int_t ndaughter = volume -> GetNdaughters();
02059   for ( int id = 0; id < ndaughter; id++ ) {
02060     TGeoNode* daughternode = volume->GetNode(id);
02061     GeoNode* geonode = dynamic_cast<GeoNode*>(daughternode);
02062     if ( geonode ) geonode -> UpdateGlobalMatrix();
02063     
02064     TGeoVolume* daughtervol = daughternode->GetVolume();
02065     this -> UpdateNodeMatrices(daughtervol);
02066   }
02067   
02068 }
02069 
02070 //_____________________________________________________________________________
02071 TGeoVolume* GeoGeometry::BuildCoilAirGapVolume(const VldContext& vldc) const {
02072   // Build coil region volume to be used in airgaps between scint and
02073   // steel planes.
02074 
02075   UpdateGlobalManager();
02076   
02077   TGeoVolume* coilVol = 0;
02078 
02079   Detector::Detector_t dettype = (Detector::Detector_t)vldc.GetDetector();
02080 
02081   switch (dettype) {
02082 
02083   case Detector::kFar:
02084     coilVol = BuildFarCoilAirGapVolume();
02085     break;
02086 
02087   case Detector::kNear:
02088     coilVol = BuildNearCoilAirGapVolume();
02089     break;
02090 
02091   default:
02092     break;
02093 
02094   }
02095 
02096   return coilVol;
02097   
02098 }
02099 
02100 
02101 //_____________________________________________________________________________
02102 TGeoVolume* GeoGeometry::BuildFarCoilAirGapVolume() const {
02103   //
02104   // Build far coil region to be used in airgaps between scint and steel
02105   // planes.  The far detector coil in the air gap
02106   // regions is built according to the same parameters as are used in
02107   // the build of the coil in the far detector scint pln:
02108   //   1)Insert a "bypass" (r=Geo::kFarBypassRad) region (not to be confused
02109   //     with the bypass plastic insert).  This is constructed of magnetized
02110   //     air, and indicates the region near the coil where the detailed
02111   //     field map will be used.
02112   //   2)Insert into the "bypass" a "flange" (r=Geo::kFlangeRad) of magnetized
02113   //     iron.
02114   //   3)Insert into the "flange" a "throat" (r=Geo::kThroatRad) of magnetized
02115   //     air.
02116   //   4)Insert into the "throat" a "coil segment" (r=Geo::kCoilRad) of
02117   //     magnetized FARCOIL medium.  The coil segment is set to rest on the
02118   //     throat (off-center in y).
02119   //
02120   // The thickness in z of all pieces is set to be -1 when defining the shapes,
02121   // and built as a TGeoVolumeMulti.  When placed as a node in the air gap
02122   // volume, the volumemulti shape will take on the thickness of its parent.
02123   // This allows for variable thickness of the air gaps in a non-perfect
02124   // geometry.
02125   //
02126 
02127   UpdateGlobalManager();
02128 
02129   // The nomenclature used here is "F" (far), "G" (gap), followed by
02130   // the two letter code to indicate the coil part type.
02131 
02132   const GeoMediumMap& medMap = GetMediumMap();
02133   
02134   // First check to see if volumemulti has been built. Need only build once.
02135   TGeoVolume* volBypass = gGeoManager->GetVolume("FGBY");
02136   if ( volBypass ) return volBypass;
02137 
02138   Double_t scale = Geo::GetScale(GetAppType());
02139 
02140   TGeoVolume* volCoil
02141     = gGeoManager->MakeTube("FGCO",medMap.GetMedium(Geo::kCRGapCoil),
02142                             0,Geo::kCoilRad*scale,-1.); // coil
02143   volCoil -> SetLineColor(42); // tan
02144 
02145   TGeoVolume* volThroat
02146     = gGeoManager->MakeTube("FGTR",medMap.GetMedium(Geo::kCRGapThroat),
02147                             0,Geo::kThroatRad*scale,-1.); // throat
02148   volThroat -> SetLineColor(kBlue);
02149 
02150   TGeoVolume* volFlange
02151     = gGeoManager->MakeTube("FGFL",medMap.GetMedium(Geo::kCRGapFlange),
02152                              0,Geo::kFlangeRad*scale,-1.); // flange
02153   volFlange -> SetLineColor(46); // rust
02154 
02155   volBypass
02156     = gGeoManager->MakeTube("FGBY",medMap.GetMedium(Geo::kCRGapBypass),
02157                              0,Geo::kFarBypassRad*scale,-1.); // bypass
02158   volBypass -> SetLineColor(kBlue);
02159   volBypass -> SetLineStyle(2); // dashed
02160   volBypass -> SetVisibility(kFALSE); // invisible by default
02161 
02162   volBypass -> AddNode(volFlange,1,gGeoIdentity);
02163   volFlange -> AddNode(volThroat,1,gGeoIdentity);
02164   volThroat -> AddNode(volCoil,1,new TGeoTranslation(0,-0.01*scale,0));
02165 
02166   return volBypass;
02167 
02168 }
02169 
02170 //_____________________________________________________________________________
02171 TGeoVolume* GeoGeometry::BuildNearCoilAirGapVolume() const {
02172   //
02173   // Build near coil region to be used in airgaps between scint and steel
02174   // planes.  The near detector coil in the air gap
02175   // regions is built according to the same parameters as are used in
02176   // the build of the coil in the near detector full coverage scint pln:
02177   //   1)Insert a "bypass" tube (r=Geo::kNearFullBypassRad) region (not to 
02178   //     be confused with the bypass plastic insert).  This is constructed of 
02179   //     magnetized air.
02180   //   2)Insert into the "bypass" a "flange" (box of halfx/y = Geo::kFlangeRad)
02181   //     of  magnetized iron.
02182   //   3)Insert into the "flange" a "throat" (box of halfx/y = Geo::kThroatRad)
02183   //     of  magnetized air.
02184   //   4)Insert into the "throat" a "coil segment" (box of halfx/y
02185   //     = Geo::kCoilRad) of magnetized aluminum.  The coil segment is set
02187   //   5)Insert into the "coil segment" tubes (r=Geo::kNearCoolRad) of
02188   //     magnetized water in an array of 6 columns x 8 rows.
02189   //
02190   // The thickness in z of all pieces is set to be -1 when defining the shapes,
02191   // and built as a TGeoVolumeMulti.  When placed as a node in the scint
02192   // plane, the volumemulti shape will take on the thickness of its parent.
02193   // This allows for variable thickness of the scint plane in a non-perfect
02194   // geometry.
02195   //
02196 
02197   UpdateGlobalManager();
02198 
02199   const GeoMediumMap& medMap = GetMediumMap();
02200   
02201   // The nomenclature used here is "N" (near), "G" (gap), followed by
02202   // the two letter code to indicate the coil part type.
02203   std::string preface = "NG";
02204 
02205   // First check to see if volumemulti has been built. Need only build once.
02206   TGeoVolume* volBypass
02207               = gGeoManager->GetVolume(std::string(preface+"BY").c_str());
02208   if ( volBypass ) return volBypass;
02209 
02210   Double_t scale = Geo::GetScale(GetAppType());
02211 
02212   TGeoVolume* volWater
02213     = gGeoManager->MakeTube(std::string(preface+"WA").c_str(),
02214                             medMap.GetMedium(Geo::kCRGapWater),0,
02215                             Geo::kNearCoolRad*scale,-1.); // water
02216   volWater -> SetLineColor(kGreen);
02217 
02218   TGeoVolume* volCoil
02219     = gGeoManager->MakeBox(std::string(preface+"CO").c_str(),
02220                           medMap.GetMedium(Geo::kCRGapCoil),
02221                           Geo::kCoilRad*scale,Geo::kCoilRad*scale,-1.); // coil
02222   volCoil -> SetLineColor(kBlack);
02223 
02224   TGeoVolume* volThroat
02225     = gGeoManager->MakeBox(std::string(preface+"TR").c_str(),
02226                            medMap.GetMedium(Geo::kCRGapThroat),
02227                      Geo::kThroatRad*scale,Geo::kThroatRad*scale,-1.); //throat
02228   volThroat -> SetLineColor(kBlue);
02229 
02230   TGeoVolume* volFlange
02231     = gGeoManager->MakeBox(std::string(preface+"FL").c_str(),
02232                            medMap.GetMedium(Geo::kCRGapFlange),
02233                      Geo::kFlangeRad*scale,Geo::kFlangeRad*scale,-1.); //flange
02234   volFlange -> SetLineColor(kBlack);
02235 
02236   volBypass
02237       = gGeoManager->MakeTube(std::string(preface+"BY").c_str(),
02238                               medMap.GetMedium(Geo::kCRGapBypass),0,
02239                               Geo::kNearFullBypassRad*scale,-1.); // bypass
02240   volBypass -> SetLineColor(kBlue);
02241   volBypass -> SetLineStyle(2); // dashed
02242 
02243   volBypass -> AddNode(volFlange,1,gGeoIdentity);
02244   volFlange -> AddNode(volThroat,1,gGeoIdentity);
02245 
02246   volThroat -> AddNode(volCoil,1,
02247                        new TGeoTranslation(-0.01*scale,-0.01*scale,0));
02248 
02249   Int_t nx = 6;
02250   Int_t ny = 8;
02251 
02252   Float_t xedge = 0.02475*scale;// dist from x-edge to center of 1st(last) tube
02253   Float_t x0   = -Geo::kCoilRad*scale + xedge;  // first tube position in x
02254   // separation of tubes in x direction
02255   Float_t xsep = 2.*(Geo::kCoilRad*scale - xedge)/(Float_t)(nx-1);
02256 
02257   Float_t yedge = 0.02221*scale;// dist from y-edge to center of 1st(last) tube
02258   Float_t y0   = -Geo::kCoilRad*scale + yedge;  // first tube position in y
02259   // separation of tubes in y direction
02260   Float_t ysep = 2.*(Geo::kCoilRad*scale - yedge)/(Float_t)(ny-1);
02261 
02262   for ( int ix = 0; ix < nx; ix++ ) {
02263     Float_t xpos = x0 + (Float_t)ix*xsep;
02264     for ( int iy = 0; iy < ny; iy++ ) {
02265       Float_t ypos = y0 + (Float_t)iy*ysep;
02266       Int_t itube = ix*ny+iy+1;
02267       volCoil -> AddNode(volWater,itube,new TGeoTranslation(xpos,ypos,0));
02268     }
02269   }
02270 
02271   return volBypass;
02272 
02273 }

Generated on Fri Mar 28 15:32:25 2008 for loon by  doxygen 1.3.9.1