GeomConverter/testResources/org/lcsim/geometry/field
diff -N Cartesian3DMagneticFieldMapTest.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Cartesian3DMagneticFieldMapTest.xml 3 Sep 2013 22:04:01 -0000 1.1
@@ -0,0 +1,35 @@
+<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
+ xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">
+
+ <info name="FieldMap3DTest"/>
+
+ <define>
+ <constant name="cm" value="10"/>
+
+ <constant name="world_side" value="30000" />
+ <constant name="world_x" value="world_side" />
+ <constant name="world_y" value="world_side" />
+ <constant name="world_z" value="world_side" />
+
+ <constant name="tracking_region_radius" value="1100.0*cm"/>
+ <constant name="tracking_region_zmax" value="150.0*cm"/>
+ </define>
+
+ <materials>
+ </materials>
+
+ <detectors>
+ </detectors>
+
+ <readouts>
+ </readouts>
+
+ <fields>
+ <field type="Cartesian3DMagneticFieldMap" name="Cartesian3DMagneticFieldMapTest"
+ filename="./testResources/org/lcsim/geometry/field/HPS_b18d36_unfolded.dat"
+ offsetX="1.0"
+ offsetY="2.0"
+ offsetZ="3.0"/>
+ </fields>
+</lccdd>
GeomConverter/test/org/lcsim/geometry/field
diff -N Cartesian3DMagneticFieldMapTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Cartesian3DMagneticFieldMapTest.java 3 Sep 2013 22:04:01 -0000 1.1
@@ -0,0 +1,73 @@
+package org.lcsim.geometry.field;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import java.io.InputStream;
+import java.util.Map;
+import static junit.framework.Assert.assertEquals;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.FieldMap;
+import org.lcsim.geometry.GeometryReader;
+import org.lcsim.geometry.compact.Field;
+
+/**
+ *
+ * @author Norman A Graf
+ *
+ * @version $Id:
+ */
+public class Cartesian3DMagneticFieldMapTest extends FieldTest
+{
+
+ public Cartesian3DMagneticFieldMapTest(String name)
+ {
+ super(name);
+ }
+
+ public void testRead() throws Exception
+ {
+ InputStream in = this.getClass().getResourceAsStream("/org/lcsim/geometry/field/Cartesian3DMagneticFieldMapTest.xml");
+ GeometryReader reader = new GeometryReader();
+ Detector det = reader.read(in);
+ FieldMap map = det.getFieldMap();
+
+ double[] off = {1., 2., 3.};
+ double[] fp = {-25.0, -8.9, -150.};
+ double[] B = new double[3];
+
+ // field at first map position should be zero since we offset the field
+ testFieldAt(map, fp[0], fp[1], fp[2], 0, 0, 0);
+ // field at first map position with offset included should equal first field values
+ testFieldAt(map, fp[0] + off[0], fp[1] + off[1], fp[2] + off[2], 0, -0.0019, 0);
+ // field at the origin
+ testFieldAt(map, 0.0 + off[0], -8.9 + off[1], 0.0 + off[2], 0., -0.5006, 0.);
+ // this field map is invariant in y, test this...
+ testFieldAt(map, 0.0 + off[0], 0. + off[1], 0.0 + off[2], 0., -0.5006, 0.);
+ testFieldAt(map, 0.0 + off[0], 8.9 + off[1], 0.0 + off[2], 0., -0.5006, 0.);
+
+ //TODO check interpolation more rigorously
+ //check all variations of accessor methods (why do we have SO many?!
+ double[] p = {fp[0] + off[0], fp[1] + off[1], fp[2] + off[2]};
+ Hep3Vector h3vP = new BasicHep3Vector(fp[0] + off[0], fp[1] + off[1], fp[2] + off[2]);
+
+ map.getField(p, B);
+ Hep3Vector h3vB = map.getField(h3vP);
+ assertEquals(B[0], h3vB.x());
+ assertEquals(B[1], h3vB.y());
+ assertEquals(B[2], h3vB.z());
+
+ double[] B2 = map.getField(p);
+ for (int i = 0; i < 3; ++i) {
+ assertEquals(B[i], B2[i]);
+ }
+
+ // test specifics of Cartesian3DMagneticFieldMap
+ Map<String, Field> fields = det.getFields();
+ assertEquals(fields.size(), 1);
+ Cartesian3DMagneticFieldMap cmap = (Cartesian3DMagneticFieldMap) fields.get("Cartesian3DMagneticFieldMapTest");
+ double[] offsets = cmap.globalOffset();
+ assertEquals(offsets[0], 1.);
+ assertEquals(offsets[1], 2.);
+ assertEquals(offsets[2], 3.);
+ }
+}
GeomConverter/src/org/lcsim/geometry/field
diff -N Cartesian3DMagneticFieldMap.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Cartesian3DMagneticFieldMap.java 3 Sep 2013 22:04:01 -0000 1.1
@@ -0,0 +1,271 @@
+package org.lcsim.geometry.field;
+
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import static java.lang.Math.sqrt;
+import java.util.StringTokenizer;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+
+/**
+ *
+ * @author Norman A Graf
+ *
+ * @version $Id:
+ */
+public class Cartesian3DMagneticFieldMap extends AbstractFieldMap
+{
+
+ private double[][][] _xField;
+ private double[][][] _yField;
+ private double[][][] _zField;
+ // The dimensions of the table
+ private int _nx, _ny, _nz;
+ // The physical limits of the defined region
+ private double _minx, _maxx, _miny, _maxy, _minz, _maxz;
+ // The physical extent of the defined region
+ private double _dx, _dy, _dz;
+ // Offsets if field map is not in global coordinates
+ private double _xOffset;
+ private double _yOffset;
+ private double _zOffset;
+ // maximum field strength
+ private double _bMax;
+ private double[] _Bfield = new double[3];
+ String _filename;
+
+ public Cartesian3DMagneticFieldMap(Element node) throws JDOMException
+ {
+ super(node);
+ _xOffset = node.getAttribute("offsetX").getDoubleValue();
+ _yOffset = node.getAttribute("offsetY").getDoubleValue();
+ _zOffset = node.getAttribute("offsetZ").getDoubleValue();
+
+ setup(node.getAttributeValue("filename"));
+ }
+
+ private void setup(String filename)
+ {
+ System.out.println("-----------------------------------------------------------");
+ System.out.println("Cartesian3DMagneticFieldMap ");
+ System.out.println("-----------------------------------------------------------");
+
+ System.out.println("Reading the field grid from " + filename + " ... ");
+
+ InputStream fis;
+ BufferedReader br;
+ String line;
+
+ try {
+ fis = new FileInputStream(filename);
+ br = new BufferedReader(new InputStreamReader(fis));
+ // ignore the first blank line
+ line = br.readLine();
+ // next line has table dimensions
+ line = br.readLine();
+ // read in the table dimensions of the file
+ StringTokenizer st = new StringTokenizer(line, " ");
+ _nx = Integer.parseInt(st.nextToken());
+ _ny = Integer.parseInt(st.nextToken());
+ _nz = Integer.parseInt(st.nextToken());
+
+
+ // Set up storage space for table
+ _xField = new double[_nx + 1][_ny + 1][_nz + 1];
+ _yField = new double[_nx + 1][_ny + 1][_nz + 1];
+ _zField = new double[_nx + 1][_ny + 1][_nz + 1];
+
+ // Ignore other header information
+ // The first line whose second character is '0' is considered to
+ // be the last line of the header.
+ do {
+ line = br.readLine();
+ st = new StringTokenizer(line, " ");
+ } while (!st.nextToken().trim().equals("0"));
+
+ // now ready to read in the values in the table
+ // format is:
+ // x y z Bx By Bz
+ //
+ int ix, iy, iz;
+ double xval = 0.;
+ double yval = 0.;
+ double zval = 0.;
+ double bx, by, bz;
+ for (ix = 0; ix < _nx; ix++) {
+ for (iy = 0; iy < _ny; iy++) {
+ for (iz = 0; iz < _nz; iz++) {
+ line = br.readLine();
+ st = new StringTokenizer(line, " ");
+ xval = Double.parseDouble(st.nextToken());
+ yval = Double.parseDouble(st.nextToken());
+ zval = Double.parseDouble(st.nextToken());
+ bx = Double.parseDouble(st.nextToken());
+ by = Double.parseDouble(st.nextToken());
+ bz = Double.parseDouble(st.nextToken());
+ if (ix == 0 && iy == 0 && iz == 0) {
+ _minx = xval;
+ _miny = yval;
+ _minz = zval;
+ }
+ _xField[ix][iy][iz] = bx;
+ _yField[ix][iy][iz] = by;
+ _zField[ix][iy][iz] = bz;
+ double b = bx * bx + by * by + bz * bz;
+ if (b > _bMax) {
+ _bMax = b;
+ }
+ }
+ }
+ }
+ _bMax = sqrt(_bMax);
+
+ _maxx = xval;
+ _maxy = yval;
+ _maxz = zval;
+
+ System.out.println("\n ---> ... done reading ");
+ System.out.println(" ---> assumed the order: x, y, z, Bx, By, Bz "
+ + "\n ---> Min values x,y,z: "
+ + _minx + " " + _miny + " " + _minz + " cm "
+ + "\n ---> Max values x,y,z: "
+ + _maxx + " " + _maxy + " " + _maxz + " cm "
+ + "\n Maximum Field strength: " + _bMax + " "
+ + "\n ---> The field will be offset by " + _xOffset + " " + _yOffset + " " + _zOffset + " cm ");
+
+ _dx = _maxx - _minx;
+ _dy = _maxy - _miny;
+ _dz = _maxz - _minz;
+ System.out.println("\n ---> Range of values x,y,z: "
+ + _dx + " " + _dy + " " + _dz + " cm in z "
+ + "\n-----------------------------------------------------------");
+
+ br.close();
+ } catch (IOException x) {
+ throw new RuntimeException(x);
+ }
+
+ }
+
+ @Override
+ public void getField(double[] position, double[] b)
+ {
+ getField(position[0], position[1], position[2]);
+ System.arraycopy(_Bfield, 0, b, 0, 3);
+ }
+
+ @Override
+ public Hep3Vector getField(Hep3Vector position)
+ {
+ getField(position.x(), position.y(), position.z());
+ return new BasicHep3Vector(_Bfield[0], _Bfield[1], _Bfield[2]);
+ }
+
+ @Override
+ public double[] getField(double[] position)
+ {
+ getField(position[0], position[1], position[2]);
+ double[] field = {_Bfield[0], _Bfield[1], _Bfield[2]};
+ return field;
+ }
+
+ @Override
+ void getField(double x, double y, double z, BasicHep3Vector field)
+ {
+ getField(x, y, z);
+ field.setV(_Bfield[0], _Bfield[1], _Bfield[2]);
+ }
+
+ public double[] globalOffset()
+ {
+ return new double[]{_xOffset, _yOffset, _zOffset};
+ }
+
+ private void getField(double x, double y, double z)
+ {
+ // allow for offsets
+ x -= _xOffset;
+ y -= _yOffset;
+ z -= _zOffset;
+ // Check that the point is within the defined region
+ if (x >= _minx && x <= _maxx
+ && y >= _miny && y <= _maxy
+ && z >= _minz && z <= _maxz) {
+
+ // Position of given point within region, normalized to the range
+ // [0,1]
+ double xfraction = (x - _minx) / _dx;
+ double yfraction = (y - _miny) / _dy;
+ double zfraction = (z - _minz) / _dz;
+
+ //double xdindex, ydindex, zdindex;
+
+ // Position of the point within the cuboid defined by the
+ // nearest surrounding tabulated points
+ double[] xmodf = modf(xfraction * (_nx - 1));
+ double[] ymodf = modf(yfraction * (_ny - 1));
+ double[] zmodf = modf(zfraction * (_nz - 1));
+
+ // The indices of the nearest tabulated point whose coordinates
+ // are all less than those of the given point
+
+ int xindex = (int) xmodf[0];
+ int yindex = (int) ymodf[0];
+ int zindex = (int) zmodf[0];
+ double xlocal = xmodf[1];
+ double ylocal = ymodf[1];
+ double zlocal = zmodf[1];
+ // bilinear interpolation
+ _Bfield[0] =
+ _xField[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) * (1 - zlocal)
+ + _xField[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) * zlocal
+ + _xField[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal * (1 - zlocal)
+ + _xField[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal * zlocal
+ + _xField[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) * (1 - zlocal)
+ + _xField[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) * zlocal
+ + _xField[xindex + 1][yindex + 1][zindex] * xlocal * ylocal * (1 - zlocal)
+ + _xField[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
+ _Bfield[1] =
+ _yField[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) * (1 - zlocal)
+ + _yField[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) * zlocal
+ + _yField[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal * (1 - zlocal)
+ + _yField[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal * zlocal
+ + _yField[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) * (1 - zlocal)
+ + _yField[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) * zlocal
+ + _yField[xindex + 1][yindex + 1][zindex] * xlocal * ylocal * (1 - zlocal)
+ + _yField[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
+ _Bfield[2] =
+ _zField[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) * (1 - zlocal)
+ + _zField[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) * zlocal
+ + _zField[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal * (1 - zlocal)
+ + _zField[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal * zlocal
+ + _zField[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) * (1 - zlocal)
+ + _zField[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) * zlocal
+ + _zField[xindex + 1][yindex + 1][zindex] * xlocal * ylocal * (1 - zlocal)
+ + _zField[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
+
+ } else {
+ _Bfield[0] = 0.0;
+ _Bfield[1] = 0.0;
+ _Bfield[2] = 0.0;
+ }
+ }
+
+ //TODO pass double[] as argument to minimize internal array creation
+ private double[] modf(double fullDouble)
+ {
+ int intVal = (int) fullDouble;
+ double remainder = fullDouble - intVal;
+
+ double[] retVal = new double[2];
+ retVal[0] = intVal;
+ retVal[1] = remainder;
+
+ return retVal;
+ }
+}