Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

# -*- coding: utf-8 -*- 

#------------------------------------------------------------------- 

#  Filename: unpack.py 

#  Purpose: Routines for unpacking SEG Y data formats. 

#   Author: Lion Krischer 

#    Email: krischer@geophysik.uni-muenchen.de 

# 

# Copyright (C) 2010 Lion Krischer 

#--------------------------------------------------------------------- 

""" 

Functions that will all take a file pointer and the sample count and return a 

numpy array with the unpacked values. 

""" 

from util import clibsegy 

 

import ctypes as C 

import numpy as np 

import sys 

import os 

import warnings 

 

# Get the system byteorder. 

BYTEORDER = sys.byteorder 

if BYTEORDER == 'little': 

    BYTEORDER = '<' 

else: 

    BYTEORDER = '>' 

 

 

clibsegy.ibm2ieee.argtypes = [ 

    np.ctypeslib.ndpointer(dtype='float32', ndim=1, flags='C_CONTIGUOUS'), 

    C.c_int] 

clibsegy.ibm2ieee.restype = C.c_void_p 

 

 

def unpack_4byte_IBM(file, count, endian='>'): 

    """ 

    Unpacks 4 byte IBM floating points. 

    """ 

    # Read as 4 byte integer so bit shifting works. 

    data = np.fromstring(file.read(count * 4), dtype='float32') 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    length = len(data) 

    # Call the C code which transforms the data inplace. 

    clibsegy.ibm2ieee(data, length) 

    return data 

 

 

# Old pure Python/NumPy code 

# 

#def unpack_4byte_IBM(file, count, endian='>'): 

#    """ 

#    Unpacks 4 byte IBM floating points. 

#    """ 

#    # Read as 4 byte integer so bit shifting works. 

#    data = np.fromstring(file.read(count * 4), dtype='int32') 

#    # Swap the byteorder if necessary. 

#    if BYTEORDER != endian: 

#        data = data.byteswap() 

#    # See http://mail.scipy.org/pipermail/scipy-user/2009-January/019392.html 

#    # XXX: Might need check for values out of range: 

#    # http://bytes.com/topic/c/answers/ 

#    #         221981-c-code-converting-ibm-370-floating-point-ieee-754-a 

#    sign = np.bitwise_and(np.right_shift(data, 31), 0x01) 

#    exponent = np.bitwise_and(np.right_shift(data, 24), 0x7f) 

#    mantissa = np.bitwise_and(data, 0x00ffffff) 

#    # Force single precision. 

#    mantissa = np.require(mantissa, 'float32') 

#    mantissa /= 0x1000000 

#    # Do the following calculation in a weird way to avoid autocasting to 

#    # float64. 

#    # data = (1.0 - 2.0 * sign) * mantissa * 16.0 ** (exponent - 64.0) 

#    sign *= -2.0 

#    sign += 1.0 

#    mantissa *= 16.0 ** (exponent - 64) 

#    mantissa *= sign 

#    return mantissa 

 

 

def unpack_4byte_Integer(file, count, endian='>'): 

    """ 

    Unpacks 4 byte integers. 

    """ 

    # Read as 4 byte integer so bit shifting works. 

    data = np.fromstring(file.read(count * 4), dtype='int32') 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    return data 

 

 

def unpack_2byte_Integer(file, count, endian='>'): 

    """ 

    Unpacks 2 byte integers. 

    """ 

    # Read as 4 byte integer so bit shifting works. 

    data = np.fromstring(file.read(count * 2), dtype='int16') 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    return data 

 

 

def unpack_4byte_Fixed_point(file, count, endian='>'): 

    raise NotImplementedError 

 

 

def unpack_4byte_IEEE(file, count, endian='>'): 

    """ 

    Unpacks 4 byte IEEE floating points. 

    """ 

    # Read as 4 byte integer so bit shifting works. 

    data = np.fromstring(file.read(count * 4), dtype='float32') 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    return data 

 

 

def unpack_1byte_Integer(file, count, endian='>'): 

    raise NotImplementedError 

 

 

class OnTheFlyDataUnpacker: 

    """ 

    Tie-up a data sample unpack function with its parameters. 

 

    This class allows for data to be read directly from the disk as needed, 

    preventing the need to store data in memory. 

    """ 

    def __init__(self, unpack_function, filename, filemode, seek, count, 

                 endian='>'): 

        self.unpack_function = unpack_function 

        self.filename = filename 

        self.filemode = filemode 

        self.seek = seek 

        self.count = count 

        self.endian = endian 

        self.mtime = os.path.getmtime(self.filename) 

 

    def __call__(self): 

        mtime = os.path.getmtime(self.filename) 

        if mtime != self.mtime: 

            msg = "File '%s' changed since reading headers" % self.filename 

            msg += "; data may be read incorrectly " 

            msg += "(modification time = %s)." % mtime 

            warnings.warn(msg) 

        file = open(self.filename, self.filemode) 

        file.seek(self.seek) 

        return self.unpack_function(file, self.count, endian=self.endian)