Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/dataset/active_faults.py: 82%

80 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-10-06 09:48 +0000

1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6''' 

7GEM Global Active Faults Database 

8(`GEM GAF-DB <https://github.com/GEMScienceTools/gem-global-active-faults>`_). 

9 

10If the database is not already available, it will be downloaded 

11automatically on first use. 

12 

13.. note:: 

14 

15 If you use this dataset, please cite: 

16 

17 Styron, Richard, and Marco Pagani. “The GEM Global Active Faults Database.” 

18 Earthquake Spectra, vol. 36, no. 1_suppl, Oct. 2020, pp. 160–180, 

19 doi:10.1177/8755293020944182. 

20''' 

21 

22import re 

23import logging 

24import numpy as num 

25from os import path as op 

26from collections import OrderedDict 

27import json 

28 

29from pyrocko import config, util 

30 

31 

32def parse_3tup(s): 

33 m = re.match(r'^\(?([^,]+),([^,]*),([^,]*)\)$', s) 

34 if m: 

35 return [float(m.group(1)) if m.group(1) else None for i in range(3)] 

36 else: 

37 return [None, None, None] 

38 

39 

40logger = logging.getLogger('ActiveFaults') 

41 

42 

43class ActiveFault(object): 

44 ''' 

45 Representation of a single active fault. 

46 ''' 

47 __fields__ = OrderedDict([ 

48 

49 ('lat', list), 

50 ('lon', list), 

51 ('average_dip', float), 

52 ('average_rake', float), 

53 ('lower_seis_depth', float), 

54 ('upper_seis_depth', float), 

55 ('slip_type', str), 

56 ]) 

57 

58 __slots__ = list(__fields__.keys()) 

59 

60 def get_property(self, fault_obj, attr): 

61 try: 

62 values = float(fault_obj['properties'][attr][1:3]) 

63 except KeyError: 

64 if attr == 'lower_seis_depth' or attr == 'upper_seis_depth': 

65 values = 0 

66 else: 

67 values = -999 

68 return values 

69 

70 def __init__(self, f): 

71 nodes = f['geometry']['coordinates'] 

72 props = f['properties'] 

73 lons = [p[0] for p in nodes] 

74 lats = [p[1] for p in nodes] 

75 self.lon = lons 

76 self.lat = lats 

77 self.slip_type = props.get('slip_type', 'Unknown') 

78 

79 for attr, attr_type in self.__fields__.items(): 

80 if attr in props: 

81 if props[attr] is None or props[attr] == '': 

82 continue 

83 

84 if isinstance(props[attr], attr_type): 

85 v = props[attr] 

86 

87 elif attr_type is float: 

88 try: 

89 v = parse_3tup(props[attr])[0] 

90 except TypeError: 

91 v = float(props[attr]) 

92 

93 elif attr_type is int: 

94 v = int(props[attr]) 

95 

96 else: 

97 v = None 

98 

99 setattr(self, attr, v) 

100 

101 def get_surface_line(self): 

102 arr = num.empty((len(self.lat), 2)) 

103 for i in range(len(self.lat)): 

104 arr[i, 0] = self.lat[i] 

105 arr[i, 1] = self.lon[i] 

106 

107 return arr 

108 

109 def __str__(self): 

110 d = {attr: getattr(self, attr) for attr in self.__fields__.keys()} 

111 return '\n'.join(['%s: %s' % (attr, val) for attr, val in d.items()]) 

112 

113 

114class ActiveFaults(object): 

115 ''' 

116 GEM Global Active Faults Database (`GEM GAF-DB 

117 <https://github.com/GEMScienceTools/gem-global-active-faults>`_). 

118 

119 :ivar active_faults: 

120 Fault parameters. 

121 :vartype active_faults: 

122 :py:class:`list` of :py:class:`ActiveFault` 

123 ''' 

124 URL_GEM_ACTIVE_FAULTS = 'https://raw.githubusercontent.com/cossatot/gem-global-active-faults/master/geojson/gem_active_faults.geojson' # noqa 

125 

126 def __init__(self): 

127 self.fname_active_faults = op.join( 

128 config.config().fault_lines_dir, 'gem_active_faults.geojson') 

129 

130 if not op.exists(self.fname_active_faults): 

131 self.download() 

132 

133 self.active_faults = [] 

134 self._load_faults(self.fname_active_faults) 

135 

136 def _load_faults(self, fname): 

137 with open(fname, 'r') as f: 

138 gj = json.load(f) 

139 faults = gj['features'] 

140 for f in faults: 

141 fault = ActiveFault(f) 

142 self.active_faults.append(fault) 

143 logger.debug('loaded %d fault', self.nactive_faults) 

144 

145 def download(self): 

146 logger.info('Downloading GEM active faults database...') 

147 util.download_file(self.URL_GEM_ACTIVE_FAULTS, 

148 self.fname_active_faults) 

149 

150 @property 

151 def nactive_faults(self): 

152 return len(self.active_faults) 

153 

154 def nactive_faults_nodes(self): 

155 return int(sum(len(f.lat) for f in self.active_faults)) 

156 

157 def get_coords(self): 

158 return num.array([f['coordinates'] for f in self.active_faults]) 

159 

160 

161if __name__ == '__main__': 

162 logging.basicConfig(level=logging.DEBUG) 

163 activefaults = ActiveFaults()