|
37 | 37 | vertical_velocity_pressure, virtual_potential_temperature, |
38 | 38 | virtual_temperature, virtual_temperature_from_dewpoint, |
39 | 39 | wet_bulb_potential_temperature, wet_bulb_temperature) |
40 | | -from metpy.calc.thermo import _find_append_zero_crossings |
| 40 | +from metpy.calc.thermo import _find_append_zero_crossings, galvez_davison_index |
41 | 41 | from metpy.testing import (assert_almost_equal, assert_array_almost_equal, assert_nan, |
42 | 42 | version_check) |
43 | 43 | from metpy.units import is_quantity, masked_array, units |
@@ -2309,6 +2309,50 @@ def index_xarray_data(): |
2309 | 2309 | coords={'isobaric': pressure, 'time': ['2020-01-01T00:00Z']}) |
2310 | 2310 |
|
2311 | 2311 |
|
| 2312 | +@pytest.fixture() |
| 2313 | +def index_xarray_data_expanded(): |
| 2314 | + """Create expanded data for testing that index calculations work with xarray data. |
| 2315 | +
|
| 2316 | + Specifically for Galvez Davison Index calculation, which requires 950hPa pressure |
| 2317 | + """ |
| 2318 | + pressure = xr.DataArray( |
| 2319 | + [950., 850., 700., 500.], dims=('isobaric',), attrs={'units': 'hPa'} |
| 2320 | + ) |
| 2321 | + temp = xr.DataArray([[[[306., 305., 304.], [303., 302., 301.]], |
| 2322 | + [[296., 295., 294.], [293., 292., 291.]], |
| 2323 | + [[286., 285., 284.], [283., 282., 281.]], |
| 2324 | + [[276., 275., 274.], [273., 272., 271.]]]] * units.K, |
| 2325 | + dims=('time', 'isobaric', 'y', 'x')) |
| 2326 | + |
| 2327 | + profile = xr.DataArray([[[[299., 298., 297.], [296., 295., 294.]], |
| 2328 | + [[289., 288., 287.], [286., 285., 284.]], |
| 2329 | + [[279., 278., 277.], [276., 275., 274.]], |
| 2330 | + [[269., 268., 267.], [266., 265., 264.]]]] * units.K, |
| 2331 | + dims=('time', 'isobaric', 'y', 'x')) |
| 2332 | + |
| 2333 | + dewp = xr.DataArray([[[[304., 303., 302.], [301., 300., 299.]], |
| 2334 | + [[294., 293., 292.], [291., 290., 289.]], |
| 2335 | + [[284., 283., 282.], [281., 280., 279.]], |
| 2336 | + [[274., 273., 272.], [271., 270., 269.]]]] * units.K, |
| 2337 | + dims=('time', 'isobaric', 'y', 'x')) |
| 2338 | + |
| 2339 | + dirw = xr.DataArray([[[[135., 135., 135.], [135., 135., 135.]], |
| 2340 | + [[180., 180., 180.], [180., 180., 180.]], |
| 2341 | + [[225., 225., 225.], [225., 225., 225.]], |
| 2342 | + [[270., 270., 270.], [270., 270., 270.]]]] * units.degree, |
| 2343 | + dims=('time', 'isobaric', 'y', 'x')) |
| 2344 | + |
| 2345 | + speed = xr.DataArray([[[[15., 15., 15.], [15., 15., 15.]], |
| 2346 | + [[20., 20., 20.], [20., 20., 20.]], |
| 2347 | + [[25., 25., 25.], [25., 25., 25.]], |
| 2348 | + [[50., 50., 50.], [50., 50., 50.]]]] * units.knots, |
| 2349 | + dims=('time', 'isobaric', 'y', 'x')) |
| 2350 | + |
| 2351 | + return xr.Dataset({'temperature': temp, 'profile': profile, 'dewpoint': dewp, |
| 2352 | + 'wind_direction': dirw, 'wind_speed': speed}, |
| 2353 | + coords={'isobaric': pressure, 'time': ['2023-01-01T00:00Z']}) |
| 2354 | + |
| 2355 | + |
2312 | 2356 | def test_lifted_index(): |
2313 | 2357 | """Test the Lifted Index calculation.""" |
2314 | 2358 | pressure = np.array([1014., 1000., 997., 981.2, 947.4, 925., 914.9, 911., |
@@ -2398,6 +2442,109 @@ def test_k_index_xarray(index_xarray_data): |
2398 | 2442 | np.array([[[312., 311., 310.], [309., 308., 307.]]]) * units.K) |
2399 | 2443 |
|
2400 | 2444 |
|
| 2445 | +def test_gdi(): |
| 2446 | + """Test the Galvez Davison Index calculation.""" |
| 2447 | + pressure = np.array([1014., 1000., 997., 981.2, 947.4, 925., 914.9, 911., |
| 2448 | + 902., 883., 850., 822.3, 816., 807., 793.2, 770., |
| 2449 | + 765.1, 753., 737.5, 737., 713., 700., 688., 685., |
| 2450 | + 680., 666., 659.8, 653., 643., 634., 615., 611.8, |
| 2451 | + 566.2, 516., 500., 487., 484.2, 481., 475., 460., |
| 2452 | + 400.]) * units.hPa |
| 2453 | + temperature = np.array([24.2, 24.2, 24., 23.1, 21., 19.6, 18.7, 18.4, |
| 2454 | + 19.2, 19.4, 17.2, 15.3, 14.8, 14.4, 13.4, 11.6, |
| 2455 | + 11.1, 10., 8.8, 8.8, 8.2, 7., 5.6, 5.6, |
| 2456 | + 5.6, 4.4, 3.8, 3.2, 3., 3.2, 1.8, 1.5, |
| 2457 | + -3.4, -9.3, -11.3, -13.1, -13.1, -13.1, -13.7, -15.1, |
| 2458 | + -23.5]) * units.degC |
| 2459 | + dewpoint = np.array([23.2, 23.1, 22.8, 22., 20.2, 19., 17.6, 17., |
| 2460 | + 16.8, 15.5, 14., 11.7, 11.2, 8.4, 7., 4.6, |
| 2461 | + 5., 6., 4.2, 4.1, -1.8, -2., -1.4, -0.4, |
| 2462 | + -3.4, -5.6, -4.3, -2.8, -7., -25.8, -31.2, -31.4, |
| 2463 | + -34.1, -37.3, -32.3, -34.1, -37.3, -41.1, -37.7, -58.1, |
| 2464 | + -57.5]) * units.degC |
| 2465 | + |
| 2466 | + relative_humidity = relative_humidity_from_dewpoint(temperature, dewpoint) |
| 2467 | + mixrat = mixing_ratio_from_relative_humidity(pressure, temperature, relative_humidity) |
| 2468 | + gdi = galvez_davison_index(pressure, temperature, mixrat, pressure[0]) |
| 2469 | + |
| 2470 | + # Compare with value from hand calculation |
| 2471 | + assert_almost_equal(gdi, 6.635, decimal=1) |
| 2472 | + |
| 2473 | + |
| 2474 | +def test_gdi_xarray(index_xarray_data_expanded): |
| 2475 | + """Test the GDI calculation with a grid of xarray data.""" |
| 2476 | + pressure = index_xarray_data_expanded.isobaric |
| 2477 | + temperature = index_xarray_data_expanded.temperature |
| 2478 | + dewpoint = index_xarray_data_expanded.dewpoint |
| 2479 | + mixing_ratio = mixing_ratio_from_relative_humidity( |
| 2480 | + pressure, temperature, relative_humidity_from_dewpoint(temperature, dewpoint)) |
| 2481 | + |
| 2482 | + result = galvez_davison_index( |
| 2483 | + pressure, |
| 2484 | + temperature, |
| 2485 | + mixing_ratio, |
| 2486 | + pressure[0] |
| 2487 | + ) |
| 2488 | + |
| 2489 | + assert_array_almost_equal( |
| 2490 | + result, |
| 2491 | + np.array([[[189.5890429, 157.4307982, 129.9739099], |
| 2492 | + [106.6763526, 87.0637477, 70.7202505]]]) |
| 2493 | + ) |
| 2494 | + |
| 2495 | + |
| 2496 | +def test_gdi_arrays(index_xarray_data_expanded): |
| 2497 | + """Test GDI on 3-D Quantity arrays with an array of surface pressure.""" |
| 2498 | + ds = index_xarray_data_expanded.isel(time=0).squeeze() |
| 2499 | + pressure = ds.isobaric.metpy.unit_array[:, None, None] |
| 2500 | + temperature = ds.temperature.metpy.unit_array |
| 2501 | + dewpoint = ds.dewpoint.metpy.unit_array |
| 2502 | + mixing_ratio = mixing_ratio_from_relative_humidity( |
| 2503 | + pressure, temperature, relative_humidity_from_dewpoint(temperature, dewpoint)) |
| 2504 | + surface_pressure = units.Quantity( |
| 2505 | + np.broadcast_to(pressure.m, temperature.shape), pressure.units)[0] |
| 2506 | + |
| 2507 | + result = galvez_davison_index(pressure, temperature, mixing_ratio, surface_pressure) |
| 2508 | + |
| 2509 | + assert_array_almost_equal( |
| 2510 | + result, |
| 2511 | + np.array([[189.5890429, 157.4307982, 129.9739099], |
| 2512 | + [106.6763526, 87.0637477, 70.7202505]]) |
| 2513 | + ) |
| 2514 | + |
| 2515 | + |
| 2516 | +def test_gdi_profile(index_xarray_data_expanded): |
| 2517 | + """Test GDI calculation on an individual profile.""" |
| 2518 | + ds = index_xarray_data_expanded.isel(time=0, y=0, x=0) |
| 2519 | + pressure = ds.isobaric.metpy.unit_array |
| 2520 | + temperature = ds.temperature.metpy.unit_array |
| 2521 | + dewpoint = ds.dewpoint.metpy.unit_array |
| 2522 | + mixing_ratio = mixing_ratio_from_relative_humidity( |
| 2523 | + pressure, temperature, relative_humidity_from_dewpoint(temperature, dewpoint)) |
| 2524 | + |
| 2525 | + assert_almost_equal(galvez_davison_index(pressure, temperature, mixing_ratio, pressure[0]), |
| 2526 | + 189.5890429, 4) |
| 2527 | + |
| 2528 | + |
| 2529 | +def test_gdi_no_950_raises_valueerror(index_xarray_data): |
| 2530 | + """GDI requires a 950hPa or higher measurement. |
| 2531 | +
|
| 2532 | + Ensure error is raised if this data is not provided. |
| 2533 | + """ |
| 2534 | + with pytest.raises(ValueError): |
| 2535 | + pressure = index_xarray_data.isobaric |
| 2536 | + temperature = index_xarray_data.temperature |
| 2537 | + dewpoint = index_xarray_data.dewpoint |
| 2538 | + relative_humidity = relative_humidity_from_dewpoint(temperature, dewpoint) |
| 2539 | + mixrat = mixing_ratio_from_relative_humidity(pressure, temperature, relative_humidity) |
| 2540 | + galvez_davison_index( |
| 2541 | + pressure, |
| 2542 | + temperature, |
| 2543 | + mixrat, |
| 2544 | + pressure[0] |
| 2545 | + ) |
| 2546 | + |
| 2547 | + |
2401 | 2548 | def test_gradient_richardson_number(): |
2402 | 2549 | """Test gradient Richardson number calculation.""" |
2403 | 2550 | theta = units('K') * np.asarray([254.5, 258.3, 262.2]) |
|
0 commit comments