Coverage for /usr/local/lib/python3.11/dist-packages/grond/targets/phase_pick/target.py: 83%

104 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-10-26 16:08 +0000

1import logging 

2 

3import numpy as num 

4 

5from pyrocko.guts import Float, Tuple, String 

6from pyrocko import gf 

7 

8from ..base import ( 

9 MisfitTarget, TargetGroup, MisfitResult) 

10from grond.meta import has_get_plot_classes 

11 

12guts_prefix = 'grond' 

13logger = logging.getLogger('grond.targets.phase_pick.target') 

14 

15 

16def log_exclude(target, reason): 

17 logger.debug('Excluding potential target %s: %s' % ( 

18 target.string_id(), reason)) 

19 

20 

21class PhasePickTargetGroup(TargetGroup): 

22 

23 ''' 

24 Generate targets to fit phase arrival times. 

25 ''' 

26 

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.') 

38 

39 def get_targets(self, ds, event, default_path='none'): 

40 logger.debug('Selecting phase pick targets...') 

41 origin = event 

42 targets = [] 

43 

44 for st in ds.get_stations(): 

45 

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) 

59 

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 

64 

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 

69 

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 

74 

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 

79 

80 if self.depth_min is not None and \ 

81 target.depth < self.depth_min: 

82 log_exclude(target, 'depth < depth_min') 

83 continue 

84 

85 if self.depth_max is not None and \ 

86 target.depth > self.depth_max: 

87 log_exclude(target, 'depth > depth_max') 

88 continue 

89 

90 marker = ds.get_pick( 

91 event.name, 

92 target.codes[:3], 

93 target.pick_phasename) 

94 

95 if not marker: 

96 log_exclude(target, 'no pick available') 

97 continue 

98 

99 target.set_dataset(ds) 

100 targets.append(target) 

101 

102 return targets 

103 

104 

105class PhasePickResult(MisfitResult): 

106 tobs = Float.T(optional=True) 

107 tsyn = Float.T(optional=True) 

108 

109 

110@has_get_plot_classes 

111class PhasePickTarget(gf.Location, MisfitTarget): 

112 

113 ''' 

114 Target to fit phase arrival times. 

115 ''' 

116 

117 codes = Tuple.T( 

118 3, String.T(), 

119 help='network, station, location codes.') 

120 

121 store_id = gf.StringID.T( 

122 help='ID of Green\'s function store (only used for earth model).') 

123 

124 pick_synthetic_traveltime = gf.Timing.T( 

125 help='Synthetic phase arrival definition.') 

126 

127 pick_phasename = String.T( 

128 help='Name of phase in pick file.') 

129 

130 can_bootstrap_weights = True 

131 

132 def __init__(self, **kwargs): 

133 gf.Location.__init__(self, **kwargs) 

134 MisfitTarget.__init__(self, **kwargs) 

135 self._tobs_cache = {} 

136 

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 

143 

144 def string_id(self): 

145 return '.'.join(x for x in (self.path,) + self.codes) 

146 

147 def set_dataset(self, ds): 

148 MisfitTarget.set_dataset(self, ds) 

149 self._tobs_cache = {} 

150 

151 def get_plain_targets(self, engine, source): 

152 return self.prepare_modelling(engine, source, None) 

153 

154 def prepare_modelling(self, engine, source, targets): 

155 return [] 

156 

157 def get_times(self, engine, source): 

158 tsyn = None 

159 

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) 

168 

169 if marker: 

170 self._tobs_cache[k] = marker.tmin 

171 else: 

172 self._tobs_cache[k] = None 

173 

174 tobs = self._tobs_cache[k] 

175 

176 store = engine.get_store(self.store_id) 

177 tsyn = source.time + store.t( 

178 self.pick_synthetic_traveltime, source, self) 

179 

180 return tobs, tsyn 

181 

182 def finalize_modelling( 

183 self, engine, source, modelling_targets, modelling_results): 

184 

185 ds = self.get_dataset() # noqa 

186 

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 

192 

193 norm = 1.0 

194 result = PhasePickResult( 

195 tobs=tobs, 

196 tsyn=tsyn, 

197 misfits=num.array([[misfit, norm]], dtype=float)) 

198 

199 return result 

200 

201 

202__all__ = ''' 

203 PhasePickTargetGroup 

204 PhasePickTarget 

205 PhasePickResult 

206'''.split()