Coverage for /usr/local/lib/python3.11/dist-packages/grond/targets/phase_pick/target.py: 86%
104 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-26 16:25 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-26 16:25 +0000
1import logging
3import numpy as num
5from pyrocko.guts import Float, Tuple, String
6from pyrocko import gf
8from ..base import (
9 MisfitTarget, TargetGroup, MisfitResult)
10from grond.meta import has_get_plot_classes
12guts_prefix = 'grond'
13logger = logging.getLogger('grond.targets.phase_pick.target')
16def log_exclude(target, reason):
17 logger.debug('Excluding potential target %s: %s' % (
18 target.string_id(), reason))
21class PhasePickTargetGroup(TargetGroup):
23 '''
24 Generate targets to fit phase arrival times.
25 '''
27 distance_min = Float.T(optional=True)
28 distance_max = Float.T(optional=True)
29 distance_3d_min = Float.T(optional=True)
30 distance_3d_max = Float.T(optional=True)
31 depth_min = Float.T(optional=True)
32 depth_max = Float.T(optional=True)
33 store_id = gf.StringID.T(optional=True)
34 pick_synthetic_traveltime = gf.Timing.T(
35 help='Synthetic phase arrival definition.')
36 pick_phasename = String.T(
37 help='Name of phase in pick file.')
39 def get_targets(self, ds, event, default_path='none'):
40 logger.debug('Selecting phase pick targets...')
41 origin = event
42 targets = []
44 for st in ds.get_stations():
46 target = PhasePickTarget(
47 codes=st.nsl(),
48 lat=st.lat,
49 lon=st.lon,
50 north_shift=st.north_shift,
51 east_shift=st.east_shift,
52 depth=st.depth,
53 store_id=self.store_id,
54 manual_weight=self.weight,
55 normalisation_family=self.normalisation_family,
56 path=self.path or default_path,
57 pick_synthetic_traveltime=self.pick_synthetic_traveltime,
58 pick_phasename=self.pick_phasename)
60 if self.distance_min is not None and \
61 target.distance_to(origin) < self.distance_min:
62 log_exclude(target, 'distance < distance_min')
63 continue
65 if self.distance_max is not None and \
66 target.distance_to(origin) > self.distance_max:
67 log_exclude(target, 'distance > distance_max')
68 continue
70 if self.distance_3d_min is not None and \
71 target.distance_3d_to(origin) < self.distance_3d_min:
72 log_exclude(target, 'distance_3d < distance_3d_min')
73 continue
75 if self.distance_3d_max is not None and \
76 target.distance_3d_to(origin) > self.distance_3d_max:
77 log_exclude(target, 'distance_3d > distance_3d_max')
78 continue
80 if self.depth_min is not None and \
81 target.depth < self.depth_min:
82 log_exclude(target, 'depth < depth_min')
83 continue
85 if self.depth_max is not None and \
86 target.depth > self.depth_max:
87 log_exclude(target, 'depth > depth_max')
88 continue
90 marker = ds.get_pick(
91 event.name,
92 target.codes[:3],
93 target.pick_phasename)
95 if not marker:
96 log_exclude(target, 'no pick available')
97 continue
99 target.set_dataset(ds)
100 targets.append(target)
102 return targets
105class PhasePickResult(MisfitResult):
106 tobs = Float.T(optional=True)
107 tsyn = Float.T(optional=True)
110@has_get_plot_classes
111class PhasePickTarget(gf.Location, MisfitTarget):
113 '''
114 Target to fit phase arrival times.
115 '''
117 codes = Tuple.T(
118 3, String.T(),
119 help='network, station, location codes.')
121 store_id = gf.StringID.T(
122 help='ID of Green\'s function store (only used for earth model).')
124 pick_synthetic_traveltime = gf.Timing.T(
125 help='Synthetic phase arrival definition.')
127 pick_phasename = String.T(
128 help='Name of phase in pick file.')
130 can_bootstrap_weights = True
132 def __init__(self, **kwargs):
133 gf.Location.__init__(self, **kwargs)
134 MisfitTarget.__init__(self, **kwargs)
135 self._tobs_cache = {}
137 @classmethod
138 def get_plot_classes(cls):
139 from . import plot
140 plots = super(PhasePickTarget, cls).get_plot_classes()
141 plots.extend(plot.get_plot_classes())
142 return plots
144 def string_id(self):
145 return '.'.join(x for x in (self.path,) + self.codes)
147 def set_dataset(self, ds):
148 MisfitTarget.set_dataset(self, ds)
149 self._tobs_cache = {}
151 def get_plain_targets(self, engine, source):
152 return self.prepare_modelling(engine, source, None)
154 def prepare_modelling(self, engine, source, targets):
155 return []
157 def get_times(self, engine, source):
158 tsyn = None
160 k = source.name
161 if k not in self._tobs_cache:
162 ds = self.get_dataset()
163 tobs = None
164 marker = ds.get_pick(
165 source.name,
166 self.codes[:3],
167 self.pick_phasename)
169 if marker:
170 self._tobs_cache[k] = marker.tmin
171 else:
172 self._tobs_cache[k] = None
174 tobs = self._tobs_cache[k]
176 store = engine.get_store(self.store_id)
177 tsyn = source.time + store.t(
178 self.pick_synthetic_traveltime, source, self)
180 return tobs, tsyn
182 def finalize_modelling(
183 self, engine, source, modelling_targets, modelling_results):
185 ds = self.get_dataset() # noqa
187 tobs, tsyn = self.get_times(engine, source)
188 if None not in (tobs, tsyn):
189 misfit = abs(tobs - tsyn)
190 else:
191 misfit = None
193 norm = 1.0
194 result = PhasePickResult(
195 tobs=tobs,
196 tsyn=tsyn,
197 misfits=num.array([[misfit, norm]], dtype=float))
199 return result
202__all__ = '''
203 PhasePickTargetGroup
204 PhasePickTarget
205 PhasePickResult
206'''.split()