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

# http://pyrocko.org - GPLv3 

# 

# The Pyrocko Developers, 21st Century 

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

from __future__ import absolute_import, division 

from builtins import range 

 

import math 

import logging 

 

from . import pile, util, io 

 

logger = logging.getLogger('pyrocko.shadow_pile') 

 

 

class NoBasePileSet(Exception): 

pass 

 

 

class ShadowBlock(object): 

def __init__(self): 

self.mtime = None 

self.files = [] 

 

 

class ShadowPile(pile.Pile): 

 

def __init__(self, basepile=None, tinc=360., tpad=0., storepath=None): 

pile.Pile.__init__(self) 

 

self._tinc = tinc 

self._tpad = tpad 

self._storepath = storepath 

self._blocks = {} 

 

if basepile is None: 

basepile = pile.Pile() 

 

self.set_basepile(basepile) 

 

def clear(self): 

for iblock in self._blocks.keys(): 

self._clearblock() 

self._blocks = {} 

 

def set_basepile(self, basepile): 

self.clear() 

self._base = basepile 

 

def get_basepile(self): 

return self._base 

 

def set_chopsize(self, tinc, tpad=0.): 

self.clear() 

self._tinc = tinc 

self._tpad = tpad 

 

def set_store(self, storepath=None): 

self.clear() 

self._storepath = storepath 

 

def chopper( 

self, tmin=None, tmax=None, tinc=None, tpad=0., *args, **kwargs): 

 

if tmin is None: 

tmin = self.base.tmin+tpad 

 

if tmax is None: 

tmax = self.base.tmax-tpad 

 

self._update_range(tmin, tmax) 

 

return pile.Pile.chopper(self, tmin, tmax, tinc, tpad, *args, **kwargs) 

 

def process(self, iblock, tmin, tmax, traces): 

return traces 

 

def _update_range(self, tmin, tmax): 

imin = int(math.floor(tmin / self._tinc)) 

imax = int(math.floor(tmax / self._tinc)+1) 

 

todo = [] 

for i in range(imin, imax): 

wmin = i * self._tinc 

wmax = (i+1) * self._tinc 

mtime = util.gmctime(self._base.get_newest_mtime(wmin, wmax)) 

if i not in self._blocks or self._blocks[i].mtime != mtime: 

if i not in self._blocks: 

self._blocks[i] = ShadowBlock() 

 

todo.append(i) 

self._blocks[i].mtime = mtime 

else: 

if todo: 

self._process_blocks(todo[0], todo[-1]+1) 

todo = [] 

if todo: 

self._process_blocks(todo[0], todo[-1]+1) 

 

def _process_blocks(self, imin, imax): 

pmin = imin * self._tinc 

pmax = imax * self._tinc 

 

iblock = imin 

for traces in self._base.chopper(pmin, pmax, self._tinc, self._tpad): 

tmin = iblock*self._tinc 

tmax = (iblock+1)*self._tinc 

traces = self.process(iblock, tmin, tmax, traces) 

if self._tpad != 0.0: 

for trace in traces: 

trace.chop(tmin, tmax, inplace=True) 

self._clearblock(iblock) 

self._insert(iblock, traces) 

iblock += 1 

 

def _insert(self, iblock, traces): 

if traces: 

if self._storepath is not None: 

fns = io.save( 

traces, self._storepath, 

format='mseed', 

additional={'iblock': iblock}) 

 

self.load_files(fns, fileformat='mseed', show_progress=False) 

else: 

file = pile.MemTracesFile(None, traces) 

self.add_file(file) 

 

def _clearblock(self, iblock): 

for file in self._blocks[iblock].files: 

self.remove_file(file)