diff --git a/CHANGES b/CHANGES index b3916a97b6..bf7bffd7a6 100644 --- a/CHANGES +++ b/CHANGES @@ -71,7 +71,7 @@ Release 1.4 (14 June 2013) * Handle missing values from grib messages https://github.com/SciTools/iris/pull/520 -* PP export rule to calculate forecast period +* PP export rule to perform forecast period https://github.com/SciTools/iris/pull/514 * Preserve masked arrays during aggregation @@ -152,7 +152,7 @@ Features added other than [-180, 180]. * Support for customised CF profiles on export to netCDF. * The documentation now includes guidance on how to cite Iris. -* The ability to calculate the exponential of a Cube, via +* The ability to perform the exponential of a Cube, via `iris.analysis.maths.exp()`. * Experimental support for concatenating Cubes along existing dimensions via `iris.experimental.concatenate.concatenate()`. diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py index 14b28b3070..ca07ec2933 100644 --- a/benchmarks/benchmarks/__init__.py +++ b/benchmarks/benchmarks/__init__.py @@ -6,6 +6,9 @@ from os import environ import resource +import tracemalloc + +import numpy as np ARTIFICIAL_DIM_SIZE = int(10e3) # For all artificial cubes, coords etc. @@ -66,24 +69,44 @@ class TrackAddedMemoryAllocation: """ - RESULT_MINIMUM_MB = 5.0 + _DEFAULT_RESULT_MINIMUM_MB = 5.0 + _DEFAULT_RESULT_ROUND_DP = 1 + + def __init__(self, use_tracemalloc=False, result_min_mb=None, result_round_dp=None): + self._use_tracemalloc = use_tracemalloc + if result_min_mb is None: + result_min_mb = self._DEFAULT_RESULT_MINIMUM_MB + self.RESULT_MINIMUM_MB = result_min_mb + if result_round_dp is None: + result_round_dp = self._DEFAULT_RESULT_ROUND_DP + self.RESULT_ROUND_DP = result_round_dp @staticmethod def process_resident_memory_mb(): return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024.0 def __enter__(self): - self.mb_before = self.process_resident_memory_mb() + if self._use_tracemalloc: + self.mb_before = 0 + tracemalloc.start() + else: + self.mb_before = self.process_resident_memory_mb() return self def __exit__(self, *_): - self.mb_after = self.process_resident_memory_mb() + if self._use_tracemalloc: + _, peak_mem = tracemalloc.get_traced_memory() + tracemalloc.stop() + self.mb_after = peak_mem * 1.0 / 1024**2 + else: + self.mb_after = self.process_resident_memory_mb() def addedmem_mb(self): """Return measured memory growth, in Mb.""" result = self.mb_after - self.mb_before # Small results are too vulnerable to noise being interpreted as signal. result = max(self.RESULT_MINIMUM_MB, result) + result = np.round(result, self.RESULT_ROUND_DP) return result @staticmethod @@ -124,3 +147,23 @@ def on_demand_benchmark(benchmark_object): """ if "ON_DEMAND_BENCHMARKS" in environ: return benchmark_object + + +def memtrace_benchmark(use_tracemalloc=False, result_min_mb=None): + # Call which returns a decorator == 'decorator with args'. + # N.B. embeds the the call argument in the env of the decorator returned + from functools import wraps + + def decorator(decorated_func): + assert decorated_func.__name__[:6] == "track_" + + @wraps(decorated_func) + def wrapper(*args, **kwargs): + with TrackAddedMemoryAllocation( + _use_tracemalloc=use_tracemalloc, result_min_mb=result_min_mb + ): + result = decorated_func(*args, **kwargs) + + return wrapper + + return decorator diff --git a/benchmarks/benchmarks/memtrace_evaluation/__init__.py b/benchmarks/benchmarks/memtrace_evaluation/__init__.py new file mode 100644 index 0000000000..9a8953c83b --- /dev/null +++ b/benchmarks/benchmarks/memtrace_evaluation/__init__.py @@ -0,0 +1,113 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Benchmarks to evaluate tracemalloc/rss methods of memory measurement.""" + +from .. import TrackAddedMemoryAllocation +from .memory_exercising_task import SampleParallelTask + + +class MemcheckCommon: + # Basic controls over the test calculation + default_params = { + "measure": "tracemalloc", # alternate: "rss" + "runtype": "threads", # alternate: "processes" + "ysize": 10000, + "nx": 2000, + "nblocks": 6, + "nworkers": 4, + } + + def _setup(self, **kwargs): + params = self.default_params.copy() + params.update(kwargs) + measure = params["measure"] + runtype = params["runtype"] + ysize = params["ysize"] + nx = params["nx"] + nblocks = params["nblocks"] + nworkers = params["nworkers"] + + nyfull = ysize // nblocks + use_processes = {"threads": False, "processes": True}[runtype] + self.task = SampleParallelTask( + n_blocks=nblocks, + outerdim=nyfull // nblocks, + innerdim=nx, + n_workers=nworkers, + use_process_workers=use_processes, + ) + self.use_tracemalloc = {"tracemalloc": True, "rss": False}[measure] + + def run_time_calc(self): + # This usage is a bit crap, as we don't really care about the runtype. + self.task.perform() + + def run_addedmem_calc(self): + with TrackAddedMemoryAllocation( + use_tracemalloc=self.use_tracemalloc, + result_min_mb=0.0, + ) as tracer: + self.task.perform() + return tracer.addedmem_mb() + + +def memory_units_mib(func): + func.unit = "Mib" + return func + + +class MemcheckRunstyles(MemcheckCommon): + # only some are parametrised, or it's just too complicated! + param_names = [ + "measure", + "runtype", + "ysize", + ] + params = [ + # measure + ["tracemalloc", "rss"], + # runtype + ["threads", "processes"], + # ysize + [10000, 40000], + ] + + def setup(self, measure, runtype, ysize): + self._setup(measure=measure, runtype=runtype, ysize=ysize) + + def time_calc(self, measure, runtype, ysize): + self.run_time_calc() + + @memory_units_mib + def track_addmem_calc(self, measure, runtype, ysize): + return self.run_addedmem_calc() + + +class MemcheckBlocksAndWorkers(MemcheckCommon): + # only some are parametrised, or it's just too complicated! + param_names = [ + "nblocks", + "nworkers", + ] + params = [ + # nblocks + [1, 4, 9], + # nworkers + [1, 4, 9], + ] + + def setup(self, nblocks, nworkers): + self.default_params["ysize"] = 20000 + self._setup( + nblocks=nblocks, + nworkers=nworkers, + ) + + def time_calc(self, nblocks, nworkers): + self.run_time_calc() + + @memory_units_mib + def track_addmem_calc(self, nblocks, nworkers): + return self.run_addedmem_calc() diff --git a/benchmarks/benchmarks/memtrace_evaluation/memory_exercising_task.py b/benchmarks/benchmarks/memtrace_evaluation/memory_exercising_task.py new file mode 100644 index 0000000000..fc2d7cce58 --- /dev/null +++ b/benchmarks/benchmarks/memtrace_evaluation/memory_exercising_task.py @@ -0,0 +1,89 @@ +# Provide standard parallel calculations for testing the memory tracing +from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor + +import numpy as np + +""" +the basic operation is to for each worker to construct a (NY, NX) numpy +random array, of which it calculates and returns the mean(axis=0) + --> (NX,) result +The results are then collected --> (N_BLOCKS, NX), +and a mean over all calculated --> (NX,) +The final (single-value) result is the *minimum* of that. +""" + +# _SHOW_DEBUG = True +_SHOW_DEBUG = False + + +def debug(msg): + if _SHOW_DEBUG: + print(msg) + + +def subtask_operation(arg): + i_task, ny, nx = arg + debug(f"\nRunning #{i_task}({ny}, {nx}) ..") + data = np.random.uniform(0.0, 1.0, size=(ny, nx)) + sub_result = data.mean(axis=0) + debug(f"\n.. completed #{i_task}") + return sub_result + + +class SampleParallelTask: + def __init__( + self, + n_blocks=5, + outerdim=1000, + innerdim=250, + n_workers=4, + use_process_workers=False, + ): + self.n_blocks = n_blocks + self.outerdim = outerdim + self.innerdim = innerdim + self.n_workers = n_workers + if use_process_workers: + self.pool_type = ProcessPoolExecutor + else: + self.pool_type = ThreadPoolExecutor + self._setup_calc() + + def _setup_calc(self): + self._pool = self.pool_type(self.n_workers) + + def perform(self): + partial_results = self._pool.map( + subtask_operation, + [ + (i_task + 1, self.outerdim, self.innerdim) + for i_task in range(self.n_blocks) + ], + ) + combined = np.stack(list(partial_results)) + result = np.mean(combined, axis=0) + result = result.min() + return result + + +if __name__ == "__main__": + nb = 12 + nw = 3 + ny, nx = 1000, 200 + dims = (ny, nx) + use_processes = False + typ = "process" if use_processes else "thread" + msg = f"Starting: blocks={nb} workers={nw} size={dims} type={typ}" + print(msg) + calc = SampleParallelTask( + n_blocks=nb, + outerdim=ny, + innerdim=nx, + n_workers=nw, + use_process_workers=use_processes, + ) + debug("Created.") + debug("Run..") + result = calc.perform() + debug("\n.. Run DONE.") + debug(f"result = {result}") diff --git a/docs/gallery_code/general/plot_custom_aggregation.py b/docs/gallery_code/general/plot_custom_aggregation.py index 65fadfb473..d34156e342 100644 --- a/docs/gallery_code/general/plot_custom_aggregation.py +++ b/docs/gallery_code/general/plot_custom_aggregation.py @@ -9,7 +9,7 @@ :meth:`~iris.cube.Cube.rolling_window`. In this case, we have a 240-year sequence of yearly average surface temperature -over North America, and we want to calculate in how many years these exceed a +over North America, and we want to perform in how many years these exceed a certain temperature over a spell of 5 years or more. """ # noqa: D205, D212, D400 @@ -30,7 +30,7 @@ def count_spells(data, threshold, axis, spell_length): """Calculate the number of points in a sequence. - Function to calculate the number of points in a sequence where the value + Function to perform the number of points in a sequence where the value has exceeded a threshold value for at least a certain number of timepoints. Generalised to operate on multiple time sequences arranged on a specific diff --git a/docs/gallery_code/general/plot_projections_and_annotations.py b/docs/gallery_code/general/plot_projections_and_annotations.py index 6e8ba5a5af..37a18fcd71 100644 --- a/docs/gallery_code/general/plot_projections_and_annotations.py +++ b/docs/gallery_code/general/plot_projections_and_annotations.py @@ -59,7 +59,7 @@ def make_plot(projection_name, projection_crs): iplt.contour(overlay_data, 20, linewidths=2.0, colors="darkgreen", linestyles="-") # Draw a high resolution margin line, inset from the pcolormesh border. - # First calculate rectangle corners, 7% in from each corner of the data. + # First perform rectangle corners, 7% in from each corner of the data. x_coord, y_coord = main_data.coord(axis="x"), main_data.coord(axis="y") x_start, x_end = np.min(x_coord.points), np.max(x_coord.points) y_start, y_end = np.min(y_coord.points), np.max(y_coord.points) diff --git a/docs/gallery_code/meteorology/plot_hovmoller.py b/docs/gallery_code/meteorology/plot_hovmoller.py index 829b370d78..4b21de49c3 100644 --- a/docs/gallery_code/meteorology/plot_hovmoller.py +++ b/docs/gallery_code/meteorology/plot_hovmoller.py @@ -4,7 +4,7 @@ This example demonstrates the creation of a Hovmoller diagram with fine control over plot ticks and labels. The data comes from the Met Office OSTIA project -and has been pre-processed to calculate the monthly mean sea surface +and has been pre-processed to perform the monthly mean sea surface temperature. """ # noqa: D205, D212, D400 diff --git a/docs/src/further_topics/dask_best_practices/dask_parallel_loop.rst b/docs/src/further_topics/dask_best_practices/dask_parallel_loop.rst index 836503314c..cb180e6a11 100644 --- a/docs/src/further_topics/dask_best_practices/dask_parallel_loop.rst +++ b/docs/src/further_topics/dask_best_practices/dask_parallel_loop.rst @@ -44,7 +44,7 @@ We set up the NumPy arrays we will be filling with the output data:: output_arrays = [np.zeros(pressure.shape[0]) for _ in range(6)] cape, cin, lcl, lfc, el, tpw = output_data -Now we loop over the columns in the data to calculate the soundings:: +Now we loop over the columns in the data to perform the soundings:: for y in range(nlim): for x in range(nlim): diff --git a/docs/src/further_topics/lenient_maths.rst b/docs/src/further_topics/lenient_maths.rst index 51f77fb956..9f228c55bc 100644 --- a/docs/src/further_topics/lenient_maths.rst +++ b/docs/src/further_topics/lenient_maths.rst @@ -107,7 +107,7 @@ spatial extent, and acts as a ``control``, STASH m01s00i004 source 'Data from Met Office Unified Model 7.04' -Now let's subtract these cubes in order to calculate a simple ``difference``, +Now let's subtract these cubes in order to perform a simple ``difference``, .. doctest:: lenient-example @@ -134,7 +134,7 @@ Now let's subtract these cubes in order to calculate a simple ``difference``, Note that, cube maths automatically takes care of broadcasting the dimensionality of the ``control`` up to that of the ``experiment``, in order to -calculate the ``difference``. This is performed only after ensuring that both +perform the ``difference``. This is performed only after ensuring that both the **dimension coordinates** ``grid_latitude`` and ``grid_longitude`` are first :ref:`leniently equivalent `. diff --git a/docs/src/further_topics/which_regridder_to_use.rst b/docs/src/further_topics/which_regridder_to_use.rst index 5d7d7fdba1..69582101eb 100644 --- a/docs/src/further_topics/which_regridder_to_use.rst +++ b/docs/src/further_topics/which_regridder_to_use.rst @@ -27,7 +27,7 @@ the following form: +-----------------+-----------------------------------------------------------+ | **API** | Link to API documentation. | +-----------------+-----------------------------------------------------------+ -| **Method** | The type of algorithm used to calculate the result. | +| **Method** | The type of algorithm used to perform the result. | | | See section on `comparing methods`_. | +-----------------+-----------------------------------------------------------+ | **Source Grid** | The type of **coordinates** required on the ``src`` cube. | @@ -324,7 +324,7 @@ the area weighted sum). More precisely, this means that:: to the area weighted average of the result. This property will be particularly important to consider if you are intending to -calculate global properties such as average temperature or total rainfall over a +perform global properties such as average temperature or total rainfall over a given area. It may be less important if you are only interested in local behaviour, e.g., temperature at particular locations. @@ -335,7 +335,7 @@ target. With the keyword argument ``mdtol=0`` this means that there will be an a around the source mask which will be masked in the result and therefore unaccounted for in the area weighted average calculation. Conversely, with the keyword argument ``mdtol=1`` there will be an unmasked area in the result that is masked in the source. -This may be particularly important if you are intending to calculate properties +This may be particularly important if you are intending to perform properties which depend area e.g., calculating the total global rainfall based on data in units of ``kg m-2`` as an area weighted sum. With ``mdtol=0`` this will consistently underestimate this total and with ``mdtol=1`` will consistently overestimate. This can diff --git a/docs/src/userguide/cube_maths.rst b/docs/src/userguide/cube_maths.rst index 79c91ca61b..05579c3a00 100644 --- a/docs/src/userguide/cube_maths.rst +++ b/docs/src/userguide/cube_maths.rst @@ -82,10 +82,10 @@ Calculating a Cube Anomaly In section :doc:`cube_statistics` we discussed how the dimensionality of a cube can be reduced using the :meth:`Cube.collapsed ` method -to calculate a statistic over a dimension. +to perform a statistic over a dimension. -Let's use that method to calculate a mean of our air temperature time-series, -which we'll then use to calculate a time mean anomaly and highlight the powerful +Let's use that method to perform a mean of our air temperature time-series, +which we'll then use to perform a time mean anomaly and highlight the powerful benefits of cube broadcasting. First, let's remind ourselves of the shape of our air temperature time-series @@ -94,7 +94,7 @@ cube:: >>> print(air_temp.summary(True)) air_temperature / (K) (time: 240; latitude: 37; longitude: 49) -Now, we'll calculate the time-series mean using the +Now, we'll perform the time-series mean using the :meth:`Cube.collapsed ` method:: >>> air_temp_mean = air_temp.collapsed('time', iris.analysis.MEAN) @@ -103,7 +103,7 @@ Now, we'll calculate the time-series mean using the As expected the *time* dimension has been collapsed, reducing the dimensionality of the resultant *air_temp_mean* cube. This time-series mean can -now be used to calculate the time mean anomaly against the original +now be used to perform the time mean anomaly against the original time-series:: >>> anomaly = air_temp - air_temp_mean @@ -174,7 +174,7 @@ broadcasting behaviour:: Combining Multiple Phenomena to Form a New One ---------------------------------------------- -Combining cubes of potential-temperature and pressure we can calculate +Combining cubes of potential-temperature and pressure we can perform the associated temperature using the equation: .. math:: @@ -191,7 +191,7 @@ First, let's load pressure and potential temperature cubes:: phenomenon_names = ['air_potential_temperature', 'air_pressure'] pot_temperature, pressure = iris.load_cubes(filename, phenomenon_names) -In order to calculate :math:`\frac{p}{p_0}` we can define a coordinate which +In order to perform :math:`\frac{p}{p_0}` we can define a coordinate which represents the standard reference pressure of 1000 hPa:: import iris.coords @@ -205,7 +205,7 @@ the :meth:`iris.coords.Coord.convert_units` method:: p0.convert_units(pressure.units) -Now we can combine all of this information to calculate the air temperature +Now we can combine all of this information to perform the air temperature using the equation above:: temperature = pot_temperature * ( (pressure / p0) ** (287.05 / 1005) ) diff --git a/docs/src/userguide/cube_statistics.rst b/docs/src/userguide/cube_statistics.rst index fb389a5229..a63727efbd 100644 --- a/docs/src/userguide/cube_statistics.rst +++ b/docs/src/userguide/cube_statistics.rst @@ -111,12 +111,12 @@ Area Averaging Some operators support additional keywords to the ``cube.collapsed`` method. For example, :func:`iris.analysis.MEAN ` supports a weights keyword which can be combined with -:func:`iris.analysis.cartography.area_weights` to calculate an area average. +:func:`iris.analysis.cartography.area_weights` to perform an area average. Let's use the same data as was loaded in the previous example. Since ``grid_latitude`` and ``grid_longitude`` were both point coordinates we must guess bound positions for them -in order to calculate the area of the grid boxes:: +in order to perform the area of the grid boxes:: import iris.analysis.cartography cube.coord('grid_latitude').guess_bounds() diff --git a/docs/src/userguide/glossary.rst b/docs/src/userguide/glossary.rst index 6ab93125bd..f76d313084 100644 --- a/docs/src/userguide/glossary.rst +++ b/docs/src/userguide/glossary.rst @@ -71,7 +71,7 @@ Glossary A coordinate factory derives coordinates (sometimes referred to as derived coordinates) from the values of existing coordinates. E.g. A hybrid height factory might use "height above sea level" - and "height at ground level" coordinate data to calculate a + and "height at ground level" coordinate data to perform a "height above ground level" coordinate. | **Related:** :term:`Cube` diff --git a/docs/src/whatsnew/1.3.rst b/docs/src/whatsnew/1.3.rst index 1895711379..905247d250 100644 --- a/docs/src/whatsnew/1.3.rst +++ b/docs/src/whatsnew/1.3.rst @@ -20,7 +20,7 @@ Features * The documentation now includes guidance on :ref:`how to cite Iris`. -* The ability to calculate the exponential of a Cube, via +* The ability to perform the exponential of a Cube, via :func:`iris.analysis.maths.exp()`. * Experimental support for :ref:`concatenating Cubes` diff --git a/docs/src/whatsnew/1.4.rst b/docs/src/whatsnew/1.4.rst index 24a98488af..c1603370a9 100644 --- a/docs/src/whatsnew/1.4.rst +++ b/docs/src/whatsnew/1.4.rst @@ -30,7 +30,7 @@ Features * Missing values are now handled when loading GRIB messages. -* PP export rule to calculate forecast period. +* PP export rule to perform forecast period. * :func:`~iris.cube.Cube.aggregated_by` now maintains array masking. diff --git a/docs/src/whatsnew/1.6.rst b/docs/src/whatsnew/1.6.rst index 4b179b67d6..fda4b9ecbc 100644 --- a/docs/src/whatsnew/1.6.rst +++ b/docs/src/whatsnew/1.6.rst @@ -237,7 +237,7 @@ The new :data:`iris.analysis.PEAK` aggregator calculates the global peak value from a spline interpolation of the :class:`iris.cube.Cube` data payload along a nominated coordinate axis. -For example, to calculate the peak time: +For example, to perform the peak time: .. code-block:: python diff --git a/docs/src/whatsnew/1.7.rst b/docs/src/whatsnew/1.7.rst index 4c3f3197dc..9aadfb8ae1 100644 --- a/docs/src/whatsnew/1.7.rst +++ b/docs/src/whatsnew/1.7.rst @@ -104,7 +104,7 @@ Features This means that when performing cube arithmetic, the dimensionality and shape of cubes no longer need to match. For example, if the dimensionality of a cube is reduced by collapsing, then the result can be used to subtract - from the original cube to calculate an anomaly:: + from the original cube to perform an anomaly:: >>> time_mean = original_cube.collapsed('time', iris.analysis.MEAN) >>> mean_anomaly = original_cube - time_mean diff --git a/docs/src/whatsnew/3.2.rst b/docs/src/whatsnew/3.2.rst index ce544a5ecc..9ccf889289 100644 --- a/docs/src/whatsnew/3.2.rst +++ b/docs/src/whatsnew/3.2.rst @@ -178,7 +178,7 @@ v3.2.1 (11 Mar 2022) array laziness, allowing efficient comparisons even with larger-than-memory objects. (:pull:`4439`) -#. `@rcomer`_ modified :meth:`~iris.cube.Cube.aggregated_by` to calculate new +#. `@rcomer`_ modified :meth:`~iris.cube.Cube.aggregated_by` to perform new coordinate bounds using minimum and maximum for unordered coordinates, fixing :issue:`1528`. (:pull:`4315`) diff --git a/lib/iris/_constraints.py b/lib/iris/_constraints.py index b8f4665b46..87269e8171 100644 --- a/lib/iris/_constraints.py +++ b/lib/iris/_constraints.py @@ -460,7 +460,7 @@ def as_slice(self): else: # Finally, we can either provide a slice if possible, # or a tuple of indices which match. In order to determine - # if we can provide a slice, calculate the deltas between + # if we can provide a slice, perform the deltas between # the indices and check if they are the same. delta = np.diff(where_true, axis=0) # if the diff is consistent we can create a slice object diff --git a/lib/iris/_representation/cube_printout.py b/lib/iris/_representation/cube_printout.py index 1e648b25f6..5619aa5b40 100644 --- a/lib/iris/_representation/cube_printout.py +++ b/lib/iris/_representation/cube_printout.py @@ -95,7 +95,7 @@ def set_min_column_widths(self): def formatted_as_strings(self): """Return lines formatted to the set column widths.""" if self.col_widths is None: - # If not set, calculate minimum widths. + # If not set, perform minimum widths. self.set_min_column_widths() result_lines = [] for row in self.rows: diff --git a/lib/iris/analysis/__init__.py b/lib/iris/analysis/__init__.py index dc2a09d93e..d481ece857 100644 --- a/lib/iris/analysis/__init__.py +++ b/lib/iris/analysis/__init__.py @@ -5,7 +5,7 @@ """A package providing :class:`iris.cube.Cube` analysis support. This module defines a suite of :class:`~iris.analysis.Aggregator` instances, -which are used to specify the statistical measure to calculate over a +which are used to specify the statistical measure to perform over a :class:`~iris.cube.Cube`, using methods such as :meth:`~iris.cube.Cube.aggregated_by` and :meth:`~iris.cube.Cube.collapsed`. @@ -1465,7 +1465,7 @@ def _weighted_percentile(data, axis, weights, percent, returned=False, **kwargs) ---------- data : ndarray or masked array axis : int - Axis to calculate percentiles over. + Axis to perform percentiles over. weights : ndarray Array with the weights. Must have same shape as data or the shape of data along axis. @@ -1549,7 +1549,7 @@ def _proportion(array, function, axis, **kwargs): # if the incoming array is masked use that to count the total number of # values if ma.isMaskedArray(array): - # calculate the total number of non-masked values across the given axis + # perform the total number of non-masked values across the given axis if array.mask is np.bool_(False): # numpy will return a single boolean as a mask if the mask # was not explicitly specified on array construction, so in this @@ -2269,7 +2269,7 @@ def interp_order(length): class _Groupby: """Determine group slices over one or more group-by coordinates. - Generate the coordinate slices for the groups and calculate the + Generate the coordinate slices for the groups and perform the new group-by coordinates and the new shared coordinates given the group slices. Note that, new shared coordinates will be bounded coordinates. diff --git a/lib/iris/analysis/_area_weighted.py b/lib/iris/analysis/_area_weighted.py index a25a21bb47..22b0d5e270 100644 --- a/lib/iris/analysis/_area_weighted.py +++ b/lib/iris/analysis/_area_weighted.py @@ -233,7 +233,7 @@ def _get_bounds_in_units(coord, units, dtype): def _regrid_area_weighted_rectilinear_src_and_grid__prepare(src_cube, grid_cube): """First (setup) part of 'regrid_area_weighted_rectilinear_src_and_grid'. - Check inputs and calculate related info. The 'regrid info' returned + Check inputs and perform related info. The 'regrid info' returned can be re-used over many 2d slices. """ @@ -286,7 +286,7 @@ def _regrid_area_weighted_rectilinear_src_and_grid__prepare(src_cube, grid_cube) "dimensions to be created." ) - # Determine whether to calculate flat or spherical areas. + # Determine whether to perform flat or spherical areas. # Don't only rely on coord system as it may be None. spherical = ( isinstance( @@ -567,7 +567,7 @@ def _combine_xy_weights(x_info, y_info, src_shape, tgt_shape): xy_weight = y_weight[:, np.newaxis] * x_weight[np.newaxis, :] xy_weight = xy_weight.flatten() - # Given the x index and y index associated with a weight, calculate + # Given the x index and y index associated with a weight, perform # the equivalent index in the flattened (y, x) array. xy_rows = (y_rows[:, np.newaxis] * x_tgt) + x_rows[np.newaxis, :] xy_rows = xy_rows.flatten() diff --git a/lib/iris/analysis/_grid_angles.py b/lib/iris/analysis/_grid_angles.py index 80b73d81d7..00499b15fc 100644 --- a/lib/iris/analysis/_grid_angles.py +++ b/lib/iris/analysis/_grid_angles.py @@ -173,7 +173,7 @@ def gridcell_angles(x, y=None, cell_angle_boundpoints="mid-lhs, mid-rhs"): The first two dimensions are grid dimensions in the order Y, then X. The last index maps cell corners anticlockwise from bottom-left. cell_angle_boundpoints : str, default="mid-lhs, mid-rhs" - Controls which gridcell bounds locations are used to calculate angles, + Controls which gridcell bounds locations are used to perform angles, if the inputs are bounds or bounded coordinates. Valid values are 'lower-left, lower-right', which takes the angle from the lower left to the lower right corner, and 'mid-lhs, mid-rhs' which diff --git a/lib/iris/analysis/_interpolation.py b/lib/iris/analysis/_interpolation.py index 6904c5ae4f..f4e11823fc 100644 --- a/lib/iris/analysis/_interpolation.py +++ b/lib/iris/analysis/_interpolation.py @@ -386,7 +386,7 @@ def _setup(self): cube and the specified coordinates to be interpolated over. """ - # Pre-calculate control data for each interpolation coordinate. + # Pre-perform control data for each interpolation coordinate. self._src_points = [] self._coord_decreasing = [] self._circulars = [] @@ -529,7 +529,7 @@ def _points(self, sample_points, data, data_dims=None): interp_order, _ = zip(*sorted(dmap.items(), key=operator.itemgetter(1))) _, src_order = zip(*sorted(dmap.items(), key=operator.itemgetter(0))) - # Prepare the sample points for interpolation and calculate the + # Prepare the sample points for interpolation and perform the # shape of the interpolated result. interp_points = [] interp_shape = [] diff --git a/lib/iris/analysis/_regrid.py b/lib/iris/analysis/_regrid.py index 6c10b8c404..b76199223d 100644 --- a/lib/iris/analysis/_regrid.py +++ b/lib/iris/analysis/_regrid.py @@ -50,7 +50,7 @@ def _transform_xy_arrays(crs_from, x, y, crs_to): def _regrid_weighted_curvilinear_to_rectilinear__prepare(src_cube, weights, grid_cube): """First (setup) part of 'regrid_weighted_curvilinear_to_rectilinear'. - Check inputs and calculate the sparse regrid matrix and related info. + Check inputs and perform the sparse regrid matrix and related info. The 'regrid info' returned can be re-used over many cubes. """ @@ -1004,7 +1004,7 @@ def _create_cube(data, src, src_dims, tgt_coords, num_tgt_dims, regrid_callback) num_tgt_dims : int The number of dimensions that the `tgt_coords` span. regrid_callback : callable - The routine that will be used to calculate the interpolated + The routine that will be used to perform the interpolated values of any reference surfaces. Returns diff --git a/lib/iris/analysis/calculus.py b/lib/iris/analysis/calculus.py index 75b7db050b..662dc7e93c 100644 --- a/lib/iris/analysis/calculus.py +++ b/lib/iris/analysis/calculus.py @@ -129,7 +129,7 @@ def _construct_midpoint_coord(coord, circular=None): def cube_delta(cube, coord): - """Given a cube calculate the difference between each value in the coord's direction. + """Given a cube perform the difference between each value in the coord's direction. Parameters ---------- @@ -166,9 +166,7 @@ def cube_delta(cube, coord): coord.shape[0] == 1 and not getattr(coord, "circular", False) ) or not delta_dims: raise ValueError( - "Cannot calculate delta over {!r} as it has length of 1.".format( - coord.name() - ) + "Cannot perform delta over {!r} as it has length of 1.".format(coord.name()) ) delta_dim = delta_dims[0] @@ -276,7 +274,7 @@ def differentiate(cube, coord_to_differentiate): delta_coord = _construct_delta_coord(coord) delta_dim = cube.coord_dims(coord.name())[0] - # calculate delta_cube / delta_coord to give the differential. + # perform delta_cube / delta_coord to give the differential. delta_cube = iris.analysis.maths.divide(delta_cube, delta_coord, delta_dim) # Update the standard name diff --git a/lib/iris/analysis/cartography.py b/lib/iris/analysis/cartography.py index 2e7c3a3677..a6519a1d52 100644 --- a/lib/iris/analysis/cartography.py +++ b/lib/iris/analysis/cartography.py @@ -205,7 +205,7 @@ def _xy_range(cube, mode=None): Parameters ---------- cube : - The cube for which to calculate xy extents. + The cube for which to perform xy extents. mode : optional If the coordinate has bounds, set this to specify the min/max calculation. @@ -397,7 +397,7 @@ def area_weights(cube, normalize=False, compute=True, chunks=None): Parameters ---------- cube : :class:`iris.cube.Cube` - The cube to calculate area weights for. + The cube to perform area weights for. normalize : bool, default=False If False, weights are grid cell areas. If True, weights are grid cell areas divided by the total grid area. @@ -992,7 +992,7 @@ def _crs_distance_differentials(crs, x, y): crs : :class:`cartopy.crs.Projection` The coordinate reference system. x, y : array - Locations at which to calculate the differentials, + Locations at which to perform the differentials, defined in 'crs' coordinate reference system. Returns diff --git a/lib/iris/analysis/geometry.py b/lib/iris/analysis/geometry.py index 120b6dfaa6..dab1025af3 100644 --- a/lib/iris/analysis/geometry.py +++ b/lib/iris/analysis/geometry.py @@ -198,7 +198,7 @@ def geometry_area_weights(cube, geometry, normalize=False): suby_bounds = suby_coord.bounds subweights = np.empty(subshape, np.float32) - # calculate the area weights + # perform the area weights for nd_index in np.ndindex(subweights.shape): xi = nd_index[x_dim] yi = nd_index[y_dim] diff --git a/lib/iris/analysis/maths.py b/lib/iris/analysis/maths.py index 80d3ead90c..eead835e61 100644 --- a/lib/iris/analysis/maths.py +++ b/lib/iris/analysis/maths.py @@ -1048,7 +1048,7 @@ def __init__(self, data_func, units_func): data array, with the same shape as the first array. May also have keyword arguments. units_func : - Function to calculate the units of the resulting cube. + Function to perform the units of the resulting cube. Should take the cube/s as input and return an instance of :class:`cf_units.Unit`. diff --git a/lib/iris/analysis/stats.py b/lib/iris/analysis/stats.py index 8df93571f1..d225a9511e 100644 --- a/lib/iris/analysis/stats.py +++ b/lib/iris/analysis/stats.py @@ -32,7 +32,7 @@ def pearsonr( or one cube should be broadcastable to the other. Broadcasting rules are the same as those for cube arithmetic (see :ref:`cube maths`). corr_coords : str or list of str, optional - The cube coordinate name(s) over which to calculate correlations. If no + The cube coordinate name(s) over which to perform correlations. If no names are provided then correlation will be calculated over all common cube dimensions. weights : :class:`numpy.ndarray`, optional diff --git a/lib/iris/analysis/trajectory.py b/lib/iris/analysis/trajectory.py index 2111dd2504..a22d7cf21e 100644 --- a/lib/iris/analysis/trajectory.py +++ b/lib/iris/analysis/trajectory.py @@ -25,7 +25,7 @@ def __init__(self, p0, p1): self.pts = [p0, p1] - # calculate our length + # perform our length squares = 0 for key in self.pts[0].keys(): delta = self.pts[1][key] - self.pts[0][key] @@ -67,7 +67,7 @@ def __init__(self, waypoints, sample_count=10): for i in range(len(self.waypoints) - 1) ] - # calculate our total length + # perform our total length self.length = sum([seg.length for seg in segments]) # generate our sampled points @@ -80,7 +80,7 @@ def __init__(self, waypoints, sample_count=10): cur_seg = segments[cur_seg_i] len_accum = cur_seg.length for p in range(self.sample_count): - # calculate the sample position along our total length + # perform the sample position along our total length sample_at_len = p * sample_step # skip forward to the containing segment diff --git a/lib/iris/aux_factory.py b/lib/iris/aux_factory.py index 41e1e9f573..97378ed52f 100644 --- a/lib/iris/aux_factory.py +++ b/lib/iris/aux_factory.py @@ -1027,7 +1027,7 @@ def _derive(self, sigma, eta, depth, depth_c, zlev, nsigma, coord_dims_func): # Calculate the index of the 'z' dimension in the input arrays. # First find the cube 'z' dimension ... [cube_z_dim] = coord_dims_func(self.dependencies["zlev"]) - # ... then calculate the corresponding dependency dimension. + # ... then perform the corresponding dependency dimension. derived_cubedims = self.derived_dims(coord_dims_func) z_dim = derived_cubedims.index(cube_z_dim) diff --git a/lib/iris/common/resolve.py b/lib/iris/common/resolve.py index aaf36b36cc..01a3d17328 100644 --- a/lib/iris/common/resolve.py +++ b/lib/iris/common/resolve.py @@ -412,7 +412,7 @@ def _as_compatible_cubes(self): assert src_cube.ndim == len(self.mapping) - # Use the mapping to calculate the new src cube shape. + # Use the mapping to perform the new src cube shape. new_src_shape = [1] * tgt_cube.ndim for src_dim, tgt_dim in self.mapping.items(): new_src_shape[tgt_dim] = src_cube.shape[src_dim] diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 8418a630b5..05c1ce0dc9 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -4137,7 +4137,7 @@ def collapsed(self, coords, aggregator, **kwargs): dims_to_collapse.update(self.coord_dims(coord)) if aggregator.name() == "max_run" and len(dims_to_collapse) > 1: - msg = "Not possible to calculate runs over more than one dimension" + msg = "Not possible to perform runs over more than one dimension" raise ValueError(msg) if not dims_to_collapse: @@ -4675,7 +4675,7 @@ def rolling_window(self, coord, aggregator, window, **kwargs): if coord_.ndim != 1: raise ValueError( - "Cannot calculate the rolling " + "Cannot perform the rolling " "window of %s as it is a multidimensional " "coordinate." % coord_.name() ) diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index 4ffad43a2c..748448fdbe 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -425,7 +425,7 @@ def _create_cube( The :class:`iris.coords.DimCoord` for the new grid's Y coordinate. regrid_callback : - The routine that will be used to calculate the interpolated + The routine that will be used to perform the interpolated values of any reference surfaces. Returns diff --git a/lib/iris/experimental/regrid_conservative.py b/lib/iris/experimental/regrid_conservative.py index c4dbf965f8..33e20ba8d3 100644 --- a/lib/iris/experimental/regrid_conservative.py +++ b/lib/iris/experimental/regrid_conservative.py @@ -92,7 +92,7 @@ def _make_esmpy_field(x_coord, y_coord, ref_name="field", data=None, mask=None): grid_corners_y = grid.get_coords(1, ESMF.StaggerLoc.CORNER) grid_corners_y[:] = lat_bounds.T - # calculate the cell centre-points + # perform the cell centre-points # NOTE: we don't care about Iris' idea of where the points 'really' are # *but* ESMF requires the data in the CENTER for conservative regrid, # according to the documentation : diff --git a/lib/iris/experimental/ugrid/mesh.py b/lib/iris/experimental/ugrid/mesh.py index a798f7af77..5c2752688e 100644 --- a/lib/iris/experimental/ugrid/mesh.py +++ b/lib/iris/experimental/ugrid/mesh.py @@ -2961,7 +2961,7 @@ def _construct_access_arrays(self): ------- array or None Tuple of (points, bounds). - Lazy arrays which calculate the correct points and bounds from the + Lazy arrays which perform the correct points and bounds from the Mesh data, based on the location and axis. The Mesh coordinates accessed are not identified on construction, but discovered from the Mesh at the time of calculation, so that diff --git a/lib/iris/fileformats/netcdf/saver.py b/lib/iris/fileformats/netcdf/saver.py index 8d53a4d5be..f0ed4d9563 100644 --- a/lib/iris/fileformats/netcdf/saver.py +++ b/lib/iris/fileformats/netcdf/saver.py @@ -2656,7 +2656,7 @@ def attr_values_equal(val1, val2): cube.attributes.locals[attr] = value else: - # Legacy mode: calculate "local_keys" to control which attributes are local + # Legacy mode: perform "local_keys" to control which attributes are local # and which global. # TODO: when iris.FUTURE.save_split_attrs is removed, this section can also be # removed diff --git a/lib/iris/fileformats/pp.py b/lib/iris/fileformats/pp.py index c2660d022c..ee15e05ddc 100644 --- a/lib/iris/fileformats/pp.py +++ b/lib/iris/fileformats/pp.py @@ -461,7 +461,7 @@ def __setitem__(self, key, value): " containing negative indices." ) - # calculate the current length of the value of this string + # perform the current length of the value of this string current_length = len(range(*key.indices(len(self)))) # get indices for as many digits as have been requested. Putting @@ -1901,7 +1901,7 @@ def _field_gen(filename, read_data_bytes, little_ended=False): ) break - # calculate the extra length in bytes + # perform the extra length in bytes extra_len = pp_field.lbext * PP_WORD_DEPTH # Derive size and datatype of payload diff --git a/lib/iris/tests/unit/analysis/cartography/test_gridcell_angles.py b/lib/iris/tests/unit/analysis/cartography/test_gridcell_angles.py index f3798ace5a..9c4fbe2ef4 100644 --- a/lib/iris/tests/unit/analysis/cartography/test_gridcell_angles.py +++ b/lib/iris/tests/unit/analysis/cartography/test_gridcell_angles.py @@ -157,7 +157,7 @@ def test_coords_radians_args(self): self.assertArrayAllClose(result.data, self.standard_small_cube_results) def test_bounds_array_args(self): - # Check we can calculate from bounds values alone. + # Check we can perform from bounds values alone. co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) # Results drawn from coord bounds should be nearly the same, # but not exactly, because of the different 'midpoint' values. @@ -180,7 +180,7 @@ def test_unbounded_regional_coord_args(self): ) def test_points_array_args(self): - # Check we can calculate from points arrays alone (no coords). + # Check we can perform from points arrays alone (no coords). co_x, co_y = (self.standard_regional_cube.coord(axis=ax) for ax in ("x", "y")) # As previous, the leftmost and rightmost columns are not good. result = gridcell_angles(co_x.points, co_y.points) @@ -193,7 +193,7 @@ def test_unbounded_global(self): # bounds removed, should be a reasonable match for the 'ideal' one # based on the bounds. - # Make a global cube + calculate ideal bounds-based results. + # Make a global cube + perform ideal bounds-based results. global_cube = sample_2d_latlons(transformed=True) result_cube = gridcell_angles(global_cube) result_cube.convert_units("degrees") diff --git a/lib/iris/tests/unit/analysis/scipy_interpolate/test__RegularGridInterpolator.py b/lib/iris/tests/unit/analysis/scipy_interpolate/test__RegularGridInterpolator.py index 374e355c32..8d2e121bb9 100644 --- a/lib/iris/tests/unit/analysis/scipy_interpolate/test__RegularGridInterpolator.py +++ b/lib/iris/tests/unit/analysis/scipy_interpolate/test__RegularGridInterpolator.py @@ -19,7 +19,7 @@ class Test(tests.IrisTest): def setUp(self): - # Load a source cube, then generate an interpolator instance, calculate + # Load a source cube, then generate an interpolator instance, perform # the interpolation weights and set up a target grid. self.cube = stock.simple_2d() x_points = self.cube.coord("bar").points