1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
5from __future__ import absolute_import, division
7import math
8import logging
10from . import pile, util, io
12logger = logging.getLogger('pyrocko.shadow_pile')
15class NoBasePileSet(Exception):
16 pass
19class ShadowBlock(object):
20 def __init__(self):
21 self.mtime = None
22 self.files = []
25class ShadowPile(pile.Pile):
27 def __init__(self, basepile=None, tinc=360., tpad=0., storepath=None):
28 pile.Pile.__init__(self)
30 self._tinc = tinc
31 self._tpad = tpad
32 self._storepath = storepath
33 self._blocks = {}
35 if basepile is None:
36 basepile = pile.Pile()
38 self.set_basepile(basepile)
40 def clear(self):
41 for iblock in self._blocks.keys():
42 self._clearblock()
43 self._blocks = {}
45 def set_basepile(self, basepile):
46 self.clear()
47 self._base = basepile
49 def get_basepile(self):
50 return self._base
52 def set_chopsize(self, tinc, tpad=0.):
53 self.clear()
54 self._tinc = tinc
55 self._tpad = tpad
57 def set_store(self, storepath=None):
58 self.clear()
59 self._storepath = storepath
61 def chopper(
62 self, tmin=None, tmax=None, tinc=None, tpad=0., *args, **kwargs):
64 if tmin is None:
65 tmin = self.base.tmin+tpad
67 if tmax is None:
68 tmax = self.base.tmax-tpad
70 self._update_range(tmin, tmax)
72 return pile.Pile.chopper(self, tmin, tmax, tinc, tpad, *args, **kwargs)
74 def process(self, iblock, tmin, tmax, traces):
75 return traces
77 def _update_range(self, tmin, tmax):
78 imin = int(math.floor(tmin / self._tinc))
79 imax = int(math.floor(tmax / self._tinc)+1)
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()
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)
99 def _process_blocks(self, imin, imax):
100 pmin = imin * self._tinc
101 pmax = imax * self._tinc
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
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})
123 self.load_files(fns, fileformat='mseed', show_progress=False)
124 else:
125 file = pile.MemTracesFile(None, traces)
126 self.add_file(file)
128 def _clearblock(self, iblock):
129 for file in self._blocks[iblock].files:
130 self.remove_file(file)