1
2
3 """
4 Reads Oxford Diffraction Sapphire 3 images
5
6 Authors: Henning O. Sorensen & Erik Knudsen
7 Center for Fundamental Research: Metal Structures in Four Dimensions
8 Risoe National Laboratory
9 Frederiksborgvej 399
10 DK-4000 Roskilde
11 email:erik.knudsen@risoe.dk
12
13 + Jon Wright, ESRF
14
15 """
16
17 import numpy as N, logging
18 from fabioimage import fabioimage
19
20 DETECTOR_TYPES = {0: 'Sapphire/KM4CCD (1x1: 0.06mm, 2x2: 0.12mm)',
21 1: 'Sapphire2-Kodak (1x1: 0.06mm, 2x2: 0.12mm)',
22 2: 'Sapphire3-Kodak (1x1: 0.03mm, 2x2: 0.06mm, 4x4: 0.12mm)',
23 3: 'Onyx-Kodak (1x1: 0.06mm, 2x2: 0.12mm, 4x4: 0.24mm)',
24 4: 'Unknown Oxford diffraction detector'}
25
26
29
30 infile.seek(0)
31
32
33 self.header['Header Version'] = infile.readline()[:-2]
34 block = infile.readline()
35 self.header['Compression'] = block[12:15]
36 block = infile.readline()
37 self.header['NX'] = int(block[3:7])
38 self.header['NY'] = int(block[11:15])
39 self.header['OI'] = int(block[19:26])
40 self.header['OL'] = int(block[30:37])
41 block = infile.readline()
42 self.header['Header Size In Bytes'] = int(block[8:15])
43
44
45
46
47 block = infile.readline()
48
49 block = infile.readline()
50 self.header['Time'] = block[5:29]
51
52
53 infile.seek(256)
54 block = infile.read(512)
55 self.header['Binning in x'] = N.fromstring(block[0:2], N.uint16)[0]
56 self.header['Binning in y'] = N.fromstring(block[2:4], N.uint16)[0]
57 self.header['Detector size x'] = N.fromstring(block[22:24], N.uint16)[0]
58 self.header['Detector size y'] = N.fromstring(block[24:26], N.uint16)[0]
59 self.header['Pixels in x'] = N.fromstring(block[26:28], N.uint16)[0]
60 self.header['Pixels in y'] = N.fromstring(block[28:30], N.uint16)[0]
61 self.header['No of pixels'] = N.fromstring(block[36:40], N.uint32)[0]
62
63
64 block = infile.read(768)
65 self.header['Gain'] = N.fromstring(block[56:64], N.float)[0]
66 self.header['Overflows flag'] = N.fromstring(block[464:466], N.int16)[0]
67 self.header['Overflow after remeasure flag'] = N.fromstring(block[466:468], N.int16)[0]
68 self.header['Overflow threshold'] = N.fromstring(block[472:476], N.int32)[0]
69 self.header['Exposure time in sec'] = N.fromstring(block[480:488], N.float)[0]
70 self.header['Overflow time in sec'] = N.fromstring(block[488:496], N.float)[0]
71 self.header['Monitor counts of raw image 1'] = N.fromstring(block[528:532], N.int32)[0]
72 self.header['Monitor counts of raw image 2'] = N.fromstring(block[532:536], N.int32)[0]
73 self.header['Monitor counts of overflow raw image 1'] = N.fromstring(block[536:540], N.int32)[0]
74 self.header['Monitor counts of overflow raw image 2'] = N.fromstring(block[540:544], N.int32)[0]
75 self.header['Unwarping'] = N.fromstring(block[544:548], N.int32)[0]
76 self.header['Detector type'] = DETECTOR_TYPES[N.fromstring(block[548:552], N.int32)[0]]
77 self.header['Real pixel size x (mm)'] = N.fromstring(block[568:576], N.float)[0]
78 self.header['Real pixel size y (mm)'] = N.fromstring(block[576:584], N.float)[0]
79
80
81 block = infile.read(1024)
82
83 self.header['Spatial correction file'] = block[26:272]
84 self.header['Spatial correction file date'] = block[0:26]
85
86
87 start_angles_step = N.fromstring(block[284:304], N.int32)
88 end_angles_step = N.fromstring(block[324:344], N.int32)
89 step2rad = N.fromstring(block[368:408], N.float)
90
91 start_angles_deg = start_angles_step * step2rad * 180.0 / N.pi
92
93 end_angles_deg = end_angles_step * step2rad * 180.0 / N.pi
94 self.header['Omega start in deg'] = start_angles_deg[0]
95 self.header['Theta start in deg'] = start_angles_deg[1]
96 self.header['Kappa start in deg'] = start_angles_deg[2]
97 self.header['Phi start in deg'] = start_angles_deg[3]
98 self.header['Omega end in deg'] = end_angles_deg[0]
99 self.header['Theta end in deg'] = end_angles_deg[1]
100 self.header['Kappa end in deg'] = end_angles_deg[2]
101 self.header['Phi end in deg'] = end_angles_deg[3]
102
103 zero_correction_soft_step = N.fromstring(block[512:532], N.int32)
104 zero_correction_soft_deg = zero_correction_soft_step * step2rad * 180.0 / N.pi
105 self.header['Omega zero corr. in deg'] = zero_correction_soft_deg[0]
106 self.header['Theta zero corr. in deg'] = zero_correction_soft_deg[1]
107 self.header['Kappa zero corr. in deg'] = zero_correction_soft_deg[2]
108 self.header['Phi zero corr. in deg'] = zero_correction_soft_deg[3]
109
110 self.header['Beam rot in deg (e2)'] = N.fromstring(block[552:560], N.float)[0]
111 self.header['Beam rot in deg (e3)'] = N.fromstring(block[560:568], N.float)[0]
112
113 self.header['Wavelength alpha1'] = N.fromstring(block[568:576], N.float)[0]
114 self.header['Wavelength alpha2'] = N.fromstring(block[576:584], N.float)[0]
115 self.header['Wavelength alpha'] = N.fromstring(block[584:592], N.float)[0]
116 self.header['Wavelength beta'] = N.fromstring(block[592:600], N.float)[0]
117
118
119 self.header['Detector tilt e1 in deg'] = N.fromstring(block[640:648], N.float)[0]
120 self.header['Detector tilt e2 in deg'] = N.fromstring(block[648:656], N.float)[0]
121 self.header['Detector tilt e3 in deg'] = N.fromstring(block[656:664], N.float)[0]
122
123
124
125 self.header['Beam center x'] = N.fromstring(block[664:672], N.float)[0]
126 self.header['Beam center y'] = N.fromstring(block[672:680], N.float)[0]
127
128 self.header['Alpha angle in deg'] = N.fromstring(block[672:680], N.float)[0]
129
130 self.header['Beta angle in deg'] = N.fromstring(block[672:680], N.float)[0]
131
132
133 self.header['Distance in mm'] = N.fromstring(block[712:720], N.float)[0]
134
135 block = infile.read(512)
136 self.header['Stat: Min '] = N.fromstring(block[0:4], N.int32)[0]
137 self.header['Stat: Max '] = N.fromstring(block[4:8], N.int32)[0]
138 self.header['Stat: Average '] = N.fromstring(block[24:32], N.float)[0]
139 self.header['Stat: Stddev '] = N.sqrt(N.fromstring(block[32:40], N.float)[0])
140 self.header['Stat: Skewness '] = N.fromstring(block[40:48], N.float)[0]
141
142
143 block = infile.read(256)
144 self.header['Flood field image'] = block[99:126]
145
146 - def read(self, fname):
147 """
148 Read in header into self.header and
149 the data into self.data
150 """
151 self.header = {}
152 self.resetvals()
153 infile = self._open(fname)
154 self._readheader(infile)
155
156 infile.seek(self.header['Header Size In Bytes'])
157
158
159 try:
160 self.dim1 = int(self.header['NX'])
161 self.dim2 = int(self.header['NY'])
162 except:
163 raise Exception("Oxford file", str(fname) + \
164 "is corrupt, cannot read it")
165
166 if self.header['Compression'] == 'TY1':
167
168 bytecode = N.uint8
169 self.bpp = len(N.array(0, bytecode).tostring())
170 ReadBytes = self.dim1 * self.dim2 * self.bpp
171 diffs = infile.read(ReadBytes)
172 diffs = N.fromstring(diffs, bytecode)
173 offset = -127
174 diffs = diffs.astype(N.int32) + offset
175
176 if self.header['OI'] > 0:
177 bytecode = N.int16
178 self.bpp = len(N.array(0, bytecode).tostring())
179 ReadBytes = self.header['OI'] * self.bpp
180 over_short = infile.read(ReadBytes)
181 over_short = N.fromstring(over_short, bytecode)
182 if self.header['OL'] > 0:
183 bytecode = N.int32
184 self.bpp = len(N.array(0, bytecode).tostring())
185 ReadBytes = self.header['OL'] * self.bpp
186 over_long = infile.read(ReadBytes)
187 over_long = N.fromstring(over_long, bytecode)
188 block = diffs.copy()
189 old_val = 0
190 js = 0
191 jl = 0
192 print 'OVER_SHORT: ', block.dtype
193
194 for i in range(self.dim1 * self.dim2):
195 if diffs[i] < 127:
196
197 d = diffs[i]
198 elif diffs[i] == 127:
199
200 d = over_short[js]
201
202 js = js + 1
203 elif diffs[i] == 128:
204
205 d = over_long[jl]
206 jl = jl + 1
207 old_val = old_val + d
208 block[i] = old_val
209 else:
210 bytecode = N.int32
211 self.bpp = len(N.array(0, bytecode).tostring())
212 ReadBytes = self.dim1 * self.dim2 * self.bpp
213 block = N.fromstring(infile.read(ReadBytes), bytecode)
214
215 print 'OVER_SHORT2: ', block.dtype
216 print (block < 0).sum()
217
218 infile.close()
219 print "BYTECODE", bytecode
220 try:
221
222 bytecode = N.int32
223
224 self.data = N.reshape(block.astype(bytecode), [self.dim2, self.dim1])
225
226 except:
227 print len(block), self.dim2, self.dim1
228 raise IOError, \
229 'Size spec in OD-header does not match size of image data field'
230
231 self.bytecode = self.data.dtype.type
232 self.pilimage = None
233 return self
234