Changeset 13505 for fact/tools/pyscripts/pyfact/pyfact.py
- Timestamp:
- 05/02/12 12:53:13 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
fact/tools/pyscripts/pyfact/pyfact.py
r13441 r13505 6 6 from ctypes import * 7 7 import numpy as np 8 import pprint # for SlowData 8 9 from scipy import signal 9 10 … … 380 381 381 382 # ----------------------------------------------------------------------------- 383 384 class SlowData( fits ): 385 """ -Fact Fits File- 386 A Python wrapper for the fits-class implemented in pyfits.h 387 provides easy access to the fits file meta data. 388 * dictionary of file metadata - self.meta 389 * dict of table metadata - self.columns 390 * variable table column access, thus possibly increased speed while looping 391 """ 392 def __init__(self, path): 393 """ creates meta and columns dictionaries 394 """ 395 self.path = path 396 try: 397 fits.__init__(self,path) 398 except IOError: 399 print 'problem accessing data file: ', data_file_name 400 raise # stop ! no data 401 402 self.meta = self._make_meta_dict() 403 self.columns = self._make_columns_dict() 404 405 self.treat_meta_dict() 406 407 408 # list of columns, which are already registered 409 # see method register() 410 self._registered_cols = [] 411 # dict of column data, this is used, in order to be able to remove 412 # the ctypes of 413 self._table_cols = {} 414 415 # I need to count the rows, since the normal loop mechanism seems not to work. 416 self._current_row = 0 417 418 self.stacked_cols = {} 419 420 def _make_meta_dict(self): 421 """ This method retrieves meta information about the fits file and 422 stores this information in a dict 423 return: dict 424 key: string - all capital letters 425 value: tuple( numerical value, string comment) 426 """ 427 # intermediate variables for file metadata dict generation 428 keys=self.GetPy_KeyKeys() 429 values=self.GetPy_KeyValues() 430 comments=self.GetPy_KeyComments() 431 types=self.GetPy_KeyTypes() 432 433 if len(keys) != len(values): 434 raise TypeError('len(keys)',len(keys),' != len(values)', len(values)) 435 if len(keys) != len(types): 436 raise TypeError('len(keys)',len(keys),' != len(types)', len(types)) 437 if len(keys) != len(comments): 438 raise TypeError('len(keys)',len(keys),' != len(comments)', len(comments)) 439 440 meta_dict = {} 441 for i in range(len(keys)): 442 type = types[i] 443 if type == 'I': 444 value = int(values[i]) 445 elif type == 'F': 446 value = float(values[i]) 447 elif type == 'B': 448 if values[i] == 'T': 449 value = True 450 elif values[i] == 'F': 451 value = False 452 else: 453 raise TypeError("meta-type is 'B', but meta-value is neither 'T' nor 'F'. meta-value:",values[i]) 454 elif type == 'T': 455 value = values[i] 456 else: 457 raise TypeError("unknown meta-type: known meta types are: I,F,B and T. meta-type:",type) 458 meta_dict[keys[i]]=(value, comments[i]) 459 return meta_dict 460 461 462 def _make_columns_dict(self): 463 """ This method retrieves information about the columns 464 stored inside the fits files internal binary table. 465 returns: dict 466 key: string column name -- all capital letters 467 values: tuple( 468 number of elements in table field - integer 469 size of element in bytes -- this is not really interesting for any user 470 might be ommited in future versions 471 type - a single character code -- should be translated into 472 a comrehensible word 473 unit - string like 'mV' or 'ADC count' 474 """ 475 # intermediate variables for file table-metadata dict generation 476 keys=self.GetPy_ColumnKeys() 477 #offsets=self.GetPy_ColumnOffsets() #not needed on python level... 478 nums=self.GetPy_ColumnNums() 479 sizes=self.GetPy_ColumnSizes() 480 types=self.GetPy_ColumnTypes() 481 units=self.GetPy_ColumnUnits() 482 483 # zip the values 484 values = zip(nums,sizes,types,units) 485 # create the columns dictionary 486 columns = dict(zip(keys ,values)) 487 return columns 488 489 def stack(self, on=True): 490 self.next() 491 for col in self._registered_cols: 492 if isinstance( self.dict[col], type(np.array('')) ): 493 self.stacked_cols[col] = self.dict[col] 494 else: 495 # elif isinstance(self.dict[col], ctypes._SimpleCData): 496 self.stacked_cols[col] = np.array(self.dict[col]) 497 # else: 498 # raise TypeError("I don't know how to stack "+col+". It is of type: "+str(type(self.dict[col]))) 499 500 def register(self, input_str): 501 columns = self.columns 502 if input_str.lower() == 'all': 503 for col in columns: 504 self._register(col) 505 else: 506 #check if colname is in columns: 507 if input_str not in columns: 508 error_msg = 'colname:'+ input_str +' is not a column in the binary table.\n' 509 error_msg+= 'possible colnames are\n' 510 for key in columns: 511 error_msg += key+'\n' 512 raise KeyError(error_msg) 513 else: 514 self._register(input_str) 515 516 # 'private' method, do not use 517 def _register( self, colname): 518 columns = self.columns 519 local = None 520 521 number_of_elements = int(columns[colname][0]) 522 size_of_elements_in_bytes = int(columns[colname][1]) 523 ctypecode_of_elements = columns[colname][2] 524 physical_unit_of_elements = columns[colname][3] 525 526 # snippet from the C++ source code, or header file to be precise: 527 #case 'L': gLog << "bool(8)"; break; 528 #case 'B': gLog << "byte(8)"; break; 529 #case 'I': gLog << "short(16)"; break; 530 #case 'J': gLog << "int(32)"; break; 531 #case 'K': gLog << "int(64)"; break; 532 #case 'E': gLog << "float(32)"; break; 533 #case 'D': gLog << "double(64)"; break; 534 535 536 537 # the fields inside the columns can either contain single numbers, 538 # or whole arrays of numbers as well. 539 # we treat single elements differently... 540 if number_of_elements == 1: 541 # allocate some memory for a single number according to its type 542 if ctypecode_of_elements == 'J': # J is for a 4byte int, i.e. an unsigned long 543 local = ctypes.c_ulong() 544 un_c_type = long 545 elif ctypecode_of_elements == 'I': # I is for a 2byte int, i.e. an unsinged int 546 local = ctypes.c_ushort() 547 un_c_type = int 548 elif ctypecode_of_elements == 'B': # B is for a byte 549 local = ctypes.c_ubyte() 550 un_c_type = int 551 elif ctypecode_of_elements == 'D': 552 local = ctypes.c_double() 553 un_c_type = float 554 elif ctypecode_of_elements == 'E': 555 local = ctypes.c_float() 556 un_c_type = float 557 elif ctypecode_of_elements == 'A': 558 local = ctypes.c_uchar() 559 un_c_type = chr 560 elif ctypecode_of_elements == 'K': 561 local = ctypes.c_ulonglong() 562 un_c_type = long 563 else: 564 raise TypeError('unknown ctypecode_of_elements:',ctypecode_of_elements) 565 else: 566 if ctypecode_of_elements == 'B': # B is for a byte 567 nptype = np.int8 568 elif ctypecode_of_elements == 'A': # A is for a char .. but I don't know how to handle it 569 nptype = np.int8 570 elif ctypecode_of_elements == 'I': # I is for a 2byte int 571 nptype = np.int16 572 elif ctypecode_of_elements == 'J': # J is for a 4byte int 573 nptype = np.int32 574 elif ctypecode_of_elements == 'K': # B is for a byte 575 nptype = np.int64 576 elif ctypecode_of_elements == 'E': # B is for a byte 577 nptype = np.float32 578 elif ctypecode_of_elements == 'D': # B is for a byte 579 nptype = np.float64 580 else: 581 raise TypeError('unknown ctypecode_of_elements:',ctypecode_of_elements) 582 local = np.zeros( number_of_elements, nptype) 583 584 # Set the Pointer Address 585 self.SetPtrAddress(colname, local) 586 self._table_cols[colname] = local 587 if number_of_elements > 1: 588 self.__dict__[colname] = local 589 self.dict[colname] = local 590 else: 591 # remove any traces of ctypes: 592 self.__dict__[colname] = local.value 593 self.dict[colname] = local.value 594 self._registered_cols.append(colname) 595 596 597 def treat_meta_dict(self): 598 """make 'interesting' meta information available like normal members. 599 non interesting are: 600 TFORM, TUNIT, and TTYPE 601 since these are available via the columns dict. 602 """ 603 604 self.number_of_rows = self.meta['NAXIS2'][0] 605 self.number_of_columns = self.meta['TFIELDS'][0] 606 607 # there are some information in the meta dict, which are alsways there: 608 # there are regarded as not interesting: 609 uninteresting_meta = {} 610 uninteresting_meta['arraylike'] = {} 611 uninteresting = ['NAXIS', 'NAXIS1', 'NAXIS2', 612 'TFIELDS', 613 'XTENSION','EXTNAME','EXTREL', 614 'BITPIX', 'PCOUNT', 'GCOUNT', 615 'ORIGIN', 616 'PACKAGE', 'COMPILED', 'CREATOR', 617 'TELESCOP','TIMESYS','TIMEUNIT','VERSION'] 618 for key in uninteresting: 619 if key in self.meta: 620 uninteresting_meta[key]=self.meta[key] 621 del self.meta[key] 622 623 # the table meta data contains 624 625 626 # shortcut to access the meta dict. But this needs to 627 # be cleaned up quickly!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 628 meta = self.meta 629 630 # loop over keys: 631 # * try to find array-like keys 632 arraylike = {} 633 singlelike = [] 634 for key in self.meta: 635 stripped = key.rstrip('1234567890') 636 if stripped == key: 637 singlelike.append(key) 638 else: 639 if stripped not in arraylike: 640 arraylike[stripped] = 0 641 else: 642 arraylike[stripped] += 1 643 newmeta = {} 644 for key in singlelike: 645 newmeta[key.lower()] = meta[key] 646 for key in arraylike: 647 uninteresting_meta['arraylike'][key.lower()] = [] 648 for i in range(arraylike[key]+1): 649 if key+str(i) in meta: 650 uninteresting_meta['arraylike'][key.lower()].append(meta[key+str(i)]) 651 self.ui_meta = uninteresting_meta 652 # make newmeta self 653 for key in newmeta: 654 self.__dict__[key]=newmeta[key] 655 656 dict = self.__dict__.copy() 657 del dict['meta'] 658 del dict['ui_meta'] 659 self.dict = dict 660 661 def __iter__(self): 662 """ iterator """ 663 return self 664 665 def next(self): 666 """ used by __iter__ """ 667 # Here one might check, if looping makes any sense, and if not 668 # one could stop looping or so... 669 # like this: 670 # 671 # if len(self._registered_cols) == 0: 672 # print 'warning: looping without any registered columns' 673 if self._current_row < self.number_of_rows: 674 if self.GetNextRow() == False: 675 raise StopIteration 676 for col in self._registered_cols: 677 if isinstance(self._table_cols[col], ctypes._SimpleCData): 678 self.__dict__[col] = self._table_cols[col].value 679 self.dict[col] = self._table_cols[col].value 680 681 for col in self.stacked_cols: 682 if isinstance(self.dict[col], type(np.array(''))): 683 self.stacked_cols[col] = np.vstack( (self.stacked_cols[col],self.dict[col]) ) 684 else: 685 self.stacked_cols[col] = np.vstack( (self.stacked_cols[col],np.array(self.dict[col])) ) 686 self._current_row += 1 687 else: 688 raise StopIteration 689 return self 690 691 def show(self): 692 pprint.pprint(self.dict) 693 694 695 696 382 697 class fnames( object ): 383 698 """ organize file names of a FACT data run … … 455 770 # end of class definition: fnames( object ) 456 771 772 def _test_SlowData( filename ): 773 file = FactFits(filename) 774 print '-'*70 775 print "opened :", filename, " as 'file'" 776 print 777 print '-'*70 778 print 'type file.show() to look at its contents' 779 print "type file.register( columnname ) or file.register('all') in order to register columns" 780 print 781 print " due column-registration you declare, that you would like to retrieve the contents of one of the columns" 782 print " after column-registration, the 'file' has new member variables, they are named like the columns" 783 print " PLEASE NOTE: immediatly after registration, the members exist, but they are empty." 784 print " the values are assigned only, when you call file.next() or when you loop over the 'file'" 785 print 786 print "in order to loop over it, just go like this:" 787 print "for row in file:" 788 print " print row.columnname_one, row.columnname_two" 789 print 790 print "" 791 print '-'*70 792 793 794 457 795 def _test_iter( nevents ): 458 796 """ test for function __iter__ """ … … 471 809 if __name__ == '__main__': 472 810 """ tests """ 473 474 _test_iter(10) 811 import sys 812 if len(sys.argv) == 1: 813 print 'showing test of iterator of RawData class' 814 print 'in order to test the SlowData classe please use:', sys.argv[0], 'fits-file-name' 815 _test_iter(10) 816 else: 817 print 'showing test of SlowData class' 818 print 'in case you wanted to test the RawData class, please give no commandline arguments' 819 _test_SlowData(sys.argv[1])
Note:
See TracChangeset
for help on using the changeset viewer.