2323import numpy .ma as ma
2424
2525from iris ._deprecation import warn_deprecated
26- from iris ._lazy_data import as_concrete_data , is_lazy_data
26+ from iris ._lazy_data import as_concrete_data , is_lazy_data , is_lazy_masked_data
2727from iris .common import SERVICES
2828from iris .common .lenient import _lenient_client
2929import iris .exceptions
@@ -34,8 +34,7 @@ def broadcast_to_shape(array, shape, dim_map):
3434 Broadcast an array to a given shape.
3535
3636 Each dimension of the array must correspond to a dimension in the
37- given shape. Striding is used to repeat the array until it matches
38- the desired shape, returning repeated views on the original array.
37+ given shape. The result is a read-only view (see :func:`numpy.broadcast_to`).
3938 If you need to write to the resulting array, make a copy first.
4039
4140 Args:
@@ -76,35 +75,30 @@ def broadcast_to_shape(array, shape, dim_map):
7675 See more at :doc:`/userguide/real_and_lazy_data`.
7776
7877 """
79- if len (dim_map ) != array .ndim :
80- # We must check for this condition here because we cannot rely on
81- # getting an error from numpy if the dim_map argument is not the
82- # correct length, we might just get a segfault.
83- raise ValueError (
84- "dim_map must have an entry for every "
85- "dimension of the input array"
86- )
78+ n_orig_dims = len (array .shape )
79+ n_new_dims = len (shape ) - n_orig_dims
80+ array = array .reshape (array .shape + (1 ,) * n_new_dims )
81+
82+ # Get dims in required order.
83+ array = np .moveaxis (array , range (n_orig_dims ), dim_map )
84+ new_array = np .broadcast_to (array , shape )
8785
88- def _broadcast_helper (a ):
89- strides = [0 ] * len (shape )
90- for idim , dim in enumerate (dim_map ):
91- if shape [dim ] != a .shape [idim ]:
92- # We'll get garbage values if the dimensions of array are not
93- # those indicated by shape.
94- raise ValueError ("shape and array are not compatible" )
95- strides [dim ] = a .strides [idim ]
96- return np .lib .stride_tricks .as_strided (a , shape = shape , strides = strides )
97-
98- array_view = _broadcast_helper (array )
99- if ma .isMaskedArray (array ):
100- if array .mask is ma .nomask :
101- # Degenerate masks can be applied as-is.
102- mask_view = array .mask
86+ if ma .isMA (array ):
87+ # broadcast_to strips masks so we need to handle them explicitly.
88+ mask = ma .getmask (array )
89+ if mask is ma .nomask :
90+ new_mask = ma .nomask
10391 else :
104- # Mask arrays need to be handled in the same way as the data array.
105- mask_view = _broadcast_helper (array .mask )
106- array_view = ma .array (array_view , mask = mask_view )
107- return array_view
92+ new_mask = np .broadcast_to (mask , shape )
93+ new_array = ma .array (new_array , mask = new_mask )
94+
95+ elif is_lazy_masked_data (array ):
96+ # broadcast_to strips masks so we need to handle them explicitly.
97+ mask = da .ma .getmaskarray (array )
98+ new_mask = da .broadcast_to (mask , shape )
99+ new_array = da .ma .masked_array (new_array , new_mask )
100+
101+ return new_array
108102
109103
110104def delta (ndarray , dimension , circular = False ):
0 commit comments