-
Notifications
You must be signed in to change notification settings - Fork 0
/
ACTEA_area_calculations.py
97 lines (76 loc) · 2.95 KB
/
ACTEA_area_calculations.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import numpy as np
import pandas as pd
import xarray as xr
from math import radians, sin
import timeit
from shapely.geometry import box
import geopandas as gpd
def lat_lon_cell_area(lat, lon, d_lat, d_lon):
"""
Calculate the area of a cell, in km^2, on a lat/lon grid.
This applies the following equation from Santinie et al. 2010.
S = (λ_2 - λ_1)(sinφ_2 - sinφ_1)R^2
S = surface area of cell on sphere
λ_1, λ_2, = bands of longitude in radians
φ_1, φ_2 = bands of latitude in radians
R = radius of the sphere
Santini, M., Taramelli, A., & Sorichetta, A. (2010). ASPHAA: A GIS‐Based
Algorithm to Calculate Cell Area on a Latitude‐Longitude (Geographic)
Regular Grid. Transactions in GIS, 14(3), 351-377.
https://doi.org/10.1111/j.1467-9671.2010.01200.x
Parameters
----------
lat_lon_grid_cell
A shapely box with coordinates on the lat/lon grid
Returns
-------
float
The cell area in km^2
"""
R = 6371.0088 # Earth's radius in km
lat_rad = np.radians(lat)
a = np.sin(np.radians(d_lat) / 2) ** 2
c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
lat_distance = R * c
a = np.cos(lat_rad) * np.cos(lat_rad) * np.sin(np.radians(d_lon) / 2) ** 2
c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
lon_distance = R * c
return lat_distance * lon_distance
def calculate_cell_area(lat, lon, side_length):
"""
Calculate the area of a single grid cell.
"""
return lat_lon_cell_area(lat, lon, side_length, side_length)
def calculate_area_of_grid(da: xr.DataArray, side_length: float):
"""
Calculate the area of each grid cell for a DataArray with dimensions (time, lat, lon). This code
is now vectorized using xarray `apply_ufunc` and should be faster than the previous version.
Parameters:
da (xr.DataArray): The DataArray containing the grid data with dimensions (time, lat, lon).
side_length (float): The side length of each grid cell in degrees. GLORYS=1/12 and ROMS=1/64
Returns:
xr.DataArray: A DataArray containing the grid cell areas with dimensions (time, lat, lon).
"""
# Create meshgrid of latitudes and longitudes
lons, lats = np.meshgrid(da.lon.values, da.lat.values)
# Calculate areas for each grid cell
areas = xr.apply_ufunc(
calculate_cell_area,
lats,
lons,
input_core_dims=[[], []],
vectorize=True,
dask='parallelized',
output_dtypes=[float],
kwargs={'side_length': side_length}
)
# Create a DataArray with the same dimensions as the input
area_da = xr.DataArray(
areas,
dims=['lat', 'lon'],
coords={'lat': da.lat, 'lon': da.lon}
)
# Broadcast the area DataArray to match the time dimension of the input
area_da = area_da.broadcast_like(da)
# Mask the areas where the input data is NaN
return xr.where(np.isnan(da), np.nan, area_da)