summaryrefslogtreecommitdiff
path: root/detectors/sno.py
diff options
context:
space:
mode:
Diffstat (limited to 'detectors/sno.py')
-rw-r--r--detectors/sno.py71
1 files changed, 58 insertions, 13 deletions
diff --git a/detectors/sno.py b/detectors/sno.py
index 5439739..156dcbe 100644
--- a/detectors/sno.py
+++ b/detectors/sno.py
@@ -2,11 +2,12 @@ import numpy as np
import numpy.linalg
import math
from make import rotate_extrude
+from stl import mesh_from_stl
from geometry import *
from optics import *
-from solids import build_8inch_pmt
+from solids import build_8inch_pmt_with_lc
from transform import rotate, make_rotation_matrix
-import sno_pmt_locations
+import os
def sno_vessel(sphere_radius, neck_radius, neck_top, angle_step=math.pi/20):
'''Compute the 2D coordinates of the profile of one side of a
@@ -66,22 +67,66 @@ av_inside_mesh = rotate_extrude(av_inside_profile[0], av_inside_profile[1],
angle_step)
av_inside_mesh.vertices = rotate(av_inside_mesh.vertices, np.pi/2, (-1,0,0))
-def build_sno():
- pmt = build_8inch_pmt()
+dir = os.path.split(os.path.realpath(__file__))[0]
+
+def build_sno(real_av=False):
+ import h5py
+ pmtinfo = h5py.File(dir+'/sno_pmt_info.hdf5')
+
+ pmt = build_8inch_pmt_with_lc()
+
geo = Geometry()
- geo.add_solid(Solid(av_outside_mesh, glass, water, color=0x99FFFFFF))
- geo.add_solid(Solid(av_inside_mesh, water, glass, color=0x990000FF))
+
+ if real_av:
+ real_av_mesh = mesh_from_stl(dir+'/sno_av_ascii.stl.bz2')
+ real_av_mesh.vertices *= 0.0254 # inch -> meter
+ geo.add_solid(Solid(real_av_mesh, glass, water, color=0xBBAAAAFF))
+ else:
+ geo.add_solid(Solid(av_outside_mesh, acrylic_sno, water,
+ color=0xBBFFFFFF))
+ geo.add_solid(Solid(av_inside_mesh, labppo_scintillator, acrylic_sno,
+ color=0xBB0000FF))
geo.pmtids = []
- for x,y,z in zip(sno_pmt_locations.x, sno_pmt_locations.y,
- sno_pmt_locations.z):
- direction = numpy.array((-x,-y,-z))
- direction /= numpy.linalg.norm(direction)
+
+ snoman_id_dict = {}
+
+ pmt_offset = 122.0 - 2 * 0.01# max bucket height - 2 * facegap (mm)
+
+ for position, direction, idnum, pmt_type in zip(pmtinfo['pos'], pmtinfo['dir'],
+ pmtinfo['snoman_id'],
+ pmtinfo['pmt_type']):
+
+ # PMT type codes:
+ # 1 = normal; 2 = OWL; 3 = Low Gain; 4 = BUTT; 5 = Neck
+ # 6 = Calib channel; 10 = spare; 11 = invalid
+ if pmt_type != 1: # All the other PMTs have nonsense directions
+ continue
+
+
+ # Flip and renormalize
+ direction *= -1.0/numpy.linalg.norm(direction)
+
+ # Orient PMT that starts facing Y axis
y_axis = np.array((0.0,1.0,0.0))
axis = np.cross(direction, y_axis)
angle = np.arccos(np.dot(y_axis, direction))
-
rotation = make_rotation_matrix(angle, axis)
- displacement = (x/1000.0, y/1000.0, z/1000.0)
- geo.pmtids.append(geo.add_solid(pmt, rotation, displacement))
+
+ # Values in database are for front face of concentrator.
+ # need to shift so position is for equator of PMT
+ if pmt_type == 1:
+ displacement = position - direction * pmt_offset
+ displacement /= 1000.0 # mm -> m
+ chroma_id = geo.add_solid(pmt, rotation, displacement)
+ snoman_id_dict[chroma_id] = idnum
+ geo.pmtids.append(chroma_id)
+
+ # Convert dict to numpy array for fast array remapping later
+ chroma_ids = np.array(snoman_id_dict.keys())
+ snoman_ids = np.array(snoman_id_dict.values())
+ snoman_id_map = np.zeros(max(chroma_ids)+1) - 1 # Fill with -1 everywhere
+ snoman_id_map[chroma_ids] = snoman_ids
+
+ geo.snoman_id_map = snoman_id_map
return geo