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

Generated on Sat Nov 21 22:46:14 2009 for loon by  doxygen 1.3.9.1