1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6import math 

7import logging 

8 

9from . import pile, util, io 

10 

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

12 

13 

14class NoBasePileSet(Exception): 

15 pass 

16 

17 

18class ShadowBlock(object): 

19 def __init__(self): 

20 self.mtime = None 

21 self.files = [] 

22 

23 

24class ShadowPile(pile.Pile): 

25 

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

27 pile.Pile.__init__(self) 

28 

29 self._tinc = tinc 

30 self._tpad = tpad 

31 self._storepath = storepath 

32 self._blocks = {} 

33 

34 if basepile is None: 

35 basepile = pile.Pile() 

36 

37 self.set_basepile(basepile) 

38 

39 def clear(self): 

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

41 self._clearblock() 

42 self._blocks = {} 

43 

44 def set_basepile(self, basepile): 

45 self.clear() 

46 self._base = basepile 

47 

48 def get_basepile(self): 

49 return self._base 

50 

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

52 self.clear() 

53 self._tinc = tinc 

54 self._tpad = tpad 

55 

56 def set_store(self, storepath=None): 

57 self.clear() 

58 self._storepath = storepath 

59 

60 def chopper( 

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

62 

63 if tmin is None: 

64 tmin = self.base.tmin+tpad 

65 

66 if tmax is None: 

67 tmax = self.base.tmax-tpad 

68 

69 self._update_range(tmin, tmax) 

70 

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

72 

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

74 return traces 

75 

76 def _update_range(self, tmin, tmax): 

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

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

79 

80 todo = [] 

81 for i in range(imin, imax): 

82 wmin = i * self._tinc 

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

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

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

86 if i not in self._blocks: 

87 self._blocks[i] = ShadowBlock() 

88 

89 todo.append(i) 

90 self._blocks[i].mtime = mtime 

91 else: 

92 if todo: 

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

94 todo = [] 

95 if todo: 

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

97 

98 def _process_blocks(self, imin, imax): 

99 pmin = imin * self._tinc 

100 pmax = imax * self._tinc 

101 

102 iblock = imin 

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

104 tmin = iblock*self._tinc 

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

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

107 if self._tpad != 0.0: 

108 for trace in traces: 

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

110 self._clearblock(iblock) 

111 self._insert(iblock, traces) 

112 iblock += 1 

113 

114 def _insert(self, iblock, traces): 

115 if traces: 

116 if self._storepath is not None: 

117 fns = io.save( 

118 traces, self._storepath, 

119 format='mseed', 

120 additional={'iblock': iblock}) 

121 

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

123 else: 

124 file = pile.MemTracesFile(None, traces) 

125 self.add_file(file) 

126 

127 def _clearblock(self, iblock): 

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

129 self.remove_file(file)