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         float *mapBr;
00125         float *mapBz;
00126         G4double sheetR0;
00127         G4double sheetDR;
00128         G4double norm;
00129         G4bool goodMap;
00130         G4bool reflectZ;
00131         G4double currentOfMap;
00132         friend class BLCMDcoil;
00133         friend class BLCMDsolenoid;
00134         friend class SolenoidField;
00135 public:
00136         /// Default constructor.
00137         BLCoil();
00138 
00139         /// Complex Constructor. All arguments that default to 0 are related
00140         /// to generating the field map; those that are 0 will be determined
00141         /// by tolerance. To construct the map the minimum info is tolerance
00142         /// and maxR; if either of them is 0, no map will be generated or used.
00143         /// NOTE: without a map, field values inside the coils will fluctuate
00144         /// wildly, because points on the sheets are singular; map construction
00145         /// is designed to minimize this. Without a map, nSheets must be given.
00146         /// tolerance is a fraction of the best value at r=0,z=0; values
00147         /// smaller than about 0.001 are unrealistic (and expensive!).
00148         BLCoil(G4String _name, G4double _innerRadius, G4double _outerRadius,
00149                 G4double _length, G4int _nSheets=0, G4double _tolerance=0.0,
00150                 G4double _maxR=0.0, G4double _maxZ=0.0, G4double _dR=0.0,
00151                 G4double _dZ=0.0, G4int _nR=0, G4int _nZ=0, 
00152                 G4String _filename="") {
00153                         name=_name; innerRadius=_innerRadius;
00154                         outerRadius=_outerRadius; length=_length;
00155                         nSheets=_nSheets; tolerance=_tolerance; maxR=_maxR;
00156                         maxZ=_maxZ; dR=_dR; dZ=_dZ; nR=_nR; nZ=_nZ; 
00157                         filename = _filename;
00158                         mapBr=0; mapBz=0; sheetR0=0.0; sheetDR=0.0; norm=0.0; 
00159                         goodMap=false; 
00160                         if(nSheets > 0) { 
00161                                 sheetDR=(outerRadius-innerRadius)/nSheets;
00162                                 sheetR0=innerRadius + sheetDR/2.0;
00163                         }
00164                         if(filename == "") filename = name + ".dat";
00165                 }
00166 
00167         /// Destructor.
00168         virtual ~BLCoil();
00169 
00170         /// Copy constructor.
00171         BLCoil(const BLCoil& r);
00172 
00173         /// printCoil() will print a description
00174         void printCoil();
00175 
00176         /// find() returns a pointer to the named BLCoil.
00177         static BLCoil *find(G4String name);
00178 
00179         /// addField() adds the field value for the given point[] into field[].
00180         /// Note that point[] is relative to the center of the coil.
00181         /// Units for current are Amp/mm^2.
00182         void addField(const G4double point[4], G4double field[6],
00183                                         G4double currentAmpPerMm2) const;
00184 
00185         /// generateFieldMap() will generate the field map (for execution
00186         /// speedup). If just maxR and tolerance were given, all other
00187         /// map parameters will be automatically determined so that the
00188         /// estimated error is less than the specified tolerance.
00189         /// The field map is cached in a disk file which is automatically
00190         /// recreated if anything changes (may take several minutes).
00191         void generateFieldMap();
00192 
00193         /// readMapFile() will read the mapFile.
00194         void readMapFile();
00195 
00196         /// displayMapValues() will display the 4 map values around a point.
00197         void displayMapValues(G4double r, G4double z);
00198 private:
00199         /// getUnitField() will return Br and Bz for unit current.
00200         void getUnitField(G4double r, G4double z, G4double& Br, G4double& Bz);
00201 
00202         /// determineMaxR() will determine maxR based on tolerance.
00203         /// Uses nSheets=99 to determine center field, and walks out
00204         /// far enough so (Bz/Bz0)<0.5*tolerance.
00205         void determineMaxR();
00206 
00207         /// determineMaxZ() will determine maxZ based on tolerance.
00208         /// Uses nSheets=99 to determine on-axis field, and walks out
00209         /// far enough so (Bz/Bz0)<0.5*tolerance.
00210         void determineMaxZ();
00211 
00212         /// determineNsheets() will determine nSheets, given maxZ and 
00213         /// tolerance. Increases nSheets until maxError < tolerance/4
00214         /// (the other 3/4 of tolerance is for mapping errors). Checks
00215         /// just a handful of points selected to be representative.
00216         void determineNsheets();
00217 
00218         /// estimateMapError() will estimate the maximum error in mapping,
00219         /// given maxZ, nSheets, dR, dZ, nR, nZ, and an allocated but
00220         /// uninitialized fieldMap. It generates 1000 random points and
00221         /// returns the maximum error; quits early if tolerance is
00222         /// exceeded. Error is (currentMap - best)/best(r=0,z=0), where 
00223         /// best is computed with no map and nSheets=99. For each point
00224         /// it generates the 4 surrounding values of fieldMap (this is faster
00225         /// than generating the entire map first).
00226         /// Returns the maximum error of either Bz or Br, normalized to
00227         /// Bz(r=0,z=0,nSheets=99).
00228         G4double estimateMapError();
00229 
00230         /// computeError() computes the error for a single point.
00231         /// Error is (currentMap - best)/best(r=0,z=0), where best should be
00232         /// an identical BLCoil with no map and nSheets=99. If makeMap is true,
00233         /// it generates the 4 surrounding values of the fieldMap.
00234         G4double computeError(G4double r, G4double z, BLCoil &best,
00235                                                         G4bool makeMap);
00236 
00237         /// getSheetField() returns the B field from an infinitesimally-thin
00238         /// sheet of current. Arguments:
00239         /// r and z are the cylindrical coordinates of the point in question
00240         /// relative to center of the coil (axis along z), mm.
00241         /// Br and Bz return the computed B field at that point (geant4 units)
00242         /// sheetR is the radius of the current sheet (mm)
00243         /// sheetLen is the length of the current sheet (mm)
00244         /// currentAmpPerMm is the current of the sheet (Amp per linear mm)
00245         void getSheetField(G4double r, G4double z, G4double& Br, G4double& Bz,
00246                 G4double sheetR, G4double sheetLen, G4double currentAmpPerMm)
00247                                                                         const;
00248 };
00249 
00250 #endif // BLCOIL_HH
g4beamline