gtrack 0.3.0__tar.gz → 0.3.2__tar.gz
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-0.3.0 → gtrack-0.3.2}/PKG-INFO +1 -1
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/__init__.py +4 -1
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/hpc_integration.py +0 -10
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/point_rotation.py +49 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack.egg-info/PKG-INFO +1 -1
- {gtrack-0.3.0 → gtrack-0.3.2}/pyproject.toml +1 -1
- {gtrack-0.3.0 → gtrack-0.3.2}/tests/test_point_rotation.py +61 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/README.md +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/boundaries.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/config.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/geometry.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/initial_conditions.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/io_formats.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/logging.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/mesh.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/mor_seeds.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/polygon_filter.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack/spatial.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack.egg-info/SOURCES.txt +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack.egg-info/dependency_links.txt +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack.egg-info/requires.txt +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/gtrack.egg-info/top_level.txt +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/setup.cfg +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/tests/test_core.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/tests/test_geometry.py +0 -0
- {gtrack-0.3.0 → gtrack-0.3.2}/tests/test_regression.py +0 -0
|
@@ -46,7 +46,7 @@ Example
|
|
|
46
46
|
... cloud = tracker.step_to(age)
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
|
-
__version__ = "0.
|
|
49
|
+
__version__ = "0.3.1"
|
|
50
50
|
|
|
51
51
|
# Logging configuration (import first to configure before other modules)
|
|
52
52
|
from .logging import (
|
|
@@ -58,6 +58,9 @@ from .logging import (
|
|
|
58
58
|
get_logger,
|
|
59
59
|
)
|
|
60
60
|
|
|
61
|
+
# Configure logging with default level (WARNING) immediately on import
|
|
62
|
+
configure_logging()
|
|
63
|
+
|
|
61
64
|
# Core seafloor age functionality
|
|
62
65
|
from .config import TracerConfig
|
|
63
66
|
from .hpc_integration import SeafloorAgeTracker
|
|
@@ -75,17 +75,11 @@ class SeafloorAgeTracker:
|
|
|
75
75
|
topology_files: Union[str, List[str]],
|
|
76
76
|
continental_polygons: Optional[str] = None,
|
|
77
77
|
config: Optional[TracerConfig] = None,
|
|
78
|
-
verbose: bool = True,
|
|
79
78
|
):
|
|
80
79
|
from .geometry import ensure_list
|
|
81
80
|
|
|
82
81
|
self._config = config if config else TracerConfig()
|
|
83
82
|
|
|
84
|
-
# Handle deprecated verbose flag
|
|
85
|
-
if verbose:
|
|
86
|
-
from .logging import enable_verbose
|
|
87
|
-
enable_verbose()
|
|
88
|
-
|
|
89
83
|
# Handle single file or Path as list
|
|
90
84
|
rotation_files = ensure_list(rotation_files)
|
|
91
85
|
topology_files = ensure_list(topology_files)
|
|
@@ -794,7 +788,6 @@ class SeafloorAgeTracker:
|
|
|
794
788
|
topology_files: Union[str, List[str]],
|
|
795
789
|
continental_polygons: Optional[str] = None,
|
|
796
790
|
config: Optional[TracerConfig] = None,
|
|
797
|
-
verbose: bool = True,
|
|
798
791
|
) -> PointCloud:
|
|
799
792
|
"""
|
|
800
793
|
One-shot computation of seafloor ages (functional interface).
|
|
@@ -816,8 +809,6 @@ class SeafloorAgeTracker:
|
|
|
816
809
|
Path to continental polygon file.
|
|
817
810
|
config : TracerConfig, optional
|
|
818
811
|
Configuration parameters.
|
|
819
|
-
verbose : bool, default=True
|
|
820
|
-
Print progress information.
|
|
821
812
|
|
|
822
813
|
Returns
|
|
823
814
|
-------
|
|
@@ -839,7 +830,6 @@ class SeafloorAgeTracker:
|
|
|
839
830
|
topology_files=topology_files,
|
|
840
831
|
continental_polygons=continental_polygons,
|
|
841
832
|
config=config,
|
|
842
|
-
verbose=verbose,
|
|
843
833
|
)
|
|
844
834
|
|
|
845
835
|
tracker.initialize(starting_age)
|
|
@@ -148,6 +148,55 @@ class PointCloud:
|
|
|
148
148
|
xyz = LatLon2XYZ(latlon)
|
|
149
149
|
return cls(xyz=xyz, properties=properties or {})
|
|
150
150
|
|
|
151
|
+
@classmethod
|
|
152
|
+
def from_xyz(
|
|
153
|
+
cls,
|
|
154
|
+
xyz: np.ndarray,
|
|
155
|
+
properties: Optional[Dict[str, np.ndarray]] = None,
|
|
156
|
+
normalize_to_earth: bool = False
|
|
157
|
+
) -> "PointCloud":
|
|
158
|
+
"""
|
|
159
|
+
Create PointCloud from Cartesian XYZ coordinates.
|
|
160
|
+
|
|
161
|
+
This is a convenience classmethod that provides symmetry with from_latlon.
|
|
162
|
+
It can optionally normalize points to Earth's surface.
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
xyz : np.ndarray
|
|
167
|
+
Cartesian coordinates, shape (N, 3).
|
|
168
|
+
properties : dict, optional
|
|
169
|
+
Properties to attach to the points.
|
|
170
|
+
normalize_to_earth : bool, default=False
|
|
171
|
+
If True, normalize points to Earth's radius (~6.3781e6 m).
|
|
172
|
+
Useful when input points are on a unit sphere.
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
-------
|
|
176
|
+
PointCloud
|
|
177
|
+
New PointCloud with the given XYZ coordinates.
|
|
178
|
+
|
|
179
|
+
Examples
|
|
180
|
+
--------
|
|
181
|
+
>>> # Points already at Earth's radius
|
|
182
|
+
>>> xyz = np.array([[6378100, 0, 0], [0, 6378100, 0]])
|
|
183
|
+
>>> cloud = PointCloud.from_xyz(xyz)
|
|
184
|
+
>>>
|
|
185
|
+
>>> # Points on unit sphere, scale to Earth
|
|
186
|
+
>>> xyz_unit = np.array([[1, 0, 0], [0, 1, 0]])
|
|
187
|
+
>>> cloud = PointCloud.from_xyz(xyz_unit, normalize_to_earth=True)
|
|
188
|
+
"""
|
|
189
|
+
from .geometry import EARTH_RADIUS
|
|
190
|
+
xyz = np.asarray(xyz)
|
|
191
|
+
|
|
192
|
+
if normalize_to_earth:
|
|
193
|
+
# Normalize to unit sphere, then scale to Earth's radius
|
|
194
|
+
norms = np.linalg.norm(xyz, axis=1, keepdims=True)
|
|
195
|
+
norms = np.maximum(norms, 1e-10) # Avoid division by zero
|
|
196
|
+
xyz = xyz / norms * EARTH_RADIUS
|
|
197
|
+
|
|
198
|
+
return cls(xyz=xyz, properties=properties or {})
|
|
199
|
+
|
|
151
200
|
def add_property(self, name: str, values: np.ndarray) -> None:
|
|
152
201
|
"""
|
|
153
202
|
Add or update a property.
|
|
@@ -48,6 +48,67 @@ class TestPointCloud:
|
|
|
48
48
|
distances = np.linalg.norm(cloud.xyz, axis=1)
|
|
49
49
|
np.testing.assert_allclose(distances, EARTH_RADIUS, rtol=1e-10)
|
|
50
50
|
|
|
51
|
+
def test_from_xyz_basic(self):
|
|
52
|
+
"""Test creating PointCloud via from_xyz classmethod."""
|
|
53
|
+
xyz = normalize_to_sphere(np.random.randn(50, 3))
|
|
54
|
+
cloud = PointCloud.from_xyz(xyz)
|
|
55
|
+
|
|
56
|
+
assert cloud.n_points == 50
|
|
57
|
+
np.testing.assert_allclose(cloud.xyz, xyz)
|
|
58
|
+
assert cloud.plate_ids is None
|
|
59
|
+
assert len(cloud.properties) == 0
|
|
60
|
+
|
|
61
|
+
def test_from_xyz_with_properties(self):
|
|
62
|
+
"""Test from_xyz passes properties correctly."""
|
|
63
|
+
xyz = normalize_to_sphere(np.random.randn(30, 3))
|
|
64
|
+
props = {'depth': np.random.rand(30), 'temp': np.random.rand(30)}
|
|
65
|
+
cloud = PointCloud.from_xyz(xyz, properties=props)
|
|
66
|
+
|
|
67
|
+
assert cloud.n_points == 30
|
|
68
|
+
assert 'depth' in cloud.properties
|
|
69
|
+
assert 'temp' in cloud.properties
|
|
70
|
+
|
|
71
|
+
def test_from_xyz_normalize_to_earth(self):
|
|
72
|
+
"""Test from_xyz with normalize_to_earth scales to Earth's radius."""
|
|
73
|
+
# Points on unit sphere
|
|
74
|
+
xyz_unit = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
|
|
75
|
+
cloud = PointCloud.from_xyz(xyz_unit, normalize_to_earth=True)
|
|
76
|
+
|
|
77
|
+
distances = np.linalg.norm(cloud.xyz, axis=1)
|
|
78
|
+
np.testing.assert_allclose(distances, EARTH_RADIUS, rtol=1e-10)
|
|
79
|
+
|
|
80
|
+
def test_from_xyz_normalize_arbitrary_radius(self):
|
|
81
|
+
"""Test from_xyz normalizes points at arbitrary radii to Earth's radius."""
|
|
82
|
+
# Points at radius 100
|
|
83
|
+
xyz = np.array([[100.0, 0.0, 0.0], [0.0, 0.0, 50.0]])
|
|
84
|
+
cloud = PointCloud.from_xyz(xyz, normalize_to_earth=True)
|
|
85
|
+
|
|
86
|
+
distances = np.linalg.norm(cloud.xyz, axis=1)
|
|
87
|
+
np.testing.assert_allclose(distances, EARTH_RADIUS, rtol=1e-10)
|
|
88
|
+
|
|
89
|
+
# Direction should be preserved
|
|
90
|
+
direction_original = xyz / np.linalg.norm(xyz, axis=1, keepdims=True)
|
|
91
|
+
direction_result = cloud.xyz / np.linalg.norm(cloud.xyz, axis=1, keepdims=True)
|
|
92
|
+
np.testing.assert_allclose(direction_result, direction_original, atol=1e-10)
|
|
93
|
+
|
|
94
|
+
def test_from_xyz_no_normalize(self):
|
|
95
|
+
"""Test from_xyz without normalization preserves coordinates exactly."""
|
|
96
|
+
xyz = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
|
|
97
|
+
cloud = PointCloud.from_xyz(xyz, normalize_to_earth=False)
|
|
98
|
+
|
|
99
|
+
np.testing.assert_array_equal(cloud.xyz, xyz)
|
|
100
|
+
|
|
101
|
+
def test_from_xyz_near_zero_vector(self):
|
|
102
|
+
"""Test from_xyz handles near-zero vectors without crashing."""
|
|
103
|
+
xyz = np.array([[1e-15, 1e-15, 1e-15], [1.0, 0.0, 0.0]])
|
|
104
|
+
cloud = PointCloud.from_xyz(xyz, normalize_to_earth=True)
|
|
105
|
+
|
|
106
|
+
# Should not raise; second point should be at Earth's radius
|
|
107
|
+
distances = np.linalg.norm(cloud.xyz, axis=1)
|
|
108
|
+
np.testing.assert_allclose(distances[1], EARTH_RADIUS, rtol=1e-10)
|
|
109
|
+
# First point (near-zero) should still produce a finite result
|
|
110
|
+
assert np.all(np.isfinite(cloud.xyz[0]))
|
|
111
|
+
|
|
51
112
|
def test_latlon_property(self):
|
|
52
113
|
"""Test that latlon property correctly converts from XYZ."""
|
|
53
114
|
original_latlon = np.array([
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|