Skip to content

Commit 37a364f

Browse files
stelliomgithub-actions
andauthored
Fix and optimize ART buffer (#435)
Co-authored-by: github-actions <[email protected]>
1 parent 9d75d52 commit 37a364f

File tree

3 files changed

+75
-57
lines changed

3 files changed

+75
-57
lines changed

python/extpar_art_to_buffer.py

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,9 @@
2828
from namelist import input_art as iart
2929

3030

31-
def get_nearest_neighbors(lon_array,
32-
lat_array,
33-
lon_point,
34-
lat_point,
35-
metric='haversine'):
36-
"""
37-
Find the indices of n closest cells in a grid, relative to a given latitude/longitude.
38-
The function builds a BallTree from the provided 1D or 2D array of latitude and longitude and queries it to find n nearest neghbors to a given point.
39-
Borrowed from iconarray utilities
40-
"""
41-
lon_array, lat_array, lon_point, lat_point = [
42-
np.deg2rad(arr)
43-
for arr in [lon_array, lat_array, lon_point, lat_point]
44-
]
45-
lon_lat_array = np.column_stack((lon_array.flatten(), lat_array.flatten()))
46-
points = np.column_stack((lon_point, lat_point))
47-
indices = BallTree(lon_lat_array, metric=metric,
48-
leaf_size=3).query(points, k=1)[1].squeeze()
49-
return indices
50-
51-
52-
def get_neighbor_index(index, lons, lats, hlon, hlat, idxs):
53-
xx = np.ones((hlon.size))
54-
idxs[index, :] = get_nearest_neighbors(lons, lats, hlon, hlat[index] * xx)
31+
def get_neighbor_index(index, hlon, hlat, idxs, ones, balltree):
32+
points = np.column_stack((hlon, hlat[index] * ones))
33+
idxs[index, :] = balltree.query(points, k=1)[1].squeeze()
5534

5635

5736
def get_memory_map(mat, filename_mmap):
@@ -68,31 +47,42 @@ def generate_memory_map(raw_lus, soiltype_memmap_filename,
6847
return lus, idxs
6948

7049

71-
def calculate_soil_fraction(tg, lus, idxs, ncpu=2):
50+
def calculate_soil_fraction(target_grid,
51+
soil_types_raw,
52+
nearest_target_cell_to_raw_cells,
53+
ncpu=13):
7254
"""
73-
lus: LU classes from HWSD data
74-
idxs: indices corrsponding to icon grid for each grid in HWSD data
75-
tg: ICON grid
55+
target_grid: target ICON grid
56+
soil_types_raw: landuse class for each cell from the HWSD dataset (LU variable)
57+
nearest_target_cell_to_raw_cell: indices of the cell from the target ICON grid which is nearest to each cell of the raw grid (from HWSD dataset)
7658
"""
77-
soil_types = np.arange(1, 14)
78-
fracs = np.zeros((tg.lons.size, soil_types.size))
79-
grid_ids, grid_counts = np.unique(idxs, return_counts=True)
80-
81-
def get_fraction_per_soil_type(lu):
82-
grid_class, grid_count = np.unique(np.where(lus == lu, idxs, -1),
83-
return_counts=True)
84-
for grid_id in np.arange(tg.lons.size):
85-
frac = np.array(grid_count[grid_class == grid_id] /
86-
grid_counts[grid_ids == grid_id])
87-
if len(frac) != 0:
88-
fracs[grid_id, lu - 1] = frac
89-
90-
Parallel(n_jobs=ncpu,
59+
ncells_target = target_grid.lons.size
60+
nsoil_types = 13
61+
nthreads = min(nsoil_types, ncpu)
62+
63+
soil_ids = np.arange(1, nsoil_types + 1)
64+
soil_fractions_target = np.zeros((ncells_target, nsoil_types))
65+
66+
n_nearest_raw_cells = np.bincount(nearest_target_cell_to_raw_cells.ravel(),
67+
minlength=ncells_target)
68+
69+
def get_fraction_per_soil_type(soil_id):
70+
n_nearest_raw_cells_with_soil_type = np.bincount(
71+
nearest_target_cell_to_raw_cells[soil_types_raw == soil_id],
72+
minlength=ncells_target)
73+
74+
np.divide(n_nearest_raw_cells_with_soil_type,
75+
n_nearest_raw_cells,
76+
out=soil_fractions_target[:, soil_id - 1],
77+
where=n_nearest_raw_cells != 0)
78+
79+
Parallel(n_jobs=nthreads,
9180
max_nbytes='100M',
9281
mmap_mode='w+',
93-
backend='threading')(delayed(get_fraction_per_soil_type)(lu)
94-
for lu in tqdm(soil_types))
95-
return fracs
82+
backend='threading')(delayed(get_fraction_per_soil_type)(soil_id)
83+
for soil_id in tqdm(soil_ids))
84+
85+
return soil_fractions_target
9686

9787

9888
# --------------------------------------------------------------------------
@@ -171,6 +161,26 @@ def get_fraction_per_soil_type(lu):
171161
lons = np.array(tg.lons)
172162
lats = np.array(tg.lats)
173163

164+
vlons = np.array(tg.vlons)
165+
vlats = np.array(tg.vlats)
166+
167+
lon_min = max(np.min(vlons), -180.0)
168+
lon_max = min(np.max(vlons), 180.0)
169+
lat_min = max(np.min(vlats), -90.0)
170+
lat_max = min(np.max(vlats), 90.0)
171+
172+
lon_mask = (raw_lon >= lon_min) & (raw_lon <= lon_max)
173+
lat_mask = (raw_lat >= lat_min) & (raw_lat <= lat_max)
174+
175+
raw_lon = raw_lon[lon_mask]
176+
raw_lat = raw_lat[lat_mask]
177+
raw_lus = raw_lus[np.ix_(lat_mask, lon_mask)]
178+
179+
lons = np.deg2rad(lons)
180+
lats = np.deg2rad(lats)
181+
raw_lon = np.deg2rad(raw_lon)
182+
raw_lat = np.deg2rad(raw_lat)
183+
174184
# --------------------------------------------------------------------------
175185
# --------------------------------------------------------------------------
176186
logging.info("")
@@ -190,17 +200,22 @@ def get_fraction_per_soil_type(lu):
190200
)
191201
logging.info("")
192202

203+
lon_lat_array = np.column_stack((lons.ravel(), lats.ravel()))
204+
balltree = BallTree(lon_lat_array, metric="haversine", leaf_size=3)
205+
206+
ones = np.ones((raw_lon.size))
207+
193208
nrows = np.arange(raw_lat.size)
194-
Parallel(n_jobs=omp, max_nbytes='100M', mmap_mode='w+')(
195-
delayed(get_neighbor_index)(i, lons, lats, raw_lon, raw_lat, neighbor_ids)
196-
for i in tqdm(nrows))
209+
Parallel(n_jobs=omp, max_nbytes='100M', mmap_mode='w+')(delayed(
210+
get_neighbor_index)(i, raw_lon, raw_lat, neighbor_ids, ones, balltree)
211+
for i in tqdm(nrows))
197212

198213
# --------------------------------------------------------------------------
199214
logging.info("")
200215
logging.info("============= Calculate LU Fraction for target grid ========")
201216
logging.info("")
202217

203-
fracs = calculate_soil_fraction(tg, soil_types, neighbor_ids, ncpu=2)
218+
fracs = calculate_soil_fraction(tg, soil_types, neighbor_ids, ncpu=omp)
204219

205220
#--------------------------------------------------------------------------
206221
#--------------------------------------------------------------------------

python/lib/grid_def.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ def __init__(self, gridfile):
260260
self.lons = np.rad2deg(self.grid.variables["clon"][:])
261261
self.lats = np.rad2deg(self.grid.variables["clat"][:])
262262

263+
self.vlons = np.rad2deg(self.grid.variables["vlon"][:])
264+
self.vlats = np.rad2deg(self.grid.variables["vlat"][:])
265+
263266
def cdo_sellonlat(self):
264267
'''
265268
create the string for the cdo option "-sellonlatbox"

test/testsuite/data/get_data.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,38 @@ fi
1414
# mch
1515
test -d mch || exit 1
1616
cd mch/c7_globe
17-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_mch_c7_PR434.nc'
17+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_mch_c7_PR435.nc'
1818
cd -
1919

2020
test -d mch || exit 1
2121
cd mch/c1_aster
22-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_mch_c1_PR434.nc'
22+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_mch_c1_PR435.nc'
2323
cd -
2424

2525
# clm
2626
test -d clm || exit 1
2727
cd clm/12km_globe
28-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_12km_globe_PR434.nc'
28+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_12km_globe_PR435.nc'
2929
cd -
3030

3131
cd clm/ecoclimap_sg
3232
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/icon_grid_bolivia.nc'
33-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_eco_PR434.nc'
33+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_eco_PR435.nc'
3434
cd -
3535

3636
# dwd
3737
test -d dwd || exit 1
3838

3939
cd dwd/icon_d2
4040
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/icon_grid_DOM01.nc'
41-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_d2_PR434.nc'
41+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_d2_PR435.nc'
4242
cd -
4343

4444
cd dwd/icon_ecci
4545
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/icon_grid_bolivia.nc'
4646
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/clim_t2m_icon_ecci.nc'
4747
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/clim_tsea_icon_ecci.nc'
48-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_ecci_PR434.nc'
48+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_ecci_PR435.nc'
4949
cd -
5050

5151
# mpim
@@ -54,14 +54,14 @@ cd mpim/icon_r2b4
5454
wget --quiet 'http://icon-downloads.mpimet.mpg.de/grids/public/mpim/0013/icon_grid_0013_R02B04_G.nc'
5555
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/clim_t2m_icon_r2b4.nc'
5656
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/clim_tsea_icon_r2b4.nc'
57-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_mpim_PR434.nc'
57+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/external_parameter_icon_mpim_PR435.nc'
5858
cd -
5959

6060
# ecmwf
6161
test -d ecmwf || exit 1
6262
cd ecmwf/corine_icon
6363
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/corine/icon_grid_0099_R19B10.nc'
64-
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/corine/external_parameter_icon_corine_PR434.nc'
64+
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/corine/external_parameter_icon_corine_PR435.nc'
6565
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/corine/clim_tsea_corine.nc'
6666
wget --quiet 'ftp://iacftp.ethz.ch/pub_read/stelliom/corine/clim_t2m_corine.nc'
6767
cd -

0 commit comments

Comments
 (0)