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 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 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: #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: file containing the Cif Binary part. 71 @type inStream: opened file. 72 """ 73 self.cif.loadCIF(inStream, _bKeepComment=True) 74 75 # backport contents of the CIF data to the headers 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" #switch back to unix representation 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 # Compute image size 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 # # ensure the PIL image is reset 141 self.pilimage = None 142 return self
143 144 145 146 @staticmethod
147 - def analysePython(stream, size):
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 #cimport numpy 156 #import cython 157 # cdef int i,j 158 # cdef char key = 0x80 159 # cdef numpy.ndarray[double, ndim = 1] dataOut 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
187 - def analyseWeave(stream, size):
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
249 - def analyseNumpy(stream, size=None):
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 # long int 64 bits 273 listnpa.append(np.fromstring(stream[idx + 7:idx + 15], 274 dtype="int64")) 275 shift = 15 276 else: #32 bit int 277 listnpa.append(np.fromstring(stream[idx + 3:idx + 7], 278 dtype="int32")) 279 shift = 7 280 else: #int16 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
288 - def _readbinary_byte_offset(self, inStream):
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
327 - def __init__(self, _strFilename=None):
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: #load the file) 336 self.loadCIF(_strFilename)
337
338 - def readCIF(self, _strFilename):
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 #elif isinstance(_strFilename, file, bz2.BZ2File, ): 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
374 - def isAscii(_strIn):
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
392 - def _readCIF(_instream):
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
423 - def _parseCIF(self, sText):
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 #first of all : separate the cif file in fields 439 lFields = CIF._splitCIF(sText.strip()) 440 #Then : look for loops 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 # print lFields[i], lFields[i+1] 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
465 - def _splitCIF(sText):
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 ##########debuging in case we arrive at the end of the text 484 if idx >= len(sText) - 1: 485 # print sText,idx,len(sText) 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 ##########debuging in case we arrive at the end of the text 503 if idx >= len(sText) - 1: 504 # print sText,idx,len(sText) 505 lFields.append(sText[1:-1].strip()) 506 # print lFields[-1] 507 sText = "" 508 bFinished = True 509 break 510 511 if sText[idx + 1] in CIF.BLANK: 512 lFields.append(sText[1:idx].strip()) 513 # print lFields[-1] 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 # print lFields[-1] 538 sText1 = sText[len(f):].strip() 539 sText = sText1 540 return lFields
541 542 543 @staticmethod
544 - def _analyseOneLoop(lFields, iStart):
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 # in earch loop we first search the length of the loop 555 # print lFields 556 # curloop = {} 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])#.lower()) 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 #print len(keys), len(data) 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 #print element 592 loop.append(element) 593 594 else: 595 #print data 596 #print keys 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 # print element 603 loop.append(element) 604 # print loop 605 return loop, 1 + len(keys) + len(data), keys
606 607 608 609 610 611 612 ############################################################################################# 613 ######## everything needed to write a cif file ######################################### 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
638 - def _cif2str(self, _strFilename):
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 #first of all get all the keys : 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: #should add value between ;; 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: #should add value between '' 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: #should add value between ;; 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: #should add value between '' 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 #print sCifText 704 return sCifText
705 706
707 - def exists(self, sKey):
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
723 - def existsInLoop(self, sKey):
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
742 - def loadCHIPLOT(self, _strFilename):
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 # print "limitsOK:", limitsOK 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
805 - def LoopHasKey(loop, key):
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