Skip to content
Snippets Groups Projects
util.py 6.29 KiB
Newer Older
tomrink's avatar
tomrink committed
import re
import datetime
from datetime import timezone

import numpy as np
import xarray as xr
tomrink's avatar
tomrink committed
import pandas as pd
tomrink's avatar
tomrink committed
import rasterio
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import h5py
from util.util import get_grid_values_all
from util.gfs_reader import *
from util.geos_nav import GEOSNavigation
from aeolus.datasource import GFSfiles
tomrink's avatar
tomrink committed
import cartopy.crs as ccrs
tomrink's avatar
tomrink committed
from metpy.calc import shearing_deformation, static_stability, wind_speed, first_derivative
tomrink's avatar
tomrink committed
from metpy.units import units
tomrink's avatar
tomrink committed

gfs_files = GFSfiles('/Users/tomrink/data/contrail/gfs/')
# GEOSNavigation needs to be updated to support GOES-18
# geos_nav = GEOSNavigation()


def load_image(image_path):
    # Extract date time string from image path
    datetime_regex = '_\\d{8}_\\d{6}'
    datetime_string = re.search(datetime_regex, image_path)
    if datetime_string:
        datetime_string = datetime_string.group()
    dto = datetime.datetime.strptime(datetime_string, '_%Y%m%d_%H%M%S').replace(tzinfo=timezone.utc)
    ts = dto.timestamp()

    img = mpimg.imread(image_path)

    return img, ts


def get_contrail_mask_image(image, thresh=0.157):
    image = np.where(image > thresh,1, 0)
    return image


def extract(mask_image, image_ts, clavrx_path):
    gfs_file, _, _ = gfs_files.get_file(image_ts)
    xr_dataset = xr.open_dataset(gfs_file)

    clvrx_h5f = h5py.File(clavrx_path, 'r')
    cloud_top_press = get_grid_values_all(clvrx_h5f, 'cld_press_acha').flatten()
    clvrx_lons = get_grid_values_all(clvrx_h5f, 'longitude').flatten()
    clvrx_lats = get_grid_values_all(clvrx_h5f, 'latitude').flatten()

    contrail_idxs = (mask_image == 1).flatten()

tomrink's avatar
tomrink committed
    # Assuming GOES FD for now -------------------
    # elems, lines = np.meshgrid(np.arange(5424), np.arange(5424))
    # lines, elems = lines.flatten(), elems.flatten()
tomrink's avatar
tomrink committed
    # See note above regarding support for GOES-18
tomrink's avatar
tomrink committed
    # contrail_lines, contrail_elems = lines[contrail_idxs], elems[contrail_idxs]
tomrink's avatar
tomrink committed
    # contrail_lons, contrail_lats = geos_nav.lc_to_earth(contrail_elems, contrail_lines)

    contrail_press = cloud_top_press[contrail_idxs]
    contrail_lons, contrail_lats = clvrx_lons[contrail_idxs], clvrx_lats[contrail_idxs]

    keep = np.invert(np.isnan(contrail_press))
    contrail_press = contrail_press[keep]
    contrail_lons = contrail_lons[keep]
    contrail_lats = contrail_lats[keep]

tomrink's avatar
tomrink committed
    # Indexes of contrail_press for individual bins
tomrink's avatar
tomrink committed
    bins = np.arange(100, 1000, 50)
tomrink's avatar
tomrink committed
    binned_indexes = np.digitize(contrail_press, bins)

    # Store the indexes in a dictionary where the key is the bin number and value is the list of indexes
    bins_dict = {}
    for bin_num in np.unique(binned_indexes):
        bins_dict[bin_num] = np.where(binned_indexes == bin_num)[0]

tomrink's avatar
tomrink committed
    # # This does point by point computation of model parameters for each contrail pixel
    # voxel_dict = {key: [] for key in bins_dict.keys()}
    # for key in bins_dict.keys():
    #     print('working on pressure level: ', bins[key])
    #     for c_idx in bins_dict[key]:
    #         lon = contrail_lons[c_idx]
    #         lat = contrail_lats[c_idx]
    #         press = contrail_press[c_idx]
    #
    #         wind_3d = get_voxel_s(xr_dataset, ['u-wind','v-wind'], lon, lat, press)
    #         if wind_3d is not None:
    #             voxel_dict[key].append(wind_3d)
    # ------------------------------------------------------------------------------------
tomrink's avatar
tomrink committed

    # This section will compute model parameters in bulk for the region then pull for each contrail pixel
    lon_range = [np.min(contrail_lons), np.max(contrail_lons)]
    lat_range = [np.min(contrail_lats), np.max(contrail_lats)]

tomrink's avatar
tomrink committed
    uwind_3d = get_volume(xr_dataset, 'u-wind', 'm s-1', lon_range=lon_range, lat_range=lat_range)
    vwind_3d = get_volume(xr_dataset, 'v-wind', 'm s-1', lon_range=lon_range, lat_range=lat_range)
    temp_3d = get_volume(xr_dataset, 'temperature', 'degK', lon_range=lon_range, lat_range=lat_range)
    rh_3d = get_volume(xr_dataset, 'rh', '%', lon_range=lon_range, lat_range=lat_range)
tomrink's avatar
tomrink committed

tomrink's avatar
tomrink committed
    uwind_3d = uwind_3d.transpose('Pressure', 'Latitude', 'Longitude')
    vwind_3d = vwind_3d.transpose('Pressure', 'Latitude', 'Longitude')
    temp_3d = temp_3d.transpose('Pressure', 'Latitude', 'Longitude')
tomrink's avatar
tomrink committed
    rh_3d = rh_3d.transpose('Pressure', 'Latitude', 'Longitude')
tomrink's avatar
tomrink committed

tomrink's avatar
tomrink committed
    horz_shear_3d = shearing_deformation(uwind_3d, vwind_3d)
tomrink's avatar
tomrink committed
    static_3d = static_stability(temp_3d.coords['Pressure'] * units.hPa, temp_3d)
tomrink's avatar
tomrink committed
    horz_wind_spd_3d = wind_speed(uwind_3d, vwind_3d)
tomrink's avatar
tomrink committed

    # This one's a bit more work: `first_derivative` only returns a ndarray with no units, so we use the
tomrink's avatar
tomrink committed
    # helper function to create a DataArray and add units via metpy's pint support
tomrink's avatar
tomrink committed
    vert_shear_3d = first_derivative(horz_wind_spd_3d, axis=0, x=temp_3d.coords['Pressure'])
tomrink's avatar
tomrink committed
    vert_shear_3d = volume_np_to_xr(vert_shear_3d, ['Pressure', 'Latitude', 'Longitude'], lon_range=lon_range, lat_range=lat_range)
tomrink's avatar
tomrink committed
    vert_shear_3d = vert_shear_3d / units.hPa
tomrink's avatar
tomrink committed

tomrink's avatar
tomrink committed
    voxel_dict = {key: [] for key in bins_dict.keys()}
    for key in bins_dict.keys():
        print('working on pressure level: ', bins[key])
        for c_idx in bins_dict[key]:
tomrink's avatar
tomrink committed
            press = contrail_press[c_idx]
            lat = contrail_lats[c_idx]
tomrink's avatar
tomrink committed
            lon = contrail_lons[c_idx]
tomrink's avatar
tomrink committed
            if lon < 0:  # Match GFS convention
                lon += 360.0
tomrink's avatar
tomrink committed

tomrink's avatar
tomrink committed
            horz_shear_value = horz_shear_3d.interp(Pressure=press, Longitude=lon, Latitude=lat, method='nearest')
            static_value = static_3d.interp(Pressure=press, Longitude=lon, Latitude=lat, method='nearest')
            horz_wind_spd_value = horz_wind_spd_3d.interp(Pressure=press, Longitude=lon, Latitude=lat, method='nearest')
            vert_shear_value = vert_shear_3d.interp(Pressure=press, Longitude=lon, Latitude=lat, method='nearest')

tomrink's avatar
tomrink committed
            # tmp = horz_shear_3d.sel(Pressure=press, method='nearest')
            # tmp = tmp.sel(Longitude=lon, Latitude=lat, method='nearest')

tomrink's avatar
tomrink committed
            voxel_dict[key].append((press, lat, lon, horz_shear_value, static_value, horz_wind_spd_value, vert_shear_value))

    # Create pandas DataFrame for each list of tuples in voxel_dict
    voxel_dict_df = {}
    for k, v in voxel_dict.items():
tomrink's avatar
tomrink committed
        df = pd.DataFrame(v, columns=["pressure", "lat", "lon", "horz_wind_shear", "static_stability", "horz_wind_speed", "vert_wind_shear"])
tomrink's avatar
tomrink committed
        voxel_dict_df[k] = df
tomrink's avatar
tomrink committed

tomrink's avatar
tomrink committed
    xr_dataset.close()
tomrink's avatar
tomrink committed