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