Skip to content

Commit 34652f4

Browse files
committed
dev
1 parent bb7ac5b commit 34652f4

2 files changed

Lines changed: 83 additions & 42 deletions

File tree

cf/data/dask_utils.py

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from functools import partial
99

1010
import numpy as np
11+
from cfdm import integer_dtype
1112
from cfdm.data.dask_utils import cfdm_to_memory
1213
from scipy.ndimage import convolve1d
1314

@@ -508,21 +509,21 @@ def cf_healpix_bounds(
508509
hierarchy, starting at 0 for the base tessellation with 12
509510
cells. Must be an `int` for *indexing_scheme* ``'nested'``
510511
or ``'ring'``, but is ignored for *indexing_scheme*
511-
``'nested_unique'`` (in which case *refinement_level* may
512-
be `None`).
512+
``'nested_unique'``, in which case *refinement_level* may
513+
be `None`.
513514
514515
latitude: `bool`, optional
515-
If True then return latitude bounds.
516+
If True then return the bounds' latitudes.
516517
517518
longitude: `bool`, optional
518-
If True then return longitude bounds.
519+
If True then return the bounds' longitudes.
519520
520521
pole_longitude: `None` or number
521-
The longitude of coordinate bounds that lie exactly on the
522-
north (south) pole. If `None` then the longitude of such a
523-
vertex will be the same as the south (north) vertex of the
524-
same cell. If set to a number, then the longitudes of such
525-
vertices will all be given that value.
522+
The longitude of bounds that lie exactly on the north
523+
(south) pole. If `None` (the default) then the longitude
524+
of such a vertex will be the same as the south (north)
525+
vertex of the same cell. If set to a number, then the
526+
longitudes of all such vertices will be given that value.
526527
527528
:Returns:
528529
@@ -560,8 +561,8 @@ def cf_healpix_bounds(
560561
except ImportError as e:
561562
raise ImportError(
562563
f"{e}. Must install healpix (https://pypi.org/project/healpix) "
563-
"to allow the calculation of latitude/longitude coordinate "
564-
"bounds for a HEALPix grid"
564+
"for the calculation of latitude/longitude coordinate bounds "
565+
"of a HEALPix grid"
565566
)
566567

567568
a = cfdm_to_memory(a)
@@ -570,14 +571,16 @@ def cf_healpix_bounds(
570571
if a.ndim != 1:
571572
raise ValueError(
572573
"Can only calculate HEALPix cell bounds when the "
573-
f"healpix_index array has one dimension. Got shape {a.shape}"
574+
f"healpix_index array has one dimension. Got shape: {a.shape}"
574575
)
575576

576577
if latitude:
577578
pos = 1
578579
elif longitude:
579580
pos = 0
580581

582+
# Define the function that's going to calculate the bounds from
583+
# the HEALPix indices
581584
if indexing_scheme == "ring":
582585
bounds_func = healpix._chp.ring2ang_uv
583586
else:
@@ -596,26 +599,31 @@ def cf_healpix_bounds(
596599
b = np.empty((a.size, 4), dtype="float64")
597600

598601
if indexing_scheme == "nested_unique":
599-
# Create bounds for 'nested_unique' cells
602+
# Create bounds for 'nested_unique' indices
600603
orders, a = healpix.uniq2pix(a, nest=True)
601604
for order in np.unique(orders):
602605
nside = healpix.order2nside(order)
603606
indices = np.where(orders == order)[0]
604607
for j, (u, v) in enumerate(vertices):
605608
thetaphi = bounds_func(nside, a[indices], u, v)
606609
b[indices, j] = healpix.lonlat_from_thetaphi(*thetaphi)[pos]
610+
611+
del orders, indices
607612
else:
608-
# Create bounds for 'nested' or 'ring' cells
613+
# Create bounds for 'nested' or 'ring' indices
609614
nside = healpix.order2nside(refinement_level)
610615
for j, (u, v) in enumerate(vertices):
611616
thetaphi = bounds_func(nside, a, u, v)
612-
b[..., j] = healpix.lonlat_from_thetaphi(*thetaphi)[pos]
617+
b[:, j] = healpix.lonlat_from_thetaphi(*thetaphi)[pos]
618+
619+
del thetaphi, a
613620

614621
if not pos:
615622
# Ensure that longitude bounds are less than 360
616623
where_ge_360 = np.where(b >= 360)
617624
if where_ge_360[0].size:
618625
b[where_ge_360] -= 360.0
626+
del where_ge_360
619627

620628
# Vertices on the north or south pole come out with a
621629
# longitude of NaN, so replace these with sensible values:
@@ -671,14 +679,14 @@ def cf_healpix_coordinates(
671679
hierarchy, starting at 0 for the base tessellation with 12
672680
cells. Must be an `int` for *indexing_scheme* ``'nested'``
673681
or ``'ring'``, but is ignored for *indexing_scheme*
674-
``'nested_unique'`` (in which case *refinement_level* may
675-
be `None`).
682+
``'nested_unique'``, in which case *refinement_level* may
683+
be `None`.
676684
677685
latitude: `bool`, optional
678-
If True then return latitude coordinates.
686+
If True then return the coordinate latitudes.
679687
680688
longitude: `bool`, optional
681-
If True then return longitude coordinates.
689+
If True then return the coordinate longitudes.
682690
683691
:Returns:
684692
@@ -702,16 +710,16 @@ def cf_healpix_coordinates(
702710
except ImportError as e:
703711
raise ImportError(
704712
f"{e}. Must install healpix (https://pypi.org/project/healpix) "
705-
"to allow the calculation of latitude/longitude coordinates "
706-
"for a HEALPix grid"
713+
"for the calculation of latitude/longitude coordinates of a "
714+
"HEALPix grid"
707715
)
708716

709717
a = cfdm_to_memory(a)
710718

711719
if a.ndim != 1:
712720
raise ValueError(
713721
"Can only calculate HEALPix cell coordinates when the "
714-
f"healpix_index array has one dimension. Got shape {a.shape}"
722+
f"healpix_index array has one dimension. Got shape: {a.shape}"
715723
)
716724

717725
if latitude:
@@ -721,7 +729,7 @@ def cf_healpix_coordinates(
721729

722730
match indexing_scheme:
723731
case "nested_unique":
724-
# Create coordinates for 'nested_unique' cells
732+
# Create coordinates for 'nested_unique' indices
725733
c = np.empty(a.shape, dtype="float64")
726734

727735
nest = True
@@ -734,7 +742,7 @@ def cf_healpix_coordinates(
734742
)[pos]
735743

736744
case "nested" | "ring":
737-
# Create coordinates for 'nested' or 'ring' cells
745+
# Create coordinates for 'nested' or 'ring' indices
738746
nest = indexing_scheme == "nested"
739747
nside = healpix.order2nside(refinement_level)
740748
c = healpix.pix2ang(
@@ -760,12 +768,14 @@ def cf_healpix_increase_refinement(a, ncells, iaxis, quantity):
760768
an "extensive" quantity only, the broadcast values are reduced to
761769
be consistent with the new smaller cell areas.
762770
763-
.. warning:: The returned `numpy` array will take up at least
764-
*ncells* times more memory than the input array
765-
*a*. For instance, if *a* has shape ``(3600, 48)``
766-
(1.3 MiB), the HEALPix axis is ``1``, and *ncells* is
767-
``4096``, then the returned array will have shape
768-
``(3600, 196608)`` (5.3 GiB), where 196608=48*4096.
771+
.. warning:: The returned `numpy` array will take up *ncells*
772+
times more memory than the input array *a* (or two
773+
times *ncells* more memory, if *a* contains 32-bit
774+
integers and *quantity* is ``'extensive'``). For
775+
instance, if 64-bit *a* has shape ``(3600, 48)``
776+
(1.318 MiB), the HEALPix axis is ``1``, and *ncells*
777+
is ``4096``, then the returned array will have shape
778+
``(3600, 196608)`` (5.4 GiB), where 196608=48*4096.
769779
770780
K. Gorski, Eric Hivon, A. Banday, B. Wandelt, M. Bartelmann, et
771781
al.. HEALPix: A Framework for High-Resolution Discretization and
@@ -805,13 +815,19 @@ def cf_healpix_increase_refinement(a, ncells, iaxis, quantity):
805815
if quantity == "extensive":
806816
a = a / ncells
807817

818+
# Create a new dimension over which the original HEALPix axis will
819+
# be broadcast
808820
iaxis = iaxis + 1
809821
a = np.expand_dims(a, iaxis)
810822

823+
# Define the shape of the new array, and broadcast 'a' to it.
824+
# shape
811825
shape = list(a.shape)
812826
shape[iaxis] = ncells
813-
814827
a = np.broadcast_to(a, shape, subok=True)
828+
829+
# Reshape the new array to combine the original HEALPix and
830+
# broadcast dimensions into a single new HEALPix dimension
815831
a = a.reshape(
816832
shape[: iaxis - 1]
817833
+ [shape[iaxis - 1] * shape[iaxis]]
@@ -821,7 +837,7 @@ def cf_healpix_increase_refinement(a, ncells, iaxis, quantity):
821837
return a
822838

823839

824-
def cf_healpix_increase_refinement_indices(a, ncells):
840+
def cf_healpix_increase_refinement_indices(a, refinement_level, ncells):
825841
"""Increase the refinement level of HEALPix indices.
826842
827843
For instance, when going from refinement level 1 to refinement
@@ -831,12 +847,14 @@ def cf_healpix_increase_refinement_indices(a, ncells):
831847
``ncells`` is the number of cells at refinement level 2 that lie
832848
inside one cell at refinement level 1, i.e. ``ncells=4**(2-1)=4``.
833849
834-
.. warning:: The returned `numpy` array will take up at least
835-
*ncells* times more memory than the input array
836-
*a*. For instance, if *a* has shape ``(48,)`` (384
837-
B), and *ncells* is ``262144``, then the returned
838-
array will have shape ``(12582912,)`` (96 MiB), where
839-
12582912=48*262144.
850+
.. warning:: The returned `numpy` array will take up *ncells*
851+
times more memory than the input array *a* (or two
852+
times *ncells* more memory, if *a* is 32-bit and the
853+
output requires 64-bit integers). For instance, if
854+
32-bit *a* has shape ``(48,)`` (192 B), and *ncells*
855+
is ``67108864``, then the returned 64-bit array will
856+
have shape ``(3221225472,)`` (24 GiB), where
857+
3221225472=48*67108864.
840858
841859
K. Gorski, Eric Hivon, A. Banday, B. Wandelt, M. Bartelmann, et
842860
al.. HEALPix: A Framework for High-Resolution Discretization and
@@ -853,6 +871,9 @@ def cf_healpix_increase_refinement_indices(a, ncells):
853871
a: `numpy.ndarray`
854872
The array of HEALPix nested indices.
855873
874+
refinement_level: `int`
875+
The new higher HEALPix refinement level.
876+
856877
ncells: `int`
857878
The number of cells at the new refinement level which are
858879
contained in one cell at the original refinement level
@@ -865,10 +886,31 @@ def cf_healpix_increase_refinement_indices(a, ncells):
865886
"""
866887
a = cfdm_to_memory(a)
867888

868-
a = a * ncells
889+
# Set the data type to allow for the largest possible HEALPix
890+
# index at the new refinement level
891+
dtype = integer_dtype(12 * (4**refinement_level) - 1)
892+
if a.dtype != dtype:
893+
a = a.astype(dtype, copy=True)
894+
a *= ncells
895+
else:
896+
a = a * ncells
897+
898+
# Create a new dimension over which the original HEALPix axis will
899+
# be broadcast
869900
a = np.expand_dims(a, -1)
870-
a = np.broadcast_to(a, (a.size, ncells), subok=True).copy()
901+
902+
# Define the shape of the new array, and broadcast 'a' to it.
903+
shape = (a.size, ncells)
904+
a = np.broadcast_to(a, shape, subok=True).copy()
905+
906+
# Increment the broadcast values along the new dimension, so that
907+
# a[i, :] contains all of the nested indices at the higher
908+
# refinement level that correspond to index i at the original
909+
# refinement level.
871910
a += np.arange(ncells)
911+
912+
# Reshape the new array to combine the original HEALPix and
913+
# broadcast dimensions into a single new HEALPix dimension
872914
a = a.flatten()
873915

874916
return a

cf/healpix.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,6 @@ def _healpix_increase_refinement_level_indices(
279279
# Set the data type to allow for the largest possible HEALPix
280280
# index at the new refinement level
281281
dtype = integer_dtype(12 * (4**refinement_level) - 1)
282-
if dx.dtype != dtype:
283-
dx = dx.astype(dtype, copy=False)
284282

285283
# Each chunk is going to get larger by a factor of 'ncells'
286284
chunks = [(np.array(dx.chunks[0]) * ncells).tolist()]
@@ -290,6 +288,7 @@ def _healpix_increase_refinement_level_indices(
290288
chunks=tuple(chunks),
291289
dtype=dtype,
292290
meta=np.array((), dtype=dtype),
291+
refinement_level=refinement_level,
293292
ncells=ncells,
294293
)
295294

0 commit comments

Comments
 (0)