def angle2xyz(azi, zen): """Convert azimuth and zenith to cartesian.""" azi = xu.deg2rad(azi) zen = xu.deg2rad(zen) x = xu.sin(zen) * xu.sin(azi) y = xu.sin(zen) * xu.cos(azi) z = xu.cos(zen) return x, y, z
def lonlat2xyz(lon, lat): """Convert lon lat to cartesian.""" lat = xu.deg2rad(lat) lon = xu.deg2rad(lon) x = xu.cos(lat) * xu.cos(lon) y = xu.cos(lat) * xu.sin(lon) z = xu.sin(lat) return x, y, z
def overturning_improved(run): # Better method: use the actual layer pressure intervals to weight the integral field = (run.V * run.dP * cos(deg2rad(run.lat))) if 'lon' in field.dims: field = field.mean(dim='lon') factor = 2*np.pi*physconst.rearth/physconst.gravit*1E-9 psi = np.cumsum( field, axis=field.get_axis_num('lev'))*factor return psi
def __call__(self, projectables, **kwargs): projectables = self.check_areas(projectables) day_data = projectables[0] night_data = projectables[1] lim_low = np.cos(np.deg2rad(self.lim_low)) lim_high = np.cos(np.deg2rad(self.lim_high)) try: coszen = xu.cos(xu.deg2rad(projectables[2])) except IndexError: from pyorbital.astronomy import cos_zen LOG.debug("Computing sun zenith angles.") # Get chunking that matches the data try: chunks = day_data.sel(bands=day_data['bands'][0]).chunks except KeyError: chunks = day_data.chunks lons, lats = day_data.attrs["area"].get_lonlats_dask(chunks) coszen = xr.DataArray(cos_zen(day_data.attrs["start_time"], lons, lats), dims=['y', 'x'], coords=[day_data['y'], day_data['x']]) # Calculate blending weights coszen -= np.min((lim_high, lim_low)) coszen /= np.abs(lim_low - lim_high) coszen = coszen.clip(0, 1) # Apply enhancements to get images day_data = enhance2dataset(day_data) night_data = enhance2dataset(night_data) # Adjust bands so that they match # L/RGB -> RGB/RGB # LA/RGB -> RGBA/RGBA # RGB/RGBA -> RGBA/RGBA day_data = add_bands(day_data, night_data['bands']) night_data = add_bands(night_data, day_data['bands']) # Replace missing channel data with zeros day_data = zero_missing_data(day_data, night_data) night_data = zero_missing_data(night_data, day_data) # Get merged metadata attrs = combine_metadata(day_data, night_data) # Blend the two images together data = (1 - coszen) * night_data + coszen * day_data data.attrs = attrs # Split to separate bands so the mode is correct data = [data.sel(bands=b) for b in data['bands']] return super(DayNightCompositor, self).__call__(data, **kwargs)
def __call__(self, projectables, **kwargs): day_data = projectables[0] night_data = projectables[1] lim_low = np.cos(np.deg2rad(self.lim_low)) lim_high = np.cos(np.deg2rad(self.lim_high)) try: coszen = xu.cos(xu.deg2rad(projectables[2])) except IndexError: from pyorbital.astronomy import cos_zen LOG.debug("Computing sun zenith angles.") # Get chunking that matches the data try: chunks = day_data.sel(bands=day_data['bands'][0]).chunks except KeyError: chunks = day_data.chunks lons, lats = day_data.attrs["area"].get_lonlats_dask(chunks) coszen = xr.DataArray(cos_zen(day_data.attrs["start_time"], lons, lats), dims=['y', 'x'], coords=[day_data['y'], day_data['x']]) # Calculate blending weights coszen -= np.min((lim_high, lim_low)) coszen /= np.abs(lim_low - lim_high) coszen = coszen.clip(0, 1) # Apply enhancements to get images day_data = enhance2dataset(day_data) night_data = enhance2dataset(night_data) # Adjust bands so that they match # L/RGB -> RGB/RGB # LA/RGB -> RGBA/RGBA # RGB/RGBA -> RGBA/RGBA day_data = add_bands(day_data, night_data['bands']) night_data = add_bands(night_data, day_data['bands']) # Get merged metadata attrs = combine_metadata(day_data, night_data) # Blend the two images together data = (1 - coszen) * night_data + coszen * day_data data.attrs = attrs # Split to separate bands so the mode is correct data = [data.sel(bands=b) for b in data['bands']] res = super(DayNightCompositor, self).__call__(data, **kwargs) return res
def _prep_overturning(inputfield, lat=None, lev=None, levax=0): if lat is None: try: lat = inputfield.lat except: raise ValueError('Need to supply latitude array if input data is not self-describing.') if lev is None: try: lev = inputfield.lev except: raise ValueError('Need to supply pressure array if input data is not self-describing.') lat_rad = deg2rad(lat) coslat = cos(lat_rad) field = inputfield * coslat try: levax = field.get_axis_num('lev') except: pass return field, lat, lev, levax
def sunzen_corr_cos(data, cos_zen, limit=88.): """Perform Sun zenith angle correction. The correction is based on the provided cosine of the zenith angle (*cos_zen*). The correction is limited to *limit* degrees (default: 88.0 degrees). For larger zenith angles, the correction is the same as at the *limit*. Both *data* and *cos_zen* are given as 2-dimensional Numpy arrays or Numpy MaskedArrays, and they should have equal shapes. """ # Convert the zenith angle limit to cosine of zenith angle limit = xu.cos(xu.deg2rad(limit)) # Cosine correction corr = 1. / cos_zen # Use constant value (the limit) for larger zenith # angles corr = corr.where(cos_zen > limit).fillna(1 / limit) return data * corr
def __call__(self, projectables, **info): projectables = self.check_areas(projectables) vis = projectables[0] if vis.attrs.get("sunz_corrected"): LOG.debug("Sun zen correction already applied") return vis if hasattr(vis.attrs["area"], 'name'): area_name = vis.attrs["area"].name else: area_name = 'swath' + str(vis.shape) key = (vis.attrs["start_time"], area_name) tic = time.time() LOG.debug("Applying sun zen correction") if len(projectables) == 1: coszen = self.coszen.get(key) if coszen is None: from pyorbital.astronomy import cos_zen LOG.debug("Computing sun zenith angles.") lons, lats = vis.attrs["area"].get_lonlats_dask(CHUNK_SIZE) coszen = xr.DataArray(cos_zen(vis.attrs["start_time"], lons, lats), dims=['y', 'x'], coords=[vis['y'], vis['x']]) coszen = coszen.where((coszen > 0.035) & (coszen < 1)) self.coszen[key] = coszen else: coszen = xu.cos(xu.deg2rad(projectables[1])) self.coszen[key] = coszen proj = self._apply_correction(vis, coszen) proj.attrs = vis.attrs.copy() self.apply_modifier_info(vis, proj) LOG.debug( "Sun-zenith correction applied. Computation time: %5.1f (sec)", time.time() - tic) return proj
def eady_growth_rate(data): """Calculate the local Eady Growth rate. Following Vallis (2017) p.354. EGR = 0.31*du/dz*f/N Parameters ---------- data : xarray.DataSet The Isca dataset. Requires fields 'temp', 'ps', 'pfull' and 'phalf' Returns a new xarray.DataArray of growth rate values on phalf levels, in s^-1. """ N2 = ixr.brunt_vaisala(data) f = 2.0 * omega * xruf.sin(xruf.deg2rad(data.lat)) dz = ixr.domain.calculate_dz(data) du = ixr.domain.diff_pfull(data.ucomp, data) N = xruf.sqrt(N2.where(N2 > 0)) egr = 0.31 * du / dz * f / N return np.abs(egr)
def run_crefl(refl, coeffs, lon, lat, sensor_azimuth, sensor_zenith, solar_azimuth, solar_zenith, avg_elevation=None, percent=False): """Run main crefl algorithm. All input parameters are per-pixel values meaning they are the same size and shape as the input reflectance data, unless otherwise stated. :param reflectance_bands: tuple of reflectance band arrays :param coefficients: tuple of coefficients for each band (see `get_coefficients`) :param lon: input swath longitude array :param lat: input swath latitude array :param sensor_azimuth: input swath sensor azimuth angle array :param sensor_zenith: input swath sensor zenith angle array :param solar_azimuth: input swath solar azimuth angle array :param solar_zenith: input swath solar zenith angle array :param avg_elevation: average elevation (usually pre-calculated and stored in CMGDEM.hdf) :param percent: True if input reflectances are on a 0-100 scale instead of 0-1 scale (default: False) """ # FUTURE: Find a way to compute the average elevation before hand (ah2o, bh2o, ao3, tau) = coeffs # Get digital elevation map data for our granule, set ocean fill value to 0 if avg_elevation is None: LOG.debug("No average elevation information provided in CREFL") #height = np.zeros(lon.shape, dtype=np.float) height = 0. else: row = ((90.0 - lat) * avg_elevation.shape[0] / 180.0).astype(np.int32) col = ((lon + 180.0) * avg_elevation.shape[1] / 360.0).astype(np.int32) height = avg_elevation[row, col].astype(np.float64) # negative heights aren't allowed, clip to 0 height = height.where(height >= 0., 0.0) del lat, lon, row, col mus = xu.cos(xu.deg2rad(solar_zenith)) muv = xu.cos(xu.deg2rad(sensor_zenith)) phi = solar_azimuth - sensor_azimuth del solar_azimuth, solar_zenith, sensor_zenith, sensor_azimuth sphalb, rhoray, TtotraytH2O, tOG = get_atm_variables( mus, muv, phi, height, (ah2o, bh2o, ao3, tau)) if rhoray.shape[1] != refl.shape[1]: LOG.debug( "Interpolating CREFL calculations for higher resolution bands") # Assume we need to interpolate # FIXME: Do real bilinear interpolation instead of "nearest" factor = int(refl.shape[1] / rhoray.shape[1]) rhoray = np.repeat(np.repeat(rhoray, factor, axis=0), factor, axis=1) tOG = np.repeat(np.repeat(tOG, factor, axis=0), factor, axis=1) TtotraytH2O = np.repeat(np.repeat(TtotraytH2O, factor, axis=0), factor, axis=1) # if average height wasn't provided then this should stay a scalar if sphalb.size != 1: # otherwise make it the same size as the other arrays sphalb = np.repeat(np.repeat(sphalb, factor, axis=0), factor, axis=1) # Note: Assume that fill/invalid values are either NaN or we are dealing # with masked arrays if percent: corr_refl = ((refl / 100.) / tOG - rhoray) / TtotraytH2O else: corr_refl = (refl / tOG - rhoray) / TtotraytH2O corr_refl /= (1.0 + corr_refl * sphalb) return corr_refl.clip(REFLMIN, REFLMAX)