Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-07 04:37:11

0001 /*
0002  *  See header file for a description of this class.
0003  *
0004  */
0005 
0006 #include "DD4hep_MagGeoBuilder.h"
0007 #include "bLayer.h"
0008 #include "eSector.h"
0009 #include "InterpolatorBuilder.h"
0010 
0011 #include "MagneticField/Layers/interface/MagBLayer.h"
0012 #include "MagneticField/Layers/interface/MagESector.h"
0013 
0014 #include "DetectorDescription/DDCMS/interface/DDFilteredView.h"
0015 
0016 #include "Utilities/BinningTools/interface/ClusterizingHistogram.h"
0017 
0018 #include "MagneticField/Interpolation/interface/MagProviderInterpol.h"
0019 #include "MagneticField/Interpolation/interface/MFGrid.h"
0020 
0021 #include "MagneticField/VolumeGeometry/interface/MagVolume6Faces.h"
0022 #include "MagneticField/VolumeGeometry/interface/MagExceptions.h"
0023 
0024 #include "DataFormats/Math/interface/deltaPhi.h"
0025 
0026 #include "FWCore/Utilities/interface/Exception.h"
0027 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0028 #include "Utilities/General/interface/precomputed_value_sort.h"
0029 
0030 #include <iomanip>
0031 #include <string>
0032 #include <vector>
0033 #include <sstream>
0034 #include <algorithm>
0035 #include <iterator>
0036 #include <map>
0037 #include <set>
0038 #include <boost/algorithm/string/replace.hpp>
0039 
0040 using namespace std;
0041 using namespace magneticfield;
0042 using namespace edm;
0043 using namespace angle_units::operators;
0044 
0045 MagGeoBuilder::MagGeoBuilder(string tableSet, int geometryVersion, bool debug, bool mergeFile)
0046     : tableSet_(tableSet),
0047       geometryVersion_(geometryVersion),
0048       theGridFiles_(nullptr),
0049       debug_(debug),
0050       useMergeFileIfAvailable_(mergeFile) {
0051   LogTrace("MagGeoBuilder") << "Constructing a MagGeoBuilder";
0052 }
0053 
0054 MagGeoBuilder::~MagGeoBuilder() {
0055   for (auto i : bVolumes_) {
0056     delete i;
0057   }
0058   for (auto i : eVolumes_) {
0059     delete i;
0060   }
0061 }
0062 
0063 void MagGeoBuilder::summary(handles& volumes) const {
0064   // The final countdown.
0065   int ivolumes = volumes.size();  // number of volumes
0066   int isurfaces = ivolumes * 6;   // number of individual surfaces
0067   int iassigned = 0;              // How many have been assigned
0068   int iunique = 0;                // number of unique surfaces
0069   int iref_ass = 0;
0070   int iref_nass = 0;
0071 
0072   set<const void*> ptrs;
0073 
0074   for (auto i : volumes) {
0075     DDSolidShape theShape = i->shape();
0076     if (theShape == DDSolidShape::ddbox || theShape == DDSolidShape::ddcons || theShape == DDSolidShape::ddtrap ||
0077         theShape == DDSolidShape::ddtubs) {
0078       for (int side = 0; side < 6; ++side) {
0079         int references = i->references(side);
0080         if (i->isPlaneMatched(side)) {
0081           ++iassigned;
0082           bool firstOcc = (ptrs.insert(&(i->surface(side)))).second;
0083           if (firstOcc)
0084             iref_ass += references;
0085           if (references < 2) {
0086             LogTrace("MagGeoBuilder") << "*** Only 1 ref, vol: " << i->volumeno << " # " << i->copyno
0087                                       << " side: " << side;
0088           }
0089         } else {
0090           iref_nass += references;
0091           if (references > 1) {
0092             LogTrace("MagGeoBuilder") << "*** Ref_nass >1 ";
0093           }
0094         }
0095       }
0096     }  // end if theShape
0097   }  // end for
0098   iunique = ptrs.size();
0099 
0100   LogTrace("MagGeoBuilder") << "    volumes   " << ivolumes << newln << "    surfaces  " << isurfaces << newln
0101                             << "    assigned  " << iassigned << newln << "    unique    " << iunique << newln
0102                             << "    iref_ass  " << iref_ass << newln << "    iref_nass " << iref_nass;
0103 }
0104 
0105 void MagGeoBuilder::build(const cms::DDDetector* det) {
0106   cms::Volume top = det->worldVolume();
0107   cms::DDFilteredView fv(det, top);
0108   if (fv.next(0) == false) {
0109     LogError("MagGeoBuilder") << "Filtered view is empty. Cannot build.";
0110     return;
0111   }
0112 
0113   // The actual field interpolators
0114   map<string, MagProviderInterpol*> bInterpolators;
0115   map<string, MagProviderInterpol*> eInterpolators;
0116 
0117   // Counter of different volumes
0118   int bVolCount = 0;
0119   int eVolCount = 0;
0120 
0121   const string magfStr{"MAGF"};
0122   const string magfStr2{"cmsMagneticField:MAGF"};
0123   if (fv.name() != magfStr && fv.name() != magfStr2) {
0124     std::string topNodeName(fv.name());
0125     LogTrace("MagGeoBuilder") << "Filtered view top node name is " << topNodeName << ".";
0126 
0127     //see if one of the children is MAGF
0128     bool doSubDets = fv.next(0);
0129 
0130     bool go = true;
0131     while (go && doSubDets) {
0132       LogTrace("MagGeoBuilder") << "Next node name is " << fv.name() << ".";
0133       if (fv.name() == magfStr)
0134         break;
0135       else
0136         go = fv.next(0);
0137     }
0138     if (!go) {
0139       throw cms::Exception("NoMAGF")
0140           << " Neither the top node, nor any child node of the filtered view is \"MAGF\" but the top node is instead \""
0141           << topNodeName << "\"";
0142     }
0143   }
0144 
0145   // Loop over MAGF volumes and create volumeHandles.
0146   bool doSubDets = fv.next(0);
0147   if (doSubDets == false) {
0148     LogError("MagGeoBuilder") << "Filtered view has no node. Cannot build.";
0149     return;
0150   }
0151   InterpolatorBuilder interpolatorBuilder(tableSet_, useMergeFileIfAvailable_);
0152   while (doSubDets) {
0153     string name = fv.volume().volume().name();
0154     LogTrace("MagGeoBuilder") << "Name: " << name;
0155 
0156     bool expand = false;
0157     volumeHandle* v = new volumeHandle(fv, expand, debug_);
0158 
0159     if (theGridFiles_ != nullptr) {
0160       int key = (v->volumeno) * 100 + v->copyno;
0161       TableFileMap::const_iterator itable = theGridFiles_->find(key);
0162       if (itable == theGridFiles_->end()) {
0163         key = (v->volumeno) * 100;
0164         itable = theGridFiles_->find(key);
0165       }
0166 
0167       if (itable != theGridFiles_->end()) {
0168         string magFile = (*itable).second.first;
0169         stringstream conv;
0170         string svol, ssec;
0171         conv << setfill('0') << setw(3) << v->volumeno << " " << setw(2)
0172              << v->copyno;  // volume assumed to have 0s padding to 3 digits; sector assumed to have 0s padding to 2 digits
0173         conv >> svol >> ssec;
0174         boost::replace_all(magFile, "[v]", svol);
0175         boost::replace_all(magFile, "[s]", ssec);
0176         int masterSector = (*itable).second.second;
0177         if (masterSector == 0)
0178           masterSector = v->copyno;
0179         v->magFile = magFile;
0180         v->masterSector = masterSector;
0181       } else {
0182         edm::LogError("MagGeoBuilderbuild") << "ERROR: no table spec found for V " << v->volumeno << ":" << v->copyno;
0183       }
0184     }
0185 
0186     // Select volumes, build volume handles.
0187     float Z = v->center().z();
0188     float R = v->center().perp();
0189     LogTrace("MagGeoBuilder") << " Vol R and Z values determine barrel or endcap. R = " << R << ", Z = " << Z;
0190 
0191     // v 85l: Barrel is everything up to |Z| = 661.0, excluding
0192     // volume #7, centered at 6477.5
0193     // v 1103l: same numbers work fine. #16 instead of #7, same coords;
0194     // see comment below for V6,7
0195     //ASSUMPTION: no misalignment is applied to mag volumes.
0196     //FIXME: implement barrel/endcap flags as DDD SpecPars.
0197     if ((fabs(Z) < 647. || (R > 350. && fabs(Z) < 662.)) &&
0198         !(fabs(Z) > 480 && R < 172)  // in 1103l we place V_6 and V_7 in the
0199                                      // endcaps to preserve nice layer structure
0200                                      // in the barrel. This does not hurt in v85l
0201                                      // where there is a single V1
0202     ) {                              // Barrel
0203       LogTrace("MagGeoBuilder") << " (Barrel)";
0204       bVolumes_.push_back(v);
0205 
0206       // Build the interpolator of the "master" volume (the one which is
0207       // not replicated in phi)
0208       // ASSUMPTION: copyno == sector.
0209       if (v->copyno == v->masterSector) {
0210         auto i = buildInterpolator(v, interpolatorBuilder);
0211         if (i) {
0212           bInterpolators[v->magFile] = i;
0213         }
0214         ++bVolCount;
0215       }
0216     } else {  // Endcaps
0217       LogTrace("MagGeoBuilder") << " (Endcaps)";
0218       eVolumes_.push_back(v);
0219       if (v->copyno == v->masterSector) {
0220         auto i = buildInterpolator(v, interpolatorBuilder);
0221         if (i) {
0222           eInterpolators[v->magFile] = i;
0223         }
0224         ++eVolCount;
0225       }
0226     }
0227     doSubDets = fv.next(0);  // end of loop over MAGF
0228   }
0229 
0230   LogTrace("MagGeoBuilder") << "Number of volumes (barrel): " << bVolumes_.size() << newln
0231                             << "Number of volumes (endcap): " << eVolumes_.size();
0232   LogTrace("MagGeoBuilder") << "**********************************************************";
0233 
0234   // Now all volumeHandles are there, and parameters for each of the planes
0235   // are calculated.
0236 
0237   //----------------------------------------------------------------------
0238   // Print summary information
0239 
0240   if (debug_) {
0241     LogTrace("MagGeoBuilder") << "-----------------------";
0242     LogTrace("MagGeoBuilder") << "SUMMARY: Barrel ";
0243     summary(bVolumes_);
0244 
0245     LogTrace("MagGeoBuilder") << "SUMMARY: Endcaps ";
0246     summary(eVolumes_);
0247     LogTrace("MagGeoBuilder") << "-----------------------";
0248   }
0249 
0250   //----------------------------------------------------------------------
0251   // Find barrel layers.
0252 
0253   if (bVolumes_.empty()) {
0254     LogError("MagGeoBuilder") << "Error: Barrel volumes are missing. Terminating build.";
0255     return;
0256   }
0257   vector<bLayer> layers;  // the barrel layers
0258   precomputed_value_sort(bVolumes_.begin(), bVolumes_.end(), ExtractRN());
0259 
0260   // Find the layers (in R)
0261   const float resolution = 1.;  // cm
0262   float rmin = bVolumes_.front()->RN() - resolution;
0263   float rmax = bVolumes_.back()->RN() + resolution;
0264   ClusterizingHistogram hisR(int((rmax - rmin) / resolution) + 1, rmin, rmax);
0265 
0266   LogTrace("MagGeoBuilder") << " R layers: " << rmin << " " << rmax;
0267 
0268   handles::const_iterator first = bVolumes_.begin();
0269   handles::const_iterator last = bVolumes_.end();
0270 
0271   for (auto i : bVolumes_) {
0272     hisR.fill(i->RN());
0273   }
0274   vector<float> rClust = hisR.clusterize(resolution);
0275 
0276   handles::const_iterator ringStart = first;
0277   handles::const_iterator separ = first;
0278 
0279   for (unsigned int i = 0; i < rClust.size() - 1; ++i) {
0280     if (debug_)
0281       LogTrace("MagGeoBuilder") << " Layer at RN = " << rClust[i];
0282     float rSepar = (rClust[i] + rClust[i + 1]) / 2.f;
0283     while ((*separ)->RN() < rSepar)
0284       ++separ;
0285 
0286     bLayer thislayer(ringStart, separ, debug_);
0287     layers.push_back(thislayer);
0288     ringStart = separ;
0289   }
0290   {
0291     if (debug_)
0292       LogTrace("MagGeoBuilder") << " Layer at RN = " << rClust.back();
0293     bLayer thislayer(separ, last, debug_);
0294     layers.push_back(thislayer);
0295   }
0296 
0297   LogTrace("MagGeoBuilder") << "Barrel: Found " << rClust.size() << " clusters in R, " << layers.size() << " layers ";
0298 
0299   //----------------------------------------------------------------------
0300   // Find endcap sectors
0301   vector<eSector> sectors;  // the endcap sectors
0302 
0303   // Find the number of sectors (should be 12 or 24 depending on the geometry model)
0304   constexpr float phireso = 0.05;  // rad
0305   constexpr int twoPiOverPhiReso = static_cast<int>(2._pi / phireso) + 1;
0306   ClusterizingHistogram hisPhi(twoPiOverPhiReso, -1._pi, 1._pi);
0307 
0308   for (auto i : eVolumes_) {
0309     hisPhi.fill(i->minPhi());
0310   }
0311   vector<float> phiClust = hisPhi.clusterize(phireso);
0312   int nESectors = phiClust.size();
0313   if (nESectors <= 0) {
0314     LogError("MagGeoBuilder") << "ERROR: Endcap sectors are missing.  Terminating build.";
0315     return;
0316   }
0317   if (debug_ && (nESectors % 12) != 0) {
0318     LogTrace("MagGeoBuilder") << "ERROR: unexpected # of endcap sectors: " << nESectors;
0319   }
0320 
0321   //Sort in phi
0322   precomputed_value_sort(eVolumes_.begin(), eVolumes_.end(), ExtractPhi());
0323 
0324   // Handle the -pi/pi boundary: volumes crossing it could be half at the begin and half at end of the sorted list.
0325   // So, check if any of the volumes that should belong to the first bin (at -phi) are at the end of the list:
0326   float lastBinPhi = phiClust.back();
0327   handles::reverse_iterator ri = eVolumes_.rbegin();
0328   while ((*ri)->center().phi() > lastBinPhi) {
0329     ++ri;
0330   }
0331   if (ri != eVolumes_.rbegin()) {
0332     // ri points to the first element that is within the last bin.
0333     // We need to move the following element (ie ri.base()) to the beginning of the list,
0334     handles::iterator newbeg = ri.base();
0335     rotate(eVolumes_.begin(), newbeg, eVolumes_.end());
0336   }
0337 
0338   //Group volumes in sectors
0339   int offset = eVolumes_.size() / nESectors;
0340   for (int i = 0; i < nESectors; ++i) {
0341     if (debug_) {
0342       LogTrace("MagGeoBuilder") << " Sector at phi = " << (*(eVolumes_.begin() + ((i)*offset)))->center().phi();
0343       // Additional x-check: sectors are expected to be made by volumes with the same copyno
0344       int secCopyNo = -1;
0345       for (handles::const_iterator iv = eVolumes_.begin() + ((i)*offset); iv != eVolumes_.begin() + ((i + 1) * offset);
0346            ++iv) {
0347         if (secCopyNo >= 0 && (*iv)->copyno != secCopyNo)
0348           LogTrace("MagGeoBuilder") << "ERROR: volume copyno " << (*iv)->name << ":" << (*iv)->copyno
0349                                     << " differs from others in same sectors with copyno = " << secCopyNo;
0350         secCopyNo = (*iv)->copyno;
0351       }
0352     }
0353 
0354     sectors.push_back(eSector(eVolumes_.begin() + ((i)*offset), eVolumes_.begin() + ((i + 1) * offset), debug_));
0355   }
0356 
0357   LogTrace("MagGeoBuilder") << "Endcap: Found " << sectors.size() << " sectors ";
0358 
0359   //----------------------------------------------------------------------
0360   // Build MagVolumes and the MagGeometry hierarchy.
0361 
0362   //--- Barrel
0363 
0364   // Build MagVolumes and associate interpolators to them
0365   buildMagVolumes(bVolumes_, bInterpolators);
0366 
0367   // Build MagBLayers
0368   for (const auto& ilay : layers) {
0369     mBLayers_.push_back(ilay.buildMagBLayer());
0370   }
0371   LogTrace("MagGeoBuilder") << "*** BARREL ********************************************" << newln
0372                             << "Number of different volumes   = " << bVolCount << newln
0373                             << "Number of interpolators built = " << bInterpolators.size() << newln
0374                             << "Number of MagBLayers built    = " << mBLayers_.size();
0375   if (debug_) {
0376     testInside(bVolumes_);  // FIXME: all volumes should be checked in one go.
0377   }
0378   //--- Endcap
0379   // Build MagVolumes  and associate interpolators to them
0380   buildMagVolumes(eVolumes_, eInterpolators);
0381 
0382   // Build the MagESectors
0383   for (const auto& isec : sectors) {
0384     mESectors_.push_back(isec.buildMagESector());
0385   }
0386   LogTrace("MagGeoBuilder") << "*** ENDCAP ********************************************" << newln
0387                             << "Number of different volumes   = " << eVolCount << newln
0388                             << "Number of interpolators built = " << eInterpolators.size() << newln
0389                             << "Number of MagESector built    = " << mESectors_.size();
0390   if (debug_) {
0391     testInside(eVolumes_);  // FIXME: all volumes should be checked in one go.
0392   }
0393 }
0394 
0395 void MagGeoBuilder::buildMagVolumes(const handles& volumes,
0396                                     const map<string, MagProviderInterpol*>& interpolators) const {
0397   // Build all MagVolumes setting the MagProviderInterpol
0398   for (auto vol : volumes) {
0399     const MagProviderInterpol* mp = nullptr;
0400     auto found = interpolators.find(vol->magFile);
0401     if (found != interpolators.end()) {
0402       mp = found->second;
0403     } else {
0404       edm::LogError("MagGeoBuilder") << "No interpolator found for file " << vol->magFile << " vol: " << vol->volumeno
0405                                      << "\n"
0406                                      << interpolators.size();
0407     }
0408 
0409     // Search for [volume,sector] in the list of scaling factors; sector = 0 handled as wildcard
0410     // ASSUMPTION: copyno == sector.
0411     int key = (vol->volumeno) * 100 + vol->copyno;
0412     map<int, double>::const_iterator isf = theScalingFactors_.find(key);
0413     if (isf == theScalingFactors_.end()) {
0414       key = (vol->volumeno) * 100;
0415       isf = theScalingFactors_.find(key);
0416     }
0417 
0418     double sf = 1.;
0419     if (isf != theScalingFactors_.end()) {
0420       sf = (*isf).second;
0421 
0422       LogTrace("MagGeoBuilder") << "Applying scaling factor " << sf << " to " << vol->volumeno << "[" << vol->copyno
0423                                 << "] (key:" << key << ")";
0424     }
0425 
0426     const GloballyPositioned<float>* gpos = vol->placement();
0427     vol->magVolume = new MagVolume6Faces(gpos->position(), gpos->rotation(), vol->sides(), mp, sf);
0428 
0429     if (vol->copyno == vol->masterSector) {
0430       vol->magVolume->ownsFieldProvider(true);
0431     }
0432 
0433     vol->magVolume->setIsIron(vol->isIron());
0434 
0435     // The name and sector of the volume are saved for debug purposes only. They may be removed at some point...
0436     vol->magVolume->volumeNo = vol->volumeno;
0437     vol->magVolume->copyno = vol->copyno;
0438   }
0439 }
0440 
0441 MagProviderInterpol* MagGeoBuilder::buildInterpolator(const volumeHandle* vol, InterpolatorBuilder& builder) const {
0442   MagProviderInterpol* retValue = nullptr;
0443   LogTrace("MagGeoBuilder") << "Building interpolator from " << vol->volumeno << " copyno " << vol->copyno << " at "
0444                             << vol->center() << " phi: " << static_cast<double>(vol->center().phi()) / 1._pi
0445                             << " pi,  file: " << vol->magFile << " master: " << vol->masterSector;
0446   if (debug_) {
0447     // Phi of the master sector
0448     double masterSectorPhi = (vol->masterSector - 1) * 1._pi / 6.;
0449     double delta = std::abs(vol->center().phi() - masterSectorPhi);
0450     if (delta > (1._pi / 9.)) {
0451       LogTrace("MagGeoBuilder") << "***WARNING wrong sector? Vol delta from master sector is " << delta / 1._pi
0452                                 << " pi";
0453     }
0454   }
0455 
0456   try {
0457     retValue = builder.build(vol).release();
0458   } catch (edm::Exception& exc) {
0459     cerr << "MagGeoBuilder: exception in reading table; " << exc.what() << endl;
0460     if (!debug_)
0461       throw;
0462     return nullptr;
0463   } catch (MagException const& exc) {
0464     LogTrace("MagGeoBuilder") << exc.what();
0465     if (!debug_)
0466       throw;
0467     return nullptr;
0468   }
0469 
0470   if (debug_) {
0471     // Check that all grid points of the interpolator are inside the volume.
0472     const MagVolume6Faces tempVolume(
0473         vol->placement()->position(), vol->placement()->rotation(), vol->sides(), retValue);
0474 
0475     const MFGrid* grid = dynamic_cast<const MFGrid*>(retValue);
0476     if (grid != nullptr) {
0477       Dimensions sizes = grid->dimensions();
0478       LogTrace("MagGeoBuilder") << "Grid has 3 dimensions "
0479                                 << " number of nodes is " << sizes.w << " " << sizes.h << " " << sizes.d;
0480 
0481       const double tolerance = 0.03;
0482 
0483       size_t dumpCount = 0;
0484       for (int j = 0; j < sizes.h; j++) {
0485         for (int k = 0; k < sizes.d; k++) {
0486           for (int i = 0; i < sizes.w; i++) {
0487             MFGrid::LocalPoint lp = grid->nodePosition(i, j, k);
0488             if (!tempVolume.inside(lp, tolerance)) {
0489               if (++dumpCount < 2) {
0490                 MFGrid::GlobalPoint gp = tempVolume.toGlobal(lp);
0491                 LogTrace("MagGeoBuilder") << "GRID ERROR: " << i << " " << j << " " << k << " local: " << lp
0492                                           << " global: " << gp << " R= " << gp.perp() << " phi=" << gp.phi();
0493               }
0494             }
0495           }
0496         }
0497       }
0498 
0499       LogTrace("MagGeoBuilder") << "Volume:" << vol->volumeno
0500                                 << " : Number of grid points outside the MagVolume: " << dumpCount << "/"
0501                                 << sizes.w * sizes.h * sizes.d;
0502     }
0503   }
0504   return retValue;
0505 }
0506 
0507 void MagGeoBuilder::testInside(handles& volumes) const {
0508   // test inside() for all volumes.
0509   LogTrace("MagGeoBuilder") << "--------------------------------------------------";
0510   LogTrace("MagGeoBuilder") << " inside(center) test";
0511   for (auto vol : volumes) {
0512     for (auto i : volumes) {
0513       if (i == vol)
0514         continue;
0515       //if (i->magVolume == 0) continue;
0516       if (i->magVolume->inside(vol->center())) {
0517         LogTrace("MagGeoBuilder") << "*** ERROR: center of V " << vol->volumeno << ":" << vol->copyno << " is inside V "
0518                                   << i->volumeno << ":" << i->copyno;
0519       }
0520     }
0521 
0522     if (vol->magVolume->inside(vol->center())) {
0523       LogTrace("MagGeoBuilder") << "V " << vol->volumeno << ":" << vol->copyno << " OK ";
0524     } else {
0525       LogTrace("MagGeoBuilder") << "*** ERROR: center of volume is not inside it, " << vol->volumeno << ":"
0526                                 << vol->copyno;
0527     }
0528   }
0529   LogTrace("MagGeoBuilder") << "--------------------------------------------------";
0530 }
0531 
0532 vector<MagBLayer*> MagGeoBuilder::barrelLayers() const { return mBLayers_; }
0533 
0534 vector<MagESector*> MagGeoBuilder::endcapSectors() const { return mESectors_; }
0535 
0536 vector<MagVolume6Faces*> MagGeoBuilder::barrelVolumes() const {
0537   vector<MagVolume6Faces*> v;
0538   v.reserve(bVolumes_.size());
0539   for (auto i : bVolumes_) {
0540     v.push_back(i->magVolume);
0541   }
0542   return v;
0543 }
0544 
0545 vector<MagVolume6Faces*> MagGeoBuilder::endcapVolumes() const {
0546   vector<MagVolume6Faces*> v;
0547   v.reserve(eVolumes_.size());
0548   for (auto i : eVolumes_) {
0549     v.push_back(i->magVolume);
0550   }
0551   return v;
0552 }
0553 
0554 float MagGeoBuilder::maxR() const {
0555   //FIXME: should get it from the actual geometry
0556   return 900.;
0557 }
0558 
0559 float MagGeoBuilder::maxZ() const {
0560   //FIXME: should get it from the actual geometry
0561   if (geometryVersion_ >= 160812)
0562     return 2400.;
0563   else if (geometryVersion_ >= 120812)
0564     return 2000.;
0565   else
0566     return 1600.;
0567 }
0568 
0569 void MagGeoBuilder::setScaling(const std::vector<int>& keys, const std::vector<double>& values) {
0570   if (keys.size() != values.size()) {
0571     throw cms::Exception("InvalidParameter")
0572         << "Invalid field scaling parameters 'scalingVolumes' and 'scalingFactors' ";
0573   }
0574   for (unsigned int i = 0; i < keys.size(); ++i) {
0575     theScalingFactors_[keys[i]] = values[i];
0576   }
0577 }
0578 
0579 void MagGeoBuilder::setGridFiles(const TableFileMap& gridFiles) { theGridFiles_ = &gridFiles; }