1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5from __future__ import absolute_import, division 

6 

7import math 

8import logging 

9 

10from . import pile, util, io 

11 

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

13 

14 

15class NoBasePileSet(Exception): 

16 pass 

17 

18 

19class ShadowBlock(object): 

20 def __init__(self): 

21 self.mtime = None 

22 self.files = [] 

23 

24 

25class ShadowPile(pile.Pile): 

26 

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

28 pile.Pile.__init__(self) 

29 

30 self._tinc = tinc 

31 self._tpad = tpad 

32 self._storepath = storepath 

33 self._blocks = {} 

34 

35 if basepile is None: 

36 basepile = pile.Pile() 

37 

38 self.set_basepile(basepile) 

39 

40 def clear(self): 

41 for iblock in self._blocks.keys(): 

42 self._clearblock() 

43 self._blocks = {} 

44 

45 def set_basepile(self, basepile): 

46 self.clear() 

47 self._base = basepile 

48 

49 def get_basepile(self): 

50 return self._base 

51 

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

53 self.clear() 

54 self._tinc = tinc 

55 self._tpad = tpad 

56 

57 def set_store(self, storepath=None): 

58 self.clear() 

59 self._storepath = storepath 

60 

61 def chopper( 

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

63 

64 if tmin is None: 

65 tmin = self.base.tmin+tpad 

66 

67 if tmax is None: 

68 tmax = self.base.tmax-tpad 

69 

70 self._update_range(tmin, tmax) 

71 

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

73 

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

75 return traces 

76 

77 def _update_range(self, tmin, tmax): 

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

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

80 

81 todo = [] 

82 for i in range(imin, imax): 

83 wmin = i * self._tinc 

84 wmax = (i+1) * self._tinc 

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

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

87 if i not in self._blocks: 

88 self._blocks[i] = ShadowBlock() 

89 

90 todo.append(i) 

91 self._blocks[i].mtime = mtime 

92 else: 

93 if todo: 

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

95 todo = [] 

96 if todo: 

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

98 

99 def _process_blocks(self, imin, imax): 

100 pmin = imin * self._tinc 

101 pmax = imax * self._tinc 

102 

103 iblock = imin 

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

105 tmin = iblock*self._tinc 

106 tmax = (iblock+1)*self._tinc 

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

108 if self._tpad != 0.0: 

109 for trace in traces: 

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

111 self._clearblock(iblock) 

112 self._insert(iblock, traces) 

113 iblock += 1 

114 

115 def _insert(self, iblock, traces): 

116 if traces: 

117 if self._storepath is not None: 

118 fns = io.save( 

119 traces, self._storepath, 

120 format='mseed', 

121 additional={'iblock': iblock}) 

122 

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

124 else: 

125 file = pile.MemTracesFile(None, traces) 

126 self.add_file(file) 

127 

128 def _clearblock(self, iblock): 

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

130 self.remove_file(file)