1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
5from __future__ import absolute_import, division, print_function
7import numpy as num
8from pyrocko import model
9from pyrocko.guts import Int, String, List
11from pyrocko.model.station import load_stations
12from pyrocko.io import stationxml
13from pyrocko.orthodrome import distance_accurate50m_numpy, \
14 geographic_midpoint_locations
16from .base import LocationGenerator
18guts_prefix = 'pf.scenario'
21class StationGenerator(LocationGenerator):
23 def get_stations(self):
24 raise NotImplementedError
26 def get_distance_range(self, sources):
27 dists = []
28 for source in sources:
29 for station in self.get_stations():
30 dists.append(
31 source.distance_to(station))
33 return num.min(dists), num.max(dists)
35 def ensure_data(self, engine, sources, path, tmin=None, tmax=None):
36 return []
38 def add_map_artists(self, engine, sources, automap):
39 automap.add_stations(self.get_stations())
42class ImportStationGenerator(StationGenerator):
44 stations_paths = List.T(
45 optional=True,
46 help='List of files with station coordinates in Pyrocko format.')
48 stations_stationxml_paths = List.T(
49 optional=True,
50 help='List of files with station coordinates in StationXML format.')
52 pyrocko_stations = List.T(
53 model.Station.T(),
54 optional=True,
55 help='List of Pyrocko stations')
57 def __init__(self, **kwargs):
58 StationGenerator.__init__(self, **kwargs)
59 self._stations = None
61 def has_stations(self):
62 if not self.get_stations():
63 return False
64 return True
66 def get_center_latlon(self):
67 stations = self.get_stations()
68 if not stations:
69 return self._parent.get_center_latlon()
71 return geographic_midpoint_locations(self.get_stations())
73 def get_radius(self):
74 stations = self.get_stations()
75 if not stations:
76 return self._parent.get_radius()
78 clat, clon = self.get_center_latlon()
79 radii = distance_accurate50m_numpy(
80 clat, clon,
81 [st.effective_lat for st in stations],
82 [st.effective_lon for st in stations])
84 return float(radii.max())
86 def get_stations(self):
87 if self._stations is None:
89 stations = []
91 if self.stations_paths:
92 for filename in self.stations_paths:
93 stations.extend(
94 load_stations(filename))
96 if self.stations_stationxml_paths:
97 for filename in self.stations_stationxml_paths:
98 sxml = stationxml.load_xml(filename=filename)
99 stations.extend(
100 sxml.get_pyrocko_stations())
102 if self.pyrocko_stations:
103 stations.extend(self.pyrocko_stations)
105 self._stations = stations
107 return self._stations
109 def nsl(self, istation):
110 stations = self.get_stations()
111 return stations[istation].nsl()
113 def clear(self):
114 self._stations = None
116 @property
117 def nstations(self):
118 return len(self.get_stations())
121class RandomStationGenerator(StationGenerator):
123 nstations = Int.T(
124 default=10,
125 help='Number of randomly distributed stations.')
127 network_name = String.T(
128 default='CO',
129 help='Network name')
131 channels = List.T(
132 optional=True,
133 default=['BHE', 'BHN', 'BHZ'],
134 help='Seismic channels to generate. Default: BHN, BHE, BHZ')
136 def __init__(self, **kwargs):
137 StationGenerator.__init__(self, **kwargs)
138 self._stations = None
140 def clear(self):
141 StationGenerator.clear(self)
142 self._stations = None
144 def nsl(self, istation):
145 return self.network_name, 'S%03i' % (istation + 1), '',
147 def get_stations(self):
148 if self._stations is None:
150 if self.channels:
151 channels = [model.station.Channel(c) for c in self.channels]
152 else:
153 channels = None
155 stations = []
156 for istation in range(self.nstations):
157 lat, lon, north_shift, east_shift, depth = map(
158 float, self.get_coordinates(istation))
160 net, sta, loc = self.nsl(istation)
161 station = model.Station(
162 net, sta, loc,
163 lat=lat,
164 lon=lon,
165 north_shift=north_shift,
166 east_shift=east_shift,
167 depth=depth,
168 channels=channels)
170 stations.append(station)
172 self._stations = stations
174 return self._stations