Skip to content

Commit e424e99

Browse files
authored
Merge pull request #726 from davidhassell/regrid-3d
3-d spherical regridding and regridding to DSG feature types
2 parents 87a3997 + 1d752a3 commit e424e99

14 files changed

+1677
-353
lines changed

Changelog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ version NEXT
33

44
**2024-??-??**
55

6+
* Added spherical regridding to discrete sampling geometry destination
7+
grids (https://github.com/NCAS-CMS/cf-python/issues/716)
8+
* Added 3-d spherical regridding to `cf.Field.regrids`, and the option
9+
to regrid the vertical axis in logarithmic coordinates to
10+
`cf.Field.regrids` and `cf.Field.regridc`
11+
(https://github.com/NCAS-CMS/cf-python/issues/715)
612
* Fix misleading error message when it is not possible to create area
713
weights requested from `cf.Field.collapse`
814
(https://github.com/NCAS-CMS/cf-python/issues/731)

cf/data/dask_regrid.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ def regrid(
5454
source grid cells i. Note that it is typical that for a
5555
given j most w_ji will be zero, reflecting the fact only a
5656
few source grid cells intersect a particular destination
57-
grid cell. I.e. *weights* is typically a very sparse
58-
matrix.
57+
grid cell. I.e. *weights* is usually a very sparse matrix.
5958
6059
If the destination grid has masked cells, either because
6160
it spans areas outside of the source grid, or by selection
@@ -314,6 +313,27 @@ def regrid(
314313
# [0,1,3,4,2]
315314
raxis0, raxis = axis_order[-2:]
316315
axis_order = [i if i <= raxis else i - 1 for i in axis_order[:-1]]
316+
elif n_src_axes == 3 and n_dst_axes == 1:
317+
# The regridding operation decreased the number of data axes
318+
# by 2 => modify 'axis_order' to remove the removed axes.
319+
#
320+
# E.g. regular Z-lat-lon -> DSG could change 'axis_order' from
321+
# [0,2,5,1,3,4] to [0,2,3,1], or [0,2,4,5,3,1] to
322+
# [0,1,2,3]
323+
raxis0, raxis1 = axis_order[-2:]
324+
if raxis0 > raxis1:
325+
raxis0, raxis1 = raxis1, raxis0
326+
327+
new = []
328+
for i in axis_order[:-2]:
329+
if i <= raxis0:
330+
new.append(i)
331+
elif raxis0 < i <= raxis1:
332+
new.append(i - 1)
333+
else:
334+
new.append(i - 2)
335+
336+
axis_order = new
317337
elif n_src_axes != n_dst_axes:
318338
raise ValueError(
319339
f"Can't (yet) regrid from {n_src_axes} dimensions to "

cf/data/data.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3840,7 +3840,7 @@ def _regrid(
38403840
The positions of the regrid axes in the data, given in
38413841
the relative order expected by the regrid
38423842
operator. For spherical regridding this order is [Y,
3843-
X].
3843+
X] or [Z, Y, X].
38443844
38453845
*Parameter example:*
38463846
``[2, 3]``
@@ -3902,7 +3902,7 @@ def _regrid(
39023902
new_axis.extend(range(n + 1, n + n_sizes))
39033903
n += n_sizes - 1
39043904
else:
3905-
regridded_chunks.extend(c)
3905+
regridded_chunks.append(c)
39063906

39073907
n += 1
39083908

@@ -3948,6 +3948,16 @@ def _regrid(
39483948
min_weight=min_weight,
39493949
)
39503950

3951+
# Performance note:
3952+
#
3953+
# The function 'regrid_func' is copied into every Dask
3954+
# task. If we included the large 'weights_dst_mask' in the
3955+
# 'partial' definition then it would also be copied to every
3956+
# task, which "will start to be a pain in a few parts of the
3957+
# pipeline" definition. Instead we can pass it in via a
3958+
# keyword argument to 'map_blocks'.
3959+
# github.com/pangeo-data/pangeo/issues/334#issuecomment-403787663
3960+
39513961
dx = dx.map_blocks(
39523962
regrid_func,
39533963
weights_dst_mask=weights_dst_mask,

cf/docstring/docstring.py

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -115,43 +115,45 @@
115115
* ``'bilinear'``: Deprecated alias for ``'linear'``.
116116
117117
* ``'conservative_1st'``: First order conservative
118-
interpolation. Preserves the area integral of the
119-
data across the interpolation from source to
120-
destination. It uses the proportion of the area of
121-
the overlapping source and destination cells to
122-
determine appropriate weights.
118+
interpolation. Preserves the integral of the source
119+
field across the regridding. Weight calculation is
120+
based on the ratio of source cell area overlapped
121+
with the corresponding destination cell area.
123122
124123
* ``'conservative'``: Alias for ``'conservative_1st'``
125124
126125
* ``'conservative_2nd'``: Second-order conservative
127-
interpolation. As with first order conservative
128-
interpolation, preserves the area integral of the
129-
field between source and destination using a
130-
weighted sum, with weights based on the
131-
proportionate area of intersection. In addition the
132-
second-order conservative method takes the source
133-
gradient into account, so it yields a smoother
134-
destination field that typically better matches the
135-
source data.
136-
137-
* ``'patch'`` Patch recovery interpolation. A second
138-
degree 2-d polynomial regridding method, which uses
139-
a least squares algorithm to calculate the
140-
polynomials. This method typically results in
141-
better approximations to values and derivatives when
126+
interpolation. Preserves the integral of the source
127+
field across the regridding. Weight calculation is
128+
based on the ratio of source cell area overlapped
129+
with the corresponding destination cell area. The
130+
second-order conservative calculation also includes
131+
the gradient across the source cell, so in general
132+
it gives a smoother, more accurate representation of
133+
the source field. This is particularly true when
134+
going from a coarse to finer grid.
135+
136+
* ``'patch'`` Patch recovery interpolation. Patch
137+
rendezvous method of taking the least squares fit of
138+
the surrounding surface patches. This is a higher
139+
order method that may produce interpolation weights
140+
that may be slightly less than 0 or slightly greater
141+
than 1. This method typically results in better
142+
approximations to values and derivatives when
142143
compared to bilinear interpolation.
143144
144-
* ``'nearest_stod'``: Nearest neighbour interpolation
145-
for which each destination point is mapped to the
146-
closest source point. Useful for extrapolation of
147-
categorical data. Some destination cells may be
148-
unmapped.
145+
* ``'nearest_stod'``: Nearest neighbour source to
146+
destination interpolation for which each destination
147+
point is mapped to the closest source point. A
148+
source point can be mapped to multiple destination
149+
points. Useful for regridding categorical data.
149150
150-
* ``'nearest_dtos'``: Nearest neighbour interpolation
151-
for which each source point is mapped to the
152-
destination point. Useful for extrapolation of
153-
categorical data. All destination cells will be
154-
mapped.
151+
* ``'nearest_dtos'``: Nearest neighbour destination to
152+
source interpolation for which each source point is
153+
mapped to the closest destination point. A
154+
destination point can be mapped to multiple source
155+
points. Some destination points may not be
156+
mapped. Useful for regridding of categorical data.
155157
156158
* `None`: This is the default and can only be used
157159
when *dst* is a `RegridOperator`.""",
@@ -493,7 +495,9 @@
493495
494496
The computation of the weights can be much more costly
495497
than the regridding itself, in which case reading
496-
pre-calculated weights can improve performance.""",
498+
pre-calculated weights can improve performance.
499+
500+
Ignored if *dst* is a `RegridOperator`.""",
497501
# aggregated_units
498502
"{{aggregated_units: `str` or `None`, optional}}": """aggregated_units: `str` or `None`, optional
499503
The units of the aggregated array. Set to `None` to
@@ -587,6 +591,20 @@
587591
"{{weights auto: `bool`, optional}}": """auto: `bool`, optional
588592
If True then return `False` if weights can't be found,
589593
rather than raising an exception.""",
594+
# ln_z
595+
"{{ln_z: `bool` or `None`, optional}}": """ln_z: `bool` or `None`, optional
596+
If True when *z*, *src_z* or *dst_z* are also set,
597+
calculate the vertical component of the regridding
598+
weights using the natural logarithm of the vertical
599+
coordinate values. This option should be used if the
600+
quantity being regridded varies approximately linearly
601+
with logarithm of the vertical coordinates. If False,
602+
then the weights are calculated using unaltered
603+
vertical values. If `None`, the default, then an
604+
exception is raised if any of *z*, *src_z* or *dst_z*
605+
have also been set.
606+
607+
Ignored if *dst* is a `RegridOperator`.""",
590608
# pad_width
591609
"{{pad_width: sequence of `int`, optional}}": """pad_width: sequence of `int`, optional
592610
Number of values to pad before and after the edges of
@@ -603,30 +621,30 @@
603621
True, or a tuple of both if *item* is True.""",
604622
# regrid RegridOperator
605623
"{{regrid RegridOperator}}": """* `RegridOperator`: The grid is defined by a regrid
606-
operator that has been returned by a previous call
607-
with the *return_operator* parameter set to True.
608-
609-
Unlike the other options, for which the regrid
610-
weights need to be calculated, the regrid operator
611-
already contains the weights. Therefore, for cases
612-
where multiple fields with the same source grids
613-
need to be regridded to the same destination grid,
614-
using a regrid operator can give performance
615-
improvements by avoiding having to calculate the
616-
weights for each source field. Note that for the
617-
other types of *dst* parameter, the calculation of
618-
the regrid weights is not a lazy operation.
619-
620-
.. note:: The source grid of the regrid operator is
621-
immediately checked for compatibility with
622-
the grid of the source field. By default
623-
only the computationally cheap tests are
624-
performed (checking that the coordinate
625-
system, cyclicity and grid shape are the
626-
same), with the grid coordinates not being
627-
checked. The coordinates check will be
628-
carried out, however, if the
629-
*check_coordinates* parameter is True.""",
624+
operator that has been returned by a previous call
625+
with the *return_operator* parameter set to True.
626+
627+
Unlike the other options, for which the regrid weights
628+
need to be calculated, the regrid operator already
629+
contains the weights. Therefore, for cases where
630+
multiple fields with the same source grids need to be
631+
regridded to the same destination grid, using a regrid
632+
operator can give performance improvements by avoiding
633+
having to calculate the weights for each source
634+
field. Note that for the other types of *dst*
635+
parameter, the calculation of the regrid weights is
636+
not a lazy operation.
637+
638+
.. note:: The source grid of the regrid operator is
639+
immediately checked for compatibility with
640+
the grid of the source field. By default
641+
only the computationally cheap tests are
642+
performed (checking that the coordinate
643+
system, cyclicity and grid shape are the
644+
same), with the grid coordinates not being
645+
checked. The coordinates check will be
646+
carried out, however, if the
647+
*check_coordinates* parameter is True.""",
630648
# Returns cfa_file_substitutions
631649
"{{Returns cfa_file_substitutions}}": """The CFA-netCDF file name substitutions in a dictionary
632650
whose key/value pairs are the file name parts to be

0 commit comments

Comments
 (0)