Skip to content

Commit a72a39c

Browse files
committed
Merge branch 'main' into NPI-4067-check-sp3-column-alignment
2 parents 9435021 + 2b8412a commit a72a39c

6 files changed

Lines changed: 181 additions & 85 deletions

File tree

gnssanalysis/gn_datetime.py

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
logger = logging.getLogger(__name__)
1818

1919

20-
def gpsweekD(yr, doy, wkday_suff=False):
20+
def derive_gps_week(year: Union[int, str], day_of_year: Union[int, str], weekday_suffix: bool = False) -> str:
2121
"""
2222
Convert year, day-of-year to GPS week format: WWWWD or WWWW
2323
Based on code from Kristine Larson's gps.py
@@ -32,30 +32,37 @@ def gpsweekD(yr, doy, wkday_suff=False):
3232
"""
3333

3434
# Set up the date and time variables
35-
yr = int(yr)
36-
doy = int(doy)
37-
dt = _datetime.strptime(f"{yr}-{doy:03d} 01", "%Y-%j %H")
35+
year = int(year)
36+
day_of_year = int(day_of_year)
37+
dt: _datetime = _datetime.strptime(f"{year}-{day_of_year:03d} 01", "%Y-%j %H")
3838

3939
wkday = dt.weekday() + 1
4040

4141
if wkday == 7:
4242
wkday = 0
4343

44-
mn, dy, hr = dt.month, dt.day, dt.hour
44+
month, day, hour = dt.month, dt.day, dt.hour
4545

46-
if mn <= 2:
47-
yr = yr - 1
48-
mn = mn + 12
46+
if month <= 2:
47+
year = year - 1
48+
month = month + 12
4949

50-
JD = _np.floor(365.25 * yr) + _np.floor(30.6001 * (mn + 1)) + dy + hr / 24.0 + 1720981.5
51-
GPS_wk = int(_np.floor((JD - 2444244.5) / 7.0))
50+
julian_day: float = _np.floor(365.25 * year) + _np.floor(30.6001 * (month + 1)) + day + hour / 24.0 + 1720981.5
51+
GPS_wk = int(_np.floor((julian_day - 2444244.5) / 7.0))
5252

53-
if wkday_suff:
53+
if weekday_suffix:
5454
return str(GPS_wk) + str(wkday)
5555
else:
5656
return str(GPS_wk)
5757

5858

59+
def gpsweekD(yr, doy, wkday_suff=False) -> str:
60+
"""
61+
TODO DEPRECATED. Legacy wrapper for the above
62+
"""
63+
return derive_gps_week(yr, doy, wkday_suff)
64+
65+
5966
class GPSDate:
6067
"""
6168
Representation of datetime that provides easy access to
@@ -94,24 +101,49 @@ def as_datetime(self) -> _datetime:
94101
return _pd.Timestamp(self._internal_dt64).to_pydatetime()
95102

96103
@property
97-
def yr(self) -> str:
104+
def as_date(self) -> _date:
105+
"""Convert to Python `date` object."""
106+
return self._internal_dt64.astype(_date)
107+
108+
@property
109+
def year(self) -> str:
98110
"""Year"""
99111
return self.as_datetime.strftime("%Y")
100112

113+
@property # For backwards compatibility
114+
def yr(self) -> str:
115+
"""Year DEPRECATED, use GPSDate.year"""
116+
return self.year
117+
101118
@property
102-
def dy(self) -> str:
119+
def day_of_year(self) -> str:
103120
"""Day of year"""
104121
return self.as_datetime.strftime("%j")
105122

123+
@property # For backwards compatibility
124+
def dy(self) -> str:
125+
"""Day of year. DEPRECATED, use GPSDate.day_of_year"""
126+
return self.day_of_year
127+
106128
@property
107-
def gpswk(self) -> str:
129+
def gps_week(self) -> str:
108130
"""GPS week"""
109-
return gpsweekD(self.yr, self.dy, wkday_suff=False)
131+
return derive_gps_week(self.yr, self.dy, weekday_suffix=False)
132+
133+
@property # For backwards compatibility
134+
def gpswk(self) -> str:
135+
"""GPS week. DEPRECATED, use GPSDate.gps_week"""
136+
return self.gps_week
110137

111138
@property
112-
def gpswkD(self) -> str:
139+
def gps_week_and_day_of_week(self) -> str:
113140
"""GPS week with weekday suffix"""
114-
return gpsweekD(self.yr, self.dy, wkday_suff=True)
141+
return derive_gps_week(self.yr, self.dy, weekday_suffix=True)
142+
143+
@property # For backwards compatibility
144+
def gpswkD(self) -> str:
145+
"""GPS week with weekday suffix. DEPRECATED, use GPSDate.gps_week_and_day_of_week"""
146+
return self.gps_week_and_day_of_week
115147

116148
@property
117149
def next(self):
@@ -128,24 +160,27 @@ def __str__(self) -> str:
128160
return str(self._internal_dt64)
129161

130162

131-
def dt2gpswk(dt, wkday_suff=False, both=False) -> Union[str, tuple[str, str]]:
163+
def datetime_to_gps_week(dt: _datetime, wkday_suff: bool = False) -> str:
132164
"""
133-
Convert the given datetime object to a GPS week (option to include day suffix)
165+
Convert given datetime object to GPS week e.g. '2350', optionally including day suffix e.g. '23500' (Sunday)
166+
167+
:param datetime dt: datetime for which to calculate a GPS week (and optionally day)
168+
:returns str: intput datetime expressed as a GPS week (wwww) or GPS week with day (wwwwd)
134169
"""
135170
yr = dt.strftime("%Y")
136171
doy = dt.strftime("%j")
137-
if not both:
138-
return gpsweekD(yr, doy, wkday_suff=wkday_suff)
139-
else:
140-
return gpsweekD(yr, doy, wkday_suff=False), gpsweekD(yr, doy, wkday_suff=True)
172+
return derive_gps_week(yr, doy, weekday_suffix=wkday_suff)
141173

142174

143-
# TODO DEPRECATED
144-
def gpswkD2dt(gpswkD: str) -> _datetime:
175+
def dt2gpswk(dt: _datetime, wkday_suff: bool = False, both: bool = False) -> Union[str, tuple[str, str]]:
145176
"""
146-
DEPRECATED. This is a compatibility wrapper. Use gps_week_day_to_datetime() instead.
177+
TODO DEPRECATED. Please use datetime_to_gps_week()
147178
"""
148-
return gps_week_day_to_datetime(gpswkD)
179+
180+
if both:
181+
return (datetime_to_gps_week(dt, wkday_suff=False), datetime_to_gps_week(dt, wkday_suff=True))
182+
else:
183+
return datetime_to_gps_week(dt, wkday_suff=wkday_suff)
149184

150185

151186
def gps_week_day_to_datetime(gps_week_and_weekday: str) -> _datetime:
@@ -178,6 +213,14 @@ def gps_week_day_to_datetime(gps_week_and_weekday: str) -> _datetime:
178213
return dt_64.astype(_datetime)
179214

180215

216+
# TODO DEPRECATED
217+
def gpswkD2dt(gpswkD: str) -> _datetime:
218+
"""
219+
DEPRECATED. This is a compatibility wrapper. Use gps_week_day_to_datetime() instead.
220+
"""
221+
return gps_week_day_to_datetime(gpswkD)
222+
223+
181224
def yydoysec2datetime(
182225
arr: Union[_np.ndarray, _pd.Series, list], recenter: bool = False, as_j2000: bool = True, delimiter: str = ":"
183226
) -> _np.ndarray:

gnssanalysis/gn_download.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ def generate_long_filename(
336336
start_epoch: _datetime.datetime, # YYYYDDDHHMM
337337
end_epoch: _datetime.datetime = None,
338338
timespan: _datetime.timedelta = None, # LEN
339-
solution_type: str = "", # TTT
339+
solution_type: str = "", # TTT # TODO look at updating to formalised SolutionType
340340
sampling_rate: str = "15M", # SMP
341341
version: str = "0", # V
342342
project: str = "EXP", # PPP, e.g. EXP, OPS
@@ -432,12 +432,15 @@ def generate_product_filename(
432432
)
433433
else:
434434
if file_ext.lower() == "snx":
435-
product_filename = f"igs{gps_date.yr[2:]}P{gps_date.gpswk}.snx.Z"
435+
product_filename = f"igs{gps_date.year[2:]}P{gps_date.gps_week}.snx.Z"
436436
else:
437437
hour = f"{reference_start.hour:02}"
438438
prefix = "igs" if solution_type == "FIN" else "igr" if solution_type == "RAP" else "igu"
439-
product_filename = f"{prefix}{gps_date.gpswkD}_{hour}.{file_ext}.Z" if solution_type == "ULT" else \
440-
f"{prefix}{gps_date.gpswkD}.{file_ext}.Z"
439+
product_filename = (
440+
f"{prefix}{gps_date.gps_week_and_day_of_week}_{hour}.{file_ext}.Z"
441+
if solution_type == "ULT"
442+
else f"{prefix}{gps_date.gps_week_and_day_of_week}.{file_ext}.Z"
443+
)
441444
return product_filename, gps_date, reference_start
442445

443446

@@ -495,7 +498,7 @@ def attempt_ftps_download(
495498
download_dir: _Path,
496499
ftps: _ftplib.FTP_TLS,
497500
filename: str,
498-
type_of_file: str = None,
501+
type_of_file: Optional[str] = None,
499502
if_file_present: str = "prompt_user",
500503
) -> Union[_Path, None]:
501504
"""Attempt download of file (filename) given the ftps client object (ftps) to chosen location (download_dir)
@@ -739,7 +742,7 @@ def download_file_from_cddis(
739742
max_retries: int = 3,
740743
decompress: bool = True,
741744
if_file_present: str = "prompt_user",
742-
note_filetype: str = None,
745+
note_filetype: Optional[str] = None,
743746
) -> Union[_Path, None]:
744747
"""Downloads a single file from the CDDIS ftp server
745748
@@ -752,7 +755,7 @@ def download_file_from_cddis(
752755
:param str note_filetype: How to label the file for STDOUT messages, defaults to None
753756
:raises e: Raise any error that is run into by ftplib
754757
:return _Path or None: The pathlib.Path of the downloaded file (or decompressed output of it). Returns None if the
755-
file already existed and was skipped.
758+
file already existed and was skipped, or if the download failed.
756759
"""
757760
with ftp_tls(CDDIS_FTP) as ftps:
758761
ftps.cwd(ftp_folder)
@@ -793,7 +796,7 @@ def download_file_from_cddis(
793796
raise Exception("Failed to download file or raise exception. Some logic is broken.")
794797

795798

796-
def download_multiple_files_from_cddis(files: List[str], ftp_folder: str, output_folder: _Path) -> None:
799+
def download_multiple_files_from_cddis(files: list[str], ftp_folder: str, output_folder: _Path) -> None:
797800
"""Downloads multiple files in a single folder from cddis in a thread pool.
798801
799802
:param files: List of str filenames
@@ -843,7 +846,7 @@ def download_product_from_cddis(
843846
# We do this because the weekly files are released/dated as Sunday of each GPS week.
844847
start_epoch_as_gps_date = GPSDate(start_epoch)
845848
# Get GPS week number *without* DayOfWeek suffix (therefore start of the GPS Week), then convert back to datetime
846-
start_epoch = gps_week_day_to_datetime(f"{start_epoch_as_gps_date.gpswk}")
849+
start_epoch = gps_week_day_to_datetime(f"{start_epoch_as_gps_date.gps_week}")
847850
timespan = _datetime.timedelta(days=7)
848851

849852
logging.info("Attempting CDDIS Product download/s")
@@ -865,14 +868,14 @@ def download_product_from_cddis(
865868
project=project_type,
866869
)
867870
logging.debug(
868-
f"Generated filename: {product_filename}, with GPS Date: {gps_date.gpswkD} and reference: {reference_start}"
871+
f"Generated filename: {product_filename}, with GPS Date: {gps_date.gps_week_and_day_of_week} and reference: {reference_start}"
869872
)
870873

871874
ensure_folders([download_dir])
872875
download_filepaths = []
873876
with ftp_tls(CDDIS_FTP) as ftps:
874877
try:
875-
ftps.cwd(f"gnss/products/{gps_date.gpswk}")
878+
ftps.cwd(f"gnss/products/{gps_date.gps_week}")
876879
except _ftplib.all_errors as e:
877880
logging.warning(f"{reference_start} too recent")
878881
logging.warning(f"ftp_lib error: {e}")
@@ -888,11 +891,11 @@ def download_product_from_cddis(
888891
version=version,
889892
project=project_type,
890893
)
891-
ftps.cwd(f"gnss/products/{gps_date.gpswk}")
894+
ftps.cwd(f"gnss/products/{gps_date.gps_week}")
892895

893896
all_files = ftps.nlst()
894897
if not (product_filename in all_files):
895-
logging.warning(f"{product_filename} not in gnss/products/{gps_date.gpswk} - too recent")
898+
logging.warning(f"{product_filename} not in gnss/products/{gps_date.gps_week} - too recent")
896899
raise FileNotFoundError
897900

898901
# reference_start will be changed in the first run through while loop below
@@ -923,7 +926,7 @@ def download_product_from_cddis(
923926
download_filepaths.append(
924927
download_file_from_cddis(
925928
filename=product_filename,
926-
ftp_folder=f"gnss/products/{gps_date.gpswk}",
929+
ftp_folder=f"gnss/products/{gps_date.gps_week}",
927930
output_folder=download_dir,
928931
if_file_present=if_file_present,
929932
note_filetype=file_ext,

gnssanalysis/gn_frame.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ def get_frame_of_day(
5454
elif isinstance(itrf_path_or_df, str):
5555
output = _gn_io.sinex._get_snx_vector_gzchunks(filename=itrf_path_or_df, block_name="SOLUTION/ESTIMATE")
5656
if output is None:
57-
raise Exception(f"Output from _get_snx_vector_gzchunks() was None! Filepath: {itrf_path_or_df}")
57+
raise Exception(
58+
f"Failed to extract SOLUTION/ESTIMATE from Sinex. Check that file was valid: {itrf_path_or_df}"
59+
)
5860
else:
5961
raise ValueError(f"itrf_path_or_df must be a pandas DataFrame or str, got: {type(itrf_path_or_df)}")
6062

gnssanalysis/gn_io/erp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,9 @@ def erp_outfile(datetime_epoch: datetime.datetime, output_dir: pathlib.Path):
594594
# Restrict the amount data we output
595595
resampled_df = resampled_df[resampled_df["MJD"] > mjd - 3]
596596

597-
gps_date = _gn_datetime.gpsweekD(datetime_epoch.strftime("%Y"), datetime_epoch.strftime("%j"), wkday_suff=True)
597+
gps_date = _gn_datetime.derive_gps_week(
598+
datetime_epoch.strftime("%Y"), datetime_epoch.strftime("%j"), weekday_suffix=True
599+
)
598600
file_suffix = f'_{int(int(str(mjd).split(".")[1].ljust(2,"0"))*0.24):02}'
599601
file_name = f"igu{gps_date}{file_suffix}.erp"
600602

0 commit comments

Comments
 (0)