lcsim/src/org/lcsim/contrib/seedtracker
diff -u -r1.8 -r1.9
--- MaterialManager.java 24 Jun 2008 22:02:35 -0000 1.8
+++ MaterialManager.java 1 Jul 2008 22:29:09 -0000 1.9
@@ -11,9 +11,10 @@
import hep.physics.vec.Hep3Vector;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import org.lcsim.event.EventHeader;
+import java.util.Map;
import org.lcsim.detector.DetectorIdentifierHelper;
import org.lcsim.detector.IDetectorElement;
import org.lcsim.detector.identifier.IIdentifier;
@@ -29,6 +30,7 @@
import org.lcsim.detector.solids.ISolid;
import org.lcsim.detector.solids.Point3D;
import org.lcsim.detector.solids.Polycone;
+import org.lcsim.detector.solids.Polycone.ZPlane;
import org.lcsim.detector.solids.Tube;
import org.lcsim.geometry.Detector;
@@ -38,15 +40,23 @@
* @version 1.0
*/
public class MaterialManager {
- List<MaterialCylinder> _matcyl = new ArrayList<MaterialCylinder>();
- List<MaterialDisk> _matdsk = new ArrayList<MaterialDisk>();
- double _rmax;
+
+ private static final boolean DEBUG = false; //enable debug output
+ private static final boolean TUBE_ONLY = true; //only use Tube elements for calculating volume.
+
+ private List<MaterialPolyconeSegment> _matpc = new ArrayList<MaterialPolyconeSegment>();
+ private List<MaterialCylinder> _matcyl = new ArrayList<MaterialCylinder>();
+ private List<MaterialDisk> _matdsk = new ArrayList<MaterialDisk>();
+ private double _rmax;
+ private CalculationCache cache;
/** Creates a new instance of MaterialManager */
public MaterialManager() {
}
public void BuildModel(Detector det) {
+
+ cache = new CalculationCache(det);
// Build the model of tracker material
// Each volume defined in the compact.xml file is modelled as either
// a thin cylinder or disk with a thickness in radiation lengths
@@ -66,20 +76,27 @@
// Calculate the total volume of material, skip this object if 0
double vtot = TotalVolume(pvflat);
+
+ if (pvtree.getLogicalVolume().getSolid() instanceof Polycone){
+ handlePolycone(pvtree);
+ continue;
+ }
if (vtot > 0.) {
+
// Calculate the average radiation length for this volume
double X0 = RadiationLength(pvflat);
- // Determine if this volume should be modeled as a barrel or disk
- if (isCylinder(pvtree, pvflat)) {
+
+ // Determine if this volume should be modeled as barrel or disk
+ if (isCylinder(pvflat)) {
// Calculate the weighted radius of the elements
double rwgt = WeightedRadius(pvflat);
- double zmin = zmin(pvtree, pvflat);
- double zmax = zmax(pvtree, pvflat);
+ double zmin = zmin(pvflat);
+ double zmax = zmax(pvflat);
double zlen = zmax - zmin;
double thickness = vtot / (2. * Math.PI * rwgt * zlen * X0);
- if (false){
+ if (DEBUG){
System.out.println(pvtree.getName());
System.out.println("x0: "+X0 + "| zmin: "+zmin + "| zmax: "+zmax + "| vtot: "+vtot + "| thickness: "+thickness +
"| rmin: "+(rmin(pvflat)) + "| rmax: "+rmax(pvflat));
@@ -88,14 +105,14 @@
_matcyl.add(new MaterialCylinder(pvtree, rwgt, zmin, zmax, thickness));
} else {
- double zwgt = WeightedZ(pvtree, pvflat);
+ double zwgt = WeightedZ(pvflat);
double rmin = rmin(pvflat);
double rmax = rmax(pvflat);
double thickness = vtot / (Math.PI * (rmax*rmax - rmin*rmin) * X0);
- if (false){
+ if (DEBUG){
System.out.println(pvtree.getName());
- System.out.println("x0: "+X0 + "| zmin: "+zmin(pvtree,pvflat) + "| zmax: "+zmax(pvtree,pvflat) + "| vtot: "+vtot + "| thickness: "+thickness +
+ System.out.println("x0: "+X0 + "| zmin: "+zmin(pvflat) + "| zmax: "+zmax(pvflat) + "| vtot: "+vtot + "| thickness: "+thickness +
"| rmin: "+rmin + "| rmax: "+rmax);
System.out.println();
}
@@ -104,6 +121,8 @@
}
}
}
+ if(DEBUG) cache.printSizeInfo();
+ cache.clear(); // clear cache, so stuff doesn't get held in memory.
// Find the outer radius of the tracking volume
// First loop over all the subdetector elements
@@ -144,25 +163,14 @@
return _matdsk;
}
+ public List<MaterialPolyconeSegment> getMaterialPolyconeSegments() {
+ return _matpc;
+ }
+
public double getRMax() {
return _rmax;
}
-// private List<IPhysicalVolume> Flatten(IPhysicalVolume xmlvol) { // Flatten the geometry tree to find all the physical volumes for
-// // this tracker element that have no daughters
-// LinkedList<IPhysicalVolume> pvtree = new LinkedList<IPhysicalVolume>();
-// pvtree.add(xmlvol);
-// List<IPhysicalVolume> pvflat = new ArrayList<IPhysicalVolume>();
-// while (pvtree.size()>0) {
-// IPhysicalVolume pv = pvtree.poll();
-// if (pv.getLogicalVolume().getNumberOfDaughters()==0) {
-// pvflat.add(pv);
-// } else {
-// pvtree.addAll(pv.getLogicalVolume().getDaughters());
-// }
-// }
-// return pvflat;
-// }
private List<UniquePV> Flatten(IPhysicalVolume vol, IPhysicalVolumeNavigator nav){
@@ -176,14 +184,13 @@
IPhysicalVolume pv = upv.getPV();
if (pv.getLogicalVolume().getNumberOfDaughters()==0) {
-// if(pvflat.contains(upv)) System.out.println("DUPE!!!!");
pvflat.add(upv);
}
-
+
else {
for(IPhysicalVolume p : pv.getLogicalVolume().getDaughters()) {
- pvtree.add(upv.createDaughterUniquePV(p));
- }
+ pvtree.add(upv.createDaughterUniquePV(p));
+ }
}
}
@@ -191,269 +198,391 @@
}
+ //Tube only for now... (note that the problem with top-level polycones should no longer exist)
private double TotalVolume(List<UniquePV> pvlist) {
- double vtot = 0.;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
-
- if (solid instanceof Tube) vtot += safeCubicVolume(solid);
-
- }
- return vtot;
+ if (TUBE_ONLY) return cache.getVolumeGroupCalculations(pvlist).vtot_tube_only;
+ return cache.getVolumeGroupCalculations(pvlist).vtot;
}
private double RadiationLength(List<UniquePV> pvlist) {
- double X0wgt = 0.;
- double invX0 = 0.;
- double vtot = 0.;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
-
- double vol = safeCubicVolume(solid);
- vtot += vol;
- IMaterial mat = pv.getPV().getLogicalVolume().getMaterial();
- double X0 = 10. * mat.getRadiationLength() / mat.getDensity();
- if (X0 > 0.) invX0 += vol / X0;
-
- }
- if (invX0 > 0.) X0wgt = vtot / invX0;
- return X0wgt;
+ return cache.getVolumeGroupCalculations(pvlist).X0;
}
private double rmin(List<UniquePV> pvlist) {
- double rmin = 1.e10;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
- rmin = Math.min(rmin, calculateRMinSolid(solid,pv));
- }
- return rmin;
+ return cache.getVolumeGroupCalculations(pvlist).rmin;
}
private double rmax(List<UniquePV> pvlist) {
- double rmax = 0.;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
- rmax = Math.max(rmax, calculateRMaxSolid(solid,pv));
- }
- return rmax;
+ return cache.getVolumeGroupCalculations(pvlist).rmax;
}
- private double zmin(IPhysicalVolume pvtree, List<UniquePV> pvlist) {
- double zmin = 1.e10;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
-
- double z0 = pvtree.getTranslation().z();
- if (solid instanceof Tube) {
- Tube tube = (Tube) solid;
- zmin = Math.min(zmin, z0-tube.getZHalfLength());
- }
- else if (solid instanceof Box) {
- Box box = (Box) solid;
-
-// if (pvtree.getName().equals("SiTrackerBarrel_layer0")) {
-// System.out.println("====new box====");
-// System.out.println(pv.toString());
-// System.out.println("Claimed dimensions: "+2*box.getXHalfLength()+"x"+2*box.getYHalfLength()+"x"+2*box.getZHalfLength());
-//
-// }
- for (Point3D p : box.getVertices()){
- Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
-
-// if (pvtree.getName().equals("SiTrackerBarrel_layer0")) {
-// System.out.println(transformed.toString());
-// }
-
- zmin = Math.min(transformed.z(), zmin);
-// if (zmin==transformed.z()){
- //System.out.println("New zmin for "+pvtree.getName()+" at "+zmin+". Part name is "+pv.getName());
-// }
- }
- }
- else if (solid instanceof Polycone) {
- Polycone polycone = (Polycone) solid;
- zmin = Math.min(zmin, z0-polycone.getZHalfLength());
- }
- }
- return zmin;
+ private double zmin(List<UniquePV> pvlist) {
+ return cache.getVolumeGroupCalculations(pvlist).zmin;
}
- private double zmax(IPhysicalVolume pvtree, List<UniquePV> pvlist) {
- double zmax = -1.e10;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
-
- double z0 = pvtree.getTranslation().z();
-
- if (solid instanceof Tube) {
- Tube tube = (Tube) solid;
- zmax = Math.max(zmax, z0+tube.getZHalfLength());
- }
- else if (solid instanceof Box) {
- Box box = (Box) solid;
- for (Point3D p : box.getVertices()){
- Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
- zmax = Math.max(transformed.z(), zmax);
- }
- }
- else if (solid instanceof Polycone) {
- Polycone polycone = (Polycone) solid;
- zmax = Math.max(zmax, z0+polycone.getZHalfLength());
- }
- }
- return zmax;
+ private double zmax(List<UniquePV> pvlist) {
+ return cache.getVolumeGroupCalculations(pvlist).zmax;
}
- private boolean isCylinder(IPhysicalVolume pvtree, List<UniquePV> pvlist) {
+ private boolean isCylinder(List<UniquePV> pvlist) {
double rmin = rmin(pvlist);
double rmax = rmax(pvlist);
- double zmin = zmin(pvtree, pvlist);
- double zmax = zmax(pvtree, pvlist);
+ double zmin = zmin(pvlist);
+ double zmax = zmax(pvlist);
return (rmax - rmin) * Math.abs(zmax + zmin) < (zmax - zmin) * (rmax + rmin);
}
private double WeightedRadius(List<UniquePV> pvlist) {
- double rwgt = 0.;
- double totwgt = 0.;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
-
- double rmin = calculateRMinSolid(solid, pv);
- double rmax = calculateRMaxSolid(solid, pv);
- double vol = safeCubicVolume(solid);
- IMaterial mat = pv.getPV().getLogicalVolume().getMaterial();
- double X0 = 10. * mat.getRadiationLength() / mat.getDensity();
- double wgt = vol / X0;
- rwgt += 0.5 * (rmin + rmax) * wgt;
- totwgt += wgt;
-
- }
- if (totwgt > 0.) rwgt /= totwgt;
- return rwgt;
+ return cache.getVolumeGroupCalculations(pvlist).weighted_r;
}
- private double WeightedZ(IPhysicalVolume pvtree, List<UniquePV> pvlist) {
- double zwgt = 0.;
- double totwgt = 0.;
- for (UniquePV pv : pvlist) {
- ISolid solid = pv.getPV().getLogicalVolume().getSolid();
-
- double z0 = pvtree.getTranslation().z();
- double vol = safeCubicVolume(solid);
- IMaterial mat = pv.getPV().getLogicalVolume().getMaterial();
- double X0 = 10. * mat.getRadiationLength() / mat.getDensity();
- double wgt = vol / X0;
- zwgt += z0 * wgt;
- totwgt += wgt;
-
- }
- if (totwgt > 0.) zwgt /= totwgt;
- return zwgt;
+ private double WeightedZ(List<UniquePV> pvlist) {
+ return cache.getVolumeGroupCalculations(pvlist).weighted_z;
}
-
- //calculates the cubic volume and represses runtime exceptions by returning 0....
- //just in case there's something that isn't implemented
- private double safeCubicVolume(ISolid solid){
-
- try {
- return solid.getCubicVolume();
- }
- catch(Exception e) {
- return 0.0;
+ // special handling for Polycone...
+ private void handlePolycone(IPhysicalVolume pv){
+ Polycone pc = (Polycone) pv.getLogicalVolume().getSolid();
+ IMaterial mat = pv.getLogicalVolume().getMaterial();
+
+ //Loop through each segment
+ for (int i = 0; i < pc.getNumberOfZPlanes()-1; i++){
+ ZPlane zp1 = pc.getZPlane(i);
+ ZPlane zp2 = pc.getZPlane(i+1);
+
+ double z1 = zp1.getZ();
+ double z2 = zp2.getZ();
+ double vol = Polycone.getSegmentVolume(zp1, zp2);
+ double zlen = Math.abs(z2-z1);
+ double ravg = 0.25*(zp1.getRMax() + zp1.getRMin() + zp2.getRMax() + zp2.getRMin());
+ double ang = Math.atan2( 0.5 * (zp1.getRMax() + zp1.getRMin() - zp2.getRMax() - zp2.getRMin())
+ , zlen );
+ double X0 = 10*mat.getRadiationLength()/mat.getDensity();
+ double thickness = Math.cos(ang) * vol / (2 * Math.PI * ravg * zlen * X0);
+
+ //This is a cylinder
+ if(zp1.getRMax()==zp2.getRMax() && zp1.getRMin()==zp2.getRMin()) {
+ _matcyl.add(new MaterialCylinder(pv, ravg, Math.min(z1,z2), Math.max(z1,z2), thickness));
+ if(DEBUG){
+ System.out.println("Cylindrical segment of "+pv.getName());
+ System.out.println("zmin = "+ z1 + "| zmax = "+z2 + "| ravg = "+ravg + "| thickness = "+thickness);
+ }
+ }
+
+ //Otherwise this is a non-cylindrical polycone segment
+ else {
+ _matpc.add(new MaterialPolyconeSegment(pv, zp1, zp2, thickness, ang));
+ if(DEBUG){
+ System.out.println("Non-Cylindrical segment of "+pv.getName());
+ System.out.println("ZPlane 1: "+zp1.toString() + "| ZPlane 2: "+zp2.toString() + "| thickness = "+thickness);
+ }
+ }
}
}
-
-
- //functions that give the rmin and rmax of a solid...
- private double calculateRMinSolid(ISolid solid, UniquePV pv){
-
- double rmin = 1e10;
- if (solid instanceof Tube) {
- Tube tube = (Tube) solid;
- return tube.getInnerRadius();
- }
-
-
- else if (solid instanceof Box) {
- Box box = (Box) solid;
- List<Point3D> vtx = box.getVertices();
-
- for (Point3D p : vtx) {
-
- Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
- double r = Math.sqrt(transformed.x()*transformed.x() + transformed.y()*transformed.y());
- rmin = Math.min(rmin,r);
- }
- return rmin;
- }
-
- //this takes the inner radius at z = 0 of the polycone
- else if (solid instanceof Polycone) {
- Polycone poly = (Polycone) solid;
- return poly.getInnerRadiusAtZ(0);
- }
-
- return rmin;
+ /**
+ * A "struct" holding geometry information about a single physical volume
+ */
+ class VolumeInfo {
+ double rmax = 0.0;
+ double rmin = 1.e10;
+ double zmin = 1.e10;
+ double zmax = -1.e10;
}
- private double calculateRMaxSolid(ISolid solid, UniquePV pv){
-
- double rMax = 0;
- if (solid instanceof Tube) {
- Tube tube = (Tube) solid;
- return tube.getOuterRadius();
+ /**
+ * A "struct" holding geometry information about lists of physical volumes
+ */
+ class VolumeGroupInfo{
+ double rmax = 0.0;
+ double rmin = 1.e10;
+ double zmin = 1.e10;
+ double zmax = -1.e10;
+ double X0 = 0.0;
+ double weighted_r = 0.0;
+ double weighted_z = 0.0;
+ double vtot_tube_only = 0.;
+ double vtot = 0.0;
+ }
+
+ /**
+ * A class that calculates / caches geometry information about physical volumes.
+ */
+ class CalculationCache {
+ Map<UniquePV,VolumeInfo> pv_map;
+ Map<List<UniquePV>,VolumeGroupInfo> pv_group_map;
+ Map<ISolid,Double> solid_vol_map;
+ private final float load_factor = 0.75f; //(default)
+
+ /**
+ * Constructor. The detector is used to help determine the initial values of the hashmaps.
+ * @param det
+ */
+ public CalculationCache(Detector det){
+ int pv_map_size;
+ int pv_group_map_size;
+ int solid_vol_map_size;
+
+
+ //Resizing HashMaps is slow, so we use some magic numbers to speed things up a little
+ if(det.getName().indexOf("planar")>-1){ //these values should work well for the current planar model
+ if(DEBUG) System.out.println("Using initial map values for planar detector");
+ pv_map_size = (int) (130000/load_factor);
+ pv_group_map_size = (int) (120/load_factor);
+ solid_vol_map_size = (int) (1300/load_factor);
+ } else { //these values should work pretty well for sid01
+ pv_map_size = (int) (500/load_factor);
+ pv_group_map_size = (int) (200/load_factor);
+ solid_vol_map_size = (int) (250/load_factor);
+ }
+
+ pv_map = new HashMap<UniquePV,VolumeInfo>(pv_map_size,load_factor);
+ pv_group_map = new HashMap<List<UniquePV>,VolumeGroupInfo>(pv_group_map_size,load_factor);
+ solid_vol_map = new HashMap<ISolid,Double>(solid_vol_map_size, load_factor);
+
+
+ }
+
+ //clear function... after we've created the MaterialCylinders and
+ //material disks, we don't want to have this information cached anymore
+ //because it may sit around in RAM (not sure if the GC is smart enough
+ //to clear it by itself).
+
+ /**
+ * Releases the resources associated with the cache.
+ */
+ public void clear(){
+ pv_map.clear();
+ pv_group_map.clear();
+ solid_vol_map.clear();
+ System.gc();
+ }
+
+ /**
+ * Prints out the current number of objects inside the cache's data structure
+ */
+ public void printSizeInfo(){
+ System.out.println("pv_map size: "+pv_map.size());
+ System.out.println("pv_group_map size: "+pv_group_map.size());
+ System.out.println("solid_vol_map size: "+solid_vol_map.size());
+ }
+
+ /**
+ * Returns a VolumeGroupInfo object containing geometry and radiation-lenght
+ * information about the target collection of physical volumes.
+ *
+ * If a single-element collection consisting of a polycone is passed,
+ * no calculation is performed (top-level polycones are handled separately in
+ * MaterialManager).
+ *
+ * @param volgroup A list of UniquePVs
+ * @return A VolumeGroupInfo object
+ */
+ public VolumeGroupInfo getVolumeGroupCalculations(List<UniquePV> volgroup) {
+ if (pv_group_map.containsKey(volgroup)) {
+ // System.out.println("Using cached calculation");
+ return pv_group_map.get(volgroup);
+ }
+ else return performVolumeGroupCalculations(volgroup);
+ }
+
+ //This function performs all the calculations on lists of physical volumes
+ private VolumeGroupInfo performVolumeGroupCalculations(List<UniquePV> volgroup) {
+
+ VolumeGroupInfo vgi = new VolumeGroupInfo();
+
+ //If we have a top-level polycone, don't bother doing anything, because it'll be handled specially
+ if (volgroup.size()==1 && volgroup.get(0).getSolid() instanceof Polycone){
+ return vgi;
+ }
+
+ //The normal case
+ double totwgt = 0.0;
+ if (DEBUG && volgroup.isEmpty()) System.out.println("Empty volume group...");
+ for(UniquePV pv : volgroup) {
+
+ //increment total volume
+ double vol = this.getVolumeOfSolid(pv.getSolid());
+ if (pv.getSolid() instanceof Tube) vgi.vtot_tube_only += vol;
+ vgi.vtot+=vol;
+ //calculate weighted R / Z / Radiation Length
+ VolumeInfo vi = this.getVolumeCalculations(pv);
+ IMaterial mat = pv.getPV().getLogicalVolume().getMaterial();
+ double matX0 = 10.0 * mat.getRadiationLength() / mat.getDensity();
+ double wgt = vol / matX0;
+ double z0 = pv.getLtoGTransform().getTranslation().z();
+ vgi.weighted_r+= 0.5 * (vi.rmin + vi.rmax) * wgt;
+ vgi.weighted_z+= z0 * wgt;
+ totwgt += wgt;
+
+ //grab (z/r)(mins/maxes)
+ vgi.zmin = Math.min(vi.zmin,vgi.zmin);
+ vgi.zmax = Math.max(vi.zmax,vgi.zmax);
+ vgi.rmin = Math.min(vi.rmin,vgi.rmin);
+ vgi.rmax = Math.max(vi.rmax,vgi.rmax);
+
+ }
+
+ //finish weighted R/Z calculations + perform X0 calculation
+ if (totwgt > 0.) {
+ vgi.weighted_r /= totwgt;
+ vgi.weighted_z /= totwgt;
+ vgi.X0 = vgi.vtot / totwgt;
+ }
+
+
+ pv_group_map.put(volgroup,vgi);
+ return vgi;
+ }
+
+ /**
+ * Returns the cubic volume of the specified solid. Caches after first
+ * call. If solid.getCubicVolume() throws an exception, 0.0 is returned.
+ * @param solid The target ISolid
+ * @return a double corresponding to the cubic volume in mm^3
+ */
+ public double getVolumeOfSolid(ISolid solid){
+ if (solid_vol_map.containsKey(solid)){
+ return solid_vol_map.get(solid).doubleValue();
+ }
+
+ else {
+ double vol;
+ try{ vol = solid.getCubicVolume(); }
+ catch(Exception e) { vol = 0.0; }
+ solid_vol_map.put(solid,vol);
+ return vol;
+ }
}
- else if (solid instanceof Box) {
- Box box = (Box) solid;
- List<Point3D> vtx = box.getVertices();
-
- for (Point3D p : vtx) {
-
- Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
- double r = Math.sqrt(transformed.x()*transformed.x() + transformed.y()*transformed.y());
- rMax = Math.max(r, rMax);
- }
- return rMax;
+ /**
+ * Returns a VolumeInfo object containing information about the target
+ * UniquePV (rmin, rmax, zmin, zmax). The value is cached after the first
+ * call.
+ *
+ * @param pv The target UniquePV
+ * @return VolumeInfo containing information about the geometry of the PV.
+ */
+ public VolumeInfo getVolumeCalculations(UniquePV pv){
+
+ // check if the result has been cached already
+ if (pv_map.containsKey(pv)) {
+ //System.out.println("Using cached calculation");
+ return pv_map.get(pv);
+ }
+ //otherwise calculate them...
+ else return performVolumeCalculations(pv);
+
}
- else if (solid instanceof Polycone) {
- Polycone poly = (Polycone) solid;
- return poly.getOuterRadiusAtZ(0);
+ private VolumeInfo performVolumeCalculations(UniquePV pv){
+
+ VolumeInfo vi = new VolumeInfo();
+ ISolid solid = pv.getSolid();
+
+ //ASSUMPTION: tube is along z-axis and has center at r = 0
+ if (solid instanceof Tube) {
+ Tube tube = (Tube) solid;
+ double z0 = pv.getLtoGTransform().getTranslation().z();
+ vi.zmax = z0 + tube.getZHalfLength();
+ vi.zmin = z0 - tube.getZHalfLength();
+ vi.rmin = tube.getInnerRadius();
+ vi.rmax = tube.getOuterRadius();
+ }
+
+ else if (solid instanceof Box) {
+ Box box = (Box) solid;
+ for (Point3D p : box.getVertices()){
+ Hep3Vector transformed = pv.localToGlobal(p.getHep3Vector());
+ vi.zmin = Math.min(transformed.z(), vi.zmin);
+ vi.zmax = Math.max(transformed.z(), vi.zmax);
+ double r = Math.sqrt(transformed.x() * transformed.x() + transformed.y() * transformed.y());
+ vi.rmin = Math.min(vi.rmin, r);
+ vi.rmax = Math.max(vi.rmax, r);
+ }
+ }
+
+ //Note: this information will NOT be used most of the time...
+ // Polycones that are top-level elements (e.g. the beampipe) are
+ // handled specially (since the radiation length is a function of z).
+ // The information here will only be used in case a top-level element
+ // has a subelement that is a Polycone, in which case it'll be
+ // approximated as the smallest possible cylinder.
+ else if (solid instanceof Polycone) {
+ Polycone pc = (Polycone) solid;
+ List<Polycone.ZPlane> zplanes = pc.getZPlanes();
+
+ //For now, just take the minimum rmin and rmax of the polycone
+ for (Polycone.ZPlane z : zplanes){
+ if (z.getRMax()>0 && z.getRMin()>0) {
+ vi.rmin = Math.min(vi.rmin,z.getRMin());
+ vi.rmax = vi.rmax > 0. ? Math.min(vi.rmax,z.getRMax()) : z.getRMax();
+ }
+ }
+
+ vi.zmin = pc.getZPlanes().get(0).getZ();
+ vi.zmax = pc.getZPlanes().get(pc.getZPlanes().size()-1).getZ();
+
+ //check for wrong order
+ if (vi.zmin > vi.zmax) {
+ double temp = vi.zmin;
+ vi.zmin = vi.zmax;
+ vi.zmax = temp;
+ }
+ }
+
+ pv_map.put(pv,vi);
+ return vi;
}
-
- return rMax;
}
-
+
+ /**
+ * A UniquePV is a wrapper around IPhysicalVolumePath which provides
+ * some convenience methods and caches transformations.
+ */
class UniquePV{
IPhysicalVolumePath path;
IPhysicalVolumeNavigator nav;
ITransform3D transform = null;
+ /**
+ * Generates a top-level UniquePV.
+ * @param root The top-level IPhysicalVolume
+ * @param navigator The IPhysicalVolumeNavigator associated with the detector
+ */
public UniquePV(IPhysicalVolume root, IPhysicalVolumeNavigator navigator){
path = new PhysicalVolumePath();
nav = navigator;
path.add(root);
-
}
+ /**
+ * Generates a UniquePV from a path. (Shallow copy of path)
+ * @param path
+ * @param navigator
+ */
public UniquePV(IPhysicalVolumePath path, IPhysicalVolumeNavigator navigator){
this.path = path;
nav = navigator;
}
-
+
+ /**
+ * Returns the IPhysicalVolume (the last element of the path)
+ */
public IPhysicalVolume getPV(){
return path.getLeafVolume();
}
+ /**
+ * Creates a UniquePV that is a daughter of the current UniquePV (deep copy made)
+ * @param daughter
+ * @return
+ */
public UniquePV createDaughterUniquePV(IPhysicalVolume daughter){
-
IPhysicalVolumePath np = new PhysicalVolumePath();
np.addAll(path);
np.add(daughter);
@@ -461,13 +590,33 @@
}
+ /**
+ * Transforms the given vector from local to global coords.
+ * @param v the untransformed local Hep3Vector
+ * @return the transformed global Hep3Vector
+ */
public Hep3Vector localToGlobal(Hep3Vector v) {
- if(transform == null){
+ return getLtoGTransform().transformed(v);
+ }
+
+ /**
+ * Returns the solid associated with the physical volume.
+ * @return
+ */
+ public ISolid getSolid(){
+ return this.getPV().getLogicalVolume().getSolid();
+ }
+
+ /**
+ * Returns the local-to-global transform
+ * @return an ITransform3D from local coordinates to global coordinates.
+ */
+ public ITransform3D getLtoGTransform() {
+ if (transform == null) {
transform = nav.getTransform(path);
}
- return transform.transformed(v);
-
+ return transform;
}
@Override