Created
June 17, 2013 00:03
-
-
Save tjlane/5793931 to your computer and use it in GitHub Desktop.
This script converts cheetah pixelmaps from the explicit-pixel cheetah format
(which stores the x/y/z values for each pixel) to an Odin Detector object,
which employs a basis representation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
This script converts cheetah pixelmaps from the explicit-pixel cheetah format | |
(which stores the x/y/z values for each pixel) to an Odin Detector object, | |
which employs a basis representation. | |
-- TJL June 2013 | |
""" | |
import sys | |
import h5py | |
import numpy as np | |
from pypad import read | |
from pypad.plot import sketch_2x1s | |
from odin import xray | |
pixel_size = 0.10992 # mm | |
def convert_cheetah_pixelmap_to_odin(filename, energy, distance_offset): | |
""" | |
Convert a cheetah pixelmap to an Odin Detector object. | |
Parameters | |
---------- | |
filename : str | |
The path to the cheetah pixelmap. | |
energy : float | |
The energy of the beam, in eV. | |
distance_offset : float | |
A distance offset (along the z-direction), in mm. This can be measured | |
directly using a pypad.autogeom.score.PowderReference instance. | |
Returns | |
------- | |
dtc : xray.Detector | |
An Odin detector object. | |
""" | |
f = h5py.File(filename) | |
if not f.keys() == ['x', 'y', 'z']: | |
raise IOError('File: %s is not a valid pixel map, should contain fields' | |
' ["x", "y", "z"] exlusively' % filename) | |
# convert m --> mm | |
x = read.enforce_raw_img_shape( np.array(f['x']) * 1000.0 ) | |
y = read.enforce_raw_img_shape( np.array(f['y']) * 1000.0 ) | |
# for some reason z is in microns, so um --> mm | |
z = read.enforce_raw_img_shape( np.array(f['z']) / 1000.0 ) | |
f.close() | |
bg = xray.BasisGrid() | |
shape = (185, 194) # will always be this for each ASIC | |
# loop over each ASIC, and convert it into a basis grid | |
for i in range(4): | |
for j in range(16): | |
# extract all the corner positions (code ineligant but explicit) | |
# corners are numbered 0 -> 4, starting top left and continuing cw | |
corners = np.zeros(( 4, 3 )) | |
corners[0,:] = ( x[i,j,0,0], y[i,j,0,0], z[i,j,0,0] ) | |
corners[1,:] = ( x[i,j,0,-1], y[i,j,0,-1], z[i,j,0,-1] ) | |
corners[2,:] = ( x[i,j,-1,-1], y[i,j,-1,-1], z[i,j,-1,-1] ) | |
corners[3,:] = ( x[i,j,-1,0], y[i,j,-1,0], z[i,j,-1,0] ) | |
# dont use this -- takes the vectors from 2 px inside the ASIC | |
# if your starting pixel map is good, this should give the same | |
# result as the above | |
# corners[0,:] = ( x[i,j,2,2], y[i,j,2,2], z[i,j,2,2] ) | |
# corners[1,:] = ( x[i,j,2,-3], y[i,j,2,-3], z[i,j,2,-3] ) | |
# corners[2,:] = ( x[i,j,-3,-3], y[i,j,-3,-3], z[i,j,-3,-3] ) | |
# corners[3,:] = ( x[i,j,-3,2], y[i,j,-3,2], z[i,j,-3,2] ) | |
# average the vectors formed by the corners to find f/s vects | |
# the fast scan direction is the last index, s is next | |
# f points left -> right, s points bottom -> top | |
f = (( corners[1,:] - corners[0,:] ) + ( corners[2,:] - corners[3,:] )) | |
s = (( corners[3,:] - corners[0,:] ) + ( corners[2,:] - corners[1,:] )) | |
# make them pixel-size magnitude | |
f = f * (pixel_size / np.linalg.norm(f)) | |
s = s * (pixel_size / np.linalg.norm(s)) | |
# center is just the average of the 4 corners | |
c = np.mean( corners, axis=0 ) | |
assert c.shape == (3,) | |
c[2] += distance_offset | |
bg.add_grid_using_center(c, s, f, shape) | |
# recall that pypad assumes the beam is along the z-direction (CXI conven.) | |
energy /= 1000.0 # convert to keV : pypad is eV, Odin is keV | |
b = xray.Beam(1e11, energy=energy) # 1e11 photons per shot | |
d = xray.Detector(bg, b) | |
return d | |
def sketch_detector(detector): | |
""" | |
Sketch the ASICs of a detector. | |
Parameters | |
---------- | |
detector : odin.xray.Detector | |
""" | |
pix_pos = np.zeros((3, 4, 16, 185, 194)) | |
for i in range(4): | |
for j in range(16): | |
grid = d._basis_grid.grid_as_explicit(i*16 + j) | |
if grid.shape == (194,185,3): | |
for k in range(3): | |
pix_pos[k,i,j,:,:] = grid[:,:,k].T | |
else: | |
for k in range(3): | |
pix_pos[k,i,j,:,:] = grid[:,:,k] | |
sketch_2x1s(pix_pos) | |
return | |
if __name__ == '__main__': | |
print "Usage: %s <pixelmap.h5> <energy [keV]> <distance [mm]>" % sys.argv[0] | |
pixelmap = sys.argv[1] | |
energy = float(sys.argv[2]) | |
distance_offset = float(sys.argv[3]) | |
# the values for sellberg | |
# pixelmap = 'CSPAD2-Alignment-PostRun3_pixelmap.h5' | |
# energy = 9392.4 # avg eV, from sellberg | |
# distance_offset = 139.002 # mm, from sellberg | |
output = pixelmap[:-3] + '.dtc' | |
d = convert_cheetah_pixelmap_to_odin(pixelmap, energy, distance_offset) | |
sketch_detector(d) | |
d.save(output) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment