fabio 0.1.1__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Library/Python/2.7/site-packages/fabio/GEimage.py +334 -0
- Library/Python/2.7/site-packages/fabio/GEimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/GEimage_old.py +501 -0
- Library/Python/2.7/site-packages/fabio/GEimage_old.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/HiPiCimage.py +106 -0
- Library/Python/2.7/site-packages/fabio/HiPiCimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/OXDimage.py +442 -0
- Library/Python/2.7/site-packages/fabio/OXDimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/TiffIO.py +1197 -0
- Library/Python/2.7/site-packages/fabio/TiffIO.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/__init__.py +10 -0
- Library/Python/2.7/site-packages/fabio/__init__.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/adscimage.py +137 -0
- Library/Python/2.7/site-packages/fabio/adscimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/binaryimage.py +87 -0
- Library/Python/2.7/site-packages/fabio/binaryimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/bruker100image.py +96 -0
- Library/Python/2.7/site-packages/fabio/bruker100image.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/brukerimage.py +195 -0
- Library/Python/2.7/site-packages/fabio/brukerimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/byte_offset.so +0 -0
- Library/Python/2.7/site-packages/fabio/cbfimage.py +758 -0
- Library/Python/2.7/site-packages/fabio/cbfimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/cf_io.so +0 -0
- Library/Python/2.7/site-packages/fabio/compression.py +388 -0
- Library/Python/2.7/site-packages/fabio/compression.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/converters.py +54 -0
- Library/Python/2.7/site-packages/fabio/converters.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/datIO.py +60 -0
- Library/Python/2.7/site-packages/fabio/datIO.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/dm3image.py +219 -0
- Library/Python/2.7/site-packages/fabio/dm3image.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/edfimage.py +924 -0
- Library/Python/2.7/site-packages/fabio/edfimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/fabioimage.py +556 -0
- Library/Python/2.7/site-packages/fabio/fabioimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/fabioutils.py +491 -0
- Library/Python/2.7/site-packages/fabio/fabioutils.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/file_series.py +313 -0
- Library/Python/2.7/site-packages/fabio/file_series.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/fit2dmaskimage.py +94 -0
- Library/Python/2.7/site-packages/fabio/fit2dmaskimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/fit2dspreadsheetimage.py +85 -0
- Library/Python/2.7/site-packages/fabio/fit2dspreadsheetimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/kcdimage.py +131 -0
- Library/Python/2.7/site-packages/fabio/kcdimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/mar345_IO.so +0 -0
- Library/Python/2.7/site-packages/fabio/mar345image.py +320 -0
- Library/Python/2.7/site-packages/fabio/mar345image.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/marccdimage.py +309 -0
- Library/Python/2.7/site-packages/fabio/marccdimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/openimage.py +162 -0
- Library/Python/2.7/site-packages/fabio/openimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/pilatusimage.py +81 -0
- Library/Python/2.7/site-packages/fabio/pilatusimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/pnmimage.py +165 -0
- Library/Python/2.7/site-packages/fabio/pnmimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/readbytestream.py +86 -0
- Library/Python/2.7/site-packages/fabio/readbytestream.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/tifimage.py +283 -0
- Library/Python/2.7/site-packages/fabio/tifimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio/xsdimage.py +134 -0
- Library/Python/2.7/site-packages/fabio/xsdimage.pyc +0 -0
- Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/PKG-INFO +11 -0
- Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/SOURCES.txt +114 -0
- Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/dependency_links.txt +1 -0
- Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/top_level.txt +4 -0
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
"""
|
|
4
|
+
Authors: Jérôme Kieffer, ESRF
|
|
5
|
+
email:jerome.kieffer@esrf.fr
|
|
6
|
+
|
|
7
|
+
Cif Binary Files images are 2D images written by the Pilatus detector and others.
|
|
8
|
+
They use a modified (simplified) byte-offset algorithm.
|
|
9
|
+
|
|
10
|
+
CIF is a library for manipulating Crystallographic information files and tries
|
|
11
|
+
to conform to the specification of the IUCR
|
|
12
|
+
"""
|
|
13
|
+
__author__ = "Jérôme Kieffer"
|
|
14
|
+
__contact__ = "jerome.kieffer@esrf.eu"
|
|
15
|
+
__license__ = "GPLv3+"
|
|
16
|
+
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
|
|
17
|
+
__version__ = ["Generated by CIF.py: Jan 2005 - April 2012",
|
|
18
|
+
"Written by Jerome Kieffer: Jerome.Kieffer@esrf.eu",
|
|
19
|
+
"On-line data analysis / ISDD ", "ESRF Grenoble (France)"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
import os, logging
|
|
23
|
+
logger = logging.getLogger("cbfimage")
|
|
24
|
+
import numpy
|
|
25
|
+
from fabioimage import fabioimage
|
|
26
|
+
from compression import decByteOffet_numpy, md5sum, compByteOffet_numpy
|
|
27
|
+
#import time
|
|
28
|
+
|
|
29
|
+
DATA_TYPES = { "signed 8-bit integer" : numpy.int8,
|
|
30
|
+
"signed 16-bit integer" : numpy.int16,
|
|
31
|
+
"signed 32-bit integer" : numpy.int32,
|
|
32
|
+
"signed 64-bit integer" : numpy.int64
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
MINIMUM_KEYS = ["X-Binary-Size-Fastest-Dimension",
|
|
36
|
+
'ByteOrder',
|
|
37
|
+
'Data type',
|
|
38
|
+
'X dimension',
|
|
39
|
+
'Y dimension',
|
|
40
|
+
'Number of readouts']
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
STARTER = "\x0c\x1a\x04\xd5"
|
|
44
|
+
PADDING = 512
|
|
45
|
+
|
|
46
|
+
class cbfimage(fabioimage):
|
|
47
|
+
"""
|
|
48
|
+
Read the Cif Binary File data format
|
|
49
|
+
"""
|
|
50
|
+
def __init__(self, data=None , header=None, fname=None):
|
|
51
|
+
"""
|
|
52
|
+
Constructor of the class CIF Binary File reader.
|
|
53
|
+
|
|
54
|
+
@param _strFilename: the name of the file to open
|
|
55
|
+
@type _strFilename: string
|
|
56
|
+
"""
|
|
57
|
+
fabioimage.__init__(self, data, header)
|
|
58
|
+
self.cif = CIF()
|
|
59
|
+
if fname is not None: #load the file)
|
|
60
|
+
self.read(fname)
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def checkData(data=None):
|
|
64
|
+
if data is None:
|
|
65
|
+
return None
|
|
66
|
+
elif numpy.issubdtype(data.dtype, int):
|
|
67
|
+
return data
|
|
68
|
+
else:
|
|
69
|
+
return data.astype(int)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _readheader(self, inStream):
|
|
73
|
+
"""
|
|
74
|
+
Read in a header in some CBF format from a string representing binary stuff
|
|
75
|
+
|
|
76
|
+
@param inStream: file containing the Cif Binary part.
|
|
77
|
+
@type inStream: opened file.
|
|
78
|
+
"""
|
|
79
|
+
self.cif.loadCIF(inStream, _bKeepComment=True)
|
|
80
|
+
|
|
81
|
+
# backport contents of the CIF data to the headers
|
|
82
|
+
for key in self.cif:
|
|
83
|
+
if key != "_array_data.data":
|
|
84
|
+
self.header_keys.append(key)
|
|
85
|
+
self.header[key] = self.cif[key].strip(" \"\n\r\t")
|
|
86
|
+
|
|
87
|
+
if not "_array_data.data" in self.cif:
|
|
88
|
+
raise Exception("cbfimage: CBF file %s is corrupt, cannot find data block with '_array_data.data' key" % self.fname)
|
|
89
|
+
|
|
90
|
+
inStream2 = self.cif["_array_data.data"]
|
|
91
|
+
sep = "\r\n"
|
|
92
|
+
iSepPos = inStream2.find(sep)
|
|
93
|
+
if iSepPos < 0 or iSepPos > 80:
|
|
94
|
+
sep = "\n" #switch back to unix representation
|
|
95
|
+
|
|
96
|
+
lines = inStream2.split(sep)
|
|
97
|
+
for oneLine in lines[1:]:
|
|
98
|
+
if len(oneLine) < 10:
|
|
99
|
+
break
|
|
100
|
+
try:
|
|
101
|
+
key, val = oneLine.split(':' , 1)
|
|
102
|
+
except ValueError:
|
|
103
|
+
key, val = oneLine.split('=' , 1)
|
|
104
|
+
key = key.strip()
|
|
105
|
+
self.header_keys.append(key)
|
|
106
|
+
self.header[key] = val.strip(" \"\n\r\t")
|
|
107
|
+
missing = []
|
|
108
|
+
for item in MINIMUM_KEYS:
|
|
109
|
+
if item not in self.header_keys:
|
|
110
|
+
missing.append(item)
|
|
111
|
+
if len(missing) > 0:
|
|
112
|
+
logger.debug("CBF file misses the keys " + " ".join(missing))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def read(self, fname, frame=None):
|
|
116
|
+
"""
|
|
117
|
+
Read in header into self.header and
|
|
118
|
+
the data into self.data
|
|
119
|
+
"""
|
|
120
|
+
self.filename = fname
|
|
121
|
+
self.header = {}
|
|
122
|
+
self.resetvals()
|
|
123
|
+
|
|
124
|
+
infile = self._open(fname, "rb")
|
|
125
|
+
self._readheader(infile)
|
|
126
|
+
# Compute image size
|
|
127
|
+
try:
|
|
128
|
+
self.dim1 = int(self.header['X-Binary-Size-Fastest-Dimension'])
|
|
129
|
+
self.dim2 = int(self.header['X-Binary-Size-Second-Dimension'])
|
|
130
|
+
except:
|
|
131
|
+
raise Exception(IOError, "CBF file %s is corrupt, no dimensions in it" % fname)
|
|
132
|
+
try:
|
|
133
|
+
bytecode = DATA_TYPES[self.header['X-Binary-Element-Type']]
|
|
134
|
+
self.bpp = len(numpy.array(0, bytecode).tostring())
|
|
135
|
+
except KeyError:
|
|
136
|
+
bytecode = numpy.int32
|
|
137
|
+
self.bpp = 32
|
|
138
|
+
logger.warning("Defaulting type to int32")
|
|
139
|
+
if self.header["conversions"] == "x-CBF_BYTE_OFFSET":
|
|
140
|
+
self.data = self._readbinary_byte_offset(self.cif["_array_data.data"]).astype(bytecode).reshape((self.dim2, self.dim1))
|
|
141
|
+
else:
|
|
142
|
+
raise Exception(IOError, "Compression scheme not yet supported, please contact FABIO development team")
|
|
143
|
+
|
|
144
|
+
self.bytecode = self.data.dtype.type
|
|
145
|
+
self.resetvals()
|
|
146
|
+
# # ensure the PIL image is reset
|
|
147
|
+
self.pilimage = None
|
|
148
|
+
return self
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _readbinary_byte_offset(self, inStream):
|
|
153
|
+
"""
|
|
154
|
+
Read in a binary part of an x-CBF_BYTE_OFFSET compressed image
|
|
155
|
+
|
|
156
|
+
@param inStream: the binary image (without any CIF decorators)
|
|
157
|
+
@type inStream: python string.
|
|
158
|
+
@return: a linear numpy array without shape and dtype set
|
|
159
|
+
@rtype: numpy array
|
|
160
|
+
"""
|
|
161
|
+
startPos = inStream.find(STARTER) + 4
|
|
162
|
+
data = inStream[ startPos: startPos + int(self.header["X-Binary-Size"])]
|
|
163
|
+
try:
|
|
164
|
+
import byte_offset
|
|
165
|
+
except ImportError:
|
|
166
|
+
logger.warning("Error in byte_offset part: Falling back to Numpy implementation")
|
|
167
|
+
myData = decByteOffet_numpy(data, size=self.dim1 * self.dim2)
|
|
168
|
+
else:
|
|
169
|
+
myData = byte_offset.analyseCython(data, size=self.dim1 * self.dim2)
|
|
170
|
+
|
|
171
|
+
assert len(myData) == self.dim1 * self.dim2
|
|
172
|
+
return myData
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def write(self, fname):
|
|
176
|
+
"""
|
|
177
|
+
write the file in CBF format
|
|
178
|
+
@param fname: name of the file
|
|
179
|
+
@type: string
|
|
180
|
+
"""
|
|
181
|
+
if self.data is not None:
|
|
182
|
+
self.dim2, self.dim1 = self.data.shape
|
|
183
|
+
else:
|
|
184
|
+
raise RuntimeError("CBF image contains no data")
|
|
185
|
+
binary_blob = compByteOffet_numpy(self.data)
|
|
186
|
+
# l = len(binary_blob)
|
|
187
|
+
# if (l % PADDING) != 0:
|
|
188
|
+
# rem = PADDING - (l % PADDING)
|
|
189
|
+
# binary_blob += "\x00" * rem
|
|
190
|
+
dtype = "Unknown"
|
|
191
|
+
for key, value in DATA_TYPES.iteritems():
|
|
192
|
+
if value == self.data.dtype:
|
|
193
|
+
dtype = key
|
|
194
|
+
binary_block = [
|
|
195
|
+
"--CIF-BINARY-FORMAT-SECTION--",
|
|
196
|
+
"Content-Type: application/octet-stream;",
|
|
197
|
+
' conversions="x-CBF_BYTE_OFFSET"',
|
|
198
|
+
'Content-Transfer-Encoding: BINARY',
|
|
199
|
+
"X-Binary-Size: %d" % (len(binary_blob)),
|
|
200
|
+
"X-Binary-ID: 1",
|
|
201
|
+
'X-Binary-Element-Type: "%s"' % (dtype),
|
|
202
|
+
"X-Binary-Element-Byte-Order: LITTLE_ENDIAN" ,
|
|
203
|
+
"Content-MD5: %s" % md5sum(binary_blob),
|
|
204
|
+
"X-Binary-Number-of-Elements: %s" % (self.dim1 * self.dim2),
|
|
205
|
+
"X-Binary-Size-Fastest-Dimension: %d" % self.dim1,
|
|
206
|
+
"X-Binary-Size-Second-Dimension: %d" % self.dim2,
|
|
207
|
+
"X-Binary-Size-Padding: %d" % 1,
|
|
208
|
+
"",
|
|
209
|
+
STARTER + binary_blob,
|
|
210
|
+
"",
|
|
211
|
+
"--CIF-BINARY-FORMAT-SECTION----"
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
if "_array_data.header_contents" not in self.header:
|
|
215
|
+
nonCifHeaders = []
|
|
216
|
+
else:
|
|
217
|
+
nonCifHeaders = [i.strip()[2:] for i in self.header["_array_data.header_contents"].split("\n") if i.find("# ") >= 0]
|
|
218
|
+
|
|
219
|
+
for key in self.header:
|
|
220
|
+
if (key not in self.header_keys):
|
|
221
|
+
self.header_keys.append(key)
|
|
222
|
+
for key in self.header_keys:
|
|
223
|
+
if key.startswith("_") :
|
|
224
|
+
if key not in self.cif or self.cif[key] != self.header[key]:
|
|
225
|
+
self.cif[key] = self.header[key]
|
|
226
|
+
elif key.startswith("X-Binary-"):
|
|
227
|
+
pass
|
|
228
|
+
elif key.startswith("Content-"):
|
|
229
|
+
pass
|
|
230
|
+
elif key.startswith("conversions"):
|
|
231
|
+
pass
|
|
232
|
+
elif key.startswith("filename"):
|
|
233
|
+
pass
|
|
234
|
+
elif key in self.header:
|
|
235
|
+
nonCifHeaders.append("%s %s" % (key, self.header[key]))
|
|
236
|
+
if len(nonCifHeaders) > 0:
|
|
237
|
+
self.cif["_array_data.header_contents"] = "\r\n".join(["# %s" % i for i in nonCifHeaders])
|
|
238
|
+
|
|
239
|
+
self.cif["_array_data.data"] = "\r\n".join(binary_block)
|
|
240
|
+
self.cif.saveCIF(fname, linesep="\r\n", binary=True)
|
|
241
|
+
|
|
242
|
+
################################################################################
|
|
243
|
+
# CIF class
|
|
244
|
+
################################################################################
|
|
245
|
+
class CIF(dict):
|
|
246
|
+
"""
|
|
247
|
+
This is the CIF class, it represents the CIF dictionary;
|
|
248
|
+
and as a a python dictionary thus inherits from the dict built in class.
|
|
249
|
+
"""
|
|
250
|
+
EOL = ["\r", "\n", "\r\n", "\n\r"]
|
|
251
|
+
BLANK = [" ", "\t"] + EOL
|
|
252
|
+
START_COMMENT = ["\"", "\'"]
|
|
253
|
+
BINARY_MARKER = "--CIF-BINARY-FORMAT-SECTION--"
|
|
254
|
+
|
|
255
|
+
def __init__(self, _strFilename=None):
|
|
256
|
+
"""
|
|
257
|
+
Constructor of the class.
|
|
258
|
+
|
|
259
|
+
@param _strFilename: the name of the file to open
|
|
260
|
+
@type _strFilename: filename (str) or file object
|
|
261
|
+
"""
|
|
262
|
+
dict.__init__(self)
|
|
263
|
+
self._ordered = []
|
|
264
|
+
if _strFilename is not None: #load the file)
|
|
265
|
+
self.loadCIF(_strFilename)
|
|
266
|
+
|
|
267
|
+
def __setitem__(self, key, value):
|
|
268
|
+
if key not in self._ordered:
|
|
269
|
+
self._ordered.append(key)
|
|
270
|
+
return dict.__setitem__(self, key, value)
|
|
271
|
+
|
|
272
|
+
def pop(self, key):
|
|
273
|
+
if key in self._ordered:
|
|
274
|
+
self._ordered.remove(key)
|
|
275
|
+
return dict.pop(self, key)
|
|
276
|
+
|
|
277
|
+
def popitem(self, key):
|
|
278
|
+
if key in self._ordered:
|
|
279
|
+
self._ordered.remove(key)
|
|
280
|
+
return dict.popitem(self, key)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def loadCIF(self, _strFilename, _bKeepComment=False):
|
|
284
|
+
"""Load the CIF file and populates the CIF dictionary into the object
|
|
285
|
+
@param _strFilename: the name of the file to open
|
|
286
|
+
@type _strFilename: string
|
|
287
|
+
@param _strFilename: the name of the file to open
|
|
288
|
+
@type _strFilename: string
|
|
289
|
+
@return: None
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
if isinstance(_strFilename, (str, unicode)):
|
|
293
|
+
if os.path.isfile(_strFilename):
|
|
294
|
+
infile = open(_strFilename, "rb")
|
|
295
|
+
else:
|
|
296
|
+
raise RuntimeError("CIF.loadCIF: No such file to open: %s" % _strFilename)
|
|
297
|
+
#elif isinstance(_strFilename, file, bz2.BZ2File, ):
|
|
298
|
+
elif "read" in dir(_strFilename):
|
|
299
|
+
infile = _strFilename
|
|
300
|
+
else:
|
|
301
|
+
raise RuntimeError("CIF.loadCIF: what is %s type %s" % (_strFilename, type(_strFilename)))
|
|
302
|
+
if _bKeepComment:
|
|
303
|
+
self._parseCIF(infile.read())
|
|
304
|
+
else:
|
|
305
|
+
self._parseCIF(CIF._readCIF(infile))
|
|
306
|
+
readCIF = loadCIF
|
|
307
|
+
|
|
308
|
+
@staticmethod
|
|
309
|
+
def isAscii(_strIn):
|
|
310
|
+
"""
|
|
311
|
+
Check if all characters in a string are ascii,
|
|
312
|
+
|
|
313
|
+
@param _strIn: input string
|
|
314
|
+
@type _strIn: python string
|
|
315
|
+
@return: boolean
|
|
316
|
+
@rtype: boolean
|
|
317
|
+
"""
|
|
318
|
+
bIsAcii = True
|
|
319
|
+
for i in _strIn:
|
|
320
|
+
if ord(i) > 127:
|
|
321
|
+
bIsAcii = False
|
|
322
|
+
break
|
|
323
|
+
return bIsAcii
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
@staticmethod
|
|
327
|
+
def _readCIF(_instream):
|
|
328
|
+
"""
|
|
329
|
+
- Check if the filename containing the CIF data exists
|
|
330
|
+
- read the cif file
|
|
331
|
+
- removes the comments
|
|
332
|
+
|
|
333
|
+
@param _instream: the file containing the CIF data
|
|
334
|
+
@type _instream: open file in read mode
|
|
335
|
+
@return: a string containing the raw data
|
|
336
|
+
@rtype: string
|
|
337
|
+
"""
|
|
338
|
+
if not "readlines" in dir(_instream):
|
|
339
|
+
raise RuntimeError("CIF._readCIF(instream): I expected instream to be an opened file,\
|
|
340
|
+
here I got %s type %s" % (_instream, type(_instream)))
|
|
341
|
+
lLinesRead = _instream.readlines()
|
|
342
|
+
sText = ""
|
|
343
|
+
for sLine in lLinesRead:
|
|
344
|
+
iPos = sLine.find("#")
|
|
345
|
+
if iPos >= 0:
|
|
346
|
+
if CIF.isAscii(sLine):
|
|
347
|
+
sText += sLine[:iPos] + os.linesep
|
|
348
|
+
|
|
349
|
+
if iPos > 80 :
|
|
350
|
+
logger.warning("This line is too long and could cause problems in PreQuest: %s", sLine)
|
|
351
|
+
else :
|
|
352
|
+
sText += sLine
|
|
353
|
+
if len(sLine.strip()) > 80 :
|
|
354
|
+
logger.warning("This line is too long and could cause problems in PreQues: %s", sLine)
|
|
355
|
+
return sText
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _parseCIF(self, sText):
|
|
359
|
+
"""
|
|
360
|
+
- Parses the text of a CIF file
|
|
361
|
+
- Cut it in fields
|
|
362
|
+
- Find all the loops and process
|
|
363
|
+
- Find all the keys and values
|
|
364
|
+
|
|
365
|
+
@param sText: the content of the CIF - file
|
|
366
|
+
@type sText: string
|
|
367
|
+
@return: Nothing, the data are incorporated at the CIF object dictionary
|
|
368
|
+
@rtype: None
|
|
369
|
+
"""
|
|
370
|
+
loopidx = []
|
|
371
|
+
looplen = []
|
|
372
|
+
loop = []
|
|
373
|
+
#first of all : separate the cif file in fields
|
|
374
|
+
lFields = CIF._splitCIF(sText.strip())
|
|
375
|
+
#Then : look for loops
|
|
376
|
+
for i in range(len(lFields)):
|
|
377
|
+
if lFields[i].lower() == "loop_":
|
|
378
|
+
loopidx.append(i)
|
|
379
|
+
if len(loopidx) > 0:
|
|
380
|
+
for i in loopidx:
|
|
381
|
+
loopone, length, keys = CIF._analyseOneLoop(lFields, i)
|
|
382
|
+
loop.append([keys, loopone])
|
|
383
|
+
looplen.append(length)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
for i in range(len(loopidx) - 1, -1, -1):
|
|
387
|
+
f1 = lFields[:loopidx[i]] + lFields[loopidx[i] + looplen[i]:]
|
|
388
|
+
lFields = f1
|
|
389
|
+
|
|
390
|
+
self["loop_"] = loop
|
|
391
|
+
|
|
392
|
+
for i in range(len(lFields) - 1):
|
|
393
|
+
# print lFields[i], lFields[i+1]
|
|
394
|
+
if len(lFields[i + 1]) == 0 : lFields[i + 1] = "?"
|
|
395
|
+
if lFields[i][0] == "_" and lFields[i + 1][0] != "_":
|
|
396
|
+
self[lFields[i]] = lFields[i + 1]
|
|
397
|
+
|
|
398
|
+
@staticmethod
|
|
399
|
+
def _splitCIF(sText):
|
|
400
|
+
"""
|
|
401
|
+
Separate the text in fields as defined in the CIF
|
|
402
|
+
|
|
403
|
+
@param sText: the content of the CIF - file
|
|
404
|
+
@type sText: string
|
|
405
|
+
@return: list of all the fields of the CIF
|
|
406
|
+
@rtype: list
|
|
407
|
+
"""
|
|
408
|
+
lFields = []
|
|
409
|
+
while True:
|
|
410
|
+
if len(sText) == 0:
|
|
411
|
+
break
|
|
412
|
+
elif sText[0] == "'":
|
|
413
|
+
idx = 0
|
|
414
|
+
bFinished = False
|
|
415
|
+
while not bFinished:
|
|
416
|
+
idx += 1 + sText[idx + 1:].find("'")
|
|
417
|
+
##########debuging in case we arrive at the end of the text
|
|
418
|
+
if idx >= len(sText) - 1:
|
|
419
|
+
# print sText,idx,len(sText)
|
|
420
|
+
lFields.append(sText[1:-1].strip())
|
|
421
|
+
sText = ""
|
|
422
|
+
bFinished = True
|
|
423
|
+
break
|
|
424
|
+
|
|
425
|
+
if sText[idx + 1] in CIF.BLANK:
|
|
426
|
+
lFields.append(sText[1:idx].strip())
|
|
427
|
+
sText1 = sText[idx + 1:]
|
|
428
|
+
sText = sText1.strip()
|
|
429
|
+
bFinished = True
|
|
430
|
+
|
|
431
|
+
elif sText[0] == '"':
|
|
432
|
+
idx = 0
|
|
433
|
+
bFinished = False
|
|
434
|
+
while not bFinished:
|
|
435
|
+
idx += 1 + sText[idx + 1:].find('"')
|
|
436
|
+
##########debuging in case we arrive at the end of the text
|
|
437
|
+
if idx >= len(sText) - 1:
|
|
438
|
+
# print sText,idx,len(sText)
|
|
439
|
+
lFields.append(sText[1:-1].strip())
|
|
440
|
+
# print lFields[-1]
|
|
441
|
+
sText = ""
|
|
442
|
+
bFinished = True
|
|
443
|
+
break
|
|
444
|
+
|
|
445
|
+
if sText[idx + 1] in CIF.BLANK:
|
|
446
|
+
lFields.append(sText[1:idx].strip())
|
|
447
|
+
# print lFields[-1]
|
|
448
|
+
sText1 = sText[idx + 1:]
|
|
449
|
+
sText = sText1.strip()
|
|
450
|
+
bFinished = True
|
|
451
|
+
elif sText[0] == ';':
|
|
452
|
+
if sText[1:].strip().find(CIF.BINARY_MARKER) == 0:
|
|
453
|
+
idx = sText[32:].find(CIF.BINARY_MARKER)
|
|
454
|
+
if idx == -1:
|
|
455
|
+
idx = 0
|
|
456
|
+
else:
|
|
457
|
+
idx += 32 + len(CIF.BINARY_MARKER)
|
|
458
|
+
else:
|
|
459
|
+
idx = 0
|
|
460
|
+
bFinished = False
|
|
461
|
+
while not bFinished:
|
|
462
|
+
idx += 1 + sText[idx + 1:].find(';')
|
|
463
|
+
if sText[idx - 1] in CIF.EOL:
|
|
464
|
+
lFields.append(sText[1:idx - 1].strip())
|
|
465
|
+
sText1 = sText[idx + 1:]
|
|
466
|
+
sText = sText1.strip()
|
|
467
|
+
bFinished = True
|
|
468
|
+
else:
|
|
469
|
+
f = sText.split(None, 1)[0]
|
|
470
|
+
lFields.append(f)
|
|
471
|
+
# print lFields[-1]
|
|
472
|
+
sText1 = sText[len(f):].strip()
|
|
473
|
+
sText = sText1
|
|
474
|
+
return lFields
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
@staticmethod
|
|
478
|
+
def _analyseOneLoop(lFields, iStart):
|
|
479
|
+
"""Processes one loop in the data extraction of the CIF file
|
|
480
|
+
@param lFields: list of all the words contained in the cif file
|
|
481
|
+
@type lFields: list
|
|
482
|
+
@param iStart: the starting index corresponding to the "loop_" key
|
|
483
|
+
@type iStart: integer
|
|
484
|
+
@return: the list of loop dictionaries, the length of the data
|
|
485
|
+
extracted from the lFields and the list of all the keys of the loop.
|
|
486
|
+
@rtype: tuple
|
|
487
|
+
"""
|
|
488
|
+
# in earch loop we first search the length of the loop
|
|
489
|
+
# print lFields
|
|
490
|
+
# curloop = {}
|
|
491
|
+
loop = []
|
|
492
|
+
keys = []
|
|
493
|
+
i = iStart + 1
|
|
494
|
+
bFinished = False
|
|
495
|
+
while not bFinished:
|
|
496
|
+
if lFields[i][0] == "_":
|
|
497
|
+
keys.append(lFields[i])#.lower())
|
|
498
|
+
i += 1
|
|
499
|
+
else:
|
|
500
|
+
bFinished = True
|
|
501
|
+
data = []
|
|
502
|
+
while True:
|
|
503
|
+
if i >= len(lFields):
|
|
504
|
+
break
|
|
505
|
+
elif len(lFields[i]) == 0:
|
|
506
|
+
break
|
|
507
|
+
elif lFields[i][0] == "_":
|
|
508
|
+
break
|
|
509
|
+
elif lFields[i] in ["loop_", "stop_", "global_", "data_", "save_"]:
|
|
510
|
+
break
|
|
511
|
+
else:
|
|
512
|
+
data.append(lFields[i])
|
|
513
|
+
i += 1
|
|
514
|
+
#print len(keys), len(data)
|
|
515
|
+
k = 0
|
|
516
|
+
|
|
517
|
+
if len(data) < len(keys):
|
|
518
|
+
element = {}
|
|
519
|
+
for j in keys:
|
|
520
|
+
if k < len(data):
|
|
521
|
+
element[j] = data[k]
|
|
522
|
+
else :
|
|
523
|
+
element[j] = "?"
|
|
524
|
+
k += 1
|
|
525
|
+
#print element
|
|
526
|
+
loop.append(element)
|
|
527
|
+
|
|
528
|
+
else:
|
|
529
|
+
#print data
|
|
530
|
+
#print keys
|
|
531
|
+
for i in range(len(data) / len(keys)):
|
|
532
|
+
element = {}
|
|
533
|
+
for j in keys:
|
|
534
|
+
element[j] = data[k]
|
|
535
|
+
k += 1
|
|
536
|
+
# print element
|
|
537
|
+
loop.append(element)
|
|
538
|
+
# print loop
|
|
539
|
+
return loop, 1 + len(keys) + len(data), keys
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
#############################################################################################
|
|
547
|
+
######## everything needed to write a cif file #########################################
|
|
548
|
+
#############################################################################################
|
|
549
|
+
|
|
550
|
+
def saveCIF(self, _strFilename="test.cif", linesep=os.linesep, binary=False):
|
|
551
|
+
"""Transforms the CIF object in string then write it into the given file
|
|
552
|
+
@param _strFilename: the of the file to be written
|
|
553
|
+
@param linesep: line separation used (to force compatibility with windows/unix)
|
|
554
|
+
@param binary: Shall we write the data as binary (True only for imageCIF/CBF)
|
|
555
|
+
@type param: string
|
|
556
|
+
"""
|
|
557
|
+
if binary:
|
|
558
|
+
mode = "wb"
|
|
559
|
+
else:
|
|
560
|
+
mode = "w"
|
|
561
|
+
try:
|
|
562
|
+
fFile = open(_strFilename, mode)
|
|
563
|
+
except IOError:
|
|
564
|
+
print("Error during the opening of file for write: %s" %
|
|
565
|
+
_strFilename)
|
|
566
|
+
return
|
|
567
|
+
fFile.write(self.tostring(_strFilename, linesep))
|
|
568
|
+
try:
|
|
569
|
+
fFile.close()
|
|
570
|
+
except IOError:
|
|
571
|
+
print("Error during the closing of file for write: %s" %
|
|
572
|
+
_strFilename)
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def tostring(self, _strFilename=None, linesep=os.linesep):
|
|
576
|
+
"""converts a cif dictionnary to a string according to the CIF syntax
|
|
577
|
+
@param _strFilename: the name of the filename to be appended in the
|
|
578
|
+
header of the CIF file
|
|
579
|
+
@type _strFilename: string
|
|
580
|
+
@return : a sting that corresponds to the content of the CIF - file.
|
|
581
|
+
@rtype: string
|
|
582
|
+
"""
|
|
583
|
+
# sCifText = ""
|
|
584
|
+
lstStrCif = ["# " + i for i in __version__]
|
|
585
|
+
if "_chemical_name_common" in self:
|
|
586
|
+
t = self["_chemical_name_common"].split()[0]
|
|
587
|
+
elif _strFilename is not None:
|
|
588
|
+
t = os.path.splitext(os.path.split(str(_strFilename).strip())[1])[0]
|
|
589
|
+
else:
|
|
590
|
+
t = ""
|
|
591
|
+
lstStrCif.append("data_%s" % (t))
|
|
592
|
+
#first of all get all the keys :
|
|
593
|
+
lKeys = self.keys()
|
|
594
|
+
lKeys.sort()
|
|
595
|
+
for key in lKeys[:]:
|
|
596
|
+
if key in self._ordered:
|
|
597
|
+
lKeys.remove(key)
|
|
598
|
+
self._ordered += lKeys
|
|
599
|
+
|
|
600
|
+
for sKey in self._ordered:
|
|
601
|
+
if sKey == "loop_":
|
|
602
|
+
continue
|
|
603
|
+
if sKey not in self:
|
|
604
|
+
self._ordered.remove(sKey)
|
|
605
|
+
logger.debug("Skipping key %s from ordered list as no more present in dict")
|
|
606
|
+
continue
|
|
607
|
+
sValue = str(self[sKey])
|
|
608
|
+
if sValue.find("\n") > -1: #should add value between ;;
|
|
609
|
+
lLine = [sKey, ";", sValue, ";", ""]
|
|
610
|
+
elif len(sValue.split()) > 1: #should add value between ''
|
|
611
|
+
sLine = "%s '%s'" % (sKey, sValue)
|
|
612
|
+
if len(sLine) > 80:
|
|
613
|
+
lLine = [str(sKey), sValue]
|
|
614
|
+
else:
|
|
615
|
+
lLine = [sLine]
|
|
616
|
+
else:
|
|
617
|
+
sLine = "%s %s" % (sKey, sValue)
|
|
618
|
+
if len(sLine) > 80:
|
|
619
|
+
lLine = [str(sKey), sValue]
|
|
620
|
+
else:
|
|
621
|
+
lLine = [sLine]
|
|
622
|
+
lstStrCif += lLine
|
|
623
|
+
if self.has_key("loop_"):
|
|
624
|
+
for loop in self["loop_"]:
|
|
625
|
+
lstStrCif.append("loop_ ")
|
|
626
|
+
lKeys = loop[0]
|
|
627
|
+
llData = loop[1]
|
|
628
|
+
lstStrCif += [" %s" % (sKey) for sKey in lKeys]
|
|
629
|
+
for lData in llData:
|
|
630
|
+
sLine = " "
|
|
631
|
+
for key in lKeys:
|
|
632
|
+
sRawValue = lData[key]
|
|
633
|
+
if sRawValue.find("\n") > -1: #should add value between ;;
|
|
634
|
+
lstStrCif += [sLine, ";", str(sRawValue), ";"]
|
|
635
|
+
sLine = " "
|
|
636
|
+
else:
|
|
637
|
+
if len(sRawValue.split()) > 1: #should add value between ''
|
|
638
|
+
value = "'%s'" % (sRawValue)
|
|
639
|
+
else:
|
|
640
|
+
value = str(sRawValue)
|
|
641
|
+
if len(sLine) + len(value) > 78:
|
|
642
|
+
lstStrCif += [sLine]
|
|
643
|
+
sLine = " " + value
|
|
644
|
+
else:
|
|
645
|
+
sLine += " " + value
|
|
646
|
+
lstStrCif.append(sLine)
|
|
647
|
+
lstStrCif.append("")
|
|
648
|
+
return linesep.join(lstStrCif)
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def exists(self, sKey):
|
|
652
|
+
"""
|
|
653
|
+
Check if the key exists in the CIF and is non empty.
|
|
654
|
+
@param sKey: CIF key
|
|
655
|
+
@type sKey: string
|
|
656
|
+
@param cif: CIF dictionary
|
|
657
|
+
@return: True if the key exists in the CIF dictionary and is non empty
|
|
658
|
+
@rtype: boolean
|
|
659
|
+
"""
|
|
660
|
+
bExists = False
|
|
661
|
+
if self.has_key(sKey):
|
|
662
|
+
if len(self[sKey]) >= 1:
|
|
663
|
+
if self[sKey][0] not in ["?", "."]:
|
|
664
|
+
bExists = True
|
|
665
|
+
return bExists
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
def existsInLoop(self, sKey):
|
|
669
|
+
"""
|
|
670
|
+
Check if the key exists in the CIF dictionary.
|
|
671
|
+
@param sKey: CIF key
|
|
672
|
+
@type sKey: string
|
|
673
|
+
@param cif: CIF dictionary
|
|
674
|
+
@return: True if the key exists in the CIF dictionary and is non empty
|
|
675
|
+
@rtype: boolean
|
|
676
|
+
"""
|
|
677
|
+
if not self.exists("loop_"):
|
|
678
|
+
return False
|
|
679
|
+
bExists = False
|
|
680
|
+
if not bExists:
|
|
681
|
+
for i in self["loop_"]:
|
|
682
|
+
for j in i[0]:
|
|
683
|
+
if j == sKey:
|
|
684
|
+
bExists = True
|
|
685
|
+
return bExists
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def loadCHIPLOT(self, _strFilename):
|
|
689
|
+
"""
|
|
690
|
+
Load the powder diffraction CHIPLOT file and returns the
|
|
691
|
+
pd_CIF dictionary in the object
|
|
692
|
+
|
|
693
|
+
@param _strFilename: the name of the file to open
|
|
694
|
+
@type _strFilename: string
|
|
695
|
+
@return: the CIF object corresponding to the powder diffraction
|
|
696
|
+
@rtype: dictionary
|
|
697
|
+
"""
|
|
698
|
+
if not os.path.isfile(_strFilename):
|
|
699
|
+
print "I cannot find the file %s" % _strFilename
|
|
700
|
+
raise
|
|
701
|
+
lInFile = open(_strFilename, "r").readlines()
|
|
702
|
+
self["_audit_creation_method"] = 'From 2-D detector using FIT2D and CIFfile'
|
|
703
|
+
self["_pd_meas_scan_method"] = "fixed"
|
|
704
|
+
self["_pd_spec_description"] = lInFile[0].strip()
|
|
705
|
+
try:
|
|
706
|
+
iLenData = int(lInFile[3])
|
|
707
|
+
except ValueError:
|
|
708
|
+
iLenData = None
|
|
709
|
+
lOneLoop = []
|
|
710
|
+
try:
|
|
711
|
+
f2ThetaMin = float(lInFile[4].split()[0])
|
|
712
|
+
last = ""
|
|
713
|
+
for sLine in lInFile[-20:]:
|
|
714
|
+
if sLine.strip() != "":
|
|
715
|
+
last = sLine.strip()
|
|
716
|
+
f2ThetaMax = float(last.split()[0])
|
|
717
|
+
limitsOK = True
|
|
718
|
+
|
|
719
|
+
except (ValueError, IndexError):
|
|
720
|
+
limitsOK = False
|
|
721
|
+
f2ThetaMin = 180.0
|
|
722
|
+
f2ThetaMax = 0
|
|
723
|
+
# print "limitsOK:", limitsOK
|
|
724
|
+
for sLine in lInFile[4:]:
|
|
725
|
+
sCleaned = sLine.split("#")[0].strip()
|
|
726
|
+
data = sCleaned.split()
|
|
727
|
+
if len(data) == 2 :
|
|
728
|
+
if not limitsOK:
|
|
729
|
+
f2Theta = float(data[0])
|
|
730
|
+
if f2Theta < f2ThetaMin :
|
|
731
|
+
f2ThetaMin = f2Theta
|
|
732
|
+
if f2Theta > f2ThetaMax :
|
|
733
|
+
f2ThetaMax = f2Theta
|
|
734
|
+
lOneLoop.append({ "_pd_meas_intensity_total": data[1] })
|
|
735
|
+
if not iLenData:
|
|
736
|
+
iLenData = len(lOneLoop)
|
|
737
|
+
assert (iLenData == len(lOneLoop))
|
|
738
|
+
self[ "_pd_meas_2theta_range_inc" ] = "%.4f" % ((f2ThetaMax - f2ThetaMin) / (iLenData - 1))
|
|
739
|
+
if self[ "_pd_meas_2theta_range_inc" ] < 0:
|
|
740
|
+
self[ "_pd_meas_2theta_range_inc" ] = abs (self[ "_pd_meas_2theta_range_inc" ])
|
|
741
|
+
tmp = f2ThetaMax
|
|
742
|
+
f2ThetaMax = f2ThetaMin
|
|
743
|
+
f2ThetaMin = tmp
|
|
744
|
+
self[ "_pd_meas_2theta_range_max" ] = "%.4f" % f2ThetaMax
|
|
745
|
+
self[ "_pd_meas_2theta_range_min" ] = "%.4f" % f2ThetaMin
|
|
746
|
+
self[ "_pd_meas_number_of_points" ] = str(iLenData)
|
|
747
|
+
self["loop_"] = [ [ ["_pd_meas_intensity_total" ], lOneLoop ] ]
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
@staticmethod
|
|
751
|
+
def LoopHasKey(loop, key):
|
|
752
|
+
"Returns True if the key (string) exist in the array called loop"""
|
|
753
|
+
try:
|
|
754
|
+
loop.index(key)
|
|
755
|
+
return True
|
|
756
|
+
except ValueError:
|
|
757
|
+
return False
|
|
758
|
+
|