View Javadoc

1   package org.lcsim.geometry.field;
2   
3   import hep.physics.vec.BasicHep3Vector;
4   import hep.physics.vec.Hep3Vector;
5   import java.io.BufferedReader;
6   import java.io.File;
7   import java.io.FileInputStream;
8   import java.io.IOException;
9   import java.io.InputStream;
10  import java.io.InputStreamReader;
11  import static java.lang.Math.sqrt;
12  import java.net.URL;
13  import java.util.ArrayList;
14  import java.util.List;
15  import java.util.StringTokenizer;
16  import org.jdom.Element;
17  import org.jdom.JDOMException;
18  import org.lcsim.util.cache.FileCache;
19  
20  /**
21   *
22   * @author Norman A Graf
23   *
24   * @version $Id:
25   */
26  public class FieldMap3D extends AbstractFieldMap
27  {
28      private double[][][] _xField;
29      private double[][][] _yField;
30      private double[][][] _zField;
31      // The dimensions of the table
32      private int _nx, _ny, _nz;
33      // The physical limits of the defined region
34      private double _minx, _maxx, _miny, _maxy, _minz, _maxz;
35      // The physical extent of the defined region
36      private double _dx, _dy, _dz;
37      // Offsets if field map is not in global coordinates
38      private double _xOffset;
39      private double _yOffset;
40      private double _zOffset;
41      // maximum field strength
42      private double _bMax;
43      private double[] _Bfield = new double[3];
44      String _filename;
45  
46      public FieldMap3D(Element node) throws JDOMException
47      {
48          super(node);
49          _xOffset = node.getAttribute("xoffset").getDoubleValue();
50          _yOffset = node.getAttribute("yoffset").getDoubleValue();
51          _zOffset = node.getAttribute("zoffset").getDoubleValue();
52          _filename = node.getAttributeValue("filename");
53          System.out.println("Field Map location: " + _filename);
54          try {
55              setup(_filename);
56          } catch (Exception e) {
57              throw new RuntimeException("Error reading field map from " + _filename, e);
58          }
59      }
60  
61      private void setup(String filename) throws IOException
62      {
63          InputStream fis;
64          BufferedReader br;
65          String line;
66  
67          //FIXME Should specify either filename or url in the xml. Needs change to schema.
68          if (filename.startsWith("http")) {
69              FileCache cache = new FileCache();
70              File file = cache.getCachedFile(new URL(filename));
71              fis = new FileInputStream(file);
72          } else {
73              fis = new FileInputStream(filename);
74          }
75  
76          System.out.println("-----------------------------------------------------------");
77          System.out.println("FieldMap3D ");
78          System.out.println("-----------------------------------------------------------");
79          System.out.println("Reading the field grid from " + filename + " ... ");
80  
81          br = new BufferedReader(new InputStreamReader(fis));
82          // ignore the first blank line
83          line = br.readLine();
84          // next line has table dimensions
85          line = br.readLine();
86          // read in the table dimensions of the file
87          StringTokenizer st = new StringTokenizer(line, " ");
88          _nx = Integer.parseInt(st.nextToken());
89          _ny = Integer.parseInt(st.nextToken());
90          _nz = Integer.parseInt(st.nextToken());
91  
92          // Set up storage space for table
93          _xField = new double[_nx + 1][_ny + 1][_nz + 1];
94          _yField = new double[_nx + 1][_ny + 1][_nz + 1];
95          _zField = new double[_nx + 1][_ny + 1][_nz + 1];
96  
97          // Ignore other header information    
98          // The first line whose second character is '0' is considered to
99          // be the last line of the header.
100         do {
101             line = br.readLine();
102             System.out.println(line);
103             st = new StringTokenizer(line, " ");
104         } while (!st.nextToken().trim().equals("0"));
105 
106         // now ready to read in the values in the table
107         // format is:
108         // x y z Bx By Bz
109         // Recall that in Geant4 internal units 1 Tesla is equal to 0.001 so convert
110         //
111         int conversionFactor = 1000;
112         int ix, iy, iz;
113         double xval = 0.;
114         double yval = 0.;
115         double zval = 0.;
116         double bx, by, bz;
117         for (ix = 0; ix < _nx; ix++) {
118             for (iy = 0; iy < _ny; iy++) {
119                 for (iz = 0; iz < _nz; iz++) {
120                     line = br.readLine();
121                     st = new StringTokenizer(line, " ");
122                     xval = Double.parseDouble(st.nextToken());
123                     yval = Double.parseDouble(st.nextToken());
124                     zval = Double.parseDouble(st.nextToken());
125                     bx = Double.parseDouble(st.nextToken())*conversionFactor;
126                     by = Double.parseDouble(st.nextToken())*conversionFactor;
127                     bz = Double.parseDouble(st.nextToken())*conversionFactor;
128                     if (ix == 0 && iy == 0 && iz == 0) {
129                         _minx = xval;
130                         _miny = yval;
131                         _minz = zval;
132                     }
133                     _xField[ix][iy][iz] = bx;
134                     _yField[ix][iy][iz] = by;
135                     _zField[ix][iy][iz] = bz;
136                     double b = bx * bx + by * by + bz * bz;
137                     if (b > _bMax) {
138                         _bMax = b;
139                     }
140                 }
141             }
142         }
143         _bMax = sqrt(_bMax);
144 
145         _maxx = xval;
146         _maxy = yval;
147         _maxz = zval;
148 
149         System.out.println("\n ---> ... done reading ");
150         System.out.println(" ---> assumed the order:  x, y, z, Bx, By, Bz "
151                 + "\n ---> Min values x,y,z: "
152                 + _minx + " " + _miny + " " + _minz
153                 + "\n ---> Max values x,y,z: "
154                 + _maxx + " " + _maxy + " " + _maxz
155                 + "\n Maximum Field strength: " + _bMax + " "
156                 + "\n ---> The field will be offset by " + _xOffset + " " + _yOffset + " " + _zOffset);
157 
158         _dx = _maxx - _minx;
159         _dy = _maxy - _miny;
160         _dz = _maxz - _minz;
161         System.out.println("\n ---> Range of values x,y,z: "
162                 + _dx + " " + _dy + " " + _dz
163                 + "\n-----------------------------------------------------------");
164 
165         br.close();
166     }
167 
168     @Override
169     public void getField(double[] position, double[] b)
170     {
171         getField(position[0], position[1], position[2]);
172         System.arraycopy(_Bfield, 0, b, 0, 3);
173     }
174 
175     @Override
176     public Hep3Vector getField(Hep3Vector position)
177     {
178         getField(position.x(), position.y(), position.z());
179         return new BasicHep3Vector(_Bfield[0], _Bfield[1], _Bfield[2]);
180     }
181 
182     @Override
183     public double[] getField(double[] position)
184     {
185         getField(position[0], position[1], position[2]);
186         double[] field = {_Bfield[0], _Bfield[1], _Bfield[2]};
187         return field;
188     }
189 
190     @Override
191     void getField(double x, double y, double z, BasicHep3Vector field)
192     {
193         getField(x, y, z);
194         field.setV(_Bfield[0], _Bfield[1], _Bfield[2]);
195     }
196 
197     public double[] globalOffset()
198     {
199         return new double[]{_xOffset, _yOffset, _zOffset};
200     }
201 
202     private void getField(double x, double y, double z)
203     {
204         // allow for offsets
205         x -= _xOffset;
206         y -= _yOffset;
207         z -= _zOffset;
208         // Check that the point is within the defined region 
209         if (x >= _minx && x <= _maxx
210                 && y >= _miny && y <= _maxy
211                 && z >= _minz && z <= _maxz) {
212 
213             // Position of given point within region, normalized to the range
214             // [0,1]
215             double xfraction = (x - _minx) / _dx;
216             double yfraction = (y - _miny) / _dy;
217             double zfraction = (z - _minz) / _dz;
218 
219             //double xdindex, ydindex, zdindex;
220             // Position of the point within the cuboid defined by the
221             // nearest surrounding tabulated points
222             double[] xmodf = modf(xfraction * (_nx - 1));
223             double[] ymodf = modf(yfraction * (_ny - 1));
224             double[] zmodf = modf(zfraction * (_nz - 1));
225 
226             // The indices of the nearest tabulated point whose coordinates
227             // are all less than those of the given point
228             int xindex = (int) xmodf[0];
229             int yindex = (int) ymodf[0];
230             int zindex = (int) zmodf[0];
231             double xlocal = xmodf[1];
232             double ylocal = ymodf[1];
233             double zlocal = zmodf[1];
234             // bilinear interpolation
235             _Bfield[0]
236                     = _xField[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) * (1 - zlocal)
237                     + _xField[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) * zlocal
238                     + _xField[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal * (1 - zlocal)
239                     + _xField[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal * zlocal
240                     + _xField[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) * (1 - zlocal)
241                     + _xField[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) * zlocal
242                     + _xField[xindex + 1][yindex + 1][zindex] * xlocal * ylocal * (1 - zlocal)
243                     + _xField[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
244             _Bfield[1]
245                     = _yField[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) * (1 - zlocal)
246                     + _yField[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) * zlocal
247                     + _yField[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal * (1 - zlocal)
248                     + _yField[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal * zlocal
249                     + _yField[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) * (1 - zlocal)
250                     + _yField[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) * zlocal
251                     + _yField[xindex + 1][yindex + 1][zindex] * xlocal * ylocal * (1 - zlocal)
252                     + _yField[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
253             _Bfield[2]
254                     = _zField[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) * (1 - zlocal)
255                     + _zField[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) * zlocal
256                     + _zField[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal * (1 - zlocal)
257                     + _zField[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal * zlocal
258                     + _zField[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) * (1 - zlocal)
259                     + _zField[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) * zlocal
260                     + _zField[xindex + 1][yindex + 1][zindex] * xlocal * ylocal * (1 - zlocal)
261                     + _zField[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
262 
263         } else {
264             _Bfield[0] = 0.0;
265             _Bfield[1] = 0.0;
266             _Bfield[2] = 0.0;
267         }
268     }
269 
270     //TODO pass double[] as argument to minimize internal array creation
271     private double[] modf(double fullDouble)
272     {
273         int intVal = (int) fullDouble;
274         double remainder = fullDouble - intVal;
275 
276         double[] retVal = new double[2];
277         retVal[0] = intVal;
278         retVal[1] = remainder;
279 
280         return retVal;
281     }
282 }