Skip to content

Commit e2a3cae

Browse files
committed
dev
1 parent 2fa1294 commit e2a3cae

File tree

8 files changed

+410
-211
lines changed

8 files changed

+410
-211
lines changed

cf/data/dask_utils.py

Lines changed: 182 additions & 119 deletions
Large diffs are not rendered by default.

cf/docstring/docstring.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -571,25 +571,25 @@
571571
return the `esmpy.Regrid` instance that defines the
572572
regridding operation.""",
573573
# HEALPix indexing schemes
574-
"{{HEALPix indexing schemes}}": """The "nested" scheme indexes the pixels inside a single
574+
"{{HEALPix indexing schemes}}": """The nested scheme indexes the pixels inside a single
575575
coarser refinement level cell with consecutive
576-
indices. The "ring" scheme indexes the pixels moving
576+
indices. The ring scheme indexes the pixels moving
577577
down from the north to the south pole along each
578578
isolatitude ring. When the HEALPix axis is ordered
579579
with monotonically increasing indices, each type of
580580
indexing scheme is optimised for different types of
581-
operation. For instance, the "ring" scheme is
582-
optimised for Fourier transforms with spherical
583-
harmonics; and the "nested" scheme is optimised for
584-
geographical nearest-neighbour operations such as
585-
decreasing the refinement level.
581+
operation. For instance, the ring scheme is optimised
582+
for Fourier transforxms with spherical harmonics; and
583+
the nested scheme is optimised for geographical
584+
nearest-neighbour operations such as decreasing the
585+
refinement level.
586586
587587
A Multi-Order Coverage (MOC) has pixels with different
588588
refinement levels stored in the same array. An
589589
indexing scheme for an MOC has a unique index for each
590590
cell at each refinement level.
591591
592-
The "nuniq" scheme defines MOC indices such that all
592+
The nuniq scheme defines MOC indices such that all
593593
cells within a particular refinement level form a
594594
sequence of consecutive integers. E.g. for refinement
595595
level 0 the indices are 4, ..., 15, for refinement
@@ -599,7 +599,7 @@
599599
when the indices are sorted monotonically, for
600600
within-refinement level data retrievals.
601601
602-
The "zuniq" scheme defines MOC indices such that, for
602+
The zuniq scheme defines MOC indices such that, for
603603
similar refinement levels, cells in the proximity of a
604604
particular geographical location have similar index
605605
values. This means that, unlike the nuniq case, the

cf/domain.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,10 @@ def create_healpix(
282282
resulting from an attempt to create an excessive amount of
283283
chunks for the healpix_index coordinates. For instance,
284284
healpix_index coordinates at refinement level 29 would need
285-
~206 billion chunks with the default Dask chunksize of 128
286-
MiB, but with a chunksize of 1 pebibyte only 24576 chunks are
287-
required::
285+
~206 billion chunks with the default Dask chunksize of 128 MiB
286+
- almost certainly more than enough to cause a crash - but
287+
with a chunksize of 1 pebibyte only 24576 chunks are
288+
required, a much more manageable amount::
288289
289290
>>> cf.chunksize()
290291
>>> 134217728
@@ -409,6 +410,11 @@ def create_healpix(
409410
f"of {healpix_indexing_schemes!r}. Got {indexing_scheme!r}"
410411
)
411412

413+
indexing_scheme0 = indexing_scheme
414+
415+
if indexing_scheme == "zuniq":
416+
indexing_scheme = "nuniq"
417+
412418
domain = Domain()
413419
ncells = 12 * (4**refinement_level)
414420

@@ -465,9 +471,9 @@ def create_healpix(
465471

466472
domain.set_construct(cr)
467473

468-
if indexing_scheme == "zuniq":
474+
if indexing_scheme0 == "zuniq":
469475
domain = domain.healpix_indexing_scheme("zuniq", sort=False)
470-
476+
471477
return domain
472478

473479
@_inplace_enabled(default=False)

cf/field.py

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4824,7 +4824,7 @@ def healpix_decrease_refinement_level(
48244824
refinement level either
48254825

48264826
* contains no original cells, in which case that larger cell
4827-
is not included in the output,
4827+
is not included in the output;
48284828

48294829
or
48304830

@@ -4868,20 +4868,24 @@ def healpix_decrease_refinement_level(
48684868
``'root_mean_square'``, ``'standard_deviation'``,
48694869
``'sum'``, ``'sum_of_squares'``, ``'variance'``.
48704870

4871-
The method should be appropriate to nature of the
4872-
Field quantity, which is either intensive (i.e. that
4873-
does not depend on the size of the cells, such as
4874-
"sea_ice_amount" with units of kg m-2), or extensive
4875-
(i.e. that depends on the size of the cells, such as
4876-
"sea_ice_mass" with units of kg).
4871+
.. note:: The method should be appropriate to nature
4872+
of the Field quantity, which is either
4873+
intensive (i.e. that does not depend on the
4874+
size of the cells, such as "sea_ice_amount"
4875+
with units of kg m-2), or extensive
4876+
(i.e. that depends on the size of the cells,
4877+
such as "sea_ice_mass" with units of kg).
48774878

48784879
reduction: function or `None`, optional
48794880
The function used to calculate the values in the new
48804881
larger cells, from the data on the original cells. The
4881-
function must i) calculate the quantity defined by the
4882-
*method* parameter, ii) take an array of values as its
4883-
first argument, and iii) have an *axis* keyword that
4884-
specifies which of the array axes is the HEALPix axis.
4882+
function must:
4883+
4884+
* calculate the quantity defined by the *method*
4885+
parameter,
4886+
* take an array of values as its first argument,
4887+
* have an *axis* keyword that specifies which of the
4888+
array axes is the HEALPix axis.
48854889

48864890
For some methods there are default *reduction*
48874891
functions, which are only used when *reduction* is
@@ -4907,11 +4911,11 @@ def healpix_decrease_refinement_level(
49074911
If True (the default) then the HEALPix grid is
49084912
automatically converted to a form suitable for having
49094913
its refinement level changed, i.e. the indexing scheme
4910-
is changed to 'nested' and the HEALPix axis is sorted
4911-
so that the nested HEALPix indices are monotonically
4912-
increasing. If False then either an exception is
4913-
raised if the HEALPix indexing scheme is not already
4914-
'nested', or else the HEALPix axis is not sorted.
4914+
is changed to nested and the HEALPix axis is sorted so
4915+
that the nested HEALPix indices are monotonically
4916+
increasing. If False then an exception is raised if
4917+
the HEALPix indexing scheme is not already nested and
4918+
the HEALPix axis is not sorted.
49154919

49164920
.. note:: Setting to False will speed up the operation
49174921
when the HEALPix indexing scheme is already
@@ -4924,12 +4928,12 @@ def healpix_decrease_refinement_level(
49244928
(but after the HEALPix grid has been conformed, when
49254929
*conform* is True):
49264930

4927-
1. The nested HEALPix indices are strictly
4928-
monotonically increasing.
4931+
* The nested HEALPix indices are strictly
4932+
monotonically increasing.
49294933

4930-
2. Every cell at the new lower refinement level
4931-
contains zero or the maximum possible number of
4932-
cells at the original refinement level.
4934+
* Every cell at the new lower refinement level
4935+
contains zero or the maximum possible number of
4936+
cells at the original refinement level.
49334937

49344938
If False then these checks are not carried out.
49354939

@@ -4938,14 +4942,16 @@ def healpix_decrease_refinement_level(
49384942
advance that these conditions are
49394943
satisfied. If set to False and any of the
49404944
conditions are not met then either an
4941-
exception may be raised or, **much
4945+
exception will be raised or, **much
49424946
worse**, the operation could complete and
49434947
return incorrect data values.
49444948

49454949
:Returns:
49464950

49474951
`Field`
4948-
A new Field with the new HEALPix grid.
4952+
A new Field with the new HEALPix grid. The HEALPix
4953+
indices of this field will follow the nested indexing
4954+
scheme.
49494955

49504956
**Examples**
49514957

@@ -5084,6 +5090,7 @@ def healpix_decrease_refinement_level(
50845090

50855091
# Re-get the HEALPix info
50865092
hp = f.healpix_info()
5093+
50875094
elif indexing_scheme != "nested":
50885095
raise ValueError(
50895096
f"Can't decrease HEALPix refinement level of {f!r}: "
@@ -5149,7 +5156,13 @@ def healpix_decrease_refinement_level(
51495156

51505157
# Get the HEALPix axis
51515158
axis = hp["domain_axis_key"]
5152-
iaxis = f.get_data_axes().index(axis)
5159+
try:
5160+
iaxis = f.get_data_axes().index(axis)
5161+
except ValueError:
5162+
# The Field data doesn't span the size 1 HEALPix axis, so
5163+
# insert it on the left hand side.
5164+
f.insert_dimmension(axis, -1, inplace=True)
5165+
iaxis = f.ndim - 1
51535166

51545167
# Whether or not to create lat/lon coordinates for the new
51555168
# refinement level. Only do so if the original grid has
@@ -5169,7 +5182,7 @@ def healpix_decrease_refinement_level(
51695182
# ------------------------------------------------------------
51705183

51715184
# Note: Using 'Data.coarsen' works because a) the HEALPix
5172-
# indexing scheme is now "nested", and b) we know that
5185+
# indexing scheme is now nested, and b) we know that
51735186
# each new coarser cell contains the maximum possible
51745187
# number (i.e. 'ncells') of original cells.
51755188
f.data.coarsen(
@@ -5263,7 +5276,7 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
52635276
extensive or intensive quantity. An intensive quantity does
52645277
not depend on the size of the cells (such as "sea_ice_amount"
52655278
with units of kg m-2, or "air_temperature" with units of K),
5266-
and an extensive quantity depends on the size of the cells
5279+
and an extensive quantity does depend on the size of the cells
52675280
(such as "sea_ice_mass" with units of kg, or "cell_area" with
52685281
units of m2). For an extensive quantity only, the broadcast
52695282
values are reduced to be consistent with the new smaller cell
@@ -5294,7 +5307,9 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
52945307
:Returns:
52955308

52965309
`Field`
5297-
A new Field with the new HEALPix grid.
5310+
A new Field with the new HEALPix grid. The HEALPix
5311+
indices of this field will follow the nested indexing
5312+
scheme.
52985313

52995314
**Examples**
53005315

cf/healpix.py

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ def _healpix_increase_refinement_level_indices(
316316
317317
healpix_index: `Coordinate`
318318
The HEALPix indices to be changed. They must use the
319-
"nested" indexing scheme.
319+
nested indexing scheme, but this is not checked.
320320
321321
ncells: `int`
322322
The number of cells at the new higher refinement level
@@ -398,9 +398,13 @@ def _healpix_increase_refinement_level_indices(
398398
data._set_cached_elements({-1: x})
399399

400400

401-
def _healpix_indexing_scheme(f, hp, new_indexing_scheme):
401+
def _healpix_indexing_scheme(
402+
f, hp, new_indexing_scheme, moc_refinement_level=None
403+
):
402404
"""Change the indexing scheme of HEALPix indices in-place.
403405
406+
The
407+
404408
See CF Appendix F: Grid Mappings.
405409
https://doi.org/10.5281/zenodo.14274886
406410
@@ -419,7 +423,11 @@ def _healpix_indexing_scheme(f, hp, new_indexing_scheme):
419423
The HEALPix info dictionary for *f*.
420424
421425
new_indexing_scheme: `str`
422-
The new indexing scheme.
426+
The new indexing scheme. It is assumed to be different to
427+
the original indexing scheme of *f*.
428+
429+
moc_refinement_level: `int` or `None`, optional
430+
The unique refinement level of MOC indices of *f*.
423431
424432
:Returns:
425433
@@ -435,7 +443,7 @@ def _healpix_indexing_scheme(f, hp, new_indexing_scheme):
435443
refinement_level = hp.get("refinement_level")
436444

437445
old_cache = healpix_index.data._get_cached_elements()
438-
446+
439447
# Change the HEALPix indices
440448
#
441449
# `cf_healpix_indexing_scheme` has its own call to
@@ -447,21 +455,31 @@ def _healpix_indexing_scheme(f, hp, new_indexing_scheme):
447455
# Find the datatype for the largest possible index at this
448456
# refinement level
449457
if new_indexing_scheme == "nuniq":
450-
# The largest possible "nuniq" index at refinement level N is
451-
# 16*(4**N) - 1 = 4*(4**N) + 12*(4**N) - 1
452-
dtype = integer_dtype(16 * (4**refinement_level) - 1)
458+
if indexing_scheme in ("nested", "ring"):
459+
# The largest possible nested or ring index at refinement
460+
# level N is 12*(4**N) - 1
461+
dtype = integer_dtype(16 * (4**refinement_level) - 1)
462+
elif indexing_scheme == "zuniq":
463+
dtype = np.dtype("int64")
464+
453465
elif new_indexing_scheme in ("nested", "ring"):
454-
# The largest possible "nested" or "ring" index at refinement
455-
# level N is 12*(4**N) - 1
456-
dtype = integer_dtype(12 * (4**refinement_level) - 1)
466+
if indexing_scheme == "nuniq":
467+
# The largest possible nuniq index at refinement level N
468+
# is 16*(4**N) - 1 = 4*(4**N) + 12*(4**N) - 1
469+
dtype = integer_dtype(16 * (4**moc_refinement_level) - 1)
470+
elif indexing_scheme in ("nested", "ring"):
471+
dtype = healpix_index.dtype
472+
elif indexing_scheme == "zuniq":
473+
dtype = np.dtype("int64")
474+
457475
elif new_indexing_scheme == "zuniq":
458-
dtype = np.dtype('int64')
476+
dtype = np.dtype("int64")
477+
459478
else:
460479
raise NotImplementedError(
461-
"Can't yet change HEALPix indexing scheme from "
480+
"Can't change HEALPix indexing scheme from "
462481
f"{indexing_scheme!r} to {new_indexing_scheme!r}"
463482
) # pragma: no cover
464-
465483

466484
dx = dx.map_blocks(
467485
cf_healpix_indexing_scheme,
@@ -471,30 +489,34 @@ def _healpix_indexing_scheme(f, hp, new_indexing_scheme):
471489
new_indexing_scheme=new_indexing_scheme,
472490
healpix_index_dtype=dtype,
473491
refinement_level=refinement_level,
492+
moc_refinement_level=moc_refinement_level,
474493
)
475494
healpix_index.set_data(dx, copy=False)
476495

477496
# If a Dimension Coordinate is now not monotonically ordered,
478497
# convert it to an Auxiliary Coordinate
479-
if healpix_index.construct_type == "dimension_coordinate" and set(
480-
(indexing_scheme, new_indexing_scheme)
481-
) != set(("nested", "nuniq")):
498+
if (
499+
healpix_index.construct_type == "dimension_coordinate"
500+
and "ring" in set((indexing_scheme, new_indexing_scheme))
501+
):
482502
f.dimension_to_auxiliary(hp["coordinate_key"], inplace=True)
483503

484504
# Create new cached elements
485-
if old_cache:
505+
if old_cache and moc_refinement_level is None:
486506
new_cache = {}
487507
for i, value in old_cache.items():
488508
new_cache[i] = cf_healpix_indexing_scheme(
489509
np.array(value),
490-
indexing_scheme,
491-
new_indexing_scheme,
492-
healpix_index_dtype,
493-
refinement_level=refinement_level
510+
indexing_scheme=indexing_scheme,
511+
new_indexing_scheme=new_indexing_scheme,
512+
healpix_index_dtype=dtype,
513+
refinement_level=refinement_level,
514+
moc_refinement_level=moc_refinement_level,
494515
)
495-
516+
496517
healpix_index.data._set_cached_elements(new_cache)
497-
518+
519+
498520
def _healpix_locate(lat, lon, f):
499521
"""Locate HEALPix cells containing latitude-longitude locations.
500522
@@ -784,11 +806,11 @@ def healpix_max_refinement_level():
784806
785807
"""
786808
try:
787-
from healpix import nside2order
809+
import healpix
788810
except ImportError as e:
789811
raise ImportError(
790812
f"{e}. Must install healpix (https://pypi.org/project/healpix) "
791813
"to find the maximum HEALPix refinement level"
792814
)
793815

794-
return nside2order(healpix._chp.NSIDE_MAX)
816+
return healpix.nside2order(healpix._chp.NSIDE_MAX)

0 commit comments

Comments
 (0)