00001 // BLFieldMap.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 #ifndef BLFIELDMAP_HH 00019 #define BLFIELDMAP_HH 00020 00021 #include "globals.hh" 00022 #include "BLCommand.hh" 00023 00024 00025 /** class BLFieldMap implements a general field map, both B and E. 00026 * 00027 * Initially this class simply reads an input file to define the map. 00028 * Eventually it will also generate a map automatically from a BLCoil, 00029 * and from an arbitrary collection of magnets (to improve tracking 00030 * efficiency for a large number of overlapping solenoids). 00031 * 00032 * Field components are interpolated in the map; the values used are: 00033 * Bx = (interpolated value)*normB*(element_current/current_param) 00034 * Ex = (interpolated value)*normE*(element_gradient/gradient_param) 00035 * [other components are similar] 00036 * where element_current and element_gradient are from the element 00037 * definition command in the input file, and normB, normE, curren_param, 00038 * and gradient_param come from the input file. The presence of both norm 00039 * and current/gradient in the input file is to accommodate diverse 00040 * sources of input files and units. 00041 * 00042 * Outside the map the fields are zero, so if the map is truncated you 00043 * should ensure that no particles are tracked outside the map in that 00044 * region. This happens, for instance, for a beam solenoid truncated 00045 * in radius to the inside of the coil -- particles which enter the 00046 * coil will see a zero field, so the coil should be set to kill them; 00047 * particles outside the map along z but inside the bore will also see 00048 * a zero field, but that is usually OK as long as the map extends far 00049 * enough along Z to include the nonzero field region. 00050 * 00051 * 00052 * Input File format: 00053 * Blank lines, and lines beginning with # or * are comments. Lines 00054 * beginning with * are printed to stdout. Units are mm for coordinates, 00055 * Tesla for B, and MegaVolts/meter for E; use normB and normE if the 00056 * data points use different units. 00057 * 00058 * The input file starts with a set of commands to define the parameters 00059 * of the map, followed by blocks of lines containing the values of the 00060 * field components. The field component names depend on the type of map 00061 * (grid: Bx,By,Bz,Ex,Ey,Ez; cylinder: Br,Bz,Er,Ez). 00062 * Each command has a specific list of arguments to define parameters 00063 * of the map. 00064 * 00065 * BEWARE: the parsing is not exhaustive. For instance, invalid arguments 00066 * are silently ignored (which means you must verify the spelling and 00067 * capitalization of argument names). Correct inputs will yield correct 00068 * results, but invalid inputs may not be detected and may yield 00069 * seemingly-correct but unintended results. 00070 * 00071 * The first command is usually a param command, which has the following 00072 * arguments: 00073 * maxline The maximum number of characters per line (default=1023) 00074 * current The current corresponding to this map (default=1.0) 00075 * gradient The gradient corresponding to the map (default=1.0) 00076 * normE A normalization factor for E components (default=1.0) 00077 * normB A normalization factor for B components (default=1.0) 00078 * 00079 * Two types of maps are implemented: grid and cylinder. 00080 * 00081 * grid maps are a 3-D grid, with each block of data being a single 00082 * X-Y plane; within a block the lines are Y and the columns of each line 00083 * are values along X. 00084 * The grid command has the following arguments: 00085 * X0 The X value for the first value in each line 00086 * Y0 The Y value for the first line in each block 00087 * Z0 The Z value for the first block of each field component 00088 * nX The number of columns per line 00089 * nY The number of lines per block 00090 * nZ The number of blocks per field component 00091 * dX The X increment between values in each line 00092 * dY The Y increment between lines 00093 * dZ The Z increment between blocks 00094 * tolerance The tolerance for pointwise data (default=0.01 mm) 00095 * After the grid command, the following optional commands can be given: 00096 * extendX flip=... 00097 * extendY flip=... 00098 * extendZ flip=... 00099 * These commands permit a half-map to be extended to the full map 00100 * around X=0, Y=0, or Z=0 respectively. The optional flip argument is a 00101 * comma-separated list of field components whose signs will be inverted 00102 * for negative values of the coordinate. For example, "extendZ flip=Bx,Ex" 00103 * means the map from Z=0 to Z=(nZ-1)*dZ is extended symmetrically around 00104 * Z=0 to negative Z values, flipping the signs of Bx and Ex when Z<0. 00105 * This could be followed by "extendX flip=Bx,Ex", and the field flips 00106 * will be the products of both commands. 00107 * 00108 * cylinder maps are a 2-D map with rotational symmetry around the Z axis. 00109 * Each field component has a single block with lines being Z and the 00110 * columns being R. 00111 * The cylinder command has the following arguments: 00112 * Z0 The Z value for the first line in each block 00113 * nR The number of columns per line 00114 * nZ The number of lines per block 00115 * dR The R increment between colums 00116 * dZ The Z increment between lines 00117 * tolerance The tolerance for pointwise data (default=0.01 mm) 00118 * After the cylinder command, the following optional commands can be 00119 * given: 00120 * extendZ flip=... 00121 * This command behaves the same as for the grid map. 00122 * 00123 * After the commands, each block consists of a line containing the 00124 * name of the field component, followed by the lines of the block. 00125 * The values within a line can be separated by whitespace or a ',' 00126 * followed by optional whitespace. 00127 * Field components that are not given are set to 0.0 everywhere. 00128 * Missing values will be considered to be 0.0. 00129 * For grid maps the first block is for Z=Z0, and successive blocks 00130 * increment Z by dZ; the first line in a block is for Y=Y0 and the 00131 * first column in each line is for X=X0. 00132 * For cylinder maps, the first line in each block is for Z=Z0 and the 00133 * first column in each line is for R=0. 00134 * 00135 * Instead of the blocked input format, a pointwise data format can be 00136 * used. This is introduced by a line containing the command "data", 00137 * followed by the individual points of the map, one per line. 00138 * for a grid field, each line contains values for 00139 * X,Y,Z,Bx,By,Bz,Ex,Ey,Ez separated by either a comma and optional 00140 * whitespece or by whitespace. for a cylinder field each line contains 00141 * values for R,Z,Br,Bz,Er,Ez. The order of the points does not matter; 00142 * omitted grid points will be 0.0, and for duplicates the last entry 00143 * wins. If there is no E field, the Ex,Ey,Ez or Er,Ez entries should 00144 * be omitted on every line. NOTE: every line's X,Y,Z or R,Z must be 00145 * on a grid point as specified by the arguments to the grid or cylinder 00146 * commands, to within the tolerance specified; if not, an error message 00147 * is printed and the input line is ignored. 00148 * 00149 * For time=dependent fields, the "time" command is used: 00150 * time [period=12] 00151 * period, if given, is in nanoseconds, and causes the interval [0,period) 00152 * to be extended forever (before and after the values given). Because of 00153 * the interpolation used, at least two points beyond the interval 00154 * boundaries should be provided; there need not be a point at either 00155 * boundary (but usually there are). 00156 * Following the time command are lines containing 2 or 3 doubles: 00157 * t B E 00158 * where t is the time (nanoseconds), and B and E are factors for the 00159 * fields. If E is omitted, the value for B is used. These values will 00160 * be interpolated in time with a cubic spline that can handle either 00161 * uniform or non-uniform spacing of points along t. 00162 * The time command can come either before or after the cylinder or grid 00163 * commands, but not within either of their sequences. 00164 * Note a cubic spline is used to interpolate between points, and that 00165 * can cause over/under-shoot near an abrupt change. Combined with period= 00166 * this gives an excellent representation of sinewave/cosinewave. 00167 * 00168 * Note that time dependence can currently only be specified via the 00169 * time command in an input file (i.e. not programmable method exists). 00170 * 00171 * 00172 * Example block input file: 00173 * * this is an example BLFieldMap input file, suitable for a solenoid 00174 * # grid interval is 1 cm. 00175 * # The region of validity is -390<=Z<=390 and 0<=R<=90 00176 * param normB=1.0 current=1.0 00177 * cylinder Z0=0.0 nR=10 nZ=40 dR=10.0 dZ=10.0 00178 * extendZ flip=Br 00179 * Bz 00180 * ... 40 lines of 10 values, Z=0 thru Z=390 00181 * Br 00182 * ... 40 lines of 10 values, Z=0 thru Z=390 00183 * --EOF-- 00184 * 00185 * Example pointwise input file: 00186 * * this is an example BLFieldMap input file, suitable for a solenoid 00187 * # grid interval is 1 cm. 00188 * # The region of validity is -390<=Z<=390 and 0<=R<=90 00189 * param normB=1.0 current=1.0 00190 * cylinder Z0=0.0 nR=10 nZ=40 dR=10.0 dZ=10.0 00191 * extendZ flip=Br 00192 * data 00193 * ... 400 lines of 4 values, giving R,Z,Br,Bz 00194 * --EOF-- 00195 * 00196 **/ 00197 class BLFieldMap { 00198 public: 00199 /// default constructor. 00200 BLFieldMap(); 00201 00202 /// destructor. 00203 virtual ~BLFieldMap(); 00204 00205 /// readFile() reads a file to initialize the map. 00206 /// Returns true if OK, false on error. 00207 bool readFile(G4String filename); 00208 00209 /// writeFile() writes the map to a file. 00210 /// Returns true if OK, false on error. 00211 bool writeFile(G4String filename, G4String comment=""); 00212 00213 /// getFieldValue() gets the map's field to the field[] array. 00214 /// local[] must be LOCAL coordinates; local[3] (time) is ignored 00215 /// unless there is a time dependence specified. 00216 /// (elements using BLFieldMap perform the global->local conversion) 00217 void getFieldValue(const G4double local[4], G4double field[6], 00218 G4double current=1.0, G4double gradient=1.0); 00219 00220 /// getFieldValueNoTimeNoScale() as above, except no time dependence 00221 /// is applies, and no scaling is performed. 00222 void getFieldValueNoTimeNoScale(const G4double local[4], 00223 G4double field[6]); 00224 00225 /// getBoundingPoint() returns the i-th bounding point of the map. 00226 void getBoundingPoint(int i, G4double point[4]); 00227 00228 /// hasB() returns true if this map has a nonzero B field. 00229 bool hasB(); 00230 00231 /// hasE() returns true if this map has a nonzero E field. 00232 bool hasE(); 00233 00234 /// createGridMap() will create a 3-d map from a pre-defined field. 00235 /// returns false if error. 00236 bool createGridMap(G4double X0, G4double Y0, G4double Z0, G4double dX, 00237 G4double dY, G4double dZ, int nX, int nY, int nZ, 00238 class G4ElectroMagneticField *field); 00239 00240 /// createCylinderMap() will create a 2-d map from a pre-defined 00241 /// cylindrically-symmetric field. NOTE: cylindrical symmetry is 00242 /// ASSUMED; the field in the Y=0,X>=0 half-plane is used (Bx->Br...). 00243 /// returns false if error. 00244 bool createCylinderMap(G4double Z0, G4double dR, G4double dZ, int nR, 00245 int nZ, class G4ElectroMagneticField *field); 00246 00247 /// createTimeDependence() will apply the time dependence given. 00248 /// n is the # elements in the arrays; t[] is the time value for 00249 /// each point, b[] is the factor for B, and e[] is the factor for E. 00250 /// returns false if error. 00251 bool createTimeDependence(int n, G4double t[], G4double b[], 00252 G4double e[]=0, G4double period=-1.0); 00253 00254 /// getTimeFactor() returns the time factors for B and E at time t. 00255 /// returns false if error. 00256 bool getTimeFactor(G4double t, G4double *b, G4double *e); 00257 private: 00258 G4int maxline; 00259 G4double current; 00260 G4double gradient; 00261 G4double normB; 00262 G4double normE; 00263 class FieldMapImpl *impl; 00264 class TimeImpl *time; 00265 friend class FieldMapPlacement; 00266 }; 00267 00268 #endif // BLFIELDMAP_HH