gtrack 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gtrack/__init__.py +137 -0
- gtrack/boundaries.py +396 -0
- gtrack/config.py +202 -0
- gtrack/geometry.py +348 -0
- gtrack/hpc_integration.py +851 -0
- gtrack/initial_conditions.py +255 -0
- gtrack/io_formats.py +477 -0
- gtrack/logging.py +193 -0
- gtrack/mesh.py +101 -0
- gtrack/mor_seeds.py +390 -0
- gtrack/point_rotation.py +836 -0
- gtrack/polygon_filter.py +223 -0
- gtrack/spatial.py +397 -0
- gtrack-0.3.0.dist-info/METADATA +66 -0
- gtrack-0.3.0.dist-info/RECORD +17 -0
- gtrack-0.3.0.dist-info/WHEEL +5 -0
- gtrack-0.3.0.dist-info/top_level.txt +1 -0
gtrack/__init__.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
gtrack: High-performance seafloor age tracking and point rotation.
|
|
3
|
+
|
|
4
|
+
This package provides tools for:
|
|
5
|
+
- Computing seafloor ages from plate tectonic reconstructions using Lagrangian
|
|
6
|
+
particle tracking with pygplates' C++ backend (GPlately-compatible)
|
|
7
|
+
- Rotating user-provided points through geological time
|
|
8
|
+
- Filtering points by polygon containment (e.g., continental regions)
|
|
9
|
+
|
|
10
|
+
The main entry point is SeafloorAgeTracker, which provides both a stepwise
|
|
11
|
+
interface and a one-shot compute_ages() method.
|
|
12
|
+
|
|
13
|
+
Logging
|
|
14
|
+
-------
|
|
15
|
+
gtrack uses Python's logging module. Control verbosity via environment variable:
|
|
16
|
+
|
|
17
|
+
export GTRACK_LOGLEVEL=INFO # Progress messages
|
|
18
|
+
export GTRACK_LOGLEVEL=DEBUG # Detailed debug output
|
|
19
|
+
export GTRACK_LOGLEVEL=WARNING # Quiet (default)
|
|
20
|
+
|
|
21
|
+
Or programmatically:
|
|
22
|
+
|
|
23
|
+
>>> from gtrack import enable_verbose, enable_debug
|
|
24
|
+
>>> enable_verbose() # Show progress messages
|
|
25
|
+
|
|
26
|
+
Example
|
|
27
|
+
-------
|
|
28
|
+
>>> from gtrack import SeafloorAgeTracker, TracerConfig
|
|
29
|
+
>>>
|
|
30
|
+
>>> # Simple one-shot computation
|
|
31
|
+
>>> cloud = SeafloorAgeTracker.compute_ages(
|
|
32
|
+
... target_age=100,
|
|
33
|
+
... starting_age=200,
|
|
34
|
+
... rotation_files=['rotations.rot'],
|
|
35
|
+
... topology_files=['topologies.gpmlz']
|
|
36
|
+
... )
|
|
37
|
+
>>> ages = cloud.get_property('age')
|
|
38
|
+
>>>
|
|
39
|
+
>>> # Or stepwise for intermediate states
|
|
40
|
+
>>> tracker = SeafloorAgeTracker(
|
|
41
|
+
... rotation_files=['rotations.rot'],
|
|
42
|
+
... topology_files=['topologies.gpmlz']
|
|
43
|
+
... )
|
|
44
|
+
>>> tracker.initialize(starting_age=200)
|
|
45
|
+
>>> for age in range(199, -1, -1):
|
|
46
|
+
... cloud = tracker.step_to(age)
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
__version__ = "0.2.0"
|
|
50
|
+
|
|
51
|
+
# Logging configuration (import first to configure before other modules)
|
|
52
|
+
from .logging import (
|
|
53
|
+
configure_logging,
|
|
54
|
+
set_log_level,
|
|
55
|
+
enable_verbose,
|
|
56
|
+
enable_debug,
|
|
57
|
+
disable_logging,
|
|
58
|
+
get_logger,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Core seafloor age functionality
|
|
62
|
+
from .config import TracerConfig
|
|
63
|
+
from .hpc_integration import SeafloorAgeTracker
|
|
64
|
+
|
|
65
|
+
# Point rotation API
|
|
66
|
+
from .point_rotation import PointCloud, PointRotator
|
|
67
|
+
from .polygon_filter import PolygonFilter
|
|
68
|
+
from .io_formats import (
|
|
69
|
+
load_points_numpy,
|
|
70
|
+
load_points_latlon,
|
|
71
|
+
load_points_gpml,
|
|
72
|
+
save_points_numpy,
|
|
73
|
+
save_points_latlon,
|
|
74
|
+
save_points_gpml,
|
|
75
|
+
PointCloudCheckpoint,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Utility modules (for advanced users)
|
|
79
|
+
from .mesh import (
|
|
80
|
+
create_sphere_mesh_xyz,
|
|
81
|
+
create_sphere_mesh_latlon,
|
|
82
|
+
)
|
|
83
|
+
from .mor_seeds import (
|
|
84
|
+
generate_mor_seeds,
|
|
85
|
+
generate_mor_seeds_with_plate_ids,
|
|
86
|
+
get_ridge_geometries,
|
|
87
|
+
)
|
|
88
|
+
from .initial_conditions import (
|
|
89
|
+
compute_initial_ages,
|
|
90
|
+
default_age_distance_law,
|
|
91
|
+
)
|
|
92
|
+
from .boundaries import (
|
|
93
|
+
ContinentalPolygonCache,
|
|
94
|
+
ResolvedTopologyCache,
|
|
95
|
+
extract_ridge_geometries,
|
|
96
|
+
extract_ridge_points_latlon,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
__all__ = [
|
|
100
|
+
# Main API
|
|
101
|
+
"SeafloorAgeTracker",
|
|
102
|
+
"TracerConfig",
|
|
103
|
+
# Logging
|
|
104
|
+
"configure_logging",
|
|
105
|
+
"set_log_level",
|
|
106
|
+
"enable_verbose",
|
|
107
|
+
"enable_debug",
|
|
108
|
+
"disable_logging",
|
|
109
|
+
"get_logger",
|
|
110
|
+
# Point rotation
|
|
111
|
+
"PointCloud",
|
|
112
|
+
"PointRotator",
|
|
113
|
+
"PolygonFilter",
|
|
114
|
+
# IO utilities
|
|
115
|
+
"load_points_numpy",
|
|
116
|
+
"load_points_latlon",
|
|
117
|
+
"load_points_gpml",
|
|
118
|
+
"save_points_numpy",
|
|
119
|
+
"save_points_latlon",
|
|
120
|
+
"save_points_gpml",
|
|
121
|
+
"PointCloudCheckpoint",
|
|
122
|
+
# Mesh generation (advanced)
|
|
123
|
+
"create_sphere_mesh_xyz",
|
|
124
|
+
"create_sphere_mesh_latlon",
|
|
125
|
+
# MOR seeds (advanced)
|
|
126
|
+
"generate_mor_seeds",
|
|
127
|
+
"generate_mor_seeds_with_plate_ids",
|
|
128
|
+
"get_ridge_geometries",
|
|
129
|
+
# Initial conditions (advanced)
|
|
130
|
+
"compute_initial_ages",
|
|
131
|
+
"default_age_distance_law",
|
|
132
|
+
# Caching (advanced)
|
|
133
|
+
"ContinentalPolygonCache",
|
|
134
|
+
"ResolvedTopologyCache",
|
|
135
|
+
"extract_ridge_geometries",
|
|
136
|
+
"extract_ridge_points_latlon",
|
|
137
|
+
]
|
gtrack/boundaries.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Plate boundary caching and extraction utilities.
|
|
3
|
+
|
|
4
|
+
This module provides caching for resolved topologies and utility functions
|
|
5
|
+
for extracting plate boundary information. The main reconstruction is handled
|
|
6
|
+
by pygplates' C++ backend (TopologicalModel.reconstruct_geometry).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pygplates
|
|
11
|
+
from collections import OrderedDict
|
|
12
|
+
from typing import Dict, List, Optional, Tuple
|
|
13
|
+
|
|
14
|
+
from .spatial import find_polygons
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ResolvedTopologyCache:
|
|
18
|
+
"""
|
|
19
|
+
LRU cache for resolved topologies at different timesteps.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
topology_features : pygplates.FeatureCollection or list
|
|
24
|
+
Topology features for resolving.
|
|
25
|
+
rotation_model : pygplates.RotationModel
|
|
26
|
+
Rotation model for reconstruction.
|
|
27
|
+
max_cache_size : int, default=10
|
|
28
|
+
Maximum number of timesteps to cache.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
topology_features,
|
|
34
|
+
rotation_model: pygplates.RotationModel,
|
|
35
|
+
max_cache_size: int = 10,
|
|
36
|
+
):
|
|
37
|
+
self.topology_features = topology_features
|
|
38
|
+
self.rotation_model = rotation_model
|
|
39
|
+
self.max_cache_size = max_cache_size
|
|
40
|
+
|
|
41
|
+
# LRU cache: {time: (resolved_topologies, shared_boundary_sections)}
|
|
42
|
+
self._cache: OrderedDict = OrderedDict()
|
|
43
|
+
|
|
44
|
+
def get(self, time: float) -> Tuple[List, List]:
|
|
45
|
+
"""
|
|
46
|
+
Get resolved topologies and shared boundary sections for a time.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
time : float
|
|
51
|
+
Geological time (Ma).
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
resolved_topologies : list
|
|
56
|
+
List of resolved topology polygons.
|
|
57
|
+
shared_boundary_sections : list
|
|
58
|
+
List of shared boundary sections.
|
|
59
|
+
"""
|
|
60
|
+
if time in self._cache:
|
|
61
|
+
# Move to end (most recently used)
|
|
62
|
+
self._cache.move_to_end(time)
|
|
63
|
+
return self._cache[time]
|
|
64
|
+
|
|
65
|
+
# Resolve topologies
|
|
66
|
+
resolved_topologies = []
|
|
67
|
+
shared_boundary_sections = []
|
|
68
|
+
pygplates.resolve_topologies(
|
|
69
|
+
self.topology_features,
|
|
70
|
+
self.rotation_model,
|
|
71
|
+
resolved_topologies,
|
|
72
|
+
time,
|
|
73
|
+
shared_boundary_sections,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Add to cache
|
|
77
|
+
self._cache[time] = (resolved_topologies, shared_boundary_sections)
|
|
78
|
+
|
|
79
|
+
# Evict oldest if over capacity
|
|
80
|
+
while len(self._cache) > self.max_cache_size:
|
|
81
|
+
self._cache.popitem(last=False)
|
|
82
|
+
|
|
83
|
+
return resolved_topologies, shared_boundary_sections
|
|
84
|
+
|
|
85
|
+
def clear(self):
|
|
86
|
+
"""Clear the cache."""
|
|
87
|
+
self._cache.clear()
|
|
88
|
+
|
|
89
|
+
def get_memory_usage(self) -> Dict[str, float]:
|
|
90
|
+
"""Get approximate memory usage information."""
|
|
91
|
+
return {
|
|
92
|
+
'cached_timesteps': len(self._cache),
|
|
93
|
+
'max_cache_size': self.max_cache_size,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ContinentalPolygonCache:
|
|
98
|
+
"""
|
|
99
|
+
Cache for reconstructed continental polygons with efficient point-in-polygon queries.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
continental_polygons : str or pygplates.FeatureCollection
|
|
104
|
+
Continental polygon features.
|
|
105
|
+
rotation_model : pygplates.RotationModel
|
|
106
|
+
Rotation model for reconstruction.
|
|
107
|
+
max_cache_size : int, default=10
|
|
108
|
+
Maximum number of timesteps to cache.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def __init__(
|
|
112
|
+
self,
|
|
113
|
+
continental_polygons,
|
|
114
|
+
rotation_model: pygplates.RotationModel,
|
|
115
|
+
max_cache_size: int = 10,
|
|
116
|
+
):
|
|
117
|
+
# Load continental polygons
|
|
118
|
+
if isinstance(continental_polygons, str):
|
|
119
|
+
self._polygon_features = pygplates.FeatureCollection(continental_polygons)
|
|
120
|
+
else:
|
|
121
|
+
self._polygon_features = continental_polygons
|
|
122
|
+
|
|
123
|
+
self.rotation_model = rotation_model
|
|
124
|
+
self.max_cache_size = max_cache_size
|
|
125
|
+
|
|
126
|
+
# LRU cache: {time: list of reconstructed polygon geometries}
|
|
127
|
+
self._cache: OrderedDict = OrderedDict()
|
|
128
|
+
|
|
129
|
+
def get_polygons(self, time: float) -> List[pygplates.PolygonOnSphere]:
|
|
130
|
+
"""
|
|
131
|
+
Get reconstructed continental polygons at a time.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
time : float
|
|
136
|
+
Geological time (Ma).
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
list of pygplates.PolygonOnSphere
|
|
141
|
+
Reconstructed continental polygon geometries.
|
|
142
|
+
"""
|
|
143
|
+
if time in self._cache:
|
|
144
|
+
self._cache.move_to_end(time)
|
|
145
|
+
return self._cache[time]
|
|
146
|
+
|
|
147
|
+
# Reconstruct polygons
|
|
148
|
+
reconstructed = []
|
|
149
|
+
pygplates.reconstruct(
|
|
150
|
+
self._polygon_features,
|
|
151
|
+
self.rotation_model,
|
|
152
|
+
reconstructed,
|
|
153
|
+
time,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Extract polygon geometries
|
|
157
|
+
polygon_geometries = []
|
|
158
|
+
for rfg in reconstructed:
|
|
159
|
+
geom = rfg.get_reconstructed_geometry()
|
|
160
|
+
if isinstance(geom, pygplates.PolygonOnSphere):
|
|
161
|
+
polygon_geometries.append(geom)
|
|
162
|
+
|
|
163
|
+
# Cache
|
|
164
|
+
self._cache[time] = polygon_geometries
|
|
165
|
+
|
|
166
|
+
# Evict oldest if over capacity
|
|
167
|
+
while len(self._cache) > self.max_cache_size:
|
|
168
|
+
self._cache.popitem(last=False)
|
|
169
|
+
|
|
170
|
+
return polygon_geometries
|
|
171
|
+
|
|
172
|
+
def get_continental_mask(
|
|
173
|
+
self,
|
|
174
|
+
lats: np.ndarray,
|
|
175
|
+
lons: np.ndarray,
|
|
176
|
+
time: float,
|
|
177
|
+
) -> np.ndarray:
|
|
178
|
+
"""
|
|
179
|
+
Get boolean mask indicating which points are inside continental polygons.
|
|
180
|
+
|
|
181
|
+
Uses ptt.utils.points_in_polygons.find_polygons for efficient vectorized
|
|
182
|
+
point-in-polygon testing with spatial tree acceleration.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
lats : np.ndarray
|
|
187
|
+
Point latitudes in degrees.
|
|
188
|
+
lons : np.ndarray
|
|
189
|
+
Point longitudes in degrees.
|
|
190
|
+
time : float
|
|
191
|
+
Geological time (Ma).
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
np.ndarray
|
|
196
|
+
Boolean array, True for points inside continental polygons.
|
|
197
|
+
"""
|
|
198
|
+
polygons = self.get_polygons(time)
|
|
199
|
+
|
|
200
|
+
if len(polygons) == 0:
|
|
201
|
+
return np.zeros(len(lats), dtype=bool)
|
|
202
|
+
|
|
203
|
+
# Create all points in single C++ call using MultiPointOnSphere
|
|
204
|
+
points = pygplates.MultiPointOnSphere(zip(lats, lons)).get_points()
|
|
205
|
+
|
|
206
|
+
# Use vectorized point-in-polygon with spatial tree
|
|
207
|
+
containing_polygons = find_polygons(
|
|
208
|
+
points, polygons, all_polygons=False
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# Convert to boolean mask: True if point is in any polygon
|
|
212
|
+
mask = np.array([p is not None for p in containing_polygons], dtype=bool)
|
|
213
|
+
|
|
214
|
+
return mask
|
|
215
|
+
|
|
216
|
+
def clear(self):
|
|
217
|
+
"""Clear the cache."""
|
|
218
|
+
self._cache.clear()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def extract_ridge_geometries(
|
|
222
|
+
time: float,
|
|
223
|
+
topology_features,
|
|
224
|
+
rotation_model: pygplates.RotationModel,
|
|
225
|
+
) -> List[pygplates.PolylineOnSphere]:
|
|
226
|
+
"""
|
|
227
|
+
Extract mid-ocean ridge geometries at a given time.
|
|
228
|
+
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
231
|
+
time : float
|
|
232
|
+
Geological time (Ma).
|
|
233
|
+
topology_features : pygplates.FeatureCollection or list
|
|
234
|
+
Topology features.
|
|
235
|
+
rotation_model : pygplates.RotationModel
|
|
236
|
+
Rotation model.
|
|
237
|
+
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
240
|
+
list of pygplates.PolylineOnSphere
|
|
241
|
+
Ridge geometries at the specified time.
|
|
242
|
+
"""
|
|
243
|
+
resolved_topologies = []
|
|
244
|
+
shared_boundary_sections = []
|
|
245
|
+
pygplates.resolve_topologies(
|
|
246
|
+
topology_features,
|
|
247
|
+
rotation_model,
|
|
248
|
+
resolved_topologies,
|
|
249
|
+
time,
|
|
250
|
+
shared_boundary_sections,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
ridge_geometries = []
|
|
254
|
+
for shared_boundary_section in shared_boundary_sections:
|
|
255
|
+
if (
|
|
256
|
+
shared_boundary_section.get_feature().get_feature_type()
|
|
257
|
+
== pygplates.FeatureType.create_gpml("MidOceanRidge")
|
|
258
|
+
):
|
|
259
|
+
for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
|
|
260
|
+
ridge_geometries.append(shared_sub_segment.get_resolved_geometry())
|
|
261
|
+
|
|
262
|
+
return ridge_geometries
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def extract_ridge_points_latlon(
|
|
266
|
+
time: float,
|
|
267
|
+
topology_features,
|
|
268
|
+
rotation_model: pygplates.RotationModel,
|
|
269
|
+
tessellate_degrees: float = 0.5,
|
|
270
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
271
|
+
"""
|
|
272
|
+
Extract mid-ocean ridge points as lat/lon arrays.
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
time : float
|
|
277
|
+
Geological time (Ma).
|
|
278
|
+
topology_features : pygplates.FeatureCollection or list
|
|
279
|
+
Topology features.
|
|
280
|
+
rotation_model : pygplates.RotationModel
|
|
281
|
+
Rotation model.
|
|
282
|
+
tessellate_degrees : float, default=0.5
|
|
283
|
+
Tessellation resolution in degrees.
|
|
284
|
+
|
|
285
|
+
Returns
|
|
286
|
+
-------
|
|
287
|
+
lats : np.ndarray
|
|
288
|
+
Ridge point latitudes in degrees.
|
|
289
|
+
lons : np.ndarray
|
|
290
|
+
Ridge point longitudes in degrees.
|
|
291
|
+
"""
|
|
292
|
+
ridge_geometries = extract_ridge_geometries(time, topology_features, rotation_model)
|
|
293
|
+
|
|
294
|
+
if len(ridge_geometries) == 0:
|
|
295
|
+
return np.array([]), np.array([])
|
|
296
|
+
|
|
297
|
+
all_lats = []
|
|
298
|
+
all_lons = []
|
|
299
|
+
|
|
300
|
+
for geom in ridge_geometries:
|
|
301
|
+
tessellated = geom.to_tessellated(np.radians(tessellate_degrees))
|
|
302
|
+
for point in tessellated:
|
|
303
|
+
lat, lon = point.to_lat_lon()
|
|
304
|
+
all_lats.append(lat)
|
|
305
|
+
all_lons.append(lon)
|
|
306
|
+
|
|
307
|
+
return np.array(all_lats), np.array(all_lons)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def extract_subduction_geometries(
|
|
311
|
+
time: float,
|
|
312
|
+
topology_features,
|
|
313
|
+
rotation_model: pygplates.RotationModel,
|
|
314
|
+
) -> List[pygplates.PolylineOnSphere]:
|
|
315
|
+
"""
|
|
316
|
+
Extract subduction zone geometries at a given time.
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
time : float
|
|
321
|
+
Geological time (Ma).
|
|
322
|
+
topology_features : pygplates.FeatureCollection or list
|
|
323
|
+
Topology features.
|
|
324
|
+
rotation_model : pygplates.RotationModel
|
|
325
|
+
Rotation model.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
list of pygplates.PolylineOnSphere
|
|
330
|
+
Subduction zone geometries at the specified time.
|
|
331
|
+
"""
|
|
332
|
+
resolved_topologies = []
|
|
333
|
+
shared_boundary_sections = []
|
|
334
|
+
pygplates.resolve_topologies(
|
|
335
|
+
topology_features,
|
|
336
|
+
rotation_model,
|
|
337
|
+
resolved_topologies,
|
|
338
|
+
time,
|
|
339
|
+
shared_boundary_sections,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
subduction_geometries = []
|
|
343
|
+
for shared_boundary_section in shared_boundary_sections:
|
|
344
|
+
feature_type = shared_boundary_section.get_feature().get_feature_type()
|
|
345
|
+
if feature_type == pygplates.FeatureType.create_gpml("SubductionZone"):
|
|
346
|
+
for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
|
|
347
|
+
subduction_geometries.append(shared_sub_segment.get_resolved_geometry())
|
|
348
|
+
|
|
349
|
+
return subduction_geometries
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def extract_subduction_points_latlon(
|
|
353
|
+
time: float,
|
|
354
|
+
topology_features,
|
|
355
|
+
rotation_model: pygplates.RotationModel,
|
|
356
|
+
tessellate_degrees: float = 0.5,
|
|
357
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
358
|
+
"""
|
|
359
|
+
Extract subduction zone points as lat/lon arrays.
|
|
360
|
+
|
|
361
|
+
Parameters
|
|
362
|
+
----------
|
|
363
|
+
time : float
|
|
364
|
+
Geological time (Ma).
|
|
365
|
+
topology_features : pygplates.FeatureCollection or list
|
|
366
|
+
Topology features.
|
|
367
|
+
rotation_model : pygplates.RotationModel
|
|
368
|
+
Rotation model.
|
|
369
|
+
tessellate_degrees : float, default=0.5
|
|
370
|
+
Tessellation resolution in degrees.
|
|
371
|
+
|
|
372
|
+
Returns
|
|
373
|
+
-------
|
|
374
|
+
lats : np.ndarray
|
|
375
|
+
Subduction zone point latitudes in degrees.
|
|
376
|
+
lons : np.ndarray
|
|
377
|
+
Subduction zone point longitudes in degrees.
|
|
378
|
+
"""
|
|
379
|
+
subduction_geometries = extract_subduction_geometries(
|
|
380
|
+
time, topology_features, rotation_model
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
if len(subduction_geometries) == 0:
|
|
384
|
+
return np.array([]), np.array([])
|
|
385
|
+
|
|
386
|
+
all_lats = []
|
|
387
|
+
all_lons = []
|
|
388
|
+
|
|
389
|
+
for geom in subduction_geometries:
|
|
390
|
+
tessellated = geom.to_tessellated(np.radians(tessellate_degrees))
|
|
391
|
+
for point in tessellated:
|
|
392
|
+
lat, lon = point.to_lat_lon()
|
|
393
|
+
all_lats.append(lat)
|
|
394
|
+
all_lons.append(lon)
|
|
395
|
+
|
|
396
|
+
return np.array(all_lats), np.array(all_lons)
|