1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import math
7import logging
9from . import pile, util, io
11logger = logging.getLogger('pyrocko.shadow_pile')
14class NoBasePileSet(Exception):
15 pass
18class ShadowBlock(object):
19 def __init__(self):
20 self.mtime = None
21 self.files = []
24class ShadowPile(pile.Pile):
26 def __init__(self, basepile=None, tinc=360., tpad=0., storepath=None):
27 pile.Pile.__init__(self)
29 self._tinc = tinc
30 self._tpad = tpad
31 self._storepath = storepath
32 self._blocks = {}
34 if basepile is None:
35 basepile = pile.Pile()
37 self.set_basepile(basepile)
39 def clear(self):
40 for iblock in self._blocks.keys():
41 self._clearblock()
42 self._blocks = {}
44 def set_basepile(self, basepile):
45 self.clear()
46 self._base = basepile
48 def get_basepile(self):
49 return self._base
51 def set_chopsize(self, tinc, tpad=0.):
52 self.clear()
53 self._tinc = tinc
54 self._tpad = tpad
56 def set_store(self, storepath=None):
57 self.clear()
58 self._storepath = storepath
60 def chopper(
61 self, tmin=None, tmax=None, tinc=None, tpad=0., *args, **kwargs):
63 if tmin is None:
64 tmin = self.base.tmin+tpad
66 if tmax is None:
67 tmax = self.base.tmax-tpad
69 self._update_range(tmin, tmax)
71 return pile.Pile.chopper(self, tmin, tmax, tinc, tpad, *args, **kwargs)
73 def process(self, iblock, tmin, tmax, traces):
74 return traces
76 def _update_range(self, tmin, tmax):
77 imin = int(math.floor(tmin / self._tinc))
78 imax = int(math.floor(tmax / self._tinc)+1)
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()
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)
98 def _process_blocks(self, imin, imax):
99 pmin = imin * self._tinc
100 pmax = imax * self._tinc
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
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})
122 self.load_files(fns, fileformat='mseed', show_progress=False)
123 else:
124 file = pile.MemTracesFile(None, traces)
125 self.add_file(file)
127 def _clearblock(self, iblock):
128 for file in self._blocks[iblock].files:
129 self.remove_file(file)