Package fabio :: Module cbfimage
[hide private]
[frames] | no frames]

Source Code for Module fabio.cbfimage

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