1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

# https://pyrocko.org - GPLv3 

# 

# The Pyrocko Developers, 21st Century 

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

 

from __future__ import absolute_import, print_function, division 

 

import numpy as num 

 

 

def neighborhood_density(dists, neighborhood=1): 

sdists = dists.copy() 

sdists.sort(axis=1) 

meandists = num.mean(sdists[:, 1:1+neighborhood], axis=1) 

return meandists 

 

 

def _weed(dists, badnesses, neighborhood=1, interaction_radius=3., 

del_frac=4, max_del=100, max_depth=100, depth=0): 

 

if depth > max_depth: 

assert False, 'max recursion depth reached' 

 

meandists = neighborhood_density(dists, neighborhood) 

 

order = meandists.argsort() 

candidates = order[:order.size//del_frac+1] 

badness_candidates = badnesses[candidates] 

order_badness = (-badness_candidates).argsort() 

 

order[:order.size//del_frac+1] = \ 

order[:order.size//del_frac+1][order_badness] 

 

deleted = num.zeros(order.size, dtype=num.bool) 

ndeleted = 0 

for i, ind in enumerate(order): 

if (i < order.size // del_frac // 2 + 1 

and ndeleted < max_del 

and num.all( 

dists[ind, deleted] > interaction_radius*meandists[ind])): 

 

deleted[ind] = True 

ndeleted += 1 

 

if ndeleted == 0: 

return deleted 

 

kept = num.logical_not(deleted).nonzero()[0] 

 

xdists = dists[num.meshgrid(kept, kept)] 

xbadnesses = badnesses[kept] 

xdeleted = _weed(xdists, xbadnesses, neighborhood, interaction_radius, 

del_frac, max_del-ndeleted, max_depth, depth+1) 

 

deleted[kept] = xdeleted 

return deleted 

 

 

def weed(x, y, badnesses, neighborhood=1, nwanted=None, interaction_radius=3.): 

assert x.size == y.size 

n = x.size 

NEW = num.newaxis 

ax = x[NEW, :] 

ay = y[NEW, :] 

bx = x[:, NEW] 

by = y[:, NEW] 

 

if nwanted is None: 

nwanted = n // 2 

 

dx = num.abs(ax-bx) 

dx = num.where(dx > 180., 360.-dx, dx) 

 

dists = num.sqrt(dx**2 + (ay-by)**2) 

deleted = _weed( 

dists, badnesses, neighborhood, interaction_radius, del_frac=4, 

max_del=n-nwanted, max_depth=500, depth=0) 

 

kept = num.logical_not(deleted).nonzero()[0] 

dists_kept = dists[num.meshgrid(kept, kept)] 

meandists_kept = neighborhood_density(dists_kept, neighborhood) 

return deleted, meandists_kept 

 

 

def badnesses_c_mean(badnesses_nslc): 

# convert stream badnesses to station badnesses by averaging 

badnesses_nsl = {} 

for nslc, b in badnesses_nslc.items(): 

nsl = nslc[:3] 

badnesses_nsl.setdefault(nsl, []).append(b) 

 

for nsl in list(badnesses_nsl.keys()): 

this_station_badness = badnesses_nsl[nsl] 

badnesses_nsl[nsl] = sum(this_station_badness) \ 

/ len(this_station_badness) 

 

return badnesses_nsl 

 

 

def weed_stations(stations, nwanted, neighborhood=3, default_badness=1.0, 

badnesses=None, 

badnesses_ns={}, badnesses_nsl={}, badnesses_nslc={}): 

 

azimuths = num.zeros(len(stations), dtype=num.float) 

dists = num.zeros(len(stations), dtype=num.float) 

for ista, sta in enumerate(stations): 

azimuths[ista] = sta.azimuth 

dists[ista] = sta.dist_deg 

 

badnesses_nslc_mean_c = badnesses_c_mean(badnesses_nslc) 

badnesses2 = num.ones(len(stations), dtype=float) 

for ista, sta in enumerate(stations): 

nsl = sta.network, sta.station, sta.location 

if badnesses is not None: 

b = badnesses[ista] 

else: 

b = 1.0 

b *= badnesses_ns.get(nsl, 1.0) 

b *= badnesses_nsl.get(nsl, 1.0) 

b *= badnesses_nslc_mean_c.get(nsl, 1.0) 

badnesses2[ista] = b 

 

deleted, meandists_kept = weed( 

azimuths, dists, badnesses2, 

nwanted=nwanted, 

neighborhood=neighborhood) 

 

stations_weeded = [station for (delete, station) in zip(deleted, stations) 

if not delete] 

 

return stations_weeded, meandists_kept, deleted