1
2
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 - December 2010",
18 "Written by Jerome Kieffer: Jerome.Kieffer@esrf.eu",
19 "On-line data analysis / ISDD ", "ESRF Grenoble (France)"]
20
21
22 import os, logging, struct
23 import numpy as np
24 from fabioimage import fabioimage
25
26
27 DATA_TYPES = { "signed 8-bit integer" : np.int8,
28 "signed 16-bit integer" : np.int16,
29 "signed 32-bit integer" : np.int32
30 }
31
32 MINIMUM_KEYS = ["X-Binary-Size-Fastest-Dimension",
33 'ByteOrder',
34 'Data type',
35 'X dimension',
36 'Y dimension',
37 'Number of readouts']
38
39 DEFAULT_VALUES = {
40 "Data type": "signed 32-bit integer",
41 "X-Binary-Size-Fastest-Dimension": 2463,
42 "X-Binary-Element-Byte-Order": "LITTLE_ENDIAN"
43
44 }
50 """
51 Read the Cif Binary File data format
52 """
54 """
55 Constructor of the class CIF Binary File reader.
56
57 @param fname: the name of the file to open
58 @type fname: string
59 """
60 fabioimage.__init__(self)
61 self.cif = CIF()
62 if fname is not None:
63 self.read(fname)
64
65
67 """
68 Read in a header in some CBF format from a string representing binary stuff
69
70 @param inStream: file containing the Cif Binary part.
71 @type inStream: opened file.
72 """
73 self.cif.loadCIF(inStream, _bKeepComment=True)
74
75
76 for key in self.cif:
77 if key != "_array_data.data":
78 self.header_keys.append(key)
79 self.header[key] = self.cif[key].strip(" \"\n\r\t")
80
81 if not "_array_data.data" in self.cif:
82 raise Exception("cbfimage: CBF file %s is corrupt, cannot find data block with '_array_data.data' key" % self.fname)
83
84 inStream2 = self.cif["_array_data.data"]
85 sep = "\r\n"
86 iSepPos = inStream2.find(sep)
87 if iSepPos < 0 or iSepPos > 80:
88 sep = "\n"
89
90 lines = inStream2.split(sep)
91 for oneLine in lines[1:]:
92 if len(oneLine) < 10:
93 break
94 try:
95 key, val = oneLine.split(':' , 1)
96 except ValueError:
97 key, val = oneLine.split('=' , 1)
98 key = key.strip()
99 self.header_keys.append(key)
100 self.header[key] = val.strip(" \"\n\r\t")
101 missing = []
102 for item in MINIMUM_KEYS:
103 if item not in self.header_keys:
104 missing.append(item)
105 if len(missing) > 0:
106 logging.debug("CBF file misses the keys " + " ".join(missing))
107
108
109 - def read(self, fname):
110 """
111 Read in header into self.header and
112 the data into self.data
113 """
114 self.filename = fname
115 self.header = {}
116 self.resetvals()
117
118 infile = self._open(fname, "rb")
119 self._readheader(infile)
120
121 try:
122 self.dim1 = int(self.header['X-Binary-Size-Fastest-Dimension'])
123 self.dim2 = int(self.header['X-Binary-Size-Second-Dimension'])
124 except:
125 raise Exception(IOError, "CBF file %s is corrupt, no dimensions in it" % fname)
126 try:
127 bytecode = DATA_TYPES[self.header['X-Binary-Element-Type']]
128 self.bpp = len(np.array(0, bytecode).tostring())
129 except KeyError:
130 bytecode = np.int32
131 self.bpp = 32
132 logging.warning("Defaulting type to int32")
133 if self.header["conversions"] == "x-CBF_BYTE_OFFSET":
134 self.data = self._readbinary_byte_offset(self.cif["_array_data.data"]).astype(bytecode).reshape((self.dim2, self.dim1))
135 else:
136 raise Exception(IOError, "Compression scheme not yet supported, please contact FABIO development team")
137
138 self.bytecode = self.data.dtype.type
139 self.resetvals()
140
141 self.pilimage = None
142 return self
143
144
145
146 @staticmethod
148 """
149 Analyze a stream of char with any length of exception (2,4, or 8 bytes integers)
150 @param stream: string representing the compressed data
151 @param size: the size of the output array (of longInts)
152 @return: data decompressed
153 @rtype: numpy.ndarrays
154 """
155
156
157
158
159
160 logging.debug("CBF decompression using Python with Cython loops")
161 dataOut = np.zeros((size), dtype=np.int64)
162 i = 0
163 j = 0
164 last = 0
165 current = 0
166 while ((i < len(stream)) and (j < size)):
167 if (stream[i] == '\x80'):
168 if (stream[i + 1:i + 3] == "\x00\x80"):
169 if (stream[i + 3:i + 7] == "\x00\x00\x00\x80"):
170 current = struct.unpack("<q", stream[i + 7:i + 15])[0]
171 i += 15
172 else:
173 current = struct.unpack("<i", stream[i + 3:i + 7])[0]
174 i += 7
175 else:
176 current = struct.unpack("<h", stream[i + 1:i + 3])[0]
177 i += 3
178 else:
179 current = struct.unpack("<b", stream[i])[0]
180 i += 1
181 last += current
182 dataOut[j] = last
183 j += 1
184 return dataOut
185
186 @staticmethod
188 """
189 Analyze a stream of char with any length of exception (2,4, or 8 bytes integers)
190
191 @return: data decompressed
192 @rtype: numpy.ndarray
193 """
194 logging.debug("CBF decompression using Weave")
195 from scipy import weave
196 from scipy.weave import converters
197 dataIn = np.fromstring(stream, dtype="uint8")
198 n = dataIn.size
199 dataOut = np.zeros(size, dtype="int64")
200 codeC = """
201 unsigned char key = 0x80;
202 long j = 0;
203 long last=0;
204 long current=0;
205 for (int i=0; i< n; i++){
206 if (j>=size){
207 //printf("i= %i<%i, j=%i < size= %i %i\\n",i,n,j,size,dataIn(i));
208 break;
209 }
210 if (dataIn(i) == key){
211 if ( (dataIn(i+1)==0) and (dataIn(i+2)==key) ){
212 if ( (dataIn(i+3)==0) and (dataIn(i+4)==0) and (dataIn(i+5)==0) and (dataIn(i+6)==key) ) {
213 // 64 bits mode
214 char tmp = dataIn(i+14) ;
215 current = (long(tmp)<<56) | (long(dataIn(i+13))<<48) | (long(dataIn(i+12))<<40) | (long(dataIn(i+11))<<32) | (long(dataIn(i+10))<<24) | (long(dataIn(i+9))<<16) | (long(dataIn(i+8))<<8) | (long(dataIn(i+7)));
216 // printf("64 bit int at pos %i, %i, value=%ld \\n",i,j,current);
217 i+=14;
218 }else{
219 // 32 bits mode
220 char tmp = dataIn(i+6) ;
221 current = (long(tmp)<<24) | (long(dataIn(i+5))<<16) | (long(dataIn(i+4))<<8) | (long(dataIn(i+3)));
222 // printf("32 bit int at pos %i, %i, value=%ld was %i %i %i %i %i %i %i\\n",i,j,current,dataIn(i),dataIn(i+1),dataIn(i+2),dataIn(i+3),dataIn(i+4),dataIn(i+5),dataIn(i+6));
223 // printf("%ld %ld %ld %ld\\n",(long(tmp)<<24) , (long(dataIn(i+5))<<16) , (long(dataIn(i+4))<<8) ,long(dataIn(i+3)));
224 i+=6;
225 }
226 }else{
227 // 16 bit mode
228 char tmp = dataIn(i+2);
229 current = (long(tmp)<<8) | (long (dataIn(i+1)));
230 // printf("16 bit int at pos %i, %i, value=%ld was %i %i %i\\n",i,j,current,dataIn(i),dataIn(i+1),dataIn(i+2));
231 i+=2;
232 }
233 }else{
234 // 8 bit mode
235 char tmp = dataIn(i) ;
236 current= long(tmp) ;
237 }
238 last+=current;
239 dataOut(j)=last;
240 j++ ;
241 }
242 return_val=0;
243 """
244 rc = weave.inline(codeC, ["dataIn", "dataOut", "n", "size" ], verbose=2, type_converters=converters.blitz)
245 return dataOut
246
247
248 @staticmethod
250 """
251 Analyze a stream of char with any length of exception:
252 2, 4, or 8 bytes integers
253
254 @return: data decompressed
255 @rtype: numpy.ndarrays
256 """
257 logging.debug("CBF decompression using Numpy")
258 listnpa = []
259 key16 = "\x80"
260 key32 = "\x00\x80"
261 key64 = "\x00\x00\x00\x80"
262 shift = 1
263 while True:
264 idx = stream.find(key16)
265 if idx == -1:
266 listnpa.append(np.fromstring(stream, dtype="int8"))
267 break
268 listnpa.append(np.fromstring(stream[:idx], dtype="int8"))
269
270 if stream[idx + 1:idx + 3] == key32:
271 if stream[idx + 3:idx + 7] == key64:
272
273 listnpa.append(np.fromstring(stream[idx + 7:idx + 15],
274 dtype="int64"))
275 shift = 15
276 else:
277 listnpa.append(np.fromstring(stream[idx + 3:idx + 7],
278 dtype="int32"))
279 shift = 7
280 else:
281 listnpa.append(np.fromstring(stream[idx + 1:idx + 3],
282 dtype="int16"))
283 shift = 3
284 stream = stream[idx + shift:]
285 return (np.hstack(listnpa)).astype("int64").cumsum()
286
287
289 """
290 Read in a binary part of an x-CBF_BYTE_OFFSET compressed image
291
292 @param inStream: the binary image (without any CIF decorators)
293 @type inStream: python string.
294 @return: a linear numpy array without shape and dtype set
295 @rtype: numpy array
296 """
297
298 starter = "\x0c\x1a\x04\xd5"
299 startPos = inStream.find(starter) + 4
300 data = inStream[ startPos: startPos + int(self.header["X-Binary-Size"])]
301 try:
302 import byte_offset
303 except ImportError:
304 logging.warning("Error in byte_offset part: Falling back to Numpy implementation")
305 myData = cbfimage.analyseNumpy(data, size=self.dim1 * self.dim2)
306 else:
307 myData = byte_offset.analyseCython(data, size=self.dim1 * self.dim2)
308
309 assert len(myData) == self.dim1 * self.dim2
310 return myData
311
312
313
314
315
316
317 -class CIF(dict):
318 """
319 This is the CIF class, it represents the CIF dictionary;
320 and as a a python dictionary thus inherits from the dict built in class.
321 """
322 EOL = ["\r", "\n", "\r\n", "\n\r"]
323 BLANK = [" ", "\t"] + EOL
324 START_COMMENT = ["\"", "\'"]
325 BINARY_MARKER = "--CIF-BINARY-FORMAT-SECTION--"
326
328 """
329 Constructor of the class.
330
331 @param _strFilename: the name of the file to open
332 @type _strFilename: filename (str) or file object
333 """
334 dict.__init__(self)
335 if _strFilename is not None:
336 self.loadCIF(_strFilename)
337
339 """
340 Just call loadCIF:
341 Load the CIF file and sets the CIF dictionnary into the object
342
343 @param _strFilename: the name of the file to open
344 @type _strFilename: string
345 """
346 self.loadCIF(_strFilename)
347
348 - def loadCIF(self, _strFilename, _bKeepComment=False):
349 """Load the CIF file and returns the CIF dictionnary into the object
350 @param _strFilename: the name of the file to open
351 @type _strFilename: string
352 @param _bKeepComment: shall we remove comments
353 @type _bKeepComment: boolean
354 @return: None
355 """
356
357 if isinstance(_strFilename, (str, unicode)):
358 if os.path.isfile(_strFilename):
359 infile = open(_strFilename, "rb")
360 else:
361 raise RuntimeError("CIF.loadCIF: No such file to open: %s" % _strFilename)
362
363 elif "read" in dir(_strFilename):
364 infile = _strFilename
365 else:
366 raise RuntimeError("CIF.loadCIF: what is %s type %s" % (_strFilename, type(_strFilename)))
367 if _bKeepComment:
368 self._parseCIF(infile.read())
369 else:
370 self._parseCIF(CIF._readCIF(infile))
371
372
373 @staticmethod
375 """
376 Check if all characters in a string are ascii,
377
378 @param _strIn: input string
379 @type _strIn: python string
380 @return: boolean
381 @rtype: boolean
382 """
383 bIsAcii = True
384 for i in _strIn:
385 if ord(i) > 127:
386 bIsAcii = False
387 break
388 return bIsAcii
389
390
391 @staticmethod
393 """
394 -Check if the filename containing the CIF data exists
395 -read the cif file
396 -removes the comments
397
398 @param _instream: the file containing the CIF data
399 @type _instream: open file in read mode
400 @return: a string containing the raw data
401 @rtype: string
402 """
403 if not "readlines" in dir(_instream):
404 raise RuntimeError("CIF._readCIF(instream): I expected instream to be an opened file,\
405 here I got %s type %s" % (_instream, type(_instream)))
406 lLinesRead = _instream.readlines()
407 sText = ""
408 for sLine in lLinesRead:
409 iPos = sLine.find("#")
410 if iPos >= 0:
411 if CIF.isAscii(sLine):
412 sText += sLine[:iPos] + os.linesep
413
414 if iPos > 80 :
415 print("Warning, this line is too long and could cause problems in PreQuest", os.linesep, sLine)
416 else :
417 sText += sLine
418 if len(sLine.strip()) > 80 :
419 print("Warning, this line is too long and could cause problems in PreQues", os.linesep, sLine)
420 return sText
421
422
424 """
425 -Parses the text of a CIF file
426 -Cut it in fields
427 -Find all the loops and process
428 -Find all the keys and values
429
430 @param sText: the content of the CIF-file
431 @type sText: string
432 @return: Nothing, the data are incorporated at the CIF object dictionary
433 @rtype: dictionary
434 """
435 loopidx = []
436 looplen = []
437 loop = []
438
439 lFields = CIF._splitCIF(sText.strip())
440
441 for i in range(len(lFields)):
442 if lFields[i].lower() == "loop_":
443 loopidx.append(i)
444 if len(loopidx) > 0:
445 for i in loopidx:
446 loopone, length, keys = CIF._analyseOneLoop(lFields, i)
447 loop.append([keys, loopone])
448 looplen.append(length)
449
450
451 for i in range(len(loopidx) - 1, -1, -1):
452 f1 = lFields[:loopidx[i]] + lFields[loopidx[i] + looplen[i]:]
453 lFields = f1
454
455 self["loop_"] = loop
456
457 for i in range(len(lFields) - 1):
458
459 if len(lFields[i + 1]) == 0 : lFields[i + 1] = "?"
460 if lFields[i][0] == "_" and lFields[i + 1][0] != "_":
461 self[lFields[i]] = lFields[i + 1]
462
463
464 @staticmethod
466 """
467 Separate the text in fields as defined in the CIF
468
469 @param sText: the content of the CIF-file
470 @type sText: string
471 @return: list of all the fields of the CIF
472 @rtype: list
473 """
474 lFields = []
475 while True:
476 if len(sText) == 0:
477 break
478 elif sText[0] == "'":
479 idx = 0
480 bFinished = False
481 while not bFinished:
482 idx += 1 + sText[idx + 1:].find("'")
483
484 if idx >= len(sText) - 1:
485
486 lFields.append(sText[1:-1].strip())
487 sText = ""
488 bFinished = True
489 break
490
491 if sText[idx + 1] in CIF.BLANK:
492 lFields.append(sText[1:idx].strip())
493 sText1 = sText[idx + 1:]
494 sText = sText1.strip()
495 bFinished = True
496
497 elif sText[0] == '"':
498 idx = 0
499 bFinished = False
500 while not bFinished:
501 idx += 1 + sText[idx + 1:].find('"')
502
503 if idx >= len(sText) - 1:
504
505 lFields.append(sText[1:-1].strip())
506
507 sText = ""
508 bFinished = True
509 break
510
511 if sText[idx + 1] in CIF.BLANK:
512 lFields.append(sText[1:idx].strip())
513
514 sText1 = sText[idx + 1:]
515 sText = sText1.strip()
516 bFinished = True
517 elif sText[0] == ';':
518 if sText[1:].strip().find(CIF.BINARY_MARKER) == 0:
519 idx = sText[32:].find(CIF.BINARY_MARKER)
520 if idx == -1:
521 idx = 0
522 else:
523 idx += 32 + len(CIF.BINARY_MARKER)
524 else:
525 idx = 0
526 bFinished = False
527 while not bFinished:
528 idx += 1 + sText[idx + 1:].find(';')
529 if sText[idx - 1] in CIF.EOL:
530 lFields.append(sText[1:idx - 1].strip())
531 sText1 = sText[idx + 1:]
532 sText = sText1.strip()
533 bFinished = True
534 else:
535 f = sText.split(None, 1)[0]
536 lFields.append(f)
537
538 sText1 = sText[len(f):].strip()
539 sText = sText1
540 return lFields
541
542
543 @staticmethod
545 """Processes one loop in the data extraction of the CIF file
546 @param lFields: list of all the words contained in the cif file
547 @type lFields: list
548 @param iStart: the starting index corresponding to the "loop_" key
549 @type iStart: integer
550 @return: the list of loop dictionaries, the length of the data
551 extracted from the lFields and the list of all the keys of the loop.
552 @rtype: tuple
553 """
554
555
556
557 loop = []
558 keys = []
559 i = iStart + 1
560 bFinished = False
561 while not bFinished:
562 if lFields[i][0] == "_":
563 keys.append(lFields[i])
564 i += 1
565 else:
566 bFinished = True
567 data = []
568 while True:
569 if i >= len(lFields):
570 break
571 elif len(lFields[i]) == 0:
572 break
573 elif lFields[i][0] == "_":
574 break
575 elif lFields[i] in ["loop_", "stop_", "global_", "data_", "save_"]:
576 break
577 else:
578 data.append(lFields[i])
579 i += 1
580
581 k = 0
582
583 if len(data) < len(keys):
584 element = {}
585 for j in keys:
586 if k < len(data):
587 element[j] = data[k]
588 else :
589 element[j] = "?"
590 k += 1
591
592 loop.append(element)
593
594 else:
595
596
597 for i in range(len(data) / len(keys)):
598 element = {}
599 for j in keys:
600 element[j] = data[k]
601 k += 1
602
603 loop.append(element)
604
605 return loop, 1 + len(keys) + len(data), keys
606
607
608
609
610
611
612
613
614
615
616 - def saveCIF(self, _strFilename="test.cif"):
617 """
618 Transforms the CIF object in string then write it into the given file
619
620 @param _strFilename: the of the file to be written
621 @type _strFilename: string
622 """
623
624 try:
625 fFile = open(_strFilename, "w")
626 except IOError:
627 print("Error during the opening of file for write: %s" %
628 _strFilename)
629 return
630 fFile.write(self._cif2str(_strFilename))
631 try:
632 fFile.close()
633 except IOError:
634 print("Error during the closing of file for write: %s" %
635 _strFilename)
636
637
639 """converts a cif dictionnary to a string according to the CIF syntax
640 @param _strFilename: the name of the filename to be appended in the
641 header of the CIF file
642 @type _strFilename: string
643 @return : a sting that corresponds to the content of the CIF-file.
644 @rtype: string
645 """
646 sCifText = ""
647 for i in __version__:
648 sCifText += "# " + i + os.linesep
649 if self.exists("_chemical_name_common"):
650 t = self["_chemical_name_common"].split()[0]
651 else:
652 t = os.path.splitext(os.path.split(_strFilename.strip())[1])[0]
653 sCifText += "data_%s%s" % (t, os.linesep)
654
655 lKeys = self.keys()
656 lKeys.sort()
657 for sKey in lKeys:
658 if sKey == "loop_":
659 continue
660 sValue = str(self[sKey])
661 if sValue.find("\n") > -1:
662 sLine = "%s %s;%s %s %s;%s" % (sKey, os.linesep, os.linesep,
663 sValue, os.linesep, os.linesep)
664 elif len(sValue.split()) > 1:
665 sLine = "%s '%s' \n" % (sKey, sValue)
666 if len(sLine) > 80:
667 sLine = "%s %s '%s' %s" % (sKey, os.linesep,
668 sValue, os.linesep)
669 else:
670 sLine = "%s %s %s" % (sKey, sValue, os.linesep)
671 if len(sLine) > 80:
672 sLine = "%s %s %s %s" % (sKey, os.linesep,
673 sValue, os.linesep)
674 sCifText += sLine
675 if self.has_key("loop_"):
676 for loop in self["loop_"]:
677 sCifText += "loop_ " + os.linesep
678 lKeys = loop[0]
679 llData = loop[1]
680 for sKey in lKeys:
681 sCifText += " %s %s" % (sKey, os.linesep)
682 for lData in llData:
683 sLine = ""
684 for key in lKeys:
685 sRawValue = lData[key]
686 if sRawValue.find("\n") > -1:
687 sLine += "%s; %s %s;%s" % (os.linesep, sRawValue,
688 os.linesep, os.linesep)
689 sCifText += sLine
690 sLine = ""
691 else:
692 if len(sRawValue.split()) > 1:
693 value = "'%s'" % (sRawValue)
694 else:
695 value = sRawValue
696 if len(sLine) + len(value) > 78:
697 sCifText += sLine + " " + os.linesep
698 sLine = " " + value
699 else:
700 sLine += " " + value
701 sCifText += sLine + " " + os.linesep
702 sCifText += os.linesep
703
704 return sCifText
705
706
708 """
709 Check if the key exists in the CIF and is non empty.
710 @param sKey: CIF key
711 @type sKey: string
712 @return: True if the key exists in the CIF dictionary and is non empty
713 @rtype: boolean
714 """
715 bExists = False
716 if self.has_key(sKey):
717 if len(self[sKey]) >= 1:
718 if self[sKey][0] not in ["?", "."]:
719 bExists = True
720 return bExists
721
722
724 """
725 Check if the key exists in the CIF dictionary.
726 @param sKey: CIF key
727 @type sKey: string
728 @return: True if the key exists in the CIF dictionary and is non empty
729 @rtype: boolean
730 """
731 if not self.exists("loop_"):
732 return False
733 bExists = False
734 if not bExists:
735 for i in self["loop_"]:
736 for j in i[0]:
737 if j == sKey:
738 bExists = True
739 return bExists
740
741
743 """
744 Load the powder diffraction CHIPLOT file and returns the
745 pd_CIF dictionary in the object
746
747 @param _strFilename: the name of the file to open
748 @type _strFilename: string
749 @return: the CIF object corresponding to the powder diffraction
750 @rtype: dictionary
751 """
752 if not os.path.isfile(_strFilename):
753 print "I cannot find the file %s" % _strFilename
754 raise
755 lInFile = open(_strFilename, "r").readlines()
756 self["_audit_creation_method"] = 'From 2-D detector using FIT2D and CIFfile'
757 self["_pd_meas_scan_method"] = "fixed"
758 self["_pd_spec_description"] = lInFile[0].strip()
759 try:
760 iLenData = int(lInFile[3])
761 except ValueError:
762 iLenData = None
763 lOneLoop = []
764 try:
765 f2ThetaMin = float(lInFile[4].split()[0])
766 last = ""
767 for sLine in lInFile[-20:]:
768 if sLine.strip() != "":
769 last = sLine.strip()
770 f2ThetaMax = float(last.split()[0])
771 limitsOK = True
772
773 except (ValueError, IndexError):
774 limitsOK = False
775 f2ThetaMin = 180.0
776 f2ThetaMax = 0
777
778 for sLine in lInFile[4:]:
779 sCleaned = sLine.split("#")[0].strip()
780 data = sCleaned.split()
781 if len(data) == 2 :
782 if not limitsOK:
783 f2Theta = float(data[0])
784 if f2Theta < f2ThetaMin :
785 f2ThetaMin = f2Theta
786 if f2Theta > f2ThetaMax :
787 f2ThetaMax = f2Theta
788 lOneLoop.append({ "_pd_meas_intensity_total": data[1] })
789 if not iLenData:
790 iLenData = len(lOneLoop)
791 assert (iLenData == len(lOneLoop))
792 self[ "_pd_meas_2theta_range_inc" ] = "%.4f" % ((f2ThetaMax - f2ThetaMin) / (iLenData - 1))
793 if self[ "_pd_meas_2theta_range_inc" ] < 0:
794 self[ "_pd_meas_2theta_range_inc" ] = abs (self[ "_pd_meas_2theta_range_inc" ])
795 tmp = f2ThetaMax
796 f2ThetaMax = f2ThetaMin
797 f2ThetaMin = tmp
798 self[ "_pd_meas_2theta_range_max" ] = "%.4f" % f2ThetaMax
799 self[ "_pd_meas_2theta_range_min" ] = "%.4f" % f2ThetaMin
800 self[ "_pd_meas_number_of_points" ] = str(iLenData)
801 self["loop_"] = [ [ ["_pd_meas_intensity_total" ], lOneLoop ] ]
802
803
804 @staticmethod
806 "Returns True if the key (string) exist in the array called loop"""
807 try:
808 loop.index(key)
809 return True
810 except ValueError:
811 return False
812