pyhardisp 0.2.0__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.
@@ -0,0 +1,11 @@
1
+ This software is a Python translation and modification of the
2
+ IERS Conventions software (Copyright © 2008 IERS Conventions Center).
3
+
4
+ The original IERS Conventions Software License is reproduced in
5
+ LICENSE_IERS.txt and governs this derived work.
6
+
7
+ Modifications and Python translation:
8
+ Copyright (C) 2026 [Craig Miller]
9
+
10
+ This project is distributed under the terms of the
11
+ IERS Conventions Software License.
@@ -0,0 +1,77 @@
1
+ Copyright (C) 2008
2
+ * IERS Conventions Center
3
+ *
4
+ * ==================================
5
+ * IERS Conventions Software License
6
+ * ==================================
7
+ *
8
+ * NOTICE TO USER:
9
+ *
10
+ * BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING TERMS AND CONDITIONS
11
+ * WHICH APPLY TO ITS USE.
12
+ *
13
+ * 1. The Software is provided by the IERS Conventions Center ("the
14
+ * Center").
15
+ *
16
+ * 2. Permission is granted to anyone to use the Software for any
17
+ * purpose, including commercial applications, free of charge,
18
+ * subject to the conditions and restrictions listed below.
19
+ *
20
+ * 3. You (the user) may adapt the Software and its algorithms for your
21
+ * own purposes and you may distribute the resulting "derived work"
22
+ * to others, provided that the derived work complies with the
23
+ * following requirements:
24
+ *
25
+ * a) Your work shall be clearly identified so that it cannot be
26
+ * mistaken for IERS Conventions software and that it has been
27
+ * neither distributed by nor endorsed by the Center.
28
+ *
29
+ * b) Your work (including source code) must contain descriptions of
30
+ * how the derived work is based upon and/or differs from the
31
+ * original Software.
32
+ *
33
+ * c) The name(s) of all modified routine(s) that you distribute
34
+ * shall be changed.
35
+ *
36
+ * d) The origin of the IERS Conventions components of your derived
37
+ * work must not be misrepresented; you must not claim that you
38
+ * wrote the original Software.
39
+ *
40
+ * e) The source code must be included for all routine(s) that you
41
+ * distribute. This notice must be reproduced intact in any
42
+ * source distribution.
43
+ *
44
+ * 4. In any published work produced by the user and which includes
45
+ * results achieved by using the Software, you shall acknowledge
46
+ * that the Software was used in obtaining those results.
47
+ *
48
+ * 5. The Software is provided to the user "as is" and the Center makes
49
+ * no warranty as to its use or performance. The Center does not
50
+ * and cannot warrant the performance or results which the user may
51
+ * obtain by using the Software. The Center makes no warranties,
52
+ * express or implied, as to non-infringement of third party rights,
53
+ * merchantability, or fitness for any particular purpose. In no
54
+ * event will the Center be liable to the user for any consequential,
55
+ * incidental, or special damages, including any lost profits or lost
56
+ * savings, even if a Center representative has been advised of such
57
+ * damages, or for any claim by any third party.
58
+ *
59
+ * Correspondence concerning IERS Conventions software should be
60
+ * addressed as follows:
61
+ *
62
+ * Gerard Petit
63
+ * Internet email: gpetit[at]bipm.org
64
+ * Postal address: IERS Conventions Center
65
+ * Time, frequency and gravimetry section, BIPM
66
+ * Pavillon de Breteuil
67
+ * 92312 Sevres FRANCE
68
+ *
69
+ * or
70
+ *
71
+ * Brian Luzum
72
+ * Internet email: brian.luzum[at]usno.navy.mil
73
+ * Postal address: IERS Conventions Center
74
+ * Earth Orientation Department
75
+ * 3450 Massachusetts Ave, NW
76
+ * Washington, DC 20392
77
+
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include README_PYTHON_CONVERSION.md
3
+ include LICENSE_IERS.txt
4
+ include LICENCE
5
+ recursive-include src *.F
6
+ include ocean_loading_nm_s2.csv
@@ -0,0 +1,396 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyhardisp
3
+ Version: 0.2.0
4
+ Summary: Ocean loading tidal displacement calculator - Python conversion of IERS HARDISP Fortran program
5
+ Author: IERS Conventions, Python Conversion - Craig Miller
6
+ License-Expression: LicenseRef-IERS
7
+ Project-URL: Homepage, https://github.com/craigmillernz/pyhardisp
8
+ Project-URL: Repository, https://github.com/craigmillernz/pyhardisp
9
+ Keywords: HARDISP,pyhardisp,ocean-loading,tidal,displacement,geodesy,IERS
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE_IERS.txt
24
+ Requires-Dist: numpy>=1.19.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=6.0; extra == "dev"
27
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
28
+ Requires-Dist: ruff; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # PYHARDISP - Python Module Documentation
32
+
33
+ ## Overview
34
+
35
+ This document describes the Python conversion of the **HARDISP** (Harmonic Displacement) Fortran program from the IERS Conventions software collection. The program computes tidal ocean loading displacements at geodetic stations.
36
+
37
+ ## What is HARDISP?
38
+
39
+ HARDISP is a scientific program developed by the International Earth Rotation and Reference Systems Service (IERS) for calculating tidal ocean loading effects at geodetic stations. Depending on the coefficients provided by the ocean loading provider, it computes either:
40
+ - **Tidal displacements** (vertical, horizontal components) - when displacement coefficients are provided
41
+ - **Tidal gravity effects** (gravity disturbances) - when gravity-type coefficients are provided
42
+
43
+ These effects are critical corrections for:
44
+
45
+ - GPS and space geodesy
46
+ - Satellite laser ranging (SLR)
47
+ - Very Long Baseline Interferometry (VLBI)
48
+ - Superconducting gravimeter measurements
49
+ - Hydrogeodetic measurements
50
+
51
+ The program is part of the **IERS Conventions 2010** recommendations (Class 1 model) for processing raw space geodetic observations.
52
+
53
+ ## Program Purpose
54
+
55
+ Given ocean loading coefficients in BLQ format (from the Bos-Scherneck loading service or equivalent providers), HARDISP computes a time series of tidal ocean loading effects in three components:
56
+
57
+ **Output type depends on the ocean loading provider's coefficients:**
58
+ - **Displacement coefficients**: Returns displacements
59
+ - **dU**: Vertical (radial) displacement (meters)
60
+ - **dS**: South (North-South) displacement (meters)
61
+ - **dW**: West (East-West) displacement (meters)
62
+
63
+ - **Gravity coefficients**: Returns gravity effects
64
+ - **dU**: Vertical gravity effect (nm/s² or equivalent units)
65
+ - **dS**: South gravity tilt effect (nm/s²)
66
+ - **dW**: West gravity tilt effect (nm/s²)
67
+
68
+ The computation uses **342 tidal constituents** derived by spline interpolation of the tidal admittance, providing approximately 0.1% precision.
69
+
70
+ HARDISP processes the coefficients as-is, with no automatic conversions between displacement and gravity types.
71
+
72
+ ## Files
73
+
74
+ The Python conversion consists of:
75
+ **core.py** - Main Python module with optimized implementation
76
+
77
+
78
+ Original Fortran files (for reference):
79
+ - `HARDISP.F` - Main program
80
+ - `ADMINT.F` - Admittance interpolation
81
+ - `RECURS.F` - Recursive harmonic evaluation
82
+ - `TDFRPH.F` - Tidal frequency and phase calculation
83
+ - `SPLINE.F`, `EVAL.F` - Cubic spline interpolation
84
+ - `TOYMD.F`, `LEAP.F`, `JULDAT.F`, `MDAY.F` - Date/time utilities
85
+ - `ETUTC.F` - ET-UTC offset calculation
86
+ - `SHELLS.F` - Shell sort algorithm
87
+
88
+ ## Key Functions Reference
89
+
90
+ ### Date/Time Conversion Functions
91
+
92
+ ```python
93
+ import hardisp
94
+
95
+ # Check if a year is a leap year
96
+ is_leap = pyhardisp.is_leap_year(2008) # Returns 1 for true, 0 for false
97
+
98
+ # Get days before start of month
99
+ days_before_may = pyhardisp.days_before_month(2009, 5) # Returns 120
100
+
101
+ # Convert to Julian Day Number
102
+ jd = pyhardisp.julian_date(2000, 1, 1) # Returns 2451545 (J2000.0)
103
+
104
+ # Convert day-of-year to month/day
105
+ y, m, d = pyhardisp.doy_to_ymd(2008, 120) # Returns (2008, 4, 29)
106
+
107
+ # Get ET-UTC offset for decimal year
108
+ delta = pyhardisp.earth_time_offset_seconds(2009.5) # Returns difference in seconds
109
+ ```
110
+
111
+ ### Tidal Calculations
112
+
113
+ ```python
114
+ # Set the epoch for tidal calculations
115
+ pyhardisp.calculate_tidal_arguments(year=2009, day_of_year=176, hour=0, minute=0, second=0)
116
+
117
+ # Get frequency and phase of a tidal constituent
118
+ import numpy as np
119
+ doodson = np.array([2, 0, 0, 0, 0, 0]) # M2 tide
120
+ freq, phase = pyhardisp.tidal_frequency_and_phase(doodson)
121
+ ```
122
+
123
+ ### Main Class: HardispComputer
124
+
125
+ ```python
126
+ # Create a computer instance
127
+ computer = hardisp.HardispComputer()
128
+
129
+ # Load BLQ-format ocean loading coefficients
130
+ # Two methods:
131
+
132
+ # Method 1: From numpy arrays (3x11 each)
133
+ amp_data = [[0.00352, 0.00123, ...], [0.00144, ...], [0.00086, ...]]
134
+ phase_data = [[-64.7, -52.0, ...], [85.5, ...], [109.5, ...]]
135
+ computer.read_blq_format(amp_data, phase_data)
136
+
137
+ # Method 2: From BLQ text file (6 lines)
138
+ with open('station.blq', 'r') as f:
139
+ lines = f.readlines()
140
+ computer.read_blq_format(lines[:3], lines[3:])
141
+
142
+ # Compute ocean loading effects
143
+ dz, ds, dw = computer.compute_ocean_loading(
144
+ year=2009, month=6, day=25,
145
+ hour=1, minute=10, second=45,
146
+ num_epochs=24, # Number of time points
147
+ sample_interval=3600.0 # Seconds between points
148
+ )
149
+
150
+ # Output units depend on input coefficients from the ocean loading provider
151
+ # Pass units as metadata to document what you expect (doesn't affect computation)
152
+ print(f"Vertical: {dz}")
153
+ print(f"South: {ds}")
154
+ print(f"West: {dw}")
155
+ ```
156
+
157
+ ## Usage Examples
158
+
159
+ ### Example 1: Simple Time Series
160
+
161
+ ```python
162
+ import pyhardisp
163
+ import numpy as np
164
+
165
+ # Create computer instance
166
+ computer = pyhardisp.HardispComputer()
167
+
168
+ # Load BLQ ocean loading coefficients
169
+ amplitudes = [
170
+ [45.96, 10.98, 6.94, 3.07, 6.00, 1.57, 1.98, 0.91, 1.58, 0.73, 0.41], # Vertical
171
+ [99.00, 14.68, 21.49, 4.16, 2.67, 2.80, 0.86, 1.03, 0.02, 0.00, 0.01], # East
172
+ [38.30, 11.46, 8.92, 3.17, 7.47, 4.96, 2.46, 0.97, 1.06, 0.63, 0.52], # North
173
+ ]
174
+ phases = [
175
+ [53.3, 137.3, 22.4, 135.1, -171.3, 21.5, -170.7, 42.9, -3.6, -8.3, -4.3],
176
+ [140.1, 174.5, 123.5, 159.1, 167.5, 93.9, 168.8, 65.9, -47.8, -49.7, 15.5],
177
+ [-109.9, -78.7, -133.4, -85.9, 28.6, 12.2, 28.1, 16.0, 14.1, 8.0, 1.5],
178
+ ]
179
+
180
+ computer.read_blq_format(amplitudes, phases, units="nm/s^2")
181
+
182
+ # Compute 24 hourly displacements
183
+ dz, ds, dw = computer.compute_ocean_loading(
184
+ year=2009, month=6, day=25,
185
+ hour=1, minute=10, second=45,
186
+ num_epochs=24,
187
+ sample_interval=3600.0
188
+ )
189
+
190
+ print("Vertical gravity (nm/s^2):", dz)
191
+ print("South tilt (nrad): ", ds)
192
+ print("West tilt (nrad): ", dw)
193
+ ```
194
+
195
+ ### Example 2: High-Rate Analysis
196
+
197
+ ```python
198
+ # For 1Hz sampling (e.g., seismic or structural monitoring)
199
+ dz_high, ds_high, dw_high = computer.compute_ocean_loading(
200
+ year=2009, month=6, day=25,
201
+ hour=1, minute=0, second=0,
202
+ num_epochs=86400, # Full day at 1Hz
203
+ sample_interval=1.0 # 1 second intervals
204
+ )
205
+ ```
206
+
207
+ ### Example 3: Multi-Day Campaign
208
+
209
+ ```python
210
+ # Process multiple days
211
+ for day_val in range(1, 8): # Process days 1-7
212
+ dz, ds, dw = computer.compute_ocean_loading(
213
+ year=2009, month=6, day=day_val,
214
+ num_epochs=1, sample_interval=1
215
+ )
216
+ print(f"June {day_val}: max effect = {max(abs(dz), abs(ds), abs(dw)):.6f}")
217
+ ```
218
+
219
+ ## Technical Details
220
+
221
+ ### Coordinate System
222
+
223
+ The output displacements are in a **local geodetic frame** at the station:
224
+ - **dU**: Radial (positive upward)
225
+ - **dS**: South component (positive southward, i.e., negative latitude direction)
226
+ - **dW**: West component (positive westward, i.e., negative longitude direction)
227
+
228
+ ### Tidal Constituents Used
229
+
230
+ The 11 input harmonics (from BLQ format) represent:
231
+ 1. M₂ - Principal lunar semi-diurnal (12.42 hours)
232
+ 2. S₂ - Principal solar semi-diurnal (12.00 hours)
233
+ 3. N₂ - Lunar elliptic semi-diurnal (12.66 hours)
234
+ 4. K₂ - Lunisolar semi-diurnal (11.97 hours)
235
+ 5. K₁ - Lunisolar diurnal (23.93 hours)
236
+ 6. O₁ - Principal lunar diurnal (25.82 hours)
237
+ 7. P₁ - Principal solar diurnal (24.07 hours)
238
+ 8. Q₁ - Larger lunar elliptic diurnal (26.87 hours)
239
+ 9. Mf - Lunar fortnightly (13.66 days)
240
+ 10. Mm - Lunar monthly (27.55 days)
241
+ 11. Ssa - Solar semi-annual (182.6 days)
242
+
243
+ These are expanded to 342 constituents through spline interpolation for higher precision.
244
+
245
+ ### Recursion Algorithm
246
+
247
+ The program uses **Chebyshev polynomial recursion** for efficient computation of harmonic series:
248
+
249
+ Instead of computing: `x(t) = Σ A cos(ωt) + B sin(ωt)`
250
+
251
+ It uses: `x(j) = 2cos(ω)·x(j-1) - x(j-2)`
252
+
253
+ This requires only 2-3 operations per harmonic per time point, making it orders of magnitude faster than direct calculations, especially for large numbers of epochs.
254
+
255
+ ## Conversion Notes
256
+
257
+ ### Key Differences from Fortran
258
+
259
+ 1. **Integer Division**: Fortran's division truncates toward zero, while Python's `//` uses floor division. The code uses `fortran_int_divide()` function to maintain Fortran semantics.
260
+
261
+ 2. **Matrix Indexing**: Fortran uses 1-based indexing; Python uses 0-based. Conversions are handled automatically.
262
+
263
+ 3. **Floating Point**: Results may differ slightly due to different floating-point implementations and optimization levels.
264
+
265
+ 4. **Object-Oriented**: The Python version uses a class-based interface (`HardispComputer`) rather than standalone FORTRAN procedures.
266
+
267
+ ## Original Fortran Files (Reference)
268
+
269
+ The Python code was converted from these 13 Fortran files:
270
+
271
+ 1. `HARDISP.F` (465 lines) - Main program
272
+ 2. `ADMINT.F` (449 lines) - Ocean loading interpolation
273
+ 3. `RECURS.F` (180 lines) - Recursive harmonic evaluation
274
+ 4. `TDFRPH.F` (281 lines) - Frequency and phase calculation
275
+ 5. `SPLINE.F` (215 lines) - Spline setup
276
+ 6. `EVAL.F` (197 lines) - Spline evaluation
277
+ 7. `TOYMD.F` (160 lines) - Date conversion
278
+ 8. `MDAY.F` (155 lines) - Month/day calculation
279
+ 9. `LEAP.F` (154 lines) - Leap year check
280
+ 10. `JULDAT.F` (159 lines) - Julian date
281
+ 11. `SHELLS.F` (210 lines) - Shell sort
282
+ 12. `ETUTC.F` (284 lines) - ET-UTC calculation
283
+ 13. `TOYS.F` - (not in workspace but referenced)
284
+
285
+
286
+ ## Function Name Mapping (Original Fortran → New Python)
287
+
288
+ | Original Fortran | New Python Name | Purpose |
289
+ |------------------|-----------------|----------|
290
+ | LEAP | is_leap_year | Check leap year status |
291
+ | MDAY | days_before_month | Days before month start |
292
+ | JULDAT | julian_date | Convert to Julian Day Number |
293
+ | TOYMD | doy_to_ymd | Convert day-of-year to month/day |
294
+ | ETUTC | earth_time_offset_seconds | ET-UTC offset calculation |
295
+ | SPLINE | cublic_spline | Compute cubic spline coefficients |
296
+ | EVAL | spline_eval | Evaluate spline at point |
297
+ | — | spline_eval_batch | Evaluate spline at multiple points (vectorized) |
298
+ | SET_TIDAL_DATE | calculate_tidal_arguments | Initialize tidal calculations |
299
+ | TDFRPH | tidal_frequency_and_phase | Get frequency and phase |
300
+ | — | tidal_frequency_and_phase_batch | Get frequencies/phases for multiple constituents (vectorized) |
301
+ | RECURS | recursion | Recursive harmonic evaluation |
302
+ | ADMINT | admittance | Admittance interpolation |
303
+ | SHELLS | pyshells | Shell sort array indices |
304
+ | int_div (helper) | fortran_int_divide | Fortran-style integer division |
305
+
306
+ ## Features Implemented
307
+
308
+ ### Complete Conversion
309
+ - [x] All 342 tidal constituents support
310
+ - [x] Recursive harmonic evaluation (efficient)
311
+ - [x] Cubic spline interpolation
312
+ - [x] Tidal admittance calculation
313
+ - [x] BLQ format input/output
314
+ - [x] Julian date calculations
315
+ - [x] ET-UTC offset (with leap seconds through 2017)
316
+ - [x] Doodson number computations
317
+ - [x] Delaunay argument calculations
318
+
319
+ ### Additional Features
320
+ - [x] Object-oriented design with HardispComputer class
321
+ - [x] NumPy integration for high performance
322
+ - [x] Comprehensive error handling
323
+ - [x] Detailed documentation and docstrings
324
+ - [x] Test cases and validation
325
+ - [x] Performance optimizations
326
+
327
+ ## Core Components Converted
328
+
329
+ ### 1. Date/Time Functions (7 functions)
330
+ ```
331
+ ✓ is_leap_year(year) - Check leap year
332
+ ✓ days_before_month(year, month) - Days before month start
333
+ ✓ julian_date(year, month, day) - Convert to Julian date
334
+ ✓ doy_to_ymd(year, day_of_year) - Convert to month/day
335
+ ✓ earth_time_offset_seconds(year) - ET-UTC offset calculation
336
+ ```
337
+
338
+ ### 2. Spline Interpolation (3 functions)
339
+ ```
340
+ ✓ cublic_spline(x, u) - Compute cubic spline coefficients
341
+ ✓ spline_eval(y, x, u, s) - Evaluate spline at point
342
+ ✓ spline_eval_batch(y_arr, x, u, s) - Evaluate spline at multiple points (vectorized)
343
+ ```
344
+
345
+ ### 3. Tidal Frequency Calculations (3 functions)
346
+ ```
347
+ ✓ calculate_tidal_arguments(year, day, h, m, s) - Initialize tidal calculations
348
+ ✓ tidal_frequency_and_phase(doodson_number) - Get frequency and phase from Doodson number
349
+ ✓ tidal_frequency_and_phase_batch(doodson_array) - Get frequencies and phases for multiple constituents (vectorized)
350
+ ```
351
+
352
+ ### 4. Harmonic Recursion (1 function)
353
+ ```
354
+ ✓ recursion(n, hc, nf, om) - Efficient recursive harmonic evaluation
355
+ ```
356
+
357
+ ### 5. Utility Functions (2 functions)
358
+ ```
359
+ ✓ pyshells(x) - Sort array with indices (Shell sort)
360
+ ✓ fortran_int_divide(a, b) - Fortran-style integer division
361
+ ```
362
+
363
+ ### 6. Main Class: HardispComputer
364
+ ```
365
+ ✓ read_blq_format(amp, phase) - Load ocean loading coefficients
366
+ ✓ compute_ocean_loading(...) - Main computation engine
367
+ ```
368
+
369
+
370
+
371
+ ## References
372
+
373
+ 1. Petit, G. and Luzum, B. (eds.), **IERS Conventions (2010)**, IERS Technical Note No. 36, BKG (2010)
374
+ - Available at: https://www.iers.org/IERS/EN/Publications/TechnicalNotes/tn36.php
375
+
376
+ 2. Agnew, D. C., et al., **HARDISP**: Original algorithm and implementation
377
+
378
+ 3. Scherneck, H.-G., and M. S. Bos, **Ocean Loading Service**: BLQ format specification
379
+ - Available at: http://www.oso.chalmers.se/~loading/
380
+
381
+ 4. Cartwright, D. E., and A. C. Edden, **Tides of the Planet Earth**, Geophys. J. R. Astron. Soc. 65, 615-630, 1981
382
+
383
+ ## License
384
+
385
+ This Python conversion maintains the same IERS Conventions Software License as the original Fortran code. See copyright notices in source files.
386
+
387
+ ## Contact
388
+
389
+ For questions or issues with the Fortran original:
390
+ - IERS Conventions Center: https://www.iers.org/
391
+ - Email: gpetit@bipm.org or brian.luzum@usno.navy.mil
392
+
393
+ ---
394
+
395
+ *Python conversion completed: 2024*
396
+ *Original Fortran: IERS Conventions 2010*