Skip to content

Commit 63ca9ce

Browse files
committed
dev
1 parent 2ca65bd commit 63ca9ce

5 files changed

Lines changed: 153 additions & 121 deletions

File tree

cf/data/dask_utils.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -754,15 +754,18 @@ def cf_healpix_coordinates(
754754

755755

756756
def cf_healpix_increase_refinement(a, ncells, iaxis, quantity):
757-
"""Increase the refinement level of a HEALPix array.
757+
"""Increase the refinement level of a HEALPix data.
758758
759759
Data are broadcast to cells of at the higher refinement level. For
760-
an extensive field quantity (that depends on the size of the
761-
cells, such as "sea_ice_mass" with units of kg), the new values
762-
are reduced so that they are consistent with the new smaller cell
763-
areas. For an intensive field quantity (that does not depend on
764-
the size of the cells, such as "sea_ice_amount" with units of kg
765-
m-2), the broadcast values are not changed.
760+
an "extensive" quantity only, the broadcast values are reduced to
761+
be consistent with the new smaller cell areas.
762+
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.
766769
767770
K. Gorski, Eric Hivon, A. Banday, B. Wandelt, M. Bartelmann, et
768771
al.. HEALPix: A Framework for High-Resolution Discretization and
@@ -781,7 +784,7 @@ def cf_healpix_increase_refinement(a, ncells, iaxis, quantity):
781784
782785
ncells: `int`
783786
The number of cells at the new refinement level which are
784-
contained in one cell at the original refinement level
787+
contained in one cell at the original refinement level.
785788
786789
iaxis: `int`
787790
The position of the HEALPix axis in the array dimensions.
@@ -819,7 +822,7 @@ def cf_healpix_increase_refinement(a, ncells, iaxis, quantity):
819822

820823

821824
def cf_healpix_increase_refinement_indices(a, ncells):
822-
"""Increase the refinement level of HEALPix indices
825+
"""Increase the refinement level of HEALPix indices.
823826
824827
For instance, when going from refinement level 1 to refinement
825828
level 2, if *a* is ``(2, 23, 17)`` then it will be transformed to
@@ -828,6 +831,13 @@ def cf_healpix_increase_refinement_indices(a, ncells):
828831
``ncells`` is the number of cells at refinement level 2 that lie
829832
inside one cell at refinement level 1, i.e. ``ncells=4**(2-1)=4``.
830833
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.
840+
831841
K. Gorski, Eric Hivon, A. Banday, B. Wandelt, M. Bartelmann, et
832842
al.. HEALPix: A Framework for High-Resolution Discretization and
833843
Fast Analysis of Data Distributed on the Sphere. The Astrophysical
@@ -853,9 +863,6 @@ def cf_healpix_increase_refinement_indices(a, ncells):
853863
The array at the new refinement level.
854864
855865
"""
856-
# PERFORMANCE: This function can use a lot of memory when 'a'
857-
# and/or 'ncells' are large.
858-
859866
a = cfdm_to_memory(a)
860867

861868
a = a * ncells

cf/domain.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,11 @@ def create_healpix(
415415
start = 0
416416

417417
stop = start + ncells
418-
data = Data(da.arange(start, stop), units="1")
418+
dtype = cfdm.integer_dtype(stop - 1)
419+
data = Data(da.arange(start, stop, dtype=dtype), units="1")
419420

420421
# Set cached data elements
421-
data._set_cached_elements({0: start, -1: stop - 1})
422+
data._set_cached_elements({0: start, 1: start + 1, -1: stop - 1})
422423

423424
c.set_data(data, copy=False)
424425
key = domain.set_construct(c, axes=axis, copy=False)

cf/field.py

Lines changed: 38 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -4994,7 +4994,7 @@ def healpix_decrease_refinement_level(
49944994

49954995
Set the refinement level to 0 using the ``'`range'`` *method*,
49964996
which requires a new *reduction* function to be defined:
4997-
4997+
49984998
>>> import numpy as np
49994999
>>> def range_func(a, axis=None):
50005000
... return np.max(a, axis=axis) - np.min(a, axis=axis)
@@ -5114,16 +5114,17 @@ def healpix_decrease_refinement_level(
51145114
f"Can't decrease HEALPix refinement level of {f!r}: "
51155115
"'level' must be a non-negative integer less than "
51165116
"or equal to the current refinement level of "
5117-
f"{old_refinement_level}. Got {refinement_level!r}"
5117+
f"{old_refinement_level}. Got: {refinement_level!r}"
51185118
)
51195119

5120+
# Parse 'level'
51205121
if refinement_level == old_refinement_level:
51215122
# No change in refinement level
51225123
return f
51235124

51245125
# Get the number of cells at the original refinement level
5125-
# which are contained in one cell at the lower refinement
5126-
# level
5126+
# which are contained in one larger cell at the new lower
5127+
# refinement level
51275128
ncells = 4 ** (old_refinement_level - refinement_level)
51285129

51295130
# Get the healpix_index coordinates
@@ -5260,18 +5261,20 @@ def healpix_decrease_refinement_level(
52605261
def healpix_increase_refinement_level(self, refinement_level, quantity):
52615262
"""Increase the refinement level of a HEALPix grid.
52625263

5263-
Increasing the refinement level increases the resolution of
5264-
the HEALPix grid by broadcasting the Field data from each
5265-
original cell to all of the new smaller cells at the new
5266-
higher refinement level that lie inside it.
5267-
5268-
For an extensive field quantity (i.e. one that depends on the
5269-
size of the cells, such as "sea_ice_mass" with units of kg),
5270-
the broadcast values are also reduced to be consistent with
5271-
the new smaller cell areas. For an intensive field quantity
5272-
(i.e. one that does not depend on the size of the cells, such
5273-
as "sea_ice_amount" with units of kg m-2), the broadcast
5274-
values are not changed.
5264+
Increasing the HEALPix refinement level increases the
5265+
resolution of the HEALPix grid by broadcasting the Field data
5266+
from each original cell to all of the new smaller cells at the
5267+
new higher refinement level that lie inside it.
5268+
5269+
It must be specified whether the field data contains an
5270+
extensive or intensive quantity. An extensive quantity depends
5271+
on the size of the cells (such as "sea_ice_mass" with units of
5272+
kg, or "cell_area" with units of m2), and an intensive
5273+
quantity does not depend on the size of the cells (such as
5274+
"sea_ice_amount" with units of kg m-2, or "air_temperature"
5275+
with units of K). For an extensive quantity only, the
5276+
broadcast values are reduced to be consistent with the new
5277+
smaller cell areas.
52755278

52765279
**References**
52775280

@@ -5332,12 +5335,12 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
53325335
>>> print(g[0, :8] .array)
53335336
[[291.5 291.5 291.5 291.5 293.5 293.5 293.5 293.5]]
53345337

5335-
For an extensive quantity (which ``f`` is not in this example,
5336-
but we can assume that it is for demonstration purposes), each
5337-
cell at the higher refinement level has the value of a cell at
5338-
the original refinement level after dividing it by the number
5339-
of cells at the higher refinement level that lie in one cell
5340-
of the original refinement level (4 in this case):
5338+
For an extensive quantity (which the ``f`` is this example is
5339+
not, but we can assume that it is for demonstration purposes),
5340+
each cell at the higher refinement level has the value of a
5341+
cell at the original refinement level after dividing it by the
5342+
number of cells at the higher refinement level that lie in one
5343+
cell of the original refinement level (4 in this case):
53415344

53425345
>>> g = f.healpix_increase_refinement_level(2, 'extensive')
53435346
>>> print(f[0, :2] .array)
@@ -5346,11 +5349,11 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
53465349
[[72.875 72.875 72.875 72.875 73.375 73.375 73.375 73.375]]
53475350

53485351
"""
5349-
from .data.dask_utils import (
5350-
cf_healpix_increase_refinement,
5351-
cf_healpix_increase_refinement_indices,
5352+
from .data.dask_utils import cf_healpix_increase_refinement_indices
5353+
from .healpix import (
5354+
_healpix_increase_refinement_level,
5355+
healpix_max_refinement_level,
53525356
)
5353-
from .healpix import healpix_max_refinement_level
53545357

53555358
# Increasing the refinement level requires the nested indexing
53565359
# scheme
@@ -5380,7 +5383,7 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
53805383
"'level' must be an integer greater than or equal to the "
53815384
f"current refinement level of {old_refinement_level}, and "
53825385
f"less than or equal to {healpix_max_refinement_level()}. "
5383-
f"Got {refinement_level!r}"
5386+
f"Got: {refinement_level!r}"
53845387
)
53855388

53865389
if refinement_level == old_refinement_level:
@@ -5393,7 +5396,7 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
53935396
raise ValueError(
53945397
f"Can't increase HEALPix refinement level of {f!r}: "
53955398
f"'quantity' keyword must be one of {valid_quantities}. "
5396-
f"Got {quantity!r}"
5399+
f"Got: {quantity!r}"
53975400
)
53985401

53995402
# Get the number of cells at the higher refinement level which
@@ -5424,97 +5427,35 @@ def healpix_increase_refinement_level(self, refinement_level, quantity):
54245427
)
54255428
)
54265429

5427-
# Increase the refinement of the Field data
5428-
dx = f.data.to_dask_array(
5429-
_force_mask_hardness=False, _force_to_memory=False
5430-
)
5431-
5432-
if quantity == "extensive":
5433-
# Extensive data get divided by 'ncells' in
5434-
# `cf_healpix_increase_refinement`, so they end up with a
5435-
# data type of float64.
5436-
dtype = np.dtype("float64")
5437-
else:
5438-
dtype = dx.dtype
5439-
5440-
# Each chunk is going to get larger by a factor of 'ncells'
5441-
chunks = list(dx.chunks)
5442-
chunks[iaxis] = (np.array(chunks[iaxis]) * ncells).tolist()
5443-
5444-
dx = dx.map_blocks(
5445-
cf_healpix_increase_refinement,
5446-
chunks=tuple(chunks),
5447-
dtype=dtype,
5448-
meta=np.array((), dtype=dtype),
5449-
ncells=ncells,
5450-
iaxis=iaxis,
5451-
quantity=quantity,
5452-
)
5453-
54545430
# Re-size the HEALPix axis
54555431
domain_axis = f.domain_axis(axis)
5456-
domain_axis.set_size(dx.shape[iaxis])
5432+
domain_axis.set_size(f.shape[iaxis] * ncells)
54575433

5458-
f.set_data(dx, copy=False)
5434+
# Increase the refinement of the Field data
5435+
_healpix_increase_refinement_level(f, ncells, iaxis, quantity)
54595436

54605437
# Increase the refinement level of domain ancillary constructs
54615438
# that span the HEALPix axis. We're assuming that domain
54625439
# ancillary data are intensive (i.e. do not depend on the size
54635440
# of the cell).
5464-
meta = np.array((), dtype=dtype)
54655441
for key, domain_ancillary in f.domain_ancillaries(
54665442
filter_by_axis=(axis,), axis_mode="and", todict=True
54675443
).items():
54685444
iaxis = f.get_data_axes(key).index(axis)
5469-
dx = domain_ancillary.data.to_dask_array(
5470-
_force_mask_hardness=False, _force_to_memory=False
5471-
)
5472-
dtype = dx.dtype
5473-
5474-
# Each chunk is going to get larger by a factor of
5475-
# 'ncells'
5476-
chunks = list(dx.chunks)
5477-
chunks[iaxis] = (np.array(chunks[iaxis]) * ncells).tolist()
5478-
5479-
dx = dx.map_blocks(
5480-
cf_healpix_increase_refinement,
5481-
chunks=tuple(chunks),
5482-
dtype=dtype,
5483-
meta=meta,
5484-
ncells=ncells,
5485-
iaxis=iaxis,
5486-
quantity="intensive",
5445+
_healpix_increase_refinement_level(
5446+
domain_ancillary, ncells, iaxis, "intensive"
54875447
)
5488-
domain_ancillary.set_data(dx, copy=False)
54895448

54905449
# Increase the refinement level of cell measure constructs
54915450
# that span the HEALPix axis. Cell measure data are extensive
54925451
# (i.e. depend on the size of the cell).
5493-
dtype = np.dtype("float64")
5494-
meta = np.array((), dtype=dtype)
54955452
for key, cell_measure in f.cell_measures(
54965453
filter_by_axis=(axis,), axis_mode="and", todict=True
54975454
).items():
54985455
iaxis = f.get_data_axes(key).index(axis)
5499-
dx = cell_measure.data.to_dask_array(
5500-
_force_mask_hardness=False, _force_to_memory=False
5501-
)
5502-
5503-
# Each chunk is going to get larger by a factor of
5504-
# 'ncells'
5505-
chunks = list(dx.chunks)
5506-
chunks[iaxis] = (np.array(chunks[iaxis]) * ncells).tolist()
5507-
5508-
dx = dx.map_blocks(
5509-
cf_healpix_increase_refinement,
5510-
chunks=tuple(chunks),
5511-
dtype=dtype,
5512-
meta=meta,
5513-
ncells=ncells,
5514-
iaxis=iaxis,
5515-
quantity="extensive",
5456+
_healpix_increase_refinement_level(
5457+
cell_measure, ncells, iaxis, "extensive"
55165458
)
5517-
cell_measure.set_data(dx, copy=False)
55185459

55195460
# Remove all other metadata constructs that span the HEALPix
55205461
# axis (including the original healpix_index coordinate

cf/healpix.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,78 @@ def _healpix_create_latlon_coordinates(f, pole_longitude):
157157
return lat_key, lon_key
158158

159159

160+
def _healpix_increase_refinement_level(x, ncells, iaxis, quantity):
161+
"""Increase the HEALPix refinement level in-place.
162+
163+
K. Gorski, Eric Hivon, A. Banday, B. Wandelt, M. Bartelmann, et
164+
al.. HEALPix: A Framework for High-Resolution Discretization and
165+
Fast Analysis of Data Distributed on the Sphere. The Astrophysical
166+
Journal, 2005, 622 (2), pp.759-771.
167+
https://dx.doi.org/10.1086/427976
168+
169+
.. versionadded:: NEXTVERSION
170+
171+
.. seealso:: `cf.Field.healpix_increase_refinement_level`
172+
173+
:Parameters:
174+
175+
x: construct
176+
The construct containing data that is to be changed.
177+
178+
ncells: `int`
179+
The number of cells at the new refinement level which are
180+
contained in one cell at the original refinement level.
181+
182+
iaxis: `int`
183+
The position of the HEALPix axis in the construct's data
184+
dimensions.
185+
186+
quantity: `str`
187+
Whether the data represent intensive or extensive
188+
quantities, specified with ``'intensive'`` and
189+
``'extensive'`` respectively.
190+
191+
:Returns:
192+
193+
`None`
194+
195+
"""
196+
from .data.dask_utils import cf_healpix_increase_refinement
197+
198+
# Get the Dask array.
199+
#
200+
# `cf_healpix_increase_refinement` has its own call to
201+
# `cfdm_to_memory`, so we can set _force_to_memory=False.
202+
dx = x.data.to_dask_array(
203+
_force_mask_hardness=False, _force_to_memory=False
204+
)
205+
206+
if quantity == "extensive":
207+
# Extensive data get divided by 'ncells' in
208+
# `cf_healpix_increase_refinement`, so they end up with a
209+
# data type of float64.
210+
dtype = np.dtype("float64")
211+
else:
212+
dtype = dx.dtype
213+
214+
# Each chunk is going to get larger by a factor of 'ncells'
215+
chunks = list(dx.chunks)
216+
chunks[iaxis] = (np.array(chunks[iaxis]) * ncells).tolist()
217+
218+
dx = dx.map_blocks(
219+
cf_healpix_increase_refinement,
220+
chunks=tuple(chunks),
221+
dtype=dtype,
222+
meta=np.array((), dtype=dtype),
223+
ncells=ncells,
224+
iaxis=iaxis,
225+
quantity=quantity,
226+
)
227+
x.set_data(dx, copy=False)
228+
229+
160230
def _healpix_indexing_scheme(healpix_index, hp, new_indexing_scheme):
161-
"""Change the indexing scheme of HEALPix indices.
231+
"""Change the indexing scheme of HEALPix indices in-place.
162232
163233
K. Gorski, Eric Hivon, A. Banday, B. Wandelt, M. Bartelmann, et
164234
al.. HEALPix: A Framework for High-Resolution Discretization and

0 commit comments

Comments
 (0)