Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test update #701

Merged
merged 19 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[Unreleased]
### Changed
* [701](https://github.com/dbekaert/RAiDER/pull/701) - Fixed a few path typos and handle some edge cases
* [697](https://github.com/dbekaert/RAiDER/pull/697) - Added unit tests for utilFncs.py
* [686](https://github.com/dbekaert/RAiDER/pull/686) - Linted the project with `ruff`.
* [672](https://github.com/dbekaert/RAiDER/pull/672) - Linted the project with `ruff`.
* [683](https://github.com/dbekaert/RAiDER/pull/683) - Fixed a naive datetime and added default template to template generation argument

Expand Down
41 changes: 19 additions & 22 deletions test/test_gnss.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
from pathlib import Path
from RAiDER.models.customExceptions import NoStationDataFoundError
from RAiDER.gnss.downloadGNSSDelays import (
get_stats_by_llh, get_station_list, download_tropo_delays,
filterToBBox
)
from RAiDER.gnss.processDelayFiles import (
addDateTimeToFiles,
getDateTime,
concatDelayFiles
)
import datetime
import os
import pytest
from pathlib import Path

import pandas as pd
import pytest

from RAiDER.gnss.downloadGNSSDelays import download_tropo_delays, filterToBBox, get_station_list, get_stats_by_llh
from RAiDER.gnss.processDelayFiles import addDateTimeToFiles, concatDelayFiles, getDateTime
from RAiDER.models.customExceptions import NoStationDataFoundError
from test import TEST_DIR, pushd


from test import pushd, TEST_DIR
SCENARIO2_DIR = os.path.join(TEST_DIR, "scenario_2")


Expand Down Expand Up @@ -125,17 +120,19 @@ def test_download_tropo_delays2():


def test_download_tropo_delays2(tmp_path):
stations, output_file = get_station_list(
stationFile=os.path.join(SCENARIO2_DIR, 'stations.csv'))
with pushd(tmp_path):
stations, output_file = get_station_list(
stationFile=os.path.join(SCENARIO2_DIR, 'stations.csv')
)

# spot check a couple of stations
assert 'CAPE' in stations
assert 'FGNW' in stations
assert isinstance(output_file, str)
# spot check a couple of stations
assert 'CAPE' in stations
assert 'FGNW' in stations
assert isinstance(output_file, str)

# try downloading the delays
download_tropo_delays(stats=stations, years=[2022], writeDir=tmp_path)
assert True
# try downloading the delays
download_tropo_delays(stats=stations, years=[2022], writeDir=tmp_path)
assert True


def test_filterByBBox1():
Expand Down
2 changes: 1 addition & 1 deletion test/test_intersect.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def test_gnss_intersect(tmp_path, wm):
## run raider and intersect
calcDelays([str(cfg)])

gold = {"ERA5": 2.34514, "GMAO": np.nan, "HRRR": np.nan}
gold = {"ERA5": 2.34514, "GMAO": 2.34514, "HRRR": np.nan} # gmao is fake
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@royagrace this can be put back.

df = pd.read_csv(
os.path.join(outdir, f'{wm}_Delay_{date}T{time.replace(":", "")}_ztd.csv')
)
Expand Down
106 changes: 51 additions & 55 deletions test/test_synthetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
from RAiDER.losreader import Raytracing, build_ray
from RAiDER.models.weatherModel import make_weather_model_filename
from RAiDER.utilFcns import lla2ecef, write_yaml
from test import ORB_DIR, WM_DIR, pushd
from test import ORB_DIR, TEST_DIR, WM_DIR, pushd


def update_model(wm_file: str, wm_eq_type: str, wm_dir: str = "weather_files_synth"):
"""Update weather model file by the equation to test, write it to disk
"""Update weather model file by the equation to test, write it to disk.

wm_eq_type is one of: [hydro, wet_linear, wet_nonlinear]
Hydro Refractivity = k1 * (Pressure/Temp), set Pressure = Temp
Expand All @@ -33,7 +33,7 @@ def update_model(wm_file: str, wm_eq_type: str, wm_dir: str = "weather_files_syn
), "Set wm_eq_type to hydro, wet_linear, or wet_nonlinear"
# initialize dummy wm to calculate constant delays
# any model will do as 1) all constants same 2) all equations same
model = op.basename(wm_file).split('_')[0].upper().replace("-", "")
model = os.path.basename(wm_file).split('_')[0].upper().replace("-", "")
Obj = get_wm_by_name(model)[1]()
ds = xr.open_dataset(wm_file)
t = ds["t"]
Expand Down Expand Up @@ -73,8 +73,8 @@ def update_model(wm_file: str, wm_eq_type: str, wm_dir: str = "weather_files_syn


def length_of_ray(target_xyz: list, model_zs, los, max_height):
"""Build rays at xy locations

"""Build rays at xy locations."""
"""
Target xyz is a list of lists (xpts, ypts, hgt_levels)
Model_zs are all the model levels over which ray is calculated
los in los object (has the orbit info)
Expand All @@ -99,7 +99,7 @@ def length_of_ray(target_xyz: list, model_zs, los, max_height):

@dataclass
class StudyArea(object):
"""Object with shared parameters related to the study area
"""Object with shared parameters related to the study area.

region the short name corresponding to a specific bounding box.
Choose from:
Expand Down Expand Up @@ -141,7 +141,7 @@ def __init__(self, region: str, wmName: str, path: str):
self.wm_dir_synth = op.join(self.wd, "weather_files_synth")

def setup_region(self):
"""Setup the bounding box and choose orbit file based on region name
"""Setup the bounding box and choose orbit file based on region name.

Possible regions are:
LA (Los Angeles, California; midlatitude)
Expand Down Expand Up @@ -193,7 +193,7 @@ def make_config_dict(self):
@pytest.mark.skip()
@pytest.mark.parametrize("region", "AK LA Fort".split())
def test_dl_real(tmp_path, region, mod="ERA5"):
"""Download the real weather model to overwrite
"""Download the real weather model to overwrite.

This 'golden dataset' shouldnt be changed
"""
Expand All @@ -216,7 +216,7 @@ def test_dl_real(tmp_path, region, mod="ERA5"):

@pytest.mark.parametrize("region", "AK LA Fort".split())
def test_hydrostatic_eq(tmp_path, region, mod="ERA-5"):
"""Test hydrostatic equation: Hydro Refractivity = k1 * (Pressure/Temp)
"""Test hydrostatic equation: Hydro Refractivity = k1 * (Pressure/Temp).

The hydrostatic delay reduces to an integral along the ray path when P=T.
However the constants k1 and scaling of 10^-6 will remain present leading
Expand All @@ -231,60 +231,57 @@ def test_hydrostatic_eq(tmp_path, region, mod="ERA-5"):
Ensure that normalized residual is not significantly different from 0
significantly different = 6 decimal places
"""
with pushd(tmp_path):
## setup the config files
SAobj = StudyArea(region, mod, tmp_path)
dct_cfg = SAobj.make_config_dict()
dct_cfg["runtime_group"]["weather_model_directory"] = SAobj.wm_dir_synth
dct_cfg["download_only"] = False
## setup the config files
SAobj = StudyArea(region, mod, TEST_DIR)
dct_cfg = SAobj.make_config_dict()
dct_cfg["runtime_group"]["weather_model_directory"] = SAobj.wm_dir_synth
dct_cfg["download_only"] = False

## update the weather model; t = p for hydrostatic
update_model(SAobj.path_wm_real, "hydro", SAobj.wm_dir_synth)

## run raider with the synthetic model
cfg = write_yaml(dct_cfg, 'temp.yaml')
calcDelays([str(cfg)])

# get the just created synthetic delays
wm_name = SAobj.wmName.replace("-", "") # incase of ERA-5
out_name = f'{SAobj.wd}/{wm_name}_tropo_{SAobj.dts.replace("_", "")}_ray.nc'
ds = xr.open_dataset(out_name)
da = ds["hydro"]
ds.close()
del ds

## update the weather model; t = p for hydrostatic
update_model(SAobj.path_wm_real, "hydro", SAobj.wm_dir_synth)
# now build the rays at the unbuffered wm nodes
max_tropo_height = SAobj.wmObj._zlevels[-1] - 1
targ_xyz = [da.x.data, da.y.data, da.z.data]
ray_length = length_of_ray(
targ_xyz, SAobj.wmObj._zlevels, SAobj.los, max_tropo_height
)

## run raider with the synthetic model
cfg = write_yaml(dct_cfg, 'temp.yaml')
calcDelays([str(cfg)])
# scale by constant (units K/Pa) to match raider (m K / Pa)
ray_data = ray_length * SAobj.wmObj._k1

# get the just created synthetic delays
wm_name = SAobj.wmName.replace("-", "") # incase of ERA-5
ds = xr.open_dataset(
f'{SAobj.wd}/{wm_name}_tropo_{SAobj.dts.replace("_", "")}_ray.nc'
)
da = ds["hydro"]
ds.close()
del ds
# actual raider data
# undo scaling of ppm; units are meters * K/Pa
raid_data = da.data * 1e6

# now build the rays at the unbuffered wm nodes
max_tropo_height = SAobj.wmObj._zlevels[-1] - 1
targ_xyz = [da.x.data, da.y.data, da.z.data]
ray_length = length_of_ray(
targ_xyz, SAobj.wmObj._zlevels, SAobj.los, max_tropo_height
)

# scale by constant (units K/Pa) to match raider (m K / Pa)
ray_data = ray_length * SAobj.wmObj._k1

# actual raider data
# undo scaling of ppm; units are meters * K/Pa
raid_data = da.data * 1e6

assert np.all(np.abs(ray_data) > 1)
assert np.all(np.abs(raid_data) > 1)
assert np.all(np.abs(ray_data) > 1)
assert np.all(np.abs(raid_data) > 1)

# normalize with the theoretical data and compare difference with 0
resid = (ray_data - raid_data) / ray_data
np.testing.assert_almost_equal(0, resid, decimal=6)
# normalize with the theoretical data and compare difference with 0
resid = (ray_data - raid_data) / ray_data
np.testing.assert_almost_equal(0, resid, decimal=6)

da.close()
del da
da.close()
del da


@pytest.mark.parametrize("region", "AK LA Fort".split())
def test_wet_eq_linear(tmp_path, region, mod="ERA-5"):
"""Test linear part of wet equation.

Wet Refractivity = k2 * (E/T) + k3 * (E/T^2)
E = relative humidty; T = temperature
E = relative humidty; T = temperature.

The wet delay reduces to an integral along the ray path when E=T and k3 = 0
However the constants k2 and scaling of 10^-6 will remain present, leading
Expand All @@ -297,9 +294,8 @@ def test_wet_eq_linear(tmp_path, region, mod="ERA-5"):
Check they are both large enough for meaningful numerical comparison (>1)
Compute residual and normalize by theoretical ray length (calculated here)
Ensure that normalized residual is not significantly different from 0
significantly different = 7 decimal places
significantly different = 7 decimal places
"""

with pushd(tmp_path):
# create temp directory for file that is created
dir_to_del = "tmp_dir"
Expand Down Expand Up @@ -359,8 +355,8 @@ def test_wet_eq_linear(tmp_path, region, mod="ERA-5"):

@pytest.mark.parametrize("region", "AK LA Fort".split())
def test_wet_eq_nonlinear(tmp_path, region, mod="ERA-5"):
"""Test the nonlinear part of the wet equation.

"""Test the nonlinear part of the wet equation."""
"""
Wet Refractivity = k2 * (E/T) + k3 * (E/T^2)
E = relative humidty; T = temperature

Expand Down
Loading