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

# http://pyrocko.org - GPLv3 

# 

# The Pyrocko Developers, 21st Century 

# ---|P------/S----------~Lg---------- 

'''File IO module for SICK traces format.''' 

from __future__ import division, absolute_import 

import os 

from struct import unpack 

 

from pyrocko.file import (File, numtype2type, NoDataAvailable, 

size_record_header, FileError) 

from pyrocko import trace 

from pyrocko.util import ensuredirs 

from .io_common import FileLoadError, FileSaveError 

 

record_formats = { 

 

'trace': { 

'network': 'string', 

'station': 'string', 

'location': 'string', 

'channel': 'string', 

'tmin': 'time_string', 

'tmax': 'time_string', 

'deltat': 'f8', 

'ydata': ('@i2', '@i4', '@i8', '@i2', '@i4', '@i8', '@f4', '@f8'), 

}, 

} 

 

 

def extract(tr, format): 

d = {} 

for k in format.keys(): 

d[k] = getattr(tr, k) 

return d 

 

 

class TracesFileIO(File): 

 

def __init__(self, file): 

File.__init__( 

self, file, 

type_label='YAFF', 

version='0000', 

record_formats=record_formats) 

 

def get_type(self, key, value): 

return numtype2type[value.dtype.type] 

 

def from_dict(self, d): 

return trace.Trace(**d) 

 

def to_dict(self, tr): 

return extract(tr, record_formats['trace']) 

 

def load(self, load_data=True): 

while True: 

try: 

r = None 

r = self.next_record() 

 

if r.type == 'trace': 

exclude = None 

if not load_data: 

exclude = ('ydata',) 

 

d = r.unpack(exclude=exclude) 

tr = self.from_dict(d) 

yield tr 

 

except NoDataAvailable: 

break 

 

def save(self, traces): 

for tr in traces: 

r = self.add_record('trace', make_hash=True) 

r.pack(self.to_dict(tr)) 

r.close() 

 

 

def iload(filename, load_data=True): 

try: 

f = open(filename, 'rb') 

tf = TracesFileIO(f) 

for tr in tf.load(load_data=load_data): 

yield tr 

 

except (OSError, FileError) as e: 

raise FileLoadError(e) 

 

finally: 

tf.close() 

f.close() 

 

 

def save(traces, filename_template, additional={}, max_open_files=10, 

overwrite=True): 

 

fns = set() 

open_files = {} 

 

def close_files(): 

while open_files: 

open_files.popitem()[1].close() 

 

for tr in traces: 

fn = tr.fill_template(filename_template, **additional) 

 

if fn not in open_files: 

if len(open_files) >= max_open_files: 

close_files() 

 

if fn not in fns: 

if not overwrite and os.path.exists(fn): 

raise FileSaveError('file exists: %s' % fn) 

 

ensuredirs(fn) 

 

open_files[fn] = open(fn, ['wb', 'ab'][fn in fns]) 

fns.add(fn) 

 

tf = TracesFileIO(open_files[fn]) 

tf.save([tr]) 

tf.close() 

 

close_files() 

 

return list(fns) 

 

 

def detect(first512): 

 

if len(first512) < size_record_header: 

return False 

 

label, version, size_record, size_payload, hash, type = unpack( 

'>4s4sQQ20s20s', first512[:size_record_header]) 

 

if label == b'YAFF' and version == b'0000' and type.strip() == b'trace': 

return True 

 

return False