BLCoil.hh

Go to the documentation of this file.
00001 //      BLCoil.hh
00002 /*
00003 This source file is part of G4beamline, http://g4beamline.muonsinc.com
00004 Copyright (C) 2003,2004,2005,2006 by Tom Roberts, all rights reserved.
00005 
00006 This program is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU General Public License
00008 as published by the Free Software Foundation; either version 2
00009 of the License, or (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 http://www.gnu.org/copyleft/gpl.html
00017 */
00018 
00019 #ifndef BLCOIL_HH
00020 #define BLCOIL_HH
00021 
00022 #include <map>
00023 
00024 #include "globals.hh"
00025 #include "BLCommand.hh"
00026 #ifdef STUB
00027 #include "NTuple.hh"
00028 #endif // STUB
00029 
00030 /**     BLCoil creates and implements a coil (part of a solenoid)
00031  *
00032  *      A BLCoil consists only of the parameters describing the coil geometry
00033  *      and a field map for unit current density. It is not a BLElement, and
00034  *      cannot be placed geometrically -- see BLSolenoid for that.
00035  *
00036  *      Cylindrical symmetry around z is assumed. The field is approximated
00037  *      by computing the field from nSheets infinitesimally-thin current
00038  *      sheets interpolating from innerRadius to OuterRadius, each length
00039  *      long. The solution to Maxwell's Equations for each sheet is used.
00040  *
00041  *      The field has been verified to be correct within 0.2% for both a
00042  *      long solenoid and for a pair of Helmholtz coils.
00043  *
00044  *      Effect of nSheets on accuracy: consider the coil innerRadius=330.0*mm,
00045  *      outerRadius=505.0*mm, length=167.0*mm. Compute the maximum error
00046  *      for 1000 random points, excluding the region within 2 cm of the coils;
00047  *      use 99 sheets as the "correct" value. In the region 0<=r<2*outerRadius,
00048  *      0<z<10*outerRadius, for 0.1% accuracy one needs 11 sheets, and for 1%
00049  *      one needs 4 sheets. In the region 0<=r<innerRadius/2, same z, for 0.1%
00050  *      accuracy one needs 5 sheets, and for 1% one needs 2 sheets. Note that
00051  *      inside the coils this approximation of using thin sheets is not very
00052  *      good; but interpolating on a grid and coordinating sheet positions
00053  *      with the grid is probably about as good as one can do -- at least the
00054  *      values will be smooth (which is not true for the bare computation --
00055  *      there's a singularity at every sheet, and Bz jumps from +infinity
00056  *      to -infinity across the sheet). 
00057  *
00058  *      Note that Bz does not decrease to 0.1% of its central value until
00059  *      z>10*(innerRadius+outerRadius)/2; it decreases to 1% at ~5 times that
00060  *      average radius.
00061  *
00062  *
00063  *      BLCoil can also read a mapFile defining the field (rather than doing
00064  *      the above computation). For instance, it could be from opera-2d.
00065  *      The mapFile gives tables of Bz and Br on a grid in the z-r plane.
00066  *      mapFile format:
00067  *              lines beginning with # are comments, and are ignored.
00068  *              The first line contains the parameters in name=value form:
00069  *                      z0      initial value of z (mm)
00070  *                      dz      grid interval along z (mm)
00071  *                      nz      number of grid points along z
00072  *                      dr      grid interval along r (mm)
00073  *                      nr      number of grid points along r
00074  *                      reflectZ set nonzero to reflect in the z=0 plane
00075  *                              (inverting Br)
00076  *                      current the current for this field (A/mm^2)
00077  *              All parameters are required. If reflectZ is nonzero then
00078  *              z0 must be 0.0 (only z>=0 is contained in the file).
00079  *              The point with local coordinates (z=0,r=0) is what gets placed.
00080  *
00081  *              Then follow the two maps in any order. Each map begins
00082  *              with a line giving its name (Bz or Br) in column 1, followed
00083  *              by nz lines each containing nr floats (Tesla). The first
00084  *              value in each line is for r=0. Values are separated by one
00085  *              or more spaces (the first value on each line may but need not
00086  *              be preceeded by spaces).
00087  *      The main reason to use a mapFile is to accurately include the effects
00088  *      of iron. That implies that the map may not be accurate for values
00089  *      of current other than that for which the map was generated.
00090  *
00091  *      See BLCMDfieldmap for a more general EM field read from a map-file.
00092  *
00093  *
00094  *      BLCoil was separated from BLSolenoid so multiple solenoids with the
00095  *      same geometry (coil) could share a single (large) field map for the
00096  *      coil -- the B field is scaled by current/currentOfMap, where 
00097  *      currentOfMap is 1.0 for the computed field, and is the current 
00098  *      parameter from a mapFile.
00099  *
00100  *      This class does not use BLFieldMap becuase it predates it, and
00101  *      because the map must include the parameters so construct() will
00102  *      know whether or not the map corresponds to the current values.
00103  *      You can, of course, build a solenoid out of a BLTubs and a
00104  *      BLFieldMap.
00105  **/
00106 class BLCoil {
00107         static std::map<G4String,BLCoil*> mapCoil;
00108         G4String name;
00109         G4double innerRadius;
00110         G4double outerRadius;
00111         G4double length;
00112         G4int nSheets;
00113         G4String material;
00114         G4double tolerance;
00115         G4double maxR;
00116         G4double minZ;
00117         G4double maxZ;
00118         G4double dR;
00119         G4double dZ;
00120         G4int nR;
00121         G4int nZ;
00122         G4String filename;
00123         G4String mapFile;
00124         G4int exactComputation;
00125         float *mapBr;
00126         float *mapBz;
00127         G4double sheetR0;
00128         G4double sheetDR;
00129         G4double norm;
00130         G4bool goodMap;
00131         G4bool reflectZ;
00132         G4double currentOfMap;
00133         friend class BLCMDcoil;
00134         friend class BLCMDsolenoid;
00135         friend class SolenoidField;
00136 public:
00137         /// Default constructor.
00138         BLCoil();
00139 
00140         /// Complex Constructor. All arguments that default to 0 are related
00141         /// to generating the field map; those that are 0 will be determined
00142         /// by tolerance. To construct the map the minimum info is tolerance
00143         /// and maxR; if either of them is 0, no map will be generated or used.
00144         /// NOTE: without a map, field values inside the coils will fluctuate
00145         /// wildly, because points on the sheets are singular; map construction
00146         /// is designed to minimize this. Without a map, nSheets must be given.
00147         /// tolerance is a fraction of the best value at r=0,z=0; values
00148         /// smaller than about 0.001 are unrealistic (and expensive!).
00149         BLCoil(G4String _name, G4double _innerRadius, G4double _outerRadius,
00150                 G4double _length, G4int _nSheets=0, G4double _tolerance=0.0,
00151                 G4double _maxR=0.0, G4double _maxZ=0.0, G4double _dR=0.0,
00152                 G4double _dZ=0.0, G4int _nR=0, G4int _nZ=0, 
00153                 G4String _filename="") {
00154                         name=_name; innerRadius=_innerRadius;
00155                         outerRadius=_outerRadius; length=_length;
00156                         nSheets=_nSheets; tolerance=_tolerance; maxR=_maxR;
00157                         maxZ=_maxZ; dR=_dR; dZ=_dZ; nR=_nR; nZ=_nZ; 
00158                         filename = _filename;
00159                         exactComputation = 0;
00160                         mapBr=0; mapBz=0; sheetR0=0.0; sheetDR=0.0; norm=0.0; 
00161                         goodMap=false; 
00162                         if(nSheets > 0) { 
00163                                 sheetDR=(outerRadius-innerRadius)/nSheets;
00164                                 sheetR0=innerRadius + sheetDR/2.0;
00165                         }
00166                         if(filename == "") filename = name + ".dat";
00167                 }
00168 
00169         /// Destructor.
00170         virtual ~BLCoil();
00171 
00172         /// Copy constructor.
00173         BLCoil(const BLCoil& r);
00174 
00175         /// printCoil() will print a description
00176         void printCoil();
00177 
00178         /// find() returns a pointer to the named BLCoil.
00179         static BLCoil *find(G4String name);
00180 
00181         /// addField() adds the field value for the given point[] into field[].
00182         /// Note that point[] is relative to the center of the coil.
00183         /// Units for current are Amp/mm^2.
00184         void addField(const G4double point[4], G4double field[6],
00185                                         G4double currentAmpPerMm2) const;
00186 
00187         /// generateFieldMap() will generate the field map (for execution
00188         /// speedup). If just maxR and tolerance were given, all other
00189         /// map parameters will be automatically determined so that the
00190         /// estimated error is less than the specified tolerance.
00191         /// The field map is cached in a disk file which is automatically
00192         /// recreated if anything changes (may take several minutes).
00193         void generateFieldMap();
00194 
00195         /// readMapFile() will read the mapFile.
00196         void readMapFile();
00197 
00198         /// displayMapValues() will display the 4 map values around a point.
00199         void displayMapValues(G4double r, G4double z);
00200 private:
00201         /// getUnitField() will return Br and Bz for unit current.
00202         void getUnitField(G4double r, G4double z, G4double& Br, G4double& Bz);
00203 
00204         /// determineMaxR() will determine maxR based on tolerance.
00205         /// Uses nSheets=99 to determine center field, and walks out
00206         /// far enough so (Bz/Bz0)<0.5*tolerance.
00207         void determineMaxR();
00208 
00209         /// determineMaxZ() will determine maxZ based on tolerance.
00210         /// Uses nSheets=99 to determine on-axis field, and walks out
00211         /// far enough so (Bz/Bz0)<0.5*tolerance.
00212         void determineMaxZ();
00213 
00214         /// determineNsheets() will determine nSheets, given maxZ and 
00215         /// tolerance. Increases nSheets until maxError < tolerance/4
00216         /// (the other 3/4 of tolerance is for mapping errors). Checks
00217         /// just a handful of points selected to be representative.
00218         void determineNsheets();
00219 
00220         /// estimateMapError() will estimate the maximum error in mapping,
00221         /// given maxZ, nSheets, dR, dZ, nR, nZ, and an allocated but
00222         /// uninitialized fieldMap. It generates 1000 random points and
00223         /// returns the maximum error; quits early if tolerance is
00224         /// exceeded. Error is (currentMap - best)/best(r=0,z=0), where 
00225         /// best is computed with no map and nSheets=99. For each point
00226         /// it generates the 4 surrounding values of fieldMap (this is faster
00227         /// than generating the entire map first).
00228         /// Returns the maximum error of either Bz or Br, normalized to
00229         /// Bz(r=0,z=0,nSheets=99).
00230         G4double estimateMapError();
00231 
00232         /// computeError() computes the error for a single point.
00233         /// Error is (currentMap - best)/best(r=0,z=0), where best should be
00234         /// an identical BLCoil with no map and nSheets=99. If makeMap is true,
00235         /// it generates the 4 surrounding values of the fieldMap.
00236         G4double computeError(G4double r, G4double z, BLCoil &best,
00237                                                         G4bool makeMap);
00238 
00239         /// getSheetField() returns the B field from an infinitesimally-thin
00240         /// sheet of current. Arguments:
00241         /// r and z are the cylindrical coordinates of the point in question
00242         /// relative to center of the coil (axis along z), mm.
00243         /// Br and Bz return the computed B field at that point (geant4 units)
00244         /// sheetR is the radius of the current sheet (mm)
00245         /// sheetLen is the length of the current sheet (mm)
00246         /// currentAmpPerMm is the current of the sheet (Amp per linear mm)
00247         void getSheetField(G4double r, G4double z, G4double& Br, G4double& Bz,
00248                 G4double sheetR, G4double sheetLen, G4double currentAmpPerMm)
00249                                                                         const;
00250 };
00251 
00252 #endif // BLCOIL_HH
g4beamline