From 5a03d6828d6b27d895ce505ec15a17aa2a11e555 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 15 Jun 2021 12:55:29 -0500 Subject: [PATCH 01/23] wip - refactor --- pangeo_forge_recipes/recipes/xarray_zarr.py | 810 +++++++++++++------- 1 file changed, 535 insertions(+), 275 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index ee508b72..173f44e1 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -7,7 +7,7 @@ from contextlib import ExitStack, contextmanager from dataclasses import dataclass, field, replace from itertools import product -from typing import Callable, Dict, List, Optional, Sequence, Tuple +from typing import Callable, Dict, List, Optional, Tuple import dask import numpy as np @@ -15,7 +15,7 @@ import zarr from ..patterns import FilePattern, prune_pattern -from ..storage import AbstractTarget, CacheFSSpecTarget, MetadataTarget, file_opener +from ..storage import AbstractTarget, CacheFSSpecTarget, FSSpecTarget, MetadataTarget, file_opener from ..utils import ( chunk_bounds_and_conflicts, chunked_iterable, @@ -51,6 +51,467 @@ def _chunk_metadata_fname(chunk_key) -> str: # - https://stackoverflow.com/questions/51575931/class-inheritance-in-python-3-7-dataclasses +def expand_target_dim(target: FSSpecTarget, concat_dim: Optional[str], dimsize: int) -> None: + target_mapper = target.get_mapper() + zgroup = zarr.open_group(target_mapper) + ds = open_target(target) + sequence_axes = { + v: ds[v].get_axis_num(concat_dim) for v in ds.variables if concat_dim in ds[v].dims + } + + for v, axis in sequence_axes.items(): + arr = zgroup[v] + shape = list(arr.shape) + shape[axis] = dimsize + logger.debug(f"resizing array {v} to shape {shape}") + arr.resize(shape) + + # now explicity write the sequence coordinate to avoid missing data + # when reopening + if concat_dim in zgroup: + zgroup[concat_dim][:] = 0 + + +def open_target(target: FSSpecTarget) -> xr.Dataset: + return xr.open_zarr(target.get_mapper()) + + +def input_position(input_key, file_pattern: FilePattern, concat_dim: Optional[str]): + assert concat_dim is not None + concat_dim_axis = list(file_pattern.dims).index(concat_dim) + return input_key[concat_dim_axis] + + +def cache_input_metadata( + input_key: InputKey, + metadata_cache: Optional[MetadataTarget], + file_pattern: FilePattern, + input_cache: Optional[CacheFSSpecTarget], + cache_inputs: bool, + copy_input_to_local_file: bool, + xarray_open_kwargs: dict, + delete_input_encoding: bool, + process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], +): + # TODO(TOM): figure out where caching should happen + if metadata_cache is None: + raise ValueError("metadata_cache is not set.") + logger.info(f"Caching metadata for input '{input_key}'") + with open_input( + input_key, + file_pattern=file_pattern, + input_cache=input_cache, + cache_inputs=cache_inputs, + copy_input_to_local_file=copy_input_to_local_file, + xarray_open_kwargs=xarray_open_kwargs, + delete_input_encoding=delete_input_encoding, + process_input=process_input, + ) as ds: + input_metadata = ds.to_dict(data=False) + metadata_cache[_input_metadata_fname(input_key)] = input_metadata + + +def cache_input( + input_key: InputKey, + cache_inputs: bool, + input_cache: Optional[CacheFSSpecTarget], + file_pattern: FilePattern, + fsspec_open_kwargs: dict, + cache_metadata: bool, + copy_input_to_local_file: bool, + xarray_open_kwargs: dict, + delete_input_encoding: bool, + process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], + metadata_cache: Optional[MetadataTarget], +): + if cache_inputs: + if input_cache is None: + raise ValueError("input_cache is not set.") + logger.info(f"Caching input '{input_key}'") + fname = file_pattern[input_key] + input_cache.cache_file(fname, **fsspec_open_kwargs) + + if cache_metadata: + return cache_input_metadata( + input_key, + file_pattern=file_pattern, + input_cache=input_cache, + cache_inputs=cache_inputs, + copy_input_to_local_file=copy_input_to_local_file, + xarray_open_kwargs=xarray_open_kwargs, + delete_input_encoding=delete_input_encoding, + process_input=process_input, + metadata_cache=metadata_cache, + ) + + +def region_and_conflicts_for_chunk( + chunks_inputs: Dict[ChunkKey, Tuple[InputKey]], + chunk_key: ChunkKey, + nitems_per_input: Optional[int], + file_pattern: FilePattern, + input_sequence_lens, + concat_dim_chunks: Optional[int], + concat_dim: Optional[str], +): + # return a dict suitable to pass to xr.to_zarr(region=...) + # specifies where in the overall array to put this chunk's data + # also return the conflicts with other chunks + + input_keys = chunks_inputs[chunk_key] + + if nitems_per_input: + input_sequence_lens = (nitems_per_input,) * file_pattern.dims[concat_dim] # type: ignore + # TODO(Tom): Handle metadata caching here + # else: + # global_metadata = metadata_cache[_GLOBAL_METADATA_KEY] + # input_sequence_lens = global_metadata["input_sequence_lens"] + + assert concat_dim_chunks is not None + + chunk_bounds, all_chunk_conflicts = chunk_bounds_and_conflicts( + chunks=input_sequence_lens, zchunks=concat_dim_chunks + ) + input_positions = [ + input_position(input_key, file_pattern, concat_dim) for input_key in input_keys + ] + start = chunk_bounds[min(input_positions)] + stop = chunk_bounds[max(input_positions) + 1] + + this_chunk_conflicts = set() + for k in input_keys: + # for multi-variable recipes, the confilcts will usually be the same + # for each variable. using a set avoids duplicate locks + for input_conflict in all_chunk_conflicts[ + input_position(input_key=k, file_pattern=file_pattern, concat_dim=concat_dim) + ]: + this_chunk_conflicts.add(input_conflict) + region_slice = slice(start, stop) + return {concat_dim: region_slice}, this_chunk_conflicts + + +@contextmanager +def open_input( + input_key: InputKey, + file_pattern: FilePattern, + input_cache: Optional[CacheFSSpecTarget], + cache_inputs: bool, + copy_input_to_local_file: bool, + xarray_open_kwargs: dict, + delete_input_encoding: bool, + process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], +) -> xr.Dataset: + fname = file_pattern[input_key] + logger.info(f"Opening input with Xarray {input_key}: '{fname}'") + cache = input_cache if cache_inputs else None + with file_opener(fname, cache=cache, copy_to_local=copy_input_to_local_file) as f: + with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler + logger.debug(f"about to call xr.open_dataset on {f}") + kw = xarray_open_kwargs.copy() + if "engine" not in kw: + kw["engine"] = "h5netcdf" + ds = xr.open_dataset(f, **kw) + logger.debug("successfully opened dataset") + ds = fix_scalar_attr_encoding(ds) + + if delete_input_encoding: + for var in ds.variables: + ds[var].encoding = {} + + if process_input is not None: + ds = process_input(ds, str(fname)) + + logger.debug(f"{ds}") + yield ds + + +@contextmanager +def open_chunk( + chunk_key: ChunkKey, + chunks_inputs: Dict[ChunkKey, Tuple[InputKey]], + concat_dim: Optional[str], + xarray_concat_kwargs: dict, + process_chunk: Optional[Callable[[xr.Dataset], xr.Dataset]], + target_chunks: Dict[str, int], + file_pattern: FilePattern, + input_cache: Optional[CacheFSSpecTarget], + cache_inputs: bool, + copy_input_to_local_file: bool, + xarray_open_kwargs: dict, + delete_input_encoding: bool, + process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], +) -> xr.Dataset: + logger.info(f"Opening inputs for chunk {chunk_key}") + inputs = chunks_inputs[chunk_key] + + # need to open an unknown number of contexts at the same time + with ExitStack() as stack: + dsets = [ + stack.enter_context( + open_input( + i, + file_pattern=file_pattern, + input_cache=input_cache, + cache_inputs=cache_inputs, + copy_input_to_local_file=copy_input_to_local_file, + xarray_open_kwargs=xarray_open_kwargs, + delete_input_encoding=delete_input_encoding, + process_input=process_input, + ) + ) + for i in inputs + ] + # explicitly chunking prevents eager evaluation during concat + dsets = [ds.chunk() for ds in dsets] + logger.info(f"Combining inputs for chunk '{chunk_key}'") + if len(dsets) > 1: + # During concat, attributes and encoding are taken from the first dataset + # https://github.com/pydata/xarray/issues/1614 + with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler + ds = xr.concat(dsets, concat_dim, **xarray_concat_kwargs) + elif len(dsets) == 1: + ds = dsets[0] + else: # pragma: no cover + assert False, "Should never happen" + + if process_chunk is not None: + with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler + ds = process_chunk(ds) + + with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler + logger.debug(f"{ds}") + + if target_chunks: + # The input may be too large to process in memory at once, so + # rechunk it to the target chunks. + ds = ds.chunk(target_chunks) + yield ds + + +def get_input_meta(metadata_cache: Optional[MetadataTarget], *input_keys: InputKey,) -> Dict: + # getitems should be async; much faster than serial calls + if metadata_cache is None: + raise ValueError("metadata_cache is not set.") + return metadata_cache.getitems([_input_metadata_fname(k) for k in input_keys]) + + +def calculate_sequence_lens( + nitems_per_input: Optional[int], + file_pattern: FilePattern, + concat_dim: Optional[str], + inputs_chunks: Dict[InputKey, Tuple[ChunkKey]], + metadata_cache: Optional[MetadataTarget], +) -> List[int]: + if nitems_per_input: + assert concat_dim is not None # TODO(mypy) + return list((nitems_per_input,) * file_pattern.dims[concat_dim]) + + # read per-input metadata; this is distinct from global metadata + # get the sequence length of every file + # this line could become problematic for large (> 10_000) lists of files + input_meta = get_input_meta(metadata_cache, *inputs_chunks) + # use a numpy array to allow reshaping + all_lens = np.array([m["dims"][concat_dim] for m in input_meta.values()]) + all_lens.shape = list(file_pattern.dims.values()) + # check that all lens are the same along the concat dim + assert concat_dim is not None # TODO(mypy) + concat_dim_axis = list(file_pattern.dims).index(concat_dim) + selector = [slice(0, 1)] * len(file_pattern.dims) + selector[concat_dim_axis] = slice(None) # this should broadcast correctly agains all_lens + sequence_lens = all_lens[tuple(selector)] + if not (all_lens == sequence_lens).all(): + raise ValueError(f"Inconsistent sequence lengths found: f{all_lens}") + return sequence_lens.squeeze().tolist() + + +def prepare_target( + target: FSSpecTarget, + target_chunks: Dict[str, int], + init_chunks: List[ChunkKey], + concat_dim: Optional[str], + nitems_per_input: Optional[int], + file_pattern: FilePattern, + inputs_chunks: Dict[InputKey, Tuple[ChunkKey]], + cache_metadata: bool, + chunks_inputs: Dict[ChunkKey, Tuple[InputKey]], + xarray_concat_kwargs: dict, + process_chunk: Optional[Callable[[xr.Dataset], xr.Dataset]], + input_cache: Optional[CacheFSSpecTarget], + cache_inputs: bool, + copy_input_to_local_file: bool, + xarray_open_kwargs: dict, + delete_input_encoding: bool, + process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], + metadata_cache: Optional[MetadataTarget], +) -> Optional[Dict[str, List[int]]]: + try: + ds = open_target(target) + logger.info("Found an existing dataset in target") + logger.debug(f"{ds}") + + if target_chunks: + # TODO: check that target_chunks id compatibile with the + # existing chunks + pass + except (FileNotFoundError, IOError, zarr.errors.GroupNotFoundError): + logger.info("Creating a new dataset in target") + + # need to rewrite this as an append loop + for chunk_key in init_chunks: + with open_chunk( + chunk_key=chunk_key, + chunks_inputs=chunks_inputs, + concat_dim=concat_dim, + xarray_concat_kwargs=xarray_concat_kwargs, + process_chunk=process_chunk, + target_chunks=target_chunks, + file_pattern=file_pattern, + input_cache=input_cache, + cache_inputs=cache_inputs, + copy_input_to_local_file=copy_input_to_local_file, + xarray_open_kwargs=xarray_open_kwargs, + delete_input_encoding=delete_input_encoding, + process_input=process_input, + ) as ds: + # ds is already chunked + + # https://github.com/pydata/xarray/blob/5287c7b2546fc8848f539bb5ee66bb8d91d8496f/xarray/core/variable.py#L1069 + for v in ds.variables: + if target_chunks: + this_var = ds[v] + chunks = { + this_var.get_axis_num(dim): chunk + for dim, chunk in target_chunks.items() + if dim in this_var.dims + } + encoding_chunks = tuple( + chunks.get(n, s) for n, s in enumerate(this_var.shape) + ) + else: + encoding_chunks = ds[v].shape + logger.debug(f"Setting variable {v} encoding chunks to {encoding_chunks}") + ds[v].encoding["chunks"] = encoding_chunks + + # load all variables that don't have the sequence dim in them + # these are usually coordinates. + # Variables that are loaded will be written even with compute=False + # TODO: make this behavior customizable + for v in ds.variables: + if concat_dim not in ds[v].dims: + ds[v].load() + + target_mapper = target.get_mapper() + logger.info(f"Storing dataset in {target.root_path}") + logger.debug(f"{ds}") + with warnings.catch_warnings(): + warnings.simplefilter( + "ignore" + ) # suppress the warning that comes with safe_chunks + ds.to_zarr(target_mapper, mode="a", compute=False, safe_chunks=False) + + # Regardless of whether there is an existing dataset or we are creating a new one, + # we need to expand the concat_dim to hold the entire expected size of the data + input_sequence_lens = calculate_sequence_lens( + nitems_per_input, file_pattern, concat_dim, inputs_chunks, metadata_cache=metadata_cache, + ) + n_sequence = sum(input_sequence_lens) + logger.info(f"Expanding target concat dim '{concat_dim}' to size {n_sequence}") + expand_target_dim(target, concat_dim, n_sequence) + + # TODO(Tom): Handle state on the object + if cache_metadata: + # if nitems_per_input is not constant, we need to cache this info + recipe_meta = {"input_sequence_lens": input_sequence_lens} + return recipe_meta + return None + + +def store_chunk( + chunk_key: ChunkKey, + target: FSSpecTarget, + concat_dim: Optional[str], + chunks_inputs: Dict[ChunkKey, Tuple[InputKey]], + nitems_per_input: Optional[int], + file_pattern: FilePattern, + input_sequence_lens, + concat_dim_chunks: Optional[int], + lock_timeout: Optional[int], + xarray_concat_kwargs: dict, + process_chunk: Optional[Callable[[xr.Dataset], xr.Dataset]], + target_chunks: Dict[str, int], + input_cache: Optional[CacheFSSpecTarget], + cache_inputs: bool, + copy_input_to_local_file: bool, + xarray_open_kwargs: dict, + delete_input_encoding: bool, + process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], +) -> None: + if target is None: + raise ValueError("target has not been set.") + with open_chunk( + chunk_key=chunk_key, + chunks_inputs=chunks_inputs, + concat_dim=concat_dim, + xarray_concat_kwargs=xarray_concat_kwargs, + process_chunk=process_chunk, + target_chunks=target_chunks, + file_pattern=file_pattern, + input_cache=input_cache, + cache_inputs=cache_inputs, + copy_input_to_local_file=copy_input_to_local_file, + xarray_open_kwargs=xarray_open_kwargs, + delete_input_encoding=delete_input_encoding, + process_input=process_input, + ) as ds_chunk: + # writing a region means that all the variables MUST have concat_dim + to_drop = [v for v in ds_chunk.variables if concat_dim not in ds_chunk[v].dims] + ds_chunk = ds_chunk.drop_vars(to_drop) + + target_mapper = target.get_mapper() + write_region, conflicts = region_and_conflicts_for_chunk( + chunks_inputs=chunks_inputs, + chunk_key=chunk_key, + nitems_per_input=nitems_per_input, + file_pattern=file_pattern, + input_sequence_lens=input_sequence_lens, + concat_dim_chunks=concat_dim_chunks, + concat_dim=concat_dim, + ) + + zgroup = zarr.open_group(target_mapper) + for vname, var_coded in ds_chunk.variables.items(): + zarr_array = zgroup[vname] + # get encoding for variable from zarr attributes + # could this backfire some way? + var_coded.encoding.update(zarr_array.attrs) + # just delete all attributes from the var; + # they are not used anyway, and there can be conflicts + # related to xarray.coding.variables.safe_setitem + var_coded.attrs = {} + with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler + var = xr.backends.zarr.encode_zarr_variable(var_coded) + data = np.asarray( + var.data + ) # TODO: can we buffer large data rather than loading it all? + zarr_region = tuple(write_region.get(dim, slice(None)) for dim in var.dims) + lock_keys = [f"{vname}-{c}" for c in conflicts] + logger.debug(f"Acquiring locks {lock_keys}") + with lock_for_conflicts(lock_keys, timeout=lock_timeout): + logger.info( + f"Storing variable {vname} chunk {chunk_key} " f"to Zarr region {zarr_region}" + ) + zarr_array[zarr_region] = data + + +def finalize_target(target: FSSpecTarget, consolidate_zarr: bool) -> None: + if target is None: + raise ValueError("target has not been set.") + if consolidate_zarr: + logger.info("Consolidating Zarr metadata") + target_mapper = target.get_mapper() + zarr.consolidate_metadata(target_mapper) + + @dataclass class XarrayZarrRecipe(BaseRecipe): """This class represents a dataset composed of many individual NetCDF files. @@ -206,303 +667,102 @@ def _set_target_chunks(self): else: self._concat_dim_chunks = self._nitems_per_input * self.inputs_per_chunk + @property + def _prepare_target(self): + func = prepare_target + args = () + kwargs = dict( + target=self.target, + target_chunks=self.target_chunks, + init_chunks=self._init_chunks, + concat_dim=self._concat_dim, + nitems_per_input=self._nitems_per_input, + file_pattern=self.file_pattern, + inputs_chunks=self._inputs_chunks, + cache_metadata=self._cache_metadata, + chunks_inputs=self._chunks_inputs, + xarray_concat_kwargs=self.xarray_concat_kwargs, + process_chunk=self.process_chunk, + input_cache=self.input_cache, + cache_inputs=self.cache_inputs, + copy_input_to_local_file=self.copy_input_to_local_file, + xarray_open_kwargs=self.xarray_open_kwargs, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + metadata_cache=self.metadata_cache, + ) + return func, args, kwargs + @property # type: ignore @closure def prepare_target(self) -> None: - if self.target is None: - raise ValueError("target is not set.") - try: - ds = self.open_target() - logger.info("Found an existing dataset in target") - logger.debug(f"{ds}") + func, args, kwargs = self._prepare_target + return func(*args, **kwargs) - if self.target_chunks: - # TODO: check that target_chunks id compatibile with the - # existing chunks - pass - - except (FileNotFoundError, IOError, zarr.errors.GroupNotFoundError): - logger.info("Creating a new dataset in target") - - # need to rewrite this as an append loop - for chunk_key in self._init_chunks: - with self.open_chunk(chunk_key) as ds: - # ds is already chunked - - # https://github.com/pydata/xarray/blob/5287c7b2546fc8848f539bb5ee66bb8d91d8496f/xarray/core/variable.py#L1069 - for v in ds.variables: - if self.target_chunks: - this_var = ds[v] - chunks = { - this_var.get_axis_num(dim): chunk - for dim, chunk in self.target_chunks.items() - if dim in this_var.dims - } - encoding_chunks = tuple( - chunks.get(n, s) for n, s in enumerate(this_var.shape) - ) - else: - encoding_chunks = ds[v].shape - logger.debug(f"Setting variable {v} encoding chunks to {encoding_chunks}") - ds[v].encoding["chunks"] = encoding_chunks - - # load all variables that don't have the sequence dim in them - # these are usually coordinates. - # Variables that are loaded will be written even with compute=False - # TODO: make this behavior customizable - for v in ds.variables: - if self._concat_dim not in ds[v].dims: - ds[v].load() - - target_mapper = self.target.get_mapper() - logger.info(f"Storing dataset in {self.target.root_path}") # type: ignore - logger.debug(f"{ds}") - with warnings.catch_warnings(): - warnings.simplefilter( - "ignore" - ) # suppress the warning that comes with safe_chunks - ds.to_zarr(target_mapper, mode="a", compute=False, safe_chunks=False) - - # Regardless of whether there is an existing dataset or we are creating a new one, - # we need to expand the concat_dim to hold the entire expected size of the data - input_sequence_lens = self.calculate_sequence_lens() - n_sequence = sum(input_sequence_lens) - logger.info(f"Expanding target concat dim '{self._concat_dim}' to size {n_sequence}") - self.expand_target_dim(self._concat_dim, n_sequence) - - if self._cache_metadata: - if self.metadata_cache is None: - raise ValueError("metadata_cache is not set") - # if nitems_per_input is not constant, we need to cache this info - recipe_meta = {"input_sequence_lens": input_sequence_lens} - self.metadata_cache[_GLOBAL_METADATA_KEY] = recipe_meta - - # TODO: figure out how to make mypy happy with this convoluted structure @property # type: ignore @closure def cache_input(self, input_key: InputKey) -> None: # type: ignore - if self.cache_inputs: - if self.input_cache is None: - raise ValueError("input_cache is not set.") - logger.info(f"Caching input '{input_key}'") - fname = self.file_pattern[input_key] - self.input_cache.cache_file(fname, **self.fsspec_open_kwargs) - - if self._cache_metadata: - self.cache_input_metadata(input_key) + cache_input( + input_key, + cache_inputs=self.cache_inputs, + input_cache=self.input_cache, + file_pattern=self.file_pattern, + fsspec_open_kwargs=self.fsspec_open_kwargs, + cache_metadata=self._cache_metadata, + copy_input_to_local_file=self.copy_input_to_local_file, + xarray_open_kwargs=self.xarray_open_kwargs, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + metadata_cache=self.metadata_cache, + ) @property # type: ignore @closure def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore - if self.target is None: - raise ValueError("target has not been set.") - with self.open_chunk(chunk_key) as ds_chunk: - # writing a region means that all the variables MUST have concat_dim - to_drop = [v for v in ds_chunk.variables if self._concat_dim not in ds_chunk[v].dims] - ds_chunk = ds_chunk.drop_vars(to_drop) - - target_mapper = self.target.get_mapper() - write_region, conflicts = self.region_and_conflicts_for_chunk(chunk_key) - - zgroup = zarr.open_group(target_mapper) - for vname, var_coded in ds_chunk.variables.items(): - zarr_array = zgroup[vname] - # get encoding for variable from zarr attributes - # could this backfire some way? - var_coded.encoding.update(zarr_array.attrs) - # just delete all attributes from the var; - # they are not used anyway, and there can be conflicts - # related to xarray.coding.variables.safe_setitem - var_coded.attrs = {} - with dask.config.set( - scheduler="single-threaded" - ): # make sure we don't use a scheduler - var = xr.backends.zarr.encode_zarr_variable(var_coded) - data = np.asarray( - var.data - ) # TODO: can we buffer large data rather than loading it all? - zarr_region = tuple(write_region.get(dim, slice(None)) for dim in var.dims) - lock_keys = [f"{vname}-{c}" for c in conflicts] - logger.debug(f"Acquiring locks {lock_keys}") - with lock_for_conflicts(lock_keys, timeout=self.lock_timeout): - logger.info( - f"Storing variable {vname} chunk {chunk_key} " - f"to Zarr region {zarr_region}" - ) - zarr_array[zarr_region] = data + # TODO(TOM): Restore the cache lookup + input_sequence_lens = calculate_sequence_lens( + self._nitems_per_input, + self.file_pattern, + self._concat_dim, + self._inputs_chunks, + metadata_cache=self.metadata_cache, + ) + assert isinstance(self.target, FSSpecTarget) # TODO(mypy): check optional + store_chunk( + chunk_key=chunk_key, + target=self.target, + concat_dim=self._concat_dim, + chunks_inputs=self._chunks_inputs, + nitems_per_input=self._nitems_per_input, + file_pattern=self.file_pattern, + input_sequence_lens=input_sequence_lens, + concat_dim_chunks=self._concat_dim_chunks, + lock_timeout=self.lock_timeout, + xarray_concat_kwargs=self.xarray_concat_kwargs, + xarray_open_kwargs=self.xarray_open_kwargs, + process_chunk=self.process_chunk, + target_chunks=self.target_chunks, + input_cache=self.input_cache, + cache_inputs=self.cache_inputs, + copy_input_to_local_file=self.copy_input_to_local_file, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + ) @property # type: ignore @closure def finalize_target(self) -> None: - if self.target is None: - raise ValueError("target has not been set.") - if self.consolidate_zarr: - logger.info("Consolidating Zarr metadata") - target_mapper = self.target.get_mapper() - zarr.consolidate_metadata(target_mapper) - - @contextmanager - def open_input(self, input_key: InputKey): - fname = self.file_pattern[input_key] - logger.info(f"Opening input with Xarray {input_key}: '{fname}'") - cache = self.input_cache if self.cache_inputs else None - with file_opener(fname, cache=cache, copy_to_local=self.copy_input_to_local_file) as f: - with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler - logger.debug(f"about to call xr.open_dataset on {f}") - kw = self.xarray_open_kwargs.copy() - if "engine" not in kw: - kw["engine"] = "h5netcdf" - ds = xr.open_dataset(f, **kw) - logger.debug("successfully opened dataset") - ds = fix_scalar_attr_encoding(ds) - - if self.delete_input_encoding: - for var in ds.variables: - ds[var].encoding = {} - - if self.process_input is not None: - ds = self.process_input(ds, str(fname)) - - logger.debug(f"{ds}") - yield ds - - def cache_input_metadata(self, input_key: InputKey): - if self.metadata_cache is None: - raise ValueError("metadata_cache is not set.") - logger.info(f"Caching metadata for input '{input_key}'") - with self.open_input(input_key) as ds: - input_metadata = ds.to_dict(data=False) - self.metadata_cache[_input_metadata_fname(input_key)] = input_metadata - - @contextmanager - def open_chunk(self, chunk_key: ChunkKey): - logger.info(f"Opening inputs for chunk {chunk_key}") - inputs = self._chunks_inputs[chunk_key] - - # need to open an unknown number of contexts at the same time - with ExitStack() as stack: - dsets = [stack.enter_context(self.open_input(i)) for i in inputs] - # explicitly chunking prevents eager evaluation during concat - dsets = [ds.chunk() for ds in dsets] - logger.info(f"Combining inputs for chunk '{chunk_key}'") - if len(dsets) > 1: - # During concat, attributes and encoding are taken from the first dataset - # https://github.com/pydata/xarray/issues/1614 - with dask.config.set( - scheduler="single-threaded" - ): # make sure we don't use a scheduler - ds = xr.concat(dsets, self._concat_dim, **self.xarray_concat_kwargs) - elif len(dsets) == 1: - ds = dsets[0] - else: # pragma: no cover - assert False, "Should never happen" - - if self.process_chunk is not None: - with dask.config.set( - scheduler="single-threaded" - ): # make sure we don't use a scheduler - ds = self.process_chunk(ds) - - with dask.config.set(scheduler="single-threaded"): # make sure we don't use a scheduler - logger.debug(f"{ds}") - - # TODO: maybe do some chunking here? - yield ds - - def open_target(self): - target_mapper = self.target.get_mapper() - return xr.open_zarr(target_mapper) - - def expand_target_dim(self, dim, dimsize): - target_mapper = self.target.get_mapper() - zgroup = zarr.open_group(target_mapper) - ds = self.open_target() - sequence_axes = {v: ds[v].get_axis_num(dim) for v in ds.variables if dim in ds[v].dims} - - for v, axis in sequence_axes.items(): - arr = zgroup[v] - shape = list(arr.shape) - shape[axis] = dimsize - logger.debug(f"resizing array {v} to shape {shape}") - arr.resize(shape) - - # now explicity write the sequence coordinate to avoid missing data - # when reopening - if dim in zgroup: - zgroup[dim][:] = 0 + assert isinstance(self.finalize_target, FSSpecTarget) # TODO(mypy): check optional + return finalize_target(self.target, self.consolidate_zarr) def iter_inputs(self): for input in self._inputs_chunks: yield input - def region_and_conflicts_for_chunk(self, chunk_key: ChunkKey): - # return a dict suitable to pass to xr.to_zarr(region=...) - # specifies where in the overall array to put this chunk's data - # also return the conflicts with other chunks - - input_keys = self._chunks_inputs[chunk_key] - - if self._nitems_per_input: - input_sequence_lens = (self._nitems_per_input,) * self.file_pattern.dims[ - self._concat_dim # type: ignore - ] - else: - if self.metadata_cache is None: - raise ValueError("metadata_cache is not set.") - global_metadata = self.metadata_cache[_GLOBAL_METADATA_KEY] - input_sequence_lens = global_metadata["input_sequence_lens"] - - chunk_bounds, all_chunk_conflicts = chunk_bounds_and_conflicts( - input_sequence_lens, self._concat_dim_chunks # type: ignore - ) - input_positions = [self.input_position(input_key) for input_key in input_keys] - start = chunk_bounds[min(input_positions)] - stop = chunk_bounds[max(input_positions) + 1] - - this_chunk_conflicts = set() - for k in input_keys: - # for multi-variable recipes, the confilcts will usually be the same - # for each variable. using a set avoids duplicate locks - for input_conflict in all_chunk_conflicts[self.input_position(k)]: - this_chunk_conflicts.add(input_conflict) - region_slice = slice(start, stop) - return {self._concat_dim: region_slice}, this_chunk_conflicts - def iter_chunks(self): for k in self._chunks_inputs: yield k - def get_input_meta(self, *input_keys: Sequence[InputKey]) -> Dict: - # getitems should be async; much faster than serial calls - if self.metadata_cache is None: - raise ValueError("metadata_cache is not set.") - return self.metadata_cache.getitems([_input_metadata_fname(k) for k in input_keys]) - - def input_position(self, input_key): - # returns the index position of an input key wrt the concat_dim - concat_dim_axis = list(self.file_pattern.dims).index(self._concat_dim) - return input_key[concat_dim_axis] - - def calculate_sequence_lens(self): - if self._nitems_per_input: - return list((self._nitems_per_input,) * self.file_pattern.dims[self._concat_dim]) - - # read per-input metadata; this is distinct from global metadata - # get the sequence length of every file - # this line could become problematic for large (> 10_000) lists of files - input_meta = self.get_input_meta(*self._inputs_chunks) - # use a numpy array to allow reshaping - all_lens = np.array([m["dims"][self._concat_dim] for m in input_meta.values()]) - all_lens.shape = list(self.file_pattern.dims.values()) - # check that all lens are the same along the concat dim - concat_dim_axis = list(self.file_pattern.dims).index(self._concat_dim) - selector = [slice(0, 1)] * len(self.file_pattern.dims) - selector[concat_dim_axis] = slice(None) # this should broadcast correctly agains all_lens - sequence_lens = all_lens[tuple(selector)] - if not (all_lens == sequence_lens).all(): - raise ValueError(f"Inconsistent sequence lengths found: f{all_lens}") - return sequence_lens.squeeze().tolist() - def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: """Convenience function for users to introspect recipe.""" return self._chunks_inputs[chunk_key] From a835911c7d3c6b6c505ec246d34814b2557d2964 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 15 Jun 2021 13:06:53 -0500 Subject: [PATCH 02/23] wip - refactor --- pangeo_forge_recipes/recipes/xarray_zarr.py | 105 ++++++++++++-------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 173f44e1..1a478289 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -670,7 +670,6 @@ def _set_target_chunks(self): @property def _prepare_target(self): func = prepare_target - args = () kwargs = dict( target=self.target, target_chunks=self.target_chunks, @@ -691,35 +690,40 @@ def _prepare_target(self): process_input=self.process_input, metadata_cache=self.metadata_cache, ) - return func, args, kwargs + return func, kwargs @property # type: ignore @closure def prepare_target(self) -> None: - func, args, kwargs = self._prepare_target - return func(*args, **kwargs) + func, kwargs = self._prepare_target + return func(**kwargs) - @property # type: ignore - @closure - def cache_input(self, input_key: InputKey) -> None: # type: ignore - cache_input( - input_key, - cache_inputs=self.cache_inputs, - input_cache=self.input_cache, - file_pattern=self.file_pattern, - fsspec_open_kwargs=self.fsspec_open_kwargs, - cache_metadata=self._cache_metadata, - copy_input_to_local_file=self.copy_input_to_local_file, - xarray_open_kwargs=self.xarray_open_kwargs, - delete_input_encoding=self.delete_input_encoding, - process_input=self.process_input, - metadata_cache=self.metadata_cache, + @property + def _cache_input(self): + return ( + cache_input, + dict( + cache_inputs=self.cache_inputs, + input_cache=self.input_cache, + file_pattern=self.file_pattern, + fsspec_open_kwargs=self.fsspec_open_kwargs, + cache_metadata=self._cache_metadata, + copy_input_to_local_file=self.copy_input_to_local_file, + xarray_open_kwargs=self.xarray_open_kwargs, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + metadata_cache=self.metadata_cache, + ), ) @property # type: ignore @closure - def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore - # TODO(TOM): Restore the cache lookup + def cache_input(self, input_key: InputKey) -> None: # type: ignore + func, kwargs = self._cache_input + return func(input_key, **kwargs) + + @property + def _store_chunk(self): input_sequence_lens = calculate_sequence_lens( self._nitems_per_input, self.file_pattern, @@ -727,33 +731,48 @@ def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore self._inputs_chunks, metadata_cache=self.metadata_cache, ) - assert isinstance(self.target, FSSpecTarget) # TODO(mypy): check optional - store_chunk( - chunk_key=chunk_key, - target=self.target, - concat_dim=self._concat_dim, - chunks_inputs=self._chunks_inputs, - nitems_per_input=self._nitems_per_input, - file_pattern=self.file_pattern, - input_sequence_lens=input_sequence_lens, - concat_dim_chunks=self._concat_dim_chunks, - lock_timeout=self.lock_timeout, - xarray_concat_kwargs=self.xarray_concat_kwargs, - xarray_open_kwargs=self.xarray_open_kwargs, - process_chunk=self.process_chunk, - target_chunks=self.target_chunks, - input_cache=self.input_cache, - cache_inputs=self.cache_inputs, - copy_input_to_local_file=self.copy_input_to_local_file, - delete_input_encoding=self.delete_input_encoding, - process_input=self.process_input, + + return ( + store_chunk, + dict( + target=self.target, + concat_dim=self._concat_dim, + chunks_inputs=self._chunks_inputs, + nitems_per_input=self._nitems_per_input, + file_pattern=self.file_pattern, + input_sequence_lens=input_sequence_lens, + concat_dim_chunks=self._concat_dim_chunks, + lock_timeout=self.lock_timeout, + xarray_concat_kwargs=self.xarray_concat_kwargs, + xarray_open_kwargs=self.xarray_open_kwargs, + process_chunk=self.process_chunk, + target_chunks=self.target_chunks, + input_cache=self.input_cache, + cache_inputs=self.cache_inputs, + copy_input_to_local_file=self.copy_input_to_local_file, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + ), ) + @property # type: ignore + @closure + def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore + # TODO(TOM): Restore the cache lookup + assert isinstance(self.target, FSSpecTarget) # TODO(mypy): check optional + func, kwargs = self._store_chunk + func(chunk_key, **kwargs) + + @property + def _finalize_target(self): + return finalize_target, dict(target=self.target, consolidate_zarr=self.consolidate_zarr) + @property # type: ignore @closure def finalize_target(self) -> None: - assert isinstance(self.finalize_target, FSSpecTarget) # TODO(mypy): check optional - return finalize_target(self.target, self.consolidate_zarr) + func, kwargs = self._finalize_target + # assert isinstance(self.finalize_target, FSSpecTarget) # TODO(mypy): check optional + return func(**kwargs) def iter_inputs(self): for input in self._inputs_chunks: From ee263242ac4566e4590674b681ac9d887b88db9b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 15 Jun 2021 14:37:51 -0500 Subject: [PATCH 03/23] fixup --- pangeo_forge_recipes/recipes/xarray_zarr.py | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 1a478289..0acf297d 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -2,6 +2,7 @@ A Pangeo Forge Recipe """ +import functools import logging import warnings from contextlib import ExitStack, contextmanager @@ -13,6 +14,7 @@ import numpy as np import xarray as xr import zarr +from dask.delayed import Delayed from ..patterns import FilePattern, prune_pattern from ..storage import AbstractTarget, CacheFSSpecTarget, FSSpecTarget, MetadataTarget, file_opener @@ -785,3 +787,74 @@ def iter_chunks(self): def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: """Convenience function for users to introspect recipe.""" return self._chunks_inputs[chunk_key] + + def to_dask(self): + # --------------------- Cache Input ----------------------- + cache_input, kwargs = self._cache_input + cache_input_ = functools.partial(cache_input, **kwargs) + + dsk = {} + + for i, input_key in enumerate(self.iter_inputs()): + dsk[("cache_input", i)] = (cache_input_, input_key) + dsk["checkpoint-0"] = (lambda *args: None, list(dsk)) + + # --------------------- Prepare Target -------------------- + prepare_target, kwargs = self._prepare_target + prepare_target2 = lambda checkpoint, **kwargs_: prepare_target(**kwargs_) + prepare_target_ = functools.partial(prepare_target2, **kwargs) + + # TODO: these should use a token + dsk["prepare_target"] = (prepare_target_, "checkpoint-0") + + # --------------------- Store Chunk ----------------------- + store_chunk, kwargs = self._store_chunk + store_chunk2 = lambda _, input_key, **kwargs_: store_chunk(input_key, **kwargs_) + store_chunk_ = functools.partial(store_chunk2) + + keys = [] + for i, input_key in enumerate(self.iter_inputs()): + k = ("store_chunk", i) + dsk[k] = (store_chunk_, input_key, "prepare_target") + keys.append(k) + + dsk["checkpoint-1"] = (lambda *args: None, keys) + + finalize_target, kwargs = self._finalize_target + finalize_target2 = lambda checkpoint, **kwargs_: finalize_target(**kwargs_) + finalize_target_ = functools.partial(finalize_target2, **kwargs) + token = dask.base.tokenize(self) + key = f"finalize_target-{token}" + dsk[key] = (finalize_target_, "checkpoint-1") + + return Delayed(key, dsk) + + def to_prefect(self): + """Compile the recipe to a Prefect.Flow object.""" + from prefect import Flow, task, unmapped + + cache_input, kwargs = self._cache_input + cache_input_ = functools.partial(cache_input, **kwargs) + cache_input_task = task(cache_input_, name="cache_input") + + prepare_target, kwargs = self._prepare_target + prepare_target_ = functools.partial(prepare_target, **kwargs) + prepare_target_task = task(prepare_target_, name="prepare_target") + + store_chunk, kwargs = self._store_chunk + store_chunk_ = functools.partial(store_chunk, **kwargs) + store_chunk_task = task(store_chunk_, name="store_chunk") + + finalize_target, kwargs = self._finalize_target + finalize_target_ = functools.partial(finalize_target, **kwargs) + finalize_target_task = task(finalize_target_, name="finalize_target") + + with Flow("pangeo-forge-recipe") as flow: + cache_task = cache_input_task.map(input_key=list(self.iter_inputs())) + prepare_task = prepare_target_task(upstream_tasks=[cache_task]) + store_task = store_chunk_task.map( + chunk_key=list(self.iter_chunks()), upstream_tasks=[unmapped(prepare_task)], + ) + _ = finalize_target_task(upstream_tasks=[store_task]) + + return flow From d8ca1d0bbdab60c82bfc4b993c29b40b9f8d0e32 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 15 Jun 2021 20:39:39 -0500 Subject: [PATCH 04/23] fixup --- pangeo_forge_recipes/recipes/xarray_zarr.py | 150 +++++++++----------- tests/conftest.py | 27 ++-- 2 files changed, 80 insertions(+), 97 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 0acf297d..5b73eba4 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -110,6 +110,7 @@ def cache_input_metadata( process_input=process_input, ) as ds: input_metadata = ds.to_dict(data=False) + # TODO(METADATA): set metadata_cache[_input_metadata_fname(input_key)] = input_metadata @@ -294,6 +295,7 @@ def get_input_meta(metadata_cache: Optional[MetadataTarget], *input_keys: InputK # getitems should be async; much faster than serial calls if metadata_cache is None: raise ValueError("metadata_cache is not set.") + # TODO(METADATA): get return metadata_cache.getitems([_input_metadata_fname(k) for k in input_keys]) @@ -435,7 +437,6 @@ def store_chunk( chunks_inputs: Dict[ChunkKey, Tuple[InputKey]], nitems_per_input: Optional[int], file_pattern: FilePattern, - input_sequence_lens, concat_dim_chunks: Optional[int], lock_timeout: Optional[int], xarray_concat_kwargs: dict, @@ -447,9 +448,20 @@ def store_chunk( xarray_open_kwargs: dict, delete_input_encoding: bool, process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], + inputs_chunks: Dict[InputKey, Tuple[ChunkKey]], + metadata_cache: Optional[MetadataTarget], ) -> None: if target is None: raise ValueError("target has not been set.") + + input_sequence_lens = calculate_sequence_lens( + nitems_per_input=nitems_per_input, + file_pattern=file_pattern, + concat_dim=concat_dim, + inputs_chunks=inputs_chunks, + metadata_cache=metadata_cache, + ) + with open_chunk( chunk_key=chunk_key, chunks_inputs=chunks_inputs, @@ -671,8 +683,8 @@ def _set_target_chunks(self): @property def _prepare_target(self): - func = prepare_target - kwargs = dict( + return functools.partial( + prepare_target, target=self.target, target_chunks=self.target_chunks, init_chunks=self._init_chunks, @@ -692,69 +704,55 @@ def _prepare_target(self): process_input=self.process_input, metadata_cache=self.metadata_cache, ) - return func, kwargs @property # type: ignore @closure def prepare_target(self) -> None: - func, kwargs = self._prepare_target - return func(**kwargs) + return self._prepare_target() @property def _cache_input(self): - return ( + return functools.partial( cache_input, - dict( - cache_inputs=self.cache_inputs, - input_cache=self.input_cache, - file_pattern=self.file_pattern, - fsspec_open_kwargs=self.fsspec_open_kwargs, - cache_metadata=self._cache_metadata, - copy_input_to_local_file=self.copy_input_to_local_file, - xarray_open_kwargs=self.xarray_open_kwargs, - delete_input_encoding=self.delete_input_encoding, - process_input=self.process_input, - metadata_cache=self.metadata_cache, - ), + cache_inputs=self.cache_inputs, + input_cache=self.input_cache, + file_pattern=self.file_pattern, + fsspec_open_kwargs=self.fsspec_open_kwargs, + cache_metadata=self._cache_metadata, + copy_input_to_local_file=self.copy_input_to_local_file, + xarray_open_kwargs=self.xarray_open_kwargs, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + metadata_cache=self.metadata_cache, ) @property # type: ignore @closure def cache_input(self, input_key: InputKey) -> None: # type: ignore - func, kwargs = self._cache_input - return func(input_key, **kwargs) + return self._cache_input(input_key) @property def _store_chunk(self): - input_sequence_lens = calculate_sequence_lens( - self._nitems_per_input, - self.file_pattern, - self._concat_dim, - self._inputs_chunks, - metadata_cache=self.metadata_cache, - ) - - return ( + return functools.partial( store_chunk, - dict( - target=self.target, - concat_dim=self._concat_dim, - chunks_inputs=self._chunks_inputs, - nitems_per_input=self._nitems_per_input, - file_pattern=self.file_pattern, - input_sequence_lens=input_sequence_lens, - concat_dim_chunks=self._concat_dim_chunks, - lock_timeout=self.lock_timeout, - xarray_concat_kwargs=self.xarray_concat_kwargs, - xarray_open_kwargs=self.xarray_open_kwargs, - process_chunk=self.process_chunk, - target_chunks=self.target_chunks, - input_cache=self.input_cache, - cache_inputs=self.cache_inputs, - copy_input_to_local_file=self.copy_input_to_local_file, - delete_input_encoding=self.delete_input_encoding, - process_input=self.process_input, - ), + target=self.target, + concat_dim=self._concat_dim, + chunks_inputs=self._chunks_inputs, + nitems_per_input=self._nitems_per_input, + file_pattern=self.file_pattern, + concat_dim_chunks=self._concat_dim_chunks, + lock_timeout=self.lock_timeout, + xarray_concat_kwargs=self.xarray_concat_kwargs, + xarray_open_kwargs=self.xarray_open_kwargs, + process_chunk=self.process_chunk, + target_chunks=self.target_chunks, + input_cache=self.input_cache, + cache_inputs=self.cache_inputs, + copy_input_to_local_file=self.copy_input_to_local_file, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + inputs_chunks=self._inputs_chunks, + metadata_cache=self.metadata_cache, ) @property # type: ignore @@ -762,19 +760,19 @@ def _store_chunk(self): def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore # TODO(TOM): Restore the cache lookup assert isinstance(self.target, FSSpecTarget) # TODO(mypy): check optional - func, kwargs = self._store_chunk - func(chunk_key, **kwargs) + return self._store_chunk(chunk_key) @property def _finalize_target(self): - return finalize_target, dict(target=self.target, consolidate_zarr=self.consolidate_zarr) + return functools.partial( + finalize_target, target=self.target, consolidate_zarr=self.consolidate_zarr + ) @property # type: ignore @closure def finalize_target(self) -> None: - func, kwargs = self._finalize_target # assert isinstance(self.finalize_target, FSSpecTarget) # TODO(mypy): check optional - return func(**kwargs) + return self._finalize_target() def iter_inputs(self): for input in self._inputs_chunks: @@ -790,42 +788,33 @@ def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: def to_dask(self): # --------------------- Cache Input ----------------------- - cache_input, kwargs = self._cache_input - cache_input_ = functools.partial(cache_input, **kwargs) - dsk = {} for i, input_key in enumerate(self.iter_inputs()): - dsk[("cache_input", i)] = (cache_input_, input_key) + dsk[("cache_input", i)] = (self._cache_input, input_key) dsk["checkpoint-0"] = (lambda *args: None, list(dsk)) # --------------------- Prepare Target -------------------- - prepare_target, kwargs = self._prepare_target - prepare_target2 = lambda checkpoint, **kwargs_: prepare_target(**kwargs_) - prepare_target_ = functools.partial(prepare_target2, **kwargs) + prepare_target2 = lambda checkpoint: self._prepare_target() # TODO: these should use a token - dsk["prepare_target"] = (prepare_target_, "checkpoint-0") + dsk["prepare_target"] = (prepare_target2, "checkpoint-0") # --------------------- Store Chunk ----------------------- - store_chunk, kwargs = self._store_chunk - store_chunk2 = lambda _, input_key, **kwargs_: store_chunk(input_key, **kwargs_) - store_chunk_ = functools.partial(store_chunk2) + store_chunk2 = lambda checkpoint, input_key: self._store_chunk(input_key) keys = [] - for i, input_key in enumerate(self.iter_inputs()): + for i, chunk_key in enumerate(self.iter_chunks()): k = ("store_chunk", i) - dsk[k] = (store_chunk_, input_key, "prepare_target") + dsk[k] = (store_chunk2, "prepare_target", chunk_key) keys.append(k) dsk["checkpoint-1"] = (lambda *args: None, keys) - finalize_target, kwargs = self._finalize_target - finalize_target2 = lambda checkpoint, **kwargs_: finalize_target(**kwargs_) - finalize_target_ = functools.partial(finalize_target2, **kwargs) + finalize_target2 = lambda checkpoint, **kwargs_: self._finalize_target() token = dask.base.tokenize(self) key = f"finalize_target-{token}" - dsk[key] = (finalize_target_, "checkpoint-1") + dsk[key] = (finalize_target2, "checkpoint-1") return Delayed(key, dsk) @@ -833,21 +822,10 @@ def to_prefect(self): """Compile the recipe to a Prefect.Flow object.""" from prefect import Flow, task, unmapped - cache_input, kwargs = self._cache_input - cache_input_ = functools.partial(cache_input, **kwargs) - cache_input_task = task(cache_input_, name="cache_input") - - prepare_target, kwargs = self._prepare_target - prepare_target_ = functools.partial(prepare_target, **kwargs) - prepare_target_task = task(prepare_target_, name="prepare_target") - - store_chunk, kwargs = self._store_chunk - store_chunk_ = functools.partial(store_chunk, **kwargs) - store_chunk_task = task(store_chunk_, name="store_chunk") - - finalize_target, kwargs = self._finalize_target - finalize_target_ = functools.partial(finalize_target, **kwargs) - finalize_target_task = task(finalize_target_, name="finalize_target") + cache_input_task = task(self._cache_input, name="cache_input") + prepare_target_task = task(self._prepare_target, name="prepare_target") + store_chunk_task = task(self._store_chunk, name="store_chunk") + finalize_target_task = task(self._finalize_target, name="finalize_target") with Flow("pangeo-forge-recipe") as flow: cache_task = cache_input_task.map(input_key=list(self.iter_inputs())) diff --git a/tests/conftest.py b/tests/conftest.py index 9850cbb2..f41705e3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -289,19 +289,24 @@ def execute(rec): pipeline = rec.to_pipelines() plan = ex.pipelines_to_plan(pipeline) - if request.param == "dask": - client = Client(dask_cluster) - - if request.param == "prefect-dask": - from prefect.executors import DaskExecutor - - prefect_executor = DaskExecutor(address=dask_cluster.scheduler_address) - plan.run(executor=prefect_executor) + if "prefect" in request.param: + flow = rec.to_prefect() + + if request.param == "prefect-dask": + from prefect.executors import DaskExecutor + + prefect_executor = DaskExecutor(address=dask_cluster.scheduler_address) + else: + prefect_executor = None + + flow.run(executor=prefect_executor) + elif request.param == "dask": + # import dask; dask.config.set(scheduler="single-threaded") + with Client(dask_cluster): + plan = rec.to_dask() + plan.compute() else: ex.execute_plan(plan) - if request.param == "dask": - client.close() - del client execute.param = request.param return execute From 75b6d19fb875578600d830255d6f4926698f7196 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 15 Jun 2021 20:52:52 -0500 Subject: [PATCH 05/23] wip - refactor --- pangeo_forge_recipes/recipes/xarray_zarr.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 5b73eba4..54b0f749 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -789,32 +789,33 @@ def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: def to_dask(self): # --------------------- Cache Input ----------------------- dsk = {} + token = dask.base.tokenize(self) + # TODO: HighlevelGraph layers for each of these mapped inputs. for i, input_key in enumerate(self.iter_inputs()): - dsk[("cache_input", i)] = (self._cache_input, input_key) - dsk["checkpoint-0"] = (lambda *args: None, list(dsk)) + dsk[(f"cache_input-{token}", i)] = (self._cache_input, input_key) + dsk[f"checkpoint_0-{token}"] = (lambda *args: None, list(dsk)) # --------------------- Prepare Target -------------------- prepare_target2 = lambda checkpoint: self._prepare_target() # TODO: these should use a token - dsk["prepare_target"] = (prepare_target2, "checkpoint-0") + dsk[f"prepare_target-{token}"] = (prepare_target2, f"checkpoint_0-{token}") # --------------------- Store Chunk ----------------------- store_chunk2 = lambda checkpoint, input_key: self._store_chunk(input_key) keys = [] for i, chunk_key in enumerate(self.iter_chunks()): - k = ("store_chunk", i) - dsk[k] = (store_chunk2, "prepare_target", chunk_key) + k = (f"store_chunk-{token}", i) + dsk[k] = (store_chunk2, f"prepare_target-{token}", chunk_key) keys.append(k) - dsk["checkpoint-1"] = (lambda *args: None, keys) + dsk[f"checkpoint_1-{token}"] = (lambda *args: None, keys) finalize_target2 = lambda checkpoint, **kwargs_: self._finalize_target() - token = dask.base.tokenize(self) key = f"finalize_target-{token}" - dsk[key] = (finalize_target2, "checkpoint-1") + dsk[key] = (finalize_target2, f"checkpoint_1-{token}") return Delayed(key, dsk) From 064b4584b6e5d09fbf32062002b24f70e4a43097 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 16 Jun 2021 06:23:31 -0500 Subject: [PATCH 06/23] wip - refactor --- pangeo_forge_recipes/recipes/xarray_zarr.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 54b0f749..420ed441 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -787,7 +787,7 @@ def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: return self._chunks_inputs[chunk_key] def to_dask(self): - # --------------------- Cache Input ----------------------- + # Cache Input -------------------------------------------------------- dsk = {} token = dask.base.tokenize(self) @@ -796,14 +796,15 @@ def to_dask(self): dsk[(f"cache_input-{token}", i)] = (self._cache_input, input_key) dsk[f"checkpoint_0-{token}"] = (lambda *args: None, list(dsk)) - # --------------------- Prepare Target -------------------- - prepare_target2 = lambda checkpoint: self._prepare_target() + # Prepare Target ----------------------------------------------------- + def prepare_target2(checkpoint): + return self._prepare_target() - # TODO: these should use a token dsk[f"prepare_target-{token}"] = (prepare_target2, f"checkpoint_0-{token}") - # --------------------- Store Chunk ----------------------- - store_chunk2 = lambda checkpoint, input_key: self._store_chunk(input_key) + # Store Chunk -------------------------------------------------------- + def store_chunk2(checkpoint, input_key): + return self._store_chunk(input_key) keys = [] for i, chunk_key in enumerate(self.iter_chunks()): @@ -813,7 +814,10 @@ def to_dask(self): dsk[f"checkpoint_1-{token}"] = (lambda *args: None, keys) - finalize_target2 = lambda checkpoint, **kwargs_: self._finalize_target() + # Finalize Target ---------------------------------------------------- + def finalize_target2(checkpoint): + return self._finalize_target() + key = f"finalize_target-{token}" dsk[key] = (finalize_target2, f"checkpoint_1-{token}") From a668516510e12a557c7fb46b15b1f41321126c93 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 16 Jun 2021 06:33:29 -0500 Subject: [PATCH 07/23] wip - refactor --- pangeo_forge_recipes/recipes/xarray_zarr.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 420ed441..4f790aa9 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -48,10 +48,6 @@ def _chunk_metadata_fname(chunk_key) -> str: ChunkKey = Tuple[int] InputKey = Tuple[int] -# Notes about dataclasses: -# - https://www.python.org/dev/peps/pep-0557/#inheritance -# - https://stackoverflow.com/questions/51575931/class-inheritance-in-python-3-7-dataclasses - def expand_target_dim(target: FSSpecTarget, concat_dim: Optional[str], dimsize: int) -> None: target_mapper = target.get_mapper() @@ -526,6 +522,11 @@ def finalize_target(target: FSSpecTarget, consolidate_zarr: bool) -> None: zarr.consolidate_metadata(target_mapper) +# Notes about dataclasses: +# - https://www.python.org/dev/peps/pep-0557/#inheritance +# - https://stackoverflow.com/questions/51575931/class-inheritance-in-python-3-7-dataclasses + + @dataclass class XarrayZarrRecipe(BaseRecipe): """This class represents a dataset composed of many individual NetCDF files. @@ -681,6 +682,16 @@ def _set_target_chunks(self): else: self._concat_dim_chunks = self._nitems_per_input * self.inputs_per_chunk + # Each stage of the recipe follows the same pattern: + # 1. A top-level function, e.g. `prepare_target`, that does the actual work. + # 2. A private property, e.g. `._prepare_target`, that builds a partially applied function, + # accepting just the arguments needed (e.g. a chunk_key). + # 3. A public property, e.g. `.prepare_target`, that calls the partially applied function + # with the provided arguments (e.g. a chunk_key) + # This ensures that the actual function objects shipped to and executed on + # workers do not contain any references to the `recipe` object itself, which is complicated + # to serialize. + @property def _prepare_target(self): return functools.partial( From 58c9f53725f5dd7847741f44767393f91282b0c9 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 16 Jun 2021 06:42:36 -0500 Subject: [PATCH 08/23] wip - refactor --- pangeo_forge_recipes/recipes/xarray_zarr.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 4f790aa9..c482717e 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -798,11 +798,16 @@ def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: return self._chunks_inputs[chunk_key] def to_dask(self): + """Convert the Recipe to a dask.delayed.Delayed object.""" + # This manually builds a Dask task graph with each stage of the recipe. + # We use a few "checkpoints" to ensure that downstream tasks depend + # on upstream tasks being done before starting. + + # TODO: HighlevelGraph layers for each of these mapped inputs. # Cache Input -------------------------------------------------------- dsk = {} token = dask.base.tokenize(self) - # TODO: HighlevelGraph layers for each of these mapped inputs. for i, input_key in enumerate(self.iter_inputs()): dsk[(f"cache_input-{token}", i)] = (self._cache_input, input_key) dsk[f"checkpoint_0-{token}"] = (lambda *args: None, list(dsk)) From f8eb378bb3910d95ec58f94a5c255d77a34931e5 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 16 Jun 2021 06:50:45 -0500 Subject: [PATCH 09/23] fix fsspec target class --- pangeo_forge_recipes/recipes/xarray_zarr.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index c482717e..a0fac6c4 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -17,7 +17,7 @@ from dask.delayed import Delayed from ..patterns import FilePattern, prune_pattern -from ..storage import AbstractTarget, CacheFSSpecTarget, FSSpecTarget, MetadataTarget, file_opener +from ..storage import AbstractTarget, CacheFSSpecTarget, MetadataTarget, file_opener from ..utils import ( chunk_bounds_and_conflicts, chunked_iterable, @@ -49,7 +49,7 @@ def _chunk_metadata_fname(chunk_key) -> str: InputKey = Tuple[int] -def expand_target_dim(target: FSSpecTarget, concat_dim: Optional[str], dimsize: int) -> None: +def expand_target_dim(target: CacheFSSpecTarget, concat_dim: Optional[str], dimsize: int) -> None: target_mapper = target.get_mapper() zgroup = zarr.open_group(target_mapper) ds = open_target(target) @@ -70,7 +70,7 @@ def expand_target_dim(target: FSSpecTarget, concat_dim: Optional[str], dimsize: zgroup[concat_dim][:] = 0 -def open_target(target: FSSpecTarget) -> xr.Dataset: +def open_target(target: CacheFSSpecTarget) -> xr.Dataset: return xr.open_zarr(target.get_mapper()) @@ -325,7 +325,7 @@ def calculate_sequence_lens( def prepare_target( - target: FSSpecTarget, + target: CacheFSSpecTarget, target_chunks: Dict[str, int], init_chunks: List[ChunkKey], concat_dim: Optional[str], @@ -428,7 +428,7 @@ def prepare_target( def store_chunk( chunk_key: ChunkKey, - target: FSSpecTarget, + target: CacheFSSpecTarget, concat_dim: Optional[str], chunks_inputs: Dict[ChunkKey, Tuple[InputKey]], nitems_per_input: Optional[int], @@ -513,7 +513,7 @@ def store_chunk( zarr_array[zarr_region] = data -def finalize_target(target: FSSpecTarget, consolidate_zarr: bool) -> None: +def finalize_target(target: CacheFSSpecTarget, consolidate_zarr: bool) -> None: if target is None: raise ValueError("target has not been set.") if consolidate_zarr: @@ -770,7 +770,7 @@ def _store_chunk(self): @closure def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore # TODO(TOM): Restore the cache lookup - assert isinstance(self.target, FSSpecTarget) # TODO(mypy): check optional + assert isinstance(self.target, CacheFSSpecTarget) # TODO(mypy): check optional return self._store_chunk(chunk_key) @property @@ -782,7 +782,7 @@ def _finalize_target(self): @property # type: ignore @closure def finalize_target(self) -> None: - # assert isinstance(self.finalize_target, FSSpecTarget) # TODO(mypy): check optional + # assert isinstance(self.finalize_target, CacheFSSpecTarget) # TODO(mypy): check optional return self._finalize_target() def iter_inputs(self): From e70d52662875f8835cc180cb289fc4e6d4445e4a Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 16 Jun 2021 07:56:58 -0500 Subject: [PATCH 10/23] fix fsspec target class --- pangeo_forge_recipes/recipes/xarray_zarr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index a0fac6c4..41d42b35 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -770,7 +770,7 @@ def _store_chunk(self): @closure def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore # TODO(TOM): Restore the cache lookup - assert isinstance(self.target, CacheFSSpecTarget) # TODO(mypy): check optional + # assert isinstance(self.target, CacheFSSpecTarget) # TODO(mypy): check optional return self._store_chunk(chunk_key) @property From f979311030feed52a6dd67ad14eab2a59b589766 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 08:36:34 -0500 Subject: [PATCH 11/23] Pipelines refactor --- pangeo_forge_recipes/recipes/base.py | 83 +++++++++++++++++++++++----- tests/conftest.py | 49 ++++++++-------- 2 files changed, 93 insertions(+), 39 deletions(-) diff --git a/pangeo_forge_recipes/recipes/base.py b/pangeo_forge_recipes/recipes/base.py index 8b61e83b..5ec0e74b 100644 --- a/pangeo_forge_recipes/recipes/base.py +++ b/pangeo_forge_recipes/recipes/base.py @@ -2,8 +2,6 @@ from functools import partial from typing import Callable, Hashable, Iterable -from rechunker.types import MultiStagePipeline, ParallelPipelines, Stage - # How to manually execute a recipe: ### # # t = PangeoForgeTarget() @@ -75,19 +73,70 @@ def finalize_target(self) -> Callable[[], None]: """ pass - def to_pipelines(self) -> ParallelPipelines: - """Translate recipe to pipeline for execution. + def to_function(self) -> Callable[[], None]: + """ + Translate the recipe to a Python function for execution. """ - pipeline = [] # type: MultiStagePipeline - if getattr(self, "cache_inputs", False): # TODO: formalize this contract - pipeline.append(Stage(self.cache_input, list(self.iter_inputs()))) - pipeline.append(Stage(self.prepare_target)) - pipeline.append(Stage(self.store_chunk, list(self.iter_chunks()))) - pipeline.append(Stage(self.finalize_target)) - pipelines = [] # type: ParallelPipelines - pipelines.append(pipeline) - return pipelines + def pipeline(): + # TODO: formalize this contract + if getattr(self, "cache_inputs"): + for input_key in self.iter_inputs(): + self.cache_input(input_key) + self.prepare_target() + for chunk_key in self.iter_chunks(): + self.store_chunk(chunk_key) + self.finalize_target() + + return pipeline + + def to_dask(self): + """ + Translate the recipe to a dask.Delayed object for parallel execution. + """ + import dask + + tasks = [] + if getattr(self, "cache_inputs"): + f = dask.delayed(self.cache_inputs) + for input_key in self.iter_inputs(): + tasks.append(f)(input_key) + + b0 = dask.delayed(_barrier)(*tasks) + b1 = dask.delayed(_wait_and_call)(self.prepare_target, b0) + tasks = [] + f = dask.delayed(_wait_and_call) + for chunk_key in self.iter_chunks(): + tasks.append(f(b1, chunk_key)) + + b2 = dask.delayed(_barrier)(*tasks) + b3 = dask.delayed(_wait_and_call)(self.finalize_target, b2) + return b3 + + def to_prefect(self): + """Compile the recipe to a Prefect.Flow object.""" + from prefect import Flow, task, unmapped + + has_cache_inputs = getattr(self, "cache_inputs") + if has_cache_inputs: + cache_input_task = task(self.cache_input, name="cache_input") + prepare_target_task = task(self.prepare_target, name="prepare_target") + store_chunk_task = task(self.store_chunk, name="store_chunk") + finalize_target_task = task(self.finalize_target, name="finalize_target") + + with Flow("pangeo-forge-recipe") as flow: + if has_cache_inputs: + cache_task = cache_input_task.map(input_key=list(self.iter_inputs())) + upstream_tasks = [cache_task] + else: + upstream_tasks = [] + prepare_task = prepare_target_task(upstream_tasks=upstream_tasks) + store_task = store_chunk_task.map( + chunk_key=list(self.iter_chunks()), upstream_tasks=[unmapped(prepare_task)], + ) + _ = finalize_target_task(upstream_tasks=[store_task]) + + return flow # https://stackoverflow.com/questions/59986413/achieving-multiple-inheritance-using-python-dataclasses def __post_init__(self): @@ -111,3 +160,11 @@ def wrapped(*args, **kwargs): return new_func return wrapped + + +def _barrier(*args): + pass + + +def _wait_and_call(func, b, *args): + return func(*args) diff --git a/tests/conftest.py b/tests/conftest.py index f41705e3..29ca4532 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,6 +10,7 @@ import pytest import xarray as xr from dask.distributed import Client, LocalCluster +from prefect.executors import DaskExecutor from pangeo_forge_recipes import recipes from pangeo_forge_recipes.executors import ( @@ -269,7 +270,6 @@ def redirect_logs(): @pytest.fixture(params=["manual", "python", "dask", "prefect", "prefect-dask"]) def execute_recipe(request, dask_cluster): - if request.param == "manual": def execute(r): @@ -281,32 +281,29 @@ def execute(r): r.store_chunk(chunk_key) r.finalize_target() + elif request.param == "python": + + def execute(recipe): + return recipe.to_function()() + + elif request.param == "dask": + + def execute(recipe): + with Client(dask_cluster): + return recipe.to_dask().compute() + + elif request.param == "prefect": + + def execute(recipe): + return recipe.to_prefect().run() + else: - ExecutorClass = _executors[request.param] - - def execute(rec): - ex = ExecutorClass() - pipeline = rec.to_pipelines() - plan = ex.pipelines_to_plan(pipeline) - - if "prefect" in request.param: - flow = rec.to_prefect() - - if request.param == "prefect-dask": - from prefect.executors import DaskExecutor - - prefect_executor = DaskExecutor(address=dask_cluster.scheduler_address) - else: - prefect_executor = None - - flow.run(executor=prefect_executor) - elif request.param == "dask": - # import dask; dask.config.set(scheduler="single-threaded") - with Client(dask_cluster): - plan = rec.to_dask() - plan.compute() - else: - ex.execute_plan(plan) + assert request.param == "prefect-dask" + + def execute(recipe): + flow = recipe.to_prefect() + executor = DaskExecutor(address=dask_cluster.scheduler_address) + flow.run(executor=executor) execute.param = request.param return execute From 101356095be8b20e7c11c5add027d56340fba625 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 09:36:29 -0500 Subject: [PATCH 12/23] warning for to_pipelines --- pangeo_forge_recipes/recipes/base.py | 21 +++++++++++++++++++++ tests/test_recipes.py | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/pangeo_forge_recipes/recipes/base.py b/pangeo_forge_recipes/recipes/base.py index 5ec0e74b..df51322f 100644 --- a/pangeo_forge_recipes/recipes/base.py +++ b/pangeo_forge_recipes/recipes/base.py @@ -1,7 +1,10 @@ +import warnings from abc import ABC, abstractmethod from functools import partial from typing import Callable, Hashable, Iterable +from rechunker.types import MultiStagePipeline, ParallelPipelines, Stage + # How to manually execute a recipe: ### # # t = PangeoForgeTarget() @@ -73,6 +76,24 @@ def finalize_target(self) -> Callable[[], None]: """ pass + def to_pipelines(self) -> ParallelPipelines: + """Translate recipe to pipeline for execution. + """ + warnings.warn( + "'to_pipelines' is deprecated. Use one of 'to_function', 'to_dask', or " + "'to_prefect' directly instead.", + FutureWarning, + ) + pipeline = [] # type: MultiStagePipeline + if getattr(self, "cache_inputs", False): # TODO: formalize this contract + pipeline.append(Stage(self.cache_input, list(self.iter_inputs()))) + pipeline.append(Stage(self.prepare_target)) + pipeline.append(Stage(self.store_chunk, list(self.iter_chunks()))) + pipeline.append(Stage(self.finalize_target)) + pipelines = [] # type: ParallelPipelines + pipelines.append(pipeline) + return pipelines + def to_function(self) -> Callable[[], None]: """ Translate the recipe to a Python function for execution. diff --git a/tests/test_recipes.py b/tests/test_recipes.py index 9b3a1592..ee4a1376 100644 --- a/tests/test_recipes.py +++ b/tests/test_recipes.py @@ -13,6 +13,13 @@ ] +def test_to_pipelines_warns(netCDFtoZarr_sequential_recipe): + RecipeClass, file_pattern, kwargs, ds_expected, target = netCDFtoZarr_sequential_recipe + rec = RecipeClass(file_pattern, **kwargs) + with pytest.warns(FutureWarning): + rec.to_pipelines() + + @pytest.mark.parametrize("recipe_fixture", all_recipes) def test_recipe(recipe_fixture, execute_recipe): """The basic recipe test. Use this as a template for other tests.""" From e5a0ef0fd7356b79616a013175306c3a82cf9622 Mon Sep 17 00:00:00 2001 From: Ryan Abernathey Date: Wed, 16 Jun 2021 11:19:20 -0400 Subject: [PATCH 13/23] rewrite executor docs; wip (cherry picked from commit 9c39bf77c332474260d0109ae083f4ffec694df7) --- docs/execution.md | 53 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/docs/execution.md b/docs/execution.md index ba060b5a..8eed32aa 100644 --- a/docs/execution.md +++ b/docs/execution.md @@ -39,6 +39,7 @@ recipe.prepare_target() For example, for Zarr targets, this sets up the Zarr group with the necessary arrays and metadata. +This is the most complex step, and the most likely place to get an error. ### Stage 3: Store Chunks @@ -57,43 +58,41 @@ If there is any cleanup or consolidation to be done, it happens here. recipe.finalize_target() ``` -For example, consolidating Zarr metadta happens in the finalize step. +For example, consolidating Zarr metadata happens in the finalize step. -## Execution by Executors +## Compiled Recipes Very large recipes cannot feasibly be executed this way. -To support distributed parallel execution, Pangeo Forge borrows the -[Executors framework from Rechunker](https://rechunker.readthedocs.io/en/latest/executors.html). +Instead, recipes can be _compiled_ to executable objects. +We currently support three types of compilation. -There are currently three executors implemented. -- {class}`pangeo_forge_recipes.executors.PythonPipelineExecutor`: a reference executor - using simple python -- {class}`pangeo_forge_recipes.executors.DaskPipelineExecutor`: distributed executor using Dask -- {class}`pangeo_forge_recipes.executors.PrefectPipelineExecutor`: distributed executor using Prefect +### Python Function -To use an executor, the recipe must first be transformed into a `Pipeline` object. -The full process looks like this: +To convert a recipe to a single python function, use the method `.to_function()`. +For example ```{code-block} python -pipeline = recipe.to_pipelines() -executor = PrefectPipelineExecutor() -plan = executor.pipelines_to_plan(pipeline) -executor.execute_plan(plan) # actually runs the recipe +recipe_func = recipe.to_function() +recipe_func() # actually execute the recipe ``` -## Executors +Note that the python function approach does not support parallel or distributed execution. +It's mostly just a convenience utility. -```{eval-rst} -.. autoclass:: pangeo_forge_recipes.executors.PythonPipelineExecutor - :members: -``` -```{eval-rst} -.. autoclass:: pangeo_forge_recipes.executors.DaskPipelineExecutor - :members: -``` +### Dask Delayed -```{eval-rst} -.. autoclass:: pangeo_forge_recipes.executors.PrefectPipelineExecutor - :members: +You can convert your recipe to a [Dask Delayed](https://docs.dask.org/en/latest/delayed.html) +object using the `.to_dask()` method. For example + +```{code-block} python +delayed = recipe.to_dask() +delayed.compute() ``` + +The `delayed` object can be executed by any of Dask's schedulers, including +cloud and HPC distributed schedulers. + +### Prefect Flow + +TODO... From 70eb8cc90f35f8986f7fc15713c45665047f0e17 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 10:31:00 -0500 Subject: [PATCH 14/23] Added prefect --- docs/execution.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/execution.md b/docs/execution.md index 8eed32aa..8191501d 100644 --- a/docs/execution.md +++ b/docs/execution.md @@ -95,4 +95,12 @@ cloud and HPC distributed schedulers. ### Prefect Flow -TODO... +You can convert your recipe to a [Prefect Flow](https://docs.prefect.io/core/concepts/flows.html) using +the :meth:`BaseRecipe.to_prefect()` method. For example + +```{code-block} python +flow = recipe.to_prefect() +flow.run() +``` + +By default the flow is run using Prefect's [LocalExecutor](https://docs.prefect.io/orchestration/flow_config/executors.html#localexecutor). See [executors](https://docs.prefect.io/orchestration/flow_config/executors.html) for more. From 3b0f294728210ed7d53a41d8bfff1fc6b702ea7d Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 10:50:24 -0500 Subject: [PATCH 15/23] base tests --- pangeo_forge_recipes/recipes/base.py | 20 ++++++--- tests/test_recipes.py | 65 ++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/pangeo_forge_recipes/recipes/base.py b/pangeo_forge_recipes/recipes/base.py index df51322f..b8363759 100644 --- a/pangeo_forge_recipes/recipes/base.py +++ b/pangeo_forge_recipes/recipes/base.py @@ -101,7 +101,7 @@ def to_function(self) -> Callable[[], None]: def pipeline(): # TODO: formalize this contract - if getattr(self, "cache_inputs"): + if getattr(self, "cache_inputs", False): for input_key in self.iter_inputs(): self.cache_input(input_key) self.prepare_target() @@ -118,17 +118,16 @@ def to_dask(self): import dask tasks = [] - if getattr(self, "cache_inputs"): - f = dask.delayed(self.cache_inputs) + if getattr(self, "cache_inputs", False): + f = dask.delayed(self.cache_input) for input_key in self.iter_inputs(): - tasks.append(f)(input_key) + tasks.append(f(input_key)) b0 = dask.delayed(_barrier)(*tasks) b1 = dask.delayed(_wait_and_call)(self.prepare_target, b0) tasks = [] - f = dask.delayed(_wait_and_call) for chunk_key in self.iter_chunks(): - tasks.append(f(b1, chunk_key)) + tasks.append(dask.delayed(_wait_and_call)(self.store_chunk, b1, chunk_key)) b2 = dask.delayed(_barrier)(*tasks) b3 = dask.delayed(_wait_and_call)(self.finalize_target, b2) @@ -138,7 +137,7 @@ def to_prefect(self): """Compile the recipe to a Prefect.Flow object.""" from prefect import Flow, task, unmapped - has_cache_inputs = getattr(self, "cache_inputs") + has_cache_inputs = getattr(self, "cache_inputs", False) if has_cache_inputs: cache_input_task = task(self.cache_input, name="cache_input") prepare_target_task = task(self.prepare_target, name="prepare_target") @@ -159,6 +158,13 @@ def to_prefect(self): return flow + def __iter__(self): + if hasattr(self, "cache_inputs"): + yield self.cache_input, self.iter_inputs() + yield self.prepare_target, [] + yield self.store_chunk, self.iter_chunks() + yield self.finalize_target, [] + # https://stackoverflow.com/questions/59986413/achieving-multiple-inheritance-using-python-dataclasses def __post_init__(self): # just intercept the __post_init__ calls so they diff --git a/tests/test_recipes.py b/tests/test_recipes.py index ee4a1376..61fcebe1 100644 --- a/tests/test_recipes.py +++ b/tests/test_recipes.py @@ -7,6 +7,8 @@ # need to import this way (rather than use pytest.lazy_fixture) to make it work with dask from pytest_lazyfixture import lazy_fixture +from pangeo_forge_recipes.recipes.base import BaseRecipe + all_recipes = [ lazy_fixture("netCDFtoZarr_sequential_recipe"), lazy_fixture("netCDFtoZarr_sequential_multi_variable_recipe"), @@ -177,3 +179,66 @@ def test_lock_timeout(netCDFtoZarr_sequential_recipe, execute_recipe): # if we're using a Dask executor. if execute_recipe.param in {"manual", "python", "prefect"}: assert p.call_args[1]["timeout"] == 1 + + +class MyRecipe(BaseRecipe): + def __init__(self) -> None: + super().__init__() + self.cache = {} + self.target = None + self.finalized = False + self.cache_inputs = True + + @property + def prepare_target(self): + def _(): + self.target = {} + + return _ + + @property + def cache_input(self): + def _(input_key): + self.cache[input_key] = input_key + + return _ + + @property + def store_chunk(self): + def _(chunk_key): + self.target[chunk_key] = self.cache[chunk_key] + + return _ + + @property + def finalize_target(self): + def _(): + self.finalized = True + + return _ + + def iter_inputs(self): + return iter(range(4)) + + def iter_chunks(self): + return iter(range(4)) + + +def test_base_recipe(): + recipe = MyRecipe() + recipe.to_function()() + assert recipe.finalized + assert recipe.target == {i: i for i in range(4)} + + import dask + + dask.config.set(scheduler="single-threaded") + recipe = MyRecipe() + recipe.to_dask().compute() + assert recipe.finalized + assert recipe.target == {i: i for i in range(4)} + + recipe = MyRecipe() + recipe.to_prefect().run() + assert recipe.finalized + assert recipe.target == {i: i for i in range(4)} From 0bfa2b6e83b1859804871c958696e2c9616f7e8b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 11:11:55 -0500 Subject: [PATCH 16/23] Update tutorials --- .gitignore | 3 +++ docs/tutorials/multi_variable_recipe.ipynb | 8 +++----- docs/tutorials/terraclimate.ipynb | 9 +++------ 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index a51b4046..e6fbf035 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,6 @@ dmypy.json # Pyre type checker .pyre/ _version.py + +# tutorials +*.nc diff --git a/docs/tutorials/multi_variable_recipe.ipynb b/docs/tutorials/multi_variable_recipe.ipynb index ae1a2778..a0061c40 100644 --- a/docs/tutorials/multi_variable_recipe.ipynb +++ b/docs/tutorials/multi_variable_recipe.ipynb @@ -2355,10 +2355,8 @@ } ], "source": [ - "from pangeo_forge_recipes.executors import PrefectPipelineExecutor\n", - "executor = PrefectPipelineExecutor()\n", - "flow = executor.pipelines_to_plan(recipe.to_pipelines())\n", - "flow" + "flow = recipe.to_prefect()\n", + "flow.run()" ] }, { @@ -3986,7 +3984,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.8.6" } }, "nbformat": 4, diff --git a/docs/tutorials/terraclimate.ipynb b/docs/tutorials/terraclimate.ipynb index f8a69b76..53d2bb4a 100644 --- a/docs/tutorials/terraclimate.ipynb +++ b/docs/tutorials/terraclimate.ipynb @@ -950,11 +950,8 @@ } ], "source": [ - "from pangeo_forge_recipes.executors import PrefectPipelineExecutor\n", - "pipelines = recipe.to_pipelines()\n", - "executor = PrefectPipelineExecutor()\n", - "plan = executor.pipelines_to_plan(pipelines)\n", - "executor.execute_plan(plan)" + "flow = recipe.to_prefect()\n", + "flow.run()" ] }, { @@ -3144,7 +3141,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.8.6" } }, "nbformat": 4, From 6d190ff5cc87abe296b82498f474688de4f898f9 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 14:09:36 -0500 Subject: [PATCH 17/23] simplify --- pangeo_forge_recipes/recipes/base.py | 59 +++++++++---- pangeo_forge_recipes/recipes/xarray_zarr.py | 95 ++------------------- 2 files changed, 47 insertions(+), 107 deletions(-) diff --git a/pangeo_forge_recipes/recipes/base.py b/pangeo_forge_recipes/recipes/base.py index b8363759..ced7a985 100644 --- a/pangeo_forge_recipes/recipes/base.py +++ b/pangeo_forge_recipes/recipes/base.py @@ -115,23 +115,44 @@ def to_dask(self): """ Translate the recipe to a dask.Delayed object for parallel execution. """ + # This manually builds a Dask task graph with each stage of the recipe. + # We use a few "checkpoints" to ensure that downstream tasks depend + # on upstream tasks being done before starting. We use a manual task + # graph rather than dask.delayed to avoid some expensive tokenization + # in dask.delayed import dask + from dask.delayed import Delayed + + # TODO: HighlevelGraph layers for each of these mapped inputs. + # Cache Input -------------------------------------------------------- + dsk = {} + token = dask.base.tokenize(self) + + if getattr(self, "cache_inputs", False): # TODO: formalize cache_inputs + for i, input_key in enumerate(self.iter_inputs()): + dsk[(f"cache_input-{token}", i)] = (self.cache_input, input_key) + + # Prepare Target ------------------------------------------------------ + dsk[f"checkpoint_0-{token}"] = (lambda *args: None, list(dsk)) + dsk[f"prepare_target-{token}"] = ( + _prepare_target, + f"checkpoint_0-{token}", + self.prepare_target, + ) - tasks = [] - if getattr(self, "cache_inputs", False): - f = dask.delayed(self.cache_input) - for input_key in self.iter_inputs(): - tasks.append(f(input_key)) + # Store Chunk -------------------------------------------------------- + keys = [] + for i, chunk_key in enumerate(self.iter_chunks()): + k = (f"store_chunk-{token}", i) + dsk[k] = (_store_chunk, f"prepare_target-{token}", self.store_chunk, chunk_key) + keys.append(k) - b0 = dask.delayed(_barrier)(*tasks) - b1 = dask.delayed(_wait_and_call)(self.prepare_target, b0) - tasks = [] - for chunk_key in self.iter_chunks(): - tasks.append(dask.delayed(_wait_and_call)(self.store_chunk, b1, chunk_key)) + # Finalize Target ----------------------------------------------------- + dsk[f"checkpoint_1-{token}"] = (lambda *args: None, keys) + key = f"finalize_target-{token}" + dsk[key] = (_finalize_target, f"checkpoint_1-{token}", self.finalize_target) - b2 = dask.delayed(_barrier)(*tasks) - b3 = dask.delayed(_wait_and_call)(self.finalize_target, b2) - return b3 + return Delayed(key, dsk) def to_prefect(self): """Compile the recipe to a Prefect.Flow object.""" @@ -189,9 +210,13 @@ def wrapped(*args, **kwargs): return wrapped -def _barrier(*args): - pass +def _prepare_target(checkpoint, func): + return func() + + +def _store_chunk(checkpoint, func, input_key): + return func(input_key) -def _wait_and_call(func, b, *args): - return func(*args) +def _finalize_target(checkpoint, func): + return func() diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index 41d42b35..bb2e6b66 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -14,7 +14,6 @@ import numpy as np import xarray as xr import zarr -from dask.delayed import Delayed from ..patterns import FilePattern, prune_pattern from ..storage import AbstractTarget, CacheFSSpecTarget, MetadataTarget, file_opener @@ -24,7 +23,7 @@ fix_scalar_attr_encoding, lock_for_conflicts, ) -from .base import BaseRecipe, closure +from .base import BaseRecipe # use this filename to store global recipe metadata in the metadata_cache # it will be written once (by prepare_target) and read many times (by store_chunk) @@ -693,7 +692,7 @@ def _set_target_chunks(self): # to serialize. @property - def _prepare_target(self): + def prepare_target(self): return functools.partial( prepare_target, target=self.target, @@ -716,13 +715,8 @@ def _prepare_target(self): metadata_cache=self.metadata_cache, ) - @property # type: ignore - @closure - def prepare_target(self) -> None: - return self._prepare_target() - @property - def _cache_input(self): + def cache_input(self): return functools.partial( cache_input, cache_inputs=self.cache_inputs, @@ -737,13 +731,8 @@ def _cache_input(self): metadata_cache=self.metadata_cache, ) - @property # type: ignore - @closure - def cache_input(self, input_key: InputKey) -> None: # type: ignore - return self._cache_input(input_key) - @property - def _store_chunk(self): + def store_chunk(self): return functools.partial( store_chunk, target=self.target, @@ -766,25 +755,12 @@ def _store_chunk(self): metadata_cache=self.metadata_cache, ) - @property # type: ignore - @closure - def store_chunk(self, chunk_key: ChunkKey) -> None: # type: ignore - # TODO(TOM): Restore the cache lookup - # assert isinstance(self.target, CacheFSSpecTarget) # TODO(mypy): check optional - return self._store_chunk(chunk_key) - @property - def _finalize_target(self): + def finalize_target(self): return functools.partial( finalize_target, target=self.target, consolidate_zarr=self.consolidate_zarr ) - @property # type: ignore - @closure - def finalize_target(self) -> None: - # assert isinstance(self.finalize_target, CacheFSSpecTarget) # TODO(mypy): check optional - return self._finalize_target() - def iter_inputs(self): for input in self._inputs_chunks: yield input @@ -796,64 +772,3 @@ def iter_chunks(self): def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: """Convenience function for users to introspect recipe.""" return self._chunks_inputs[chunk_key] - - def to_dask(self): - """Convert the Recipe to a dask.delayed.Delayed object.""" - # This manually builds a Dask task graph with each stage of the recipe. - # We use a few "checkpoints" to ensure that downstream tasks depend - # on upstream tasks being done before starting. - - # TODO: HighlevelGraph layers for each of these mapped inputs. - # Cache Input -------------------------------------------------------- - dsk = {} - token = dask.base.tokenize(self) - - for i, input_key in enumerate(self.iter_inputs()): - dsk[(f"cache_input-{token}", i)] = (self._cache_input, input_key) - dsk[f"checkpoint_0-{token}"] = (lambda *args: None, list(dsk)) - - # Prepare Target ----------------------------------------------------- - def prepare_target2(checkpoint): - return self._prepare_target() - - dsk[f"prepare_target-{token}"] = (prepare_target2, f"checkpoint_0-{token}") - - # Store Chunk -------------------------------------------------------- - def store_chunk2(checkpoint, input_key): - return self._store_chunk(input_key) - - keys = [] - for i, chunk_key in enumerate(self.iter_chunks()): - k = (f"store_chunk-{token}", i) - dsk[k] = (store_chunk2, f"prepare_target-{token}", chunk_key) - keys.append(k) - - dsk[f"checkpoint_1-{token}"] = (lambda *args: None, keys) - - # Finalize Target ---------------------------------------------------- - def finalize_target2(checkpoint): - return self._finalize_target() - - key = f"finalize_target-{token}" - dsk[key] = (finalize_target2, f"checkpoint_1-{token}") - - return Delayed(key, dsk) - - def to_prefect(self): - """Compile the recipe to a Prefect.Flow object.""" - from prefect import Flow, task, unmapped - - cache_input_task = task(self._cache_input, name="cache_input") - prepare_target_task = task(self._prepare_target, name="prepare_target") - store_chunk_task = task(self._store_chunk, name="store_chunk") - finalize_target_task = task(self._finalize_target, name="finalize_target") - - with Flow("pangeo-forge-recipe") as flow: - cache_task = cache_input_task.map(input_key=list(self.iter_inputs())) - prepare_task = prepare_target_task(upstream_tasks=[cache_task]) - store_task = store_chunk_task.map( - chunk_key=list(self.iter_chunks()), upstream_tasks=[unmapped(prepare_task)], - ) - _ = finalize_target_task(upstream_tasks=[store_task]) - - return flow From d962583aa46c87d4d71954c1a7891c2e2fcaad49 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Jun 2021 14:20:25 -0500 Subject: [PATCH 18/23] typing --- pangeo_forge_recipes/recipes/xarray_zarr.py | 26 ++++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index bb2e6b66..dc86fa20 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -8,7 +8,7 @@ from contextlib import ExitStack, contextmanager from dataclasses import dataclass, field, replace from itertools import product -from typing import Callable, Dict, List, Optional, Tuple +from typing import Callable, Dict, Hashable, List, Optional, Tuple import dask import numpy as np @@ -342,7 +342,7 @@ def prepare_target( delete_input_encoding: bool, process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], metadata_cache: Optional[MetadataTarget], -) -> Optional[Dict[str, List[int]]]: +) -> None: try: ds = open_target(target) logger.info("Found an existing dataset in target") @@ -418,10 +418,10 @@ def prepare_target( expand_target_dim(target, concat_dim, n_sequence) # TODO(Tom): Handle state on the object - if cache_metadata: - # if nitems_per_input is not constant, we need to cache this info - recipe_meta = {"input_sequence_lens": input_sequence_lens} - return recipe_meta + # if cache_metadata: + # # if nitems_per_input is not constant, we need to cache this info + # recipe_meta = {"input_sequence_lens": input_sequence_lens} + # return recipe_meta return None @@ -683,16 +683,14 @@ def _set_target_chunks(self): # Each stage of the recipe follows the same pattern: # 1. A top-level function, e.g. `prepare_target`, that does the actual work. - # 2. A private property, e.g. `._prepare_target`, that builds a partially applied function, - # accepting just the arguments needed (e.g. a chunk_key). - # 3. A public property, e.g. `.prepare_target`, that calls the partially applied function - # with the provided arguments (e.g. a chunk_key) + # 2. A public property, e.g. `.prepare_target`, that calls the partially applied function + # with the provided arguments if any (e.g. a chunk_key) # This ensures that the actual function objects shipped to and executed on # workers do not contain any references to the `recipe` object itself, which is complicated # to serialize. @property - def prepare_target(self): + def prepare_target(self) -> Callable[[], None]: return functools.partial( prepare_target, target=self.target, @@ -716,7 +714,7 @@ def prepare_target(self): ) @property - def cache_input(self): + def cache_input(self) -> Callable[[Hashable], None]: return functools.partial( cache_input, cache_inputs=self.cache_inputs, @@ -732,7 +730,7 @@ def cache_input(self): ) @property - def store_chunk(self): + def store_chunk(self) -> Callable[[Hashable], None]: return functools.partial( store_chunk, target=self.target, @@ -756,7 +754,7 @@ def store_chunk(self): ) @property - def finalize_target(self): + def finalize_target(self) -> Callable[[], None]: return functools.partial( finalize_target, target=self.target, consolidate_zarr=self.consolidate_zarr ) From 23c866a97a7387aa14eca4392ec2d743a5663ec8 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 24 Jun 2021 11:20:54 -0500 Subject: [PATCH 19/23] ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e6fbf035..93cabc27 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,4 @@ _version.py # tutorials *.nc +dask-worker-space From 4227b3658e31e2a883142448f207ba5cb59d256b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 24 Jun 2021 12:29:14 -0500 Subject: [PATCH 20/23] fixed metadata --- pangeo_forge_recipes/recipes/xarray_zarr.py | 32 +++++++++------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index dc86fa20..b2cd5d5f 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -40,10 +40,6 @@ def _input_metadata_fname(input_key): return "input-meta-" + _encode_key(input_key) + ".json" -def _chunk_metadata_fname(chunk_key) -> str: - return "chunk-meta-" + _encode_key(chunk_key) + ".json" - - ChunkKey = Tuple[int] InputKey = Tuple[int] @@ -90,7 +86,6 @@ def cache_input_metadata( delete_input_encoding: bool, process_input: Optional[Callable[[xr.Dataset, str], xr.Dataset]], ): - # TODO(TOM): figure out where caching should happen if metadata_cache is None: raise ValueError("metadata_cache is not set.") logger.info(f"Caching metadata for input '{input_key}'") @@ -105,7 +100,6 @@ def cache_input_metadata( process_input=process_input, ) as ds: input_metadata = ds.to_dict(data=False) - # TODO(METADATA): set metadata_cache[_input_metadata_fname(input_key)] = input_metadata @@ -151,6 +145,7 @@ def region_and_conflicts_for_chunk( input_sequence_lens, concat_dim_chunks: Optional[int], concat_dim: Optional[str], + metadata_cache: Optional[MetadataTarget], ): # return a dict suitable to pass to xr.to_zarr(region=...) # specifies where in the overall array to put this chunk's data @@ -160,10 +155,10 @@ def region_and_conflicts_for_chunk( if nitems_per_input: input_sequence_lens = (nitems_per_input,) * file_pattern.dims[concat_dim] # type: ignore - # TODO(Tom): Handle metadata caching here - # else: - # global_metadata = metadata_cache[_GLOBAL_METADATA_KEY] - # input_sequence_lens = global_metadata["input_sequence_lens"] + else: + assert metadata_cache is not None # for mypy + global_metadata = metadata_cache[_GLOBAL_METADATA_KEY] + input_sequence_lens = global_metadata["input_sequence_lens"] assert concat_dim_chunks is not None @@ -290,7 +285,6 @@ def get_input_meta(metadata_cache: Optional[MetadataTarget], *input_keys: InputK # getitems should be async; much faster than serial calls if metadata_cache is None: raise ValueError("metadata_cache is not set.") - # TODO(METADATA): get return metadata_cache.getitems([_input_metadata_fname(k) for k in input_keys]) @@ -302,7 +296,7 @@ def calculate_sequence_lens( metadata_cache: Optional[MetadataTarget], ) -> List[int]: if nitems_per_input: - assert concat_dim is not None # TODO(mypy) + assert concat_dim is not None return list((nitems_per_input,) * file_pattern.dims[concat_dim]) # read per-input metadata; this is distinct from global metadata @@ -313,7 +307,7 @@ def calculate_sequence_lens( all_lens = np.array([m["dims"][concat_dim] for m in input_meta.values()]) all_lens.shape = list(file_pattern.dims.values()) # check that all lens are the same along the concat dim - assert concat_dim is not None # TODO(mypy) + assert concat_dim is not None concat_dim_axis = list(file_pattern.dims).index(concat_dim) selector = [slice(0, 1)] * len(file_pattern.dims) selector[concat_dim_axis] = slice(None) # this should broadcast correctly agains all_lens @@ -417,12 +411,11 @@ def prepare_target( logger.info(f"Expanding target concat dim '{concat_dim}' to size {n_sequence}") expand_target_dim(target, concat_dim, n_sequence) - # TODO(Tom): Handle state on the object - # if cache_metadata: - # # if nitems_per_input is not constant, we need to cache this info - # recipe_meta = {"input_sequence_lens": input_sequence_lens} - # return recipe_meta - return None + if cache_metadata: + # if nitems_per_input is not constant, we need to cache this info + assert metadata_cache is not None # for mypy + recipe_meta = {"input_sequence_lens": input_sequence_lens} + metadata_cache[_GLOBAL_METADATA_KEY] = recipe_meta def store_chunk( @@ -485,6 +478,7 @@ def store_chunk( input_sequence_lens=input_sequence_lens, concat_dim_chunks=concat_dim_chunks, concat_dim=concat_dim, + metadata_cache=metadata_cache, ) zgroup = zarr.open_group(target_mapper) From 037ab7f80496fad06e591aaf59a35adb8cf3fc5b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 24 Jun 2021 13:34:09 -0500 Subject: [PATCH 21/23] Restore open_chunk, open_input --- pangeo_forge_recipes/recipes/xarray_zarr.py | 35 +++++++++++++++++++++ tests/test_recipes.py | 6 ++++ 2 files changed, 41 insertions(+) diff --git a/pangeo_forge_recipes/recipes/xarray_zarr.py b/pangeo_forge_recipes/recipes/xarray_zarr.py index b2cd5d5f..bf05217a 100644 --- a/pangeo_forge_recipes/recipes/xarray_zarr.py +++ b/pangeo_forge_recipes/recipes/xarray_zarr.py @@ -764,3 +764,38 @@ def iter_chunks(self): def inputs_for_chunk(self, chunk_key: ChunkKey) -> Tuple[InputKey]: """Convenience function for users to introspect recipe.""" return self._chunks_inputs[chunk_key] + + # ------------------------------------------------------------------------ + # Convenience methods + @contextmanager + def open_input(self, input_key): + with open_input( + input_key, + file_pattern=self.file_pattern, + input_cache=self.input_cache, + cache_inputs=self.cache_inputs, + copy_input_to_local_file=self.copy_input_to_local_file, + xarray_open_kwargs=self.xarray_open_kwargs, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + ) as ds: + yield ds + + @contextmanager + def open_chunk(self, chunk_key): + with open_chunk( + chunk_key, + chunks_inputs=self._chunks_inputs, + concat_dim=self._concat_dim, + xarray_concat_kwargs=self.xarray_concat_kwargs, + process_chunk=self.process_chunk, + target_chunks=self.target_chunks, + file_pattern=self.file_pattern, + input_cache=self.input_cache, + cache_inputs=self.cache_input, + copy_input_to_local_file=self.copy_input_to_local_file, + xarray_open_kwargs=self.xarray_open_kwargs, + delete_input_encoding=self.delete_input_encoding, + process_input=self.process_input, + ) as ds: + yield ds diff --git a/tests/test_recipes.py b/tests/test_recipes.py index 61fcebe1..cbefcd9b 100644 --- a/tests/test_recipes.py +++ b/tests/test_recipes.py @@ -32,6 +32,12 @@ def test_recipe(recipe_fixture, execute_recipe): ds_actual = xr.open_zarr(target.get_mapper()).load() xr.testing.assert_identical(ds_actual, ds_expected) + with rec.open_input(next(rec.iter_inputs())): + pass + + with rec.open_chunk(next(rec.iter_chunks())): + pass + @pytest.mark.parametrize("recipe_fixture", all_recipes) @pytest.mark.parametrize("nkeep", [1, 2]) From 6ec840f90ee20f475985100014a0d7aa7923e1ec Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 24 Jun 2021 13:34:20 -0500 Subject: [PATCH 22/23] Rerun tutorials --- docs/tutorials/cmip6-recipe.ipynb | 126 +- docs/tutorials/multi_variable_recipe.ipynb | 638 ++-- docs/tutorials/netcdf_zarr_sequential.ipynb | 2372 ++------------ docs/tutorials/terraclimate.ipynb | 3205 +++---------------- 4 files changed, 1216 insertions(+), 5125 deletions(-) mode change 100644 => 100755 docs/tutorials/cmip6-recipe.ipynb mode change 100644 => 100755 docs/tutorials/multi_variable_recipe.ipynb mode change 100644 => 100755 docs/tutorials/netcdf_zarr_sequential.ipynb mode change 100644 => 100755 docs/tutorials/terraclimate.ipynb diff --git a/docs/tutorials/cmip6-recipe.ipynb b/docs/tutorials/cmip6-recipe.ipynb old mode 100644 new mode 100755 index 505d5ed6..06c7c452 --- a/docs/tutorials/cmip6-recipe.ipynb +++ b/docs/tutorials/cmip6-recipe.ipynb @@ -62,25 +62,25 @@ "output_type": "stream", "text": [ "\n", - "RangeIndex: 956306 entries, 0 to 956305\n", + "RangeIndex: 990611 entries, 0 to 990610\n", "Data columns (total 13 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", - " 0 project 956306 non-null object\n", - " 1 institute 956306 non-null object\n", - " 2 model 956306 non-null object\n", - " 3 experiment_id 956306 non-null object\n", - " 4 frequency 467990 non-null object\n", - " 5 modeling_realm 467990 non-null object\n", - " 6 mip_table 956306 non-null object\n", - " 7 ensemble_member 956306 non-null object\n", - " 8 grid_label 956306 non-null object\n", - " 9 variable 956306 non-null object\n", - " 10 temporal subset 927657 non-null object\n", - " 11 version 956306 non-null object\n", - " 12 path 956306 non-null object\n", + " 0 project 990611 non-null object\n", + " 1 institute 990611 non-null object\n", + " 2 model 990611 non-null object\n", + " 3 experiment_id 990611 non-null object\n", + " 4 frequency 499599 non-null object\n", + " 5 modeling_realm 499599 non-null object\n", + " 6 mip_table 990611 non-null object\n", + " 7 ensemble_member 990611 non-null object\n", + " 8 grid_label 990611 non-null object\n", + " 9 variable 990611 non-null object\n", + " 10 temporal subset 961917 non-null object\n", + " 11 version 990611 non-null object\n", + " 12 path 990611 non-null object\n", "dtypes: object(13)\n", - "memory usage: 94.8+ MB\n" + "memory usage: 98.3+ MB\n" ] } ], @@ -259,7 +259,7 @@ { "data": { "text/plain": [ - "241944" + "242648" ] }, "execution_count": 4, @@ -326,23 +326,20 @@ "output_type": "stream", "text": [ "MRI-ESM2-0.piClim-SO2.r1i1p1f1.Amon.rlds.gn ['v20190912' 'v20200114']\n", - "CanESM5.historical.r1i1p1f1.Omon.no3.gn ['v20190306' 'v20190429']\n", - "CanESM5.historical.r6i1p1f1.Amon.ps.gn ['v20190306' 'v20190429']\n", - "IPSL-CM6A-LR.abrupt-4xCO2.r1i1p1f1.CFday.rsdscs.gr ['v20181005' 'v20190118']\n", - "MIROC6.abrupt-4xCO2.r1i1p1f1.Amon.tauv.gn ['v20190311' 'v20190705']\n", - "CESM2.abrupt-4xCO2.r1i1p1f1.Lmon.cSoilSlow.gn ['v20190425' 'v20190828' 'v20190927']\n", - "CanESM5.hist-CO2.r8i1p1f1.Omon.tauuo.gn ['v20190306' 'v20190429']\n", - "CanESM5.hist-nat.r5i1p1f1.Amon.vas.gn ['v20190306' 'v20190429']\n", - "CanESM5.ssp245-aer.r7i1p1f1.Omon.no3.gn ['v20190306' 'v20190429']\n", - "CanESM5.ssp245-stratO3.r8i1p1f1.Omon.wo.gn ['v20190306' 'v20190429']\n", - "IPSL-CM6A-LR.piClim-anthro.r1i1p1f1.Amon.rsut.gr ['v20190118' 'v20190419']\n", - "IPSL-CM6A-LR.piClim-spAer-anthro.r1i1p1f1.Lmon.nbp.gr ['v20190118' 'v20190507']\n", - "MRI-ESM2-0.piClim-lu.r1i1p1f1.Lmon.mrro.gn ['v20190603' 'v20200114']\n", - "CanESM5.ssp245.r4i1p1f1.Amon.va.gn ['v20190306' 'v20190429']\n", - "EC-Earth3-Veg.ssp245.r1i1p1f1.LImon.sbl.gr ['v20190629' 'v20200225']\n", - "IPSL-CM6A-LR.ssp126.r1i1p1f1.Omon.si.gn ['v20190121' 'v20190903']\n", - "IPSL-CM6A-LR.ssp245.r2i1p1f1.Omon.si.gn ['v20190119' 'v20190516']\n", - "IPSL-CM6A-LR.ssp585.r1i1p1f1.Omon.talkos.gn ['v20190119' 'v20190903']\n" + "CanESM5.historical.r1i1p1f1.Omon.hfds.gn ['v20190306' 'v20190429']\n", + "EC-Earth3-Veg.amip.r1i1p1f1.Lmon.mrso.gr ['v20190605' 'v20200225']\n", + "CESM2.abrupt-4xCO2.r1i1p1f1.Emon.loadso4.gn ['v20190425' 'v20190828' 'v20190927']\n", + "SAM0-UNICON.piControl.r1i1p1f1.fx.areacella.gn ['v20190323' 'v20190910']\n", + "CanESM5.hist-stratO3.r6i1p1f1.Amon.va.gn ['v20190306' 'v20190429']\n", + "CanESM5.ssp245-aer.r7i1p1f1.Omon.fgo2.gn ['v20190306' 'v20190429']\n", + "CanESM5.ssp245-nat.r8i1p1f1.Amon.va.gn ['v20190306' 'v20190429']\n", + "CanESM5.ssp245-stratO3.r8i1p1f1.Omon.uo.gn ['v20190306' 'v20190429']\n", + "IPSL-CM6A-LR.piClim-spAer-anthro.r1i1p1f1.Amon.rsdt.gr ['v20190118' 'v20190507']\n", + "CESM2.piClim-aer.r1i1p1f1.AERmon.od550aer.gn ['v20190815' 'v20191205']\n", + "CanESM5.ssp126.r2i1p1f1.Amon.psl.gn ['v20190306' 'v20190429']\n", + "CanESM5.ssp370.r5i1p1f1.Omon.thetao.gn ['v20190306' 'v20190429']\n", + "CanESM5.ssp585.r6i1p1f1.Amon.vas.gn ['v20190306' 'v20190429']\n", + "IPSL-CM6A-LR.ssp585.r1i1p1f1.Eday.loadbc.gr ['v20190119' 'v20190903']\n" ] } ], @@ -410,24 +407,7 @@ " \n", " \n", " \n", - " 463275\n", - " CMIP6\n", - " NOAA-GFDL\n", - " GFDL-CM4\n", - " historical\n", - " mon\n", - " atmos\n", - " Amon\n", - " r1i1p1f1\n", - " gr1\n", - " tas\n", - " 185001-185412\n", - " v20180301\n", - " s3://esgf-world/CMIP6/CMIP/NOAA-GFDL/GFDL-CM4/...\n", - " GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1\n", - " \n", - " \n", - " 463276\n", + " 491687\n", " CMIP6\n", " NOAA-GFDL\n", " GFDL-CM4\n", @@ -444,7 +424,7 @@ " GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1\n", " \n", " \n", - " 463277\n", + " 491688\n", " CMIP6\n", " NOAA-GFDL\n", " GFDL-CM4\n", @@ -466,24 +446,20 @@ ], "text/plain": [ " project institute model experiment_id frequency modeling_realm \\\n", - "463275 CMIP6 NOAA-GFDL GFDL-CM4 historical mon atmos \n", - "463276 CMIP6 NOAA-GFDL GFDL-CM4 historical mon atmos \n", - "463277 CMIP6 NOAA-GFDL GFDL-CM4 historical mon atmos \n", + "491687 CMIP6 NOAA-GFDL GFDL-CM4 historical mon atmos \n", + "491688 CMIP6 NOAA-GFDL GFDL-CM4 historical mon atmos \n", "\n", " mip_table ensemble_member grid_label variable temporal subset \\\n", - "463275 Amon r1i1p1f1 gr1 tas 185001-185412 \n", - "463276 Amon r1i1p1f1 gr1 tas 185001-194912 \n", - "463277 Amon r1i1p1f1 gr1 tas 195001-201412 \n", + "491687 Amon r1i1p1f1 gr1 tas 185001-194912 \n", + "491688 Amon r1i1p1f1 gr1 tas 195001-201412 \n", "\n", " version path \\\n", - "463275 v20180301 s3://esgf-world/CMIP6/CMIP/NOAA-GFDL/GFDL-CM4/... \n", - "463276 v20180701 s3://esgf-world/CMIP6/CMIP/NOAA-GFDL/GFDL-CM4/... \n", - "463277 v20180701 s3://esgf-world/CMIP6/CMIP/NOAA-GFDL/GFDL-CM4/... \n", + "491687 v20180701 s3://esgf-world/CMIP6/CMIP/NOAA-GFDL/GFDL-CM4/... \n", + "491688 v20180701 s3://esgf-world/CMIP6/CMIP/NOAA-GFDL/GFDL-CM4/... \n", "\n", " dataset \n", - "463275 GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1 \n", - "463276 GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1 \n", - "463277 GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1 " + "491687 GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1 \n", + "491688 GFDL-CM4.historical.r1i1p1f1.Amon.tas.gr1 " ] }, "execution_count": 9, @@ -918,9 +894,7 @@ { "data": { "text/plain": [ - "('/var/folders/mz/gxy_z7dx1k153xf0c3fks9_40000gp/T/tmpylua0hw7',\n", - " '/var/folders/mz/gxy_z7dx1k153xf0c3fks9_40000gp/T/tmp3o0t30ku',\n", - " '/var/folders/mz/gxy_z7dx1k153xf0c3fks9_40000gp/T/tmpe7vlie5n')" + "('/tmp/tmp27cmcgjt', '/tmp/tmp11j78jym', '/tmp/tmplvaypj2r')" ] }, "execution_count": 22, @@ -931,7 +905,7 @@ "source": [ "import tempfile\n", "from fsspec.implementations.local import LocalFileSystem\n", - "from pangeo_forge_recipes.storage import FSSpecTarget, CacheFSSpecTarget\n", + "from pangeo_forge_recipes.storage import FSSpecTarget, CacheFSSpecTarget, MetadataTarget\n", "\n", "fs_local = LocalFileSystem()\n", "\n", @@ -942,7 +916,7 @@ "cache_target = CacheFSSpecTarget(fs_local, cache_dir.name)\n", "\n", "meta_dir = tempfile.TemporaryDirectory()\n", - "meta_store = FSSpecTarget(fs_local, meta_dir.name)\n", + "meta_store = MetadataTarget(fs_local, meta_dir.name)\n", "\n", "recipe.target = target\n", "recipe.input_cache = cache_target\n", @@ -961,9 +935,7 @@ { "cell_type": "code", "execution_count": 23, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1061,7 +1033,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 25, @@ -1070,7 +1042,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -1107,9 +1079,9 @@ ], "metadata": { "kernelspec": { - "display_name": "pangeo-forge3.8", + "display_name": "Python 3", "language": "python", - "name": "pangeo-forge3.8" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1121,7 +1093,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/docs/tutorials/multi_variable_recipe.ipynb b/docs/tutorials/multi_variable_recipe.ipynb old mode 100644 new mode 100755 index a0061c40..259e06e5 --- a/docs/tutorials/multi_variable_recipe.ipynb +++ b/docs/tutorials/multi_variable_recipe.ipynb @@ -54,16 +54,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "--2021-04-15 11:28:34-- https://www.ncei.noaa.gov/thredds-ocean/fileServer/ncei/woa/temperature/decav/5deg/woa18_decav_t01_5d.nc\n", - "Resolving www.ncei.noaa.gov... 2610:20:8040:2::178, 2610:20:8040:2::167, 2610:20:8040:2::168, ...\n", - "Connecting to www.ncei.noaa.gov|2610:20:8040:2::178|:443... connected.\n", + "--2021-06-24 17:50:54-- https://www.ncei.noaa.gov/thredds-ocean/fileServer/ncei/woa/temperature/decav/5deg/woa18_decav_t01_5d.nc\n", + "Resolving www.ncei.noaa.gov (www.ncei.noaa.gov)... 205.167.25.168, 205.167.25.172, 205.167.25.167, ...\n", + "Connecting to www.ncei.noaa.gov (www.ncei.noaa.gov)|205.167.25.168|:443... connected.\n", "HTTP request sent, awaiting response... 200 \n", "Length: 2389903 (2.3M) [application/x-netcdf]\n", - "Saving to: ‘woa18_decav_t01_5d.nc.1’\n", + "Saving to: ‘woa18_decav_t01_5d.nc’\n", "\n", - "woa18_decav_t01_5d. 100%[===================>] 2.28M 1.73MB/s in 1.3s \n", + "woa18_decav_t01_5d. 100%[===================>] 2.28M 3.38MB/s in 0.7s \n", "\n", - "2021-04-15 11:28:36 (1.73 MB/s) - ‘woa18_decav_t01_5d.nc.1’ saved [2389903/2389903]\n", + "2021-06-24 17:50:55 (3.38 MB/s) - ‘woa18_decav_t01_5d.nc’ saved [2389903/2389903]\n", "\n" ] } @@ -74,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -504,10 +504,10 @@ " license: These data are openly available to the p...\n", " metadata_link: http://www.nodc.noaa.gov/OC5/WOA18/pr_wo...\n", " date_created: 2018-02-19 \n", - " date_modified: 2018-02-19
  • Conventions :
    CF-1.6, ACDD-1.3
    title :
    World Ocean Atlas 2018 : sea_water_temperature January 1955-2017 5.00 degree
    summary :
    PRERELEASE Climatological mean temperature for the global ocean from in situ profile data
    references :
    Locarnini, R. A., A. V. Mishonov, O. K. Baranova, T. P. Boyer, M. M. Zweng, H. E. Garcia, J. R. Reagan, D. Seidov, K. W. Weathers, C. R. Paver, I. V. Smolyar, 2018: World Ocean Atlas 2018, Volume 1: Temperature. A. V. Mishonov, Technical Ed., NOAA Atlas NESDIS ##
    institution :
    National Centers for Environmental Information (NCEI)
    comment :
    global climatology as part of the World Ocean Atlas project
    id :
    woa18_decav_t01_5d.nc
    naming_authority :
    gov.noaa.ncei
    sea_name :
    World-Wide Distribution
    time_coverage_start :
    1955-01-01
    time_coverage_end :
    2017-01-31
    time_coverage_duration :
    P63Y
    time_coverage_resolution :
    P01M
    geospatial_lat_min :
    -90.0
    geospatial_lat_max :
    90.0
    geospatial_lon_min :
    -180.0
    geospatial_lon_max :
    180.0
    geospatial_vertical_min :
    0.0
    geospatial_vertical_max :
    1500.0
    geospatial_lat_units :
    degrees_north
    geospatial_lat_resolution :
    5.00 degrees
    geospatial_lon_units :
    degrees_east
    geospatial_lon_resolution :
    5.00 degrees
    geospatial_vertical_units :
    m
    geospatial_vertical_resolution :
    SPECIAL
    geospatial_vertical_positive :
    down
    creator_name :
    Ocean Climate Laboratory
    creator_email :
    NCEI.info@noaa.gov
    creator_url :
    http://www.ncei.noaa.gov
    creator_type :
    group
    creator_institution :
    National Centers for Environmental Information
    project :
    World Ocean Atlas Project
    processing_level :
    processed
    keywords :
    Oceans< Ocean Temperature > Water Temperature
    keywords_vocabulary :
    ISO 19115
    standard_name_vocabulary :
    CF Standard Name Table v49
    contributor_name :
    Ocean Climate Laboratory
    contributor_role :
    Calculation of climatologies
    cdm_data_type :
    Grid
    publisher_name :
    National Centers for Environmental Information (NCEI)
    publisher_institution :
    National Centers for Environmental Information
    publisher_type :
    institution
    publisher_url :
    http://www.ncei.noaa.gov/
    publisher_email :
    NCEI.info@noaa.gov
    nodc_template_version :
    NODC_NetCDF_Grid_Template_v2.0
    license :
    These data are openly available to the public. Please acknowledge the use of these data with the text given in the acknowledgment attribute.
    metadata_link :
    http://www.nodc.noaa.gov/OC5/WOA18/pr_woa18.html
    date_created :
    2018-02-19
    date_modified :
    2018-02-19
  • " ], "text/plain": [ "\n", @@ -719,7 +719,7 @@ " date_modified: 2018-02-19 " ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -731,7 +731,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -1097,7 +1097,7 @@ " long_name: time\n", " units: months since 1955-01-01 00:00:00\n", " axis: T\n", - " climatology: climatology_bounds" + " climatology: climatology_bounds" ], "text/plain": [ "\n", @@ -1112,7 +1112,7 @@ " climatology: climatology_bounds" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -1131,7 +1131,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -1519,10 +1519,10 @@ " license: These data are openly available to the p...\n", " metadata_link: http://www.nodc.noaa.gov/OC5/WOA18/pr_wo...\n", " date_created: 2018-02-19 \n", - " date_modified: 2018-02-19
  • Conventions :
    CF-1.6, ACDD-1.3
    title :
    World Ocean Atlas 2018 : sea_water_temperature January 1955-2017 5.00 degree
    summary :
    PRERELEASE Climatological mean temperature for the global ocean from in situ profile data
    references :
    Locarnini, R. A., A. V. Mishonov, O. K. Baranova, T. P. Boyer, M. M. Zweng, H. E. Garcia, J. R. Reagan, D. Seidov, K. W. Weathers, C. R. Paver, I. V. Smolyar, 2018: World Ocean Atlas 2018, Volume 1: Temperature. A. V. Mishonov, Technical Ed., NOAA Atlas NESDIS ##
    institution :
    National Centers for Environmental Information (NCEI)
    comment :
    global climatology as part of the World Ocean Atlas project
    id :
    woa18_decav_t01_5d.nc
    naming_authority :
    gov.noaa.ncei
    sea_name :
    World-Wide Distribution
    time_coverage_start :
    1955-01-01
    time_coverage_end :
    2017-01-31
    time_coverage_duration :
    P63Y
    time_coverage_resolution :
    P01M
    geospatial_lat_min :
    -90.0
    geospatial_lat_max :
    90.0
    geospatial_lon_min :
    -180.0
    geospatial_lon_max :
    180.0
    geospatial_vertical_min :
    0.0
    geospatial_vertical_max :
    1500.0
    geospatial_lat_units :
    degrees_north
    geospatial_lat_resolution :
    5.00 degrees
    geospatial_lon_units :
    degrees_east
    geospatial_lon_resolution :
    5.00 degrees
    geospatial_vertical_units :
    m
    geospatial_vertical_resolution :
    SPECIAL
    geospatial_vertical_positive :
    down
    creator_name :
    Ocean Climate Laboratory
    creator_email :
    NCEI.info@noaa.gov
    creator_url :
    http://www.ncei.noaa.gov
    creator_type :
    group
    creator_institution :
    National Centers for Environmental Information
    project :
    World Ocean Atlas Project
    processing_level :
    processed
    keywords :
    Oceans< Ocean Temperature > Water Temperature
    keywords_vocabulary :
    ISO 19115
    standard_name_vocabulary :
    CF Standard Name Table v49
    contributor_name :
    Ocean Climate Laboratory
    contributor_role :
    Calculation of climatologies
    cdm_data_type :
    Grid
    publisher_name :
    National Centers for Environmental Information (NCEI)
    publisher_institution :
    National Centers for Environmental Information
    publisher_type :
    institution
    publisher_url :
    http://www.ncei.noaa.gov/
    publisher_email :
    NCEI.info@noaa.gov
    nodc_template_version :
    NODC_NetCDF_Grid_Template_v2.0
    license :
    These data are openly available to the public. Please acknowledge the use of these data with the text given in the acknowledgment attribute.
    metadata_link :
    http://www.nodc.noaa.gov/OC5/WOA18/pr_woa18.html
    date_created :
    2018-02-19
    date_modified :
    2018-02-19
  • " ], "text/plain": [ "\n", @@ -1734,7 +1735,7 @@ " date_modified: 2018-02-19 " ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -1747,7 +1748,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -2105,18 +2106,22 @@ " fill: currentColor;\n", "}\n", "
    <xarray.DataArray 'time' (time: 1)>\n",
    -       "array([cftime.Datetime360Day(1986, 1, 16, 0, 0, 0, 0)], dtype=object)\n",
    +       "array([cftime.Datetime360Day(1986, 1, 16, 0, 0, 0, 0, has_year_zero=False)],\n",
    +       "      dtype=object)\n",
            "Coordinates:\n",
            "  * time     (time) object 1986-01-16 00:00:00\n",
            "Attributes:\n",
            "    standard_name:  time\n",
            "    long_name:      time\n",
            "    axis:           T\n",
    -       "    climatology:    climatology_bounds
    " + " climatology: climatology_bounds" ], "text/plain": [ "\n", - "array([cftime.Datetime360Day(1986, 1, 16, 0, 0, 0, 0)], dtype=object)\n", + "array([cftime.Datetime360Day(1986, 1, 16, 0, 0, 0, 0, has_year_zero=False)],\n", + " dtype=object)\n", "Coordinates:\n", " * time (time) object 1986-01-16 00:00:00\n", "Attributes:\n", @@ -2126,7 +2131,7 @@ " climatology: climatology_bounds" ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -2160,7 +2165,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -2169,7 +2174,7 @@ "'https://www.ncei.noaa.gov/thredds-ocean/fileServer/ncei/woa/temperature/decav/5deg/woa18_decav_t02_5d.nc'" ] }, - "execution_count": 11, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -2195,7 +2200,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -2204,7 +2209,7 @@ "" ] }, - "execution_count": 16, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -2244,7 +2249,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -2264,16 +2269,16 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "XarrayZarrRecipe(file_pattern=, inputs_per_chunk=1, target=, input_cache=, metadata_cache=, cache_inputs=True, copy_input_to_local_file=False, consolidate_zarr=True, xarray_open_kwargs={'decode_times': False}, xarray_concat_kwargs={}, delete_input_encoding=True, fsspec_open_kwargs={}, process_input=, process_chunk=None, target_chunks={}, _concat_dim='time', _concat_dim_chunks=1)" + "XarrayZarrRecipe(file_pattern=, inputs_per_chunk=1, target_chunks={}, target=None, input_cache=None, metadata_cache=None, cache_inputs=True, copy_input_to_local_file=False, consolidate_zarr=True, xarray_open_kwargs={'decode_times': False}, xarray_concat_kwargs={}, delete_input_encoding=True, fsspec_open_kwargs={}, process_input=, process_chunk=None, lock_timeout=None, _concat_dim='time', _concat_dim_chunks=1)" ] }, - "execution_count": 19, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -2300,7 +2305,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -2332,24 +2337,128 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 13, "metadata": {}, "outputs": [ { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - "/opt/miniconda3/envs/pangeo-forge/lib/python3.8/contextlib.py:120: UserWarning: Tasks were created but not added to the flow: {}. This can occur when `Task` classes, including `Parameters`, are instantiated inside a `with flow:` block but not added to the flow either explicitly or as the input to another task. For more information, see https://docs.prefect.io/core/advanced_tutorials/task-guide.html#adding-tasks-to-flows.\n", - " next(self.gen)\n" + "[2021-06-24 17:51:09+0000] INFO - prefect.FlowRunner | Beginning Flow run for 'pangeo-forge-recipe'\n", + "[2021-06-24 17:51:09+0000] INFO - prefect.TaskRunner | Task 'cache_input': Starting task run...\n", + "[2021-06-24 17:51:09+0000] INFO - prefect.TaskRunner | Task 'cache_input': Finished task run for task with final state: 'Mapped'\n", + "[2021-06-24 17:51:09+0000] INFO - prefect.TaskRunner | Task 'cache_input[0]': Starting task run...\n", + "[2021-06-24 17:51:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[0]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[1]': Starting task run...\n", + "[2021-06-24 17:51:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[1]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[2]': Starting task run...\n", + "[2021-06-24 17:51:14+0000] INFO - prefect.TaskRunner | Task 'cache_input[2]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:14+0000] INFO - prefect.TaskRunner | Task 'cache_input[3]': Starting task run...\n", + "[2021-06-24 17:51:16+0000] INFO - prefect.TaskRunner | Task 'cache_input[3]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:16+0000] INFO - prefect.TaskRunner | Task 'cache_input[4]': Starting task run...\n", + "[2021-06-24 17:51:17+0000] INFO - prefect.TaskRunner | Task 'cache_input[4]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:17+0000] INFO - prefect.TaskRunner | Task 'cache_input[5]': Starting task run...\n", + "[2021-06-24 17:51:19+0000] INFO - prefect.TaskRunner | Task 'cache_input[5]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:19+0000] INFO - prefect.TaskRunner | Task 'cache_input[6]': Starting task run...\n", + "[2021-06-24 17:51:20+0000] INFO - prefect.TaskRunner | Task 'cache_input[6]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:20+0000] INFO - prefect.TaskRunner | Task 'cache_input[7]': Starting task run...\n", + "[2021-06-24 17:51:22+0000] INFO - prefect.TaskRunner | Task 'cache_input[7]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:22+0000] INFO - prefect.TaskRunner | Task 'cache_input[8]': Starting task run...\n", + "[2021-06-24 17:51:23+0000] INFO - prefect.TaskRunner | Task 'cache_input[8]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:24+0000] INFO - prefect.TaskRunner | Task 'cache_input[9]': Starting task run...\n", + "[2021-06-24 17:51:25+0000] INFO - prefect.TaskRunner | Task 'cache_input[9]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:25+0000] INFO - prefect.TaskRunner | Task 'cache_input[10]': Starting task run...\n", + "[2021-06-24 17:51:27+0000] INFO - prefect.TaskRunner | Task 'cache_input[10]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:27+0000] INFO - prefect.TaskRunner | Task 'cache_input[11]': Starting task run...\n", + "[2021-06-24 17:51:28+0000] INFO - prefect.TaskRunner | Task 'cache_input[11]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:28+0000] INFO - prefect.TaskRunner | Task 'cache_input[12]': Starting task run...\n", + "[2021-06-24 17:51:30+0000] INFO - prefect.TaskRunner | Task 'cache_input[12]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:30+0000] INFO - prefect.TaskRunner | Task 'cache_input[13]': Starting task run...\n", + "[2021-06-24 17:51:31+0000] INFO - prefect.TaskRunner | Task 'cache_input[13]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:31+0000] INFO - prefect.TaskRunner | Task 'cache_input[14]': Starting task run...\n", + "[2021-06-24 17:51:33+0000] INFO - prefect.TaskRunner | Task 'cache_input[14]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:33+0000] INFO - prefect.TaskRunner | Task 'cache_input[15]': Starting task run...\n", + "[2021-06-24 17:51:35+0000] INFO - prefect.TaskRunner | Task 'cache_input[15]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:35+0000] INFO - prefect.TaskRunner | Task 'cache_input[16]': Starting task run...\n", + "[2021-06-24 17:51:36+0000] INFO - prefect.TaskRunner | Task 'cache_input[16]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:36+0000] INFO - prefect.TaskRunner | Task 'cache_input[17]': Starting task run...\n", + "[2021-06-24 17:51:38+0000] INFO - prefect.TaskRunner | Task 'cache_input[17]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:38+0000] INFO - prefect.TaskRunner | Task 'cache_input[18]': Starting task run...\n", + "[2021-06-24 17:51:39+0000] INFO - prefect.TaskRunner | Task 'cache_input[18]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:39+0000] INFO - prefect.TaskRunner | Task 'cache_input[19]': Starting task run...\n", + "[2021-06-24 17:51:41+0000] INFO - prefect.TaskRunner | Task 'cache_input[19]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:41+0000] INFO - prefect.TaskRunner | Task 'cache_input[20]': Starting task run...\n", + "[2021-06-24 17:51:42+0000] INFO - prefect.TaskRunner | Task 'cache_input[20]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:42+0000] INFO - prefect.TaskRunner | Task 'cache_input[21]': Starting task run...\n", + "[2021-06-24 17:51:44+0000] INFO - prefect.TaskRunner | Task 'cache_input[21]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:44+0000] INFO - prefect.TaskRunner | Task 'cache_input[22]': Starting task run...\n", + "[2021-06-24 17:51:46+0000] INFO - prefect.TaskRunner | Task 'cache_input[22]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:46+0000] INFO - prefect.TaskRunner | Task 'cache_input[23]': Starting task run...\n", + "[2021-06-24 17:51:47+0000] INFO - prefect.TaskRunner | Task 'cache_input[23]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:47+0000] INFO - prefect.TaskRunner | Task 'prepare_target': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'prepare_target': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk': Finished task run for task with final state: 'Mapped'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[0]': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[0]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[1]': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[1]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[2]': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[2]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[3]': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[3]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[4]': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[4]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[5]': Starting task run...\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[5]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:48+0000] INFO - prefect.TaskRunner | Task 'store_chunk[6]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[6]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[7]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[7]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[8]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[8]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[9]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[9]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[10]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[10]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[11]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[11]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[12]': Starting task run...\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[12]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:49+0000] INFO - prefect.TaskRunner | Task 'store_chunk[13]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[13]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[14]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[14]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[15]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[15]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[16]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[16]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[17]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[17]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[18]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[18]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[19]': Starting task run...\n", + "[2021-06-24 17:51:50+0000] INFO - prefect.TaskRunner | Task 'store_chunk[19]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[20]': Starting task run...\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[20]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[21]': Starting task run...\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[21]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[22]': Starting task run...\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[22]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[23]': Starting task run...\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'store_chunk[23]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'finalize_target': Starting task run...\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.TaskRunner | Task 'finalize_target': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:51:51+0000] INFO - prefect.FlowRunner | Flow run SUCCESS: all reference tasks succeeded\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 21, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -2361,7 +2470,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -2370,90 +2479,89 @@ "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", "\n", - "%3\n", - "\n", - "\n", + "\n", + "\n", "\n", - "140330999042880\n", - "\n", - "Constant[list]\n", + "139961538659328\n", + "\n", + "Constant[list]\n", "\n", - "\n", + "\n", "\n", - "140330988292368\n", - "\n", - "MappedTaskWrapper <map>\n", + "139961538658656\n", + "\n", + "store_chunk <map>\n", "\n", - "\n", - "\n", - "140330999042880->140330988292368\n", - "\n", - "\n", - "key\n", + "\n", + "\n", + "139961538659328->139961538658656\n", + "\n", + "\n", + "chunk_key\n", "\n", - "\n", + "\n", "\n", - "140330998558976\n", - "\n", - "SingleTaskWrapper\n", + "139961538637344\n", + "\n", + "Constant[list]\n", "\n", - "\n", - "\n", - "140330987548528\n", - "\n", - "SingleTaskWrapper\n", + "\n", + "\n", + "139961536482416\n", + "\n", + "cache_input <map>\n", "\n", - "\n", - "\n", - "140330988292368->140330987548528\n", - "\n", - "\n", + "\n", + "\n", + "139961538637344->139961536482416\n", + "\n", + "\n", + "input_key\n", "\n", - "\n", - "\n", - "140330999042928\n", - "\n", - "MappedTaskWrapper <map>\n", + "\n", + "\n", + "139961538637488\n", + "\n", + "finalize_target\n", "\n", - "\n", + "\n", "\n", - "140330999042928->140330998558976\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "140330999043408\n", - "\n", - "Constant[list]\n", + "139961538658656->139961538637488\n", + "\n", + "\n", "\n", - "\n", - "\n", - "140330999043408->140330999042928\n", - "\n", - "\n", - "key\n", + "\n", + "\n", + "139961538637440\n", + "\n", + "prepare_target\n", "\n", - "\n", + "\n", "\n", - "140330987548528->140330999042928\n", - "\n", - "\n", + "139961538637440->139961538658656\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "139961536482416->139961538637440\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 26, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -2464,119 +2572,119 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[2021-04-15 11:38:45-0400] INFO - prefect.FlowRunner | Beginning Flow run for 'Rechunker'\n", - "[2021-04-15 11:38:45-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper': Starting task run...\n", - "[2021-04-15 11:38:45-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper': Finished task run for task with final state: 'Mapped'\n", - "[2021-04-15 11:38:45-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[0]': Starting task run...\n", - "[2021-04-15 11:38:46-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[0]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:46-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[1]': Starting task run...\n", - "[2021-04-15 11:38:47-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[1]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:47-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[2]': Starting task run...\n", - "[2021-04-15 11:38:49-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[2]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:49-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[3]': Starting task run...\n", - "[2021-04-15 11:38:50-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[3]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:50-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[4]': Starting task run...\n", - "[2021-04-15 11:38:51-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[4]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:51-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[5]': Starting task run...\n", - "[2021-04-15 11:38:52-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[5]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:52-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[6]': Starting task run...\n", - "[2021-04-15 11:38:53-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[6]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:53-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[7]': Starting task run...\n", - "[2021-04-15 11:38:54-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[7]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:54-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[8]': Starting task run...\n", - "[2021-04-15 11:38:56-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[8]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:56-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[9]': Starting task run...\n", - "[2021-04-15 11:38:57-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[9]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:57-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[10]': Starting task run...\n", - "[2021-04-15 11:38:58-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[10]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:58-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[11]': Starting task run...\n", - "[2021-04-15 11:38:59-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[11]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:38:59-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[12]': Starting task run...\n", - "[2021-04-15 11:39:00-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[12]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:00-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[13]': Starting task run...\n", - "[2021-04-15 11:39:01-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[13]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:01-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[14]': Starting task run...\n", - "[2021-04-15 11:39:02-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[14]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:02-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[15]': Starting task run...\n", - "[2021-04-15 11:39:03-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[15]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:03-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[16]': Starting task run...\n", - "[2021-04-15 11:39:04-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[16]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:04-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[17]': Starting task run...\n", - "[2021-04-15 11:39:05-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[17]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:05-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[18]': Starting task run...\n", - "[2021-04-15 11:39:06-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[18]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:06-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[19]': Starting task run...\n", - "[2021-04-15 11:39:07-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[19]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:07-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[20]': Starting task run...\n", - "[2021-04-15 11:39:08-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[20]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:08-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[21]': Starting task run...\n", - "[2021-04-15 11:39:09-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[21]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:09-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[22]': Starting task run...\n", - "[2021-04-15 11:39:10-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[22]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:10-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[23]': Starting task run...\n", - "[2021-04-15 11:39:10-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[23]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:10-0400] INFO - prefect.TaskRunner | Task 'SingleTaskWrapper': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'SingleTaskWrapper': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper': Finished task run for task with final state: 'Mapped'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[0]': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[0]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[1]': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[1]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[2]': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[2]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[3]': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[3]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[4]': Starting task run...\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[4]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:11-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[5]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[5]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[6]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[6]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[7]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[7]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[8]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[8]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[9]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[9]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[10]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[10]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[11]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[11]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[12]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[12]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[13]': Starting task run...\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[13]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:12-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[14]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[14]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[15]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[15]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[16]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[16]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[17]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[17]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[18]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[18]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[19]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[19]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[20]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[20]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[21]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[21]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[22]': Starting task run...\n", - "[2021-04-15 11:39:13-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[22]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:14-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[23]': Starting task run...\n", - "[2021-04-15 11:39:14-0400] INFO - prefect.TaskRunner | Task 'MappedTaskWrapper[23]': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:14-0400] INFO - prefect.TaskRunner | Task 'SingleTaskWrapper': Starting task run...\n", - "[2021-04-15 11:39:14-0400] INFO - prefect.TaskRunner | Task 'SingleTaskWrapper': Finished task run for task with final state: 'Success'\n", - "[2021-04-15 11:39:14-0400] INFO - prefect.FlowRunner | Flow run SUCCESS: all reference tasks succeeded\n" + "[2021-06-24 17:52:04+0000] INFO - prefect.FlowRunner | Beginning Flow run for 'pangeo-forge-recipe'\n", + "[2021-06-24 17:52:04+0000] INFO - prefect.TaskRunner | Task 'cache_input': Starting task run...\n", + "[2021-06-24 17:52:04+0000] INFO - prefect.TaskRunner | Task 'cache_input': Finished task run for task with final state: 'Mapped'\n", + "[2021-06-24 17:52:04+0000] INFO - prefect.TaskRunner | Task 'cache_input[0]': Starting task run...\n", + "[2021-06-24 17:52:05+0000] INFO - prefect.TaskRunner | Task 'cache_input[0]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:05+0000] INFO - prefect.TaskRunner | Task 'cache_input[1]': Starting task run...\n", + "[2021-06-24 17:52:05+0000] INFO - prefect.TaskRunner | Task 'cache_input[1]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:05+0000] INFO - prefect.TaskRunner | Task 'cache_input[2]': Starting task run...\n", + "[2021-06-24 17:52:06+0000] INFO - prefect.TaskRunner | Task 'cache_input[2]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:06+0000] INFO - prefect.TaskRunner | Task 'cache_input[3]': Starting task run...\n", + "[2021-06-24 17:52:06+0000] INFO - prefect.TaskRunner | Task 'cache_input[3]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:06+0000] INFO - prefect.TaskRunner | Task 'cache_input[4]': Starting task run...\n", + "[2021-06-24 17:52:07+0000] INFO - prefect.TaskRunner | Task 'cache_input[4]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:07+0000] INFO - prefect.TaskRunner | Task 'cache_input[5]': Starting task run...\n", + "[2021-06-24 17:52:07+0000] INFO - prefect.TaskRunner | Task 'cache_input[5]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:07+0000] INFO - prefect.TaskRunner | Task 'cache_input[6]': Starting task run...\n", + "[2021-06-24 17:52:07+0000] INFO - prefect.TaskRunner | Task 'cache_input[6]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:07+0000] INFO - prefect.TaskRunner | Task 'cache_input[7]': Starting task run...\n", + "[2021-06-24 17:52:08+0000] INFO - prefect.TaskRunner | Task 'cache_input[7]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:08+0000] INFO - prefect.TaskRunner | Task 'cache_input[8]': Starting task run...\n", + "[2021-06-24 17:52:08+0000] INFO - prefect.TaskRunner | Task 'cache_input[8]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:08+0000] INFO - prefect.TaskRunner | Task 'cache_input[9]': Starting task run...\n", + "[2021-06-24 17:52:09+0000] INFO - prefect.TaskRunner | Task 'cache_input[9]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:09+0000] INFO - prefect.TaskRunner | Task 'cache_input[10]': Starting task run...\n", + "[2021-06-24 17:52:09+0000] INFO - prefect.TaskRunner | Task 'cache_input[10]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:09+0000] INFO - prefect.TaskRunner | Task 'cache_input[11]': Starting task run...\n", + "[2021-06-24 17:52:10+0000] INFO - prefect.TaskRunner | Task 'cache_input[11]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:10+0000] INFO - prefect.TaskRunner | Task 'cache_input[12]': Starting task run...\n", + "[2021-06-24 17:52:10+0000] INFO - prefect.TaskRunner | Task 'cache_input[12]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:10+0000] INFO - prefect.TaskRunner | Task 'cache_input[13]': Starting task run...\n", + "[2021-06-24 17:52:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[13]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[14]': Starting task run...\n", + "[2021-06-24 17:52:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[14]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[15]': Starting task run...\n", + "[2021-06-24 17:52:11+0000] INFO - prefect.TaskRunner | Task 'cache_input[15]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[16]': Starting task run...\n", + "[2021-06-24 17:52:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[16]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[17]': Starting task run...\n", + "[2021-06-24 17:52:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[17]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:12+0000] INFO - prefect.TaskRunner | Task 'cache_input[18]': Starting task run...\n", + "[2021-06-24 17:52:13+0000] INFO - prefect.TaskRunner | Task 'cache_input[18]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:13+0000] INFO - prefect.TaskRunner | Task 'cache_input[19]': Starting task run...\n", + "[2021-06-24 17:52:13+0000] INFO - prefect.TaskRunner | Task 'cache_input[19]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:13+0000] INFO - prefect.TaskRunner | Task 'cache_input[20]': Starting task run...\n", + "[2021-06-24 17:52:14+0000] INFO - prefect.TaskRunner | Task 'cache_input[20]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:14+0000] INFO - prefect.TaskRunner | Task 'cache_input[21]': Starting task run...\n", + "[2021-06-24 17:52:14+0000] INFO - prefect.TaskRunner | Task 'cache_input[21]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:14+0000] INFO - prefect.TaskRunner | Task 'cache_input[22]': Starting task run...\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'cache_input[22]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'cache_input[23]': Starting task run...\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'cache_input[23]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'prepare_target': Starting task run...\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'prepare_target': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'store_chunk': Starting task run...\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'store_chunk': Finished task run for task with final state: 'Mapped'\n", + "[2021-06-24 17:52:15+0000] INFO - prefect.TaskRunner | Task 'store_chunk[0]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[0]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[1]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[1]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[2]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[2]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[3]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[3]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[4]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[4]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[5]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[5]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[6]': Starting task run...\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[6]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:16+0000] INFO - prefect.TaskRunner | Task 'store_chunk[7]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[7]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[8]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[8]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[9]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[9]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[10]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[10]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[11]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[11]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[12]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[12]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[13]': Starting task run...\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[13]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:17+0000] INFO - prefect.TaskRunner | Task 'store_chunk[14]': Starting task run...\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[14]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[15]': Starting task run...\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[15]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[16]': Starting task run...\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[16]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[17]': Starting task run...\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[17]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[18]': Starting task run...\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[18]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[19]': Starting task run...\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[19]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:18+0000] INFO - prefect.TaskRunner | Task 'store_chunk[20]': Starting task run...\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[20]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[21]': Starting task run...\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[21]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[22]': Starting task run...\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[22]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[23]': Starting task run...\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'store_chunk[23]': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'finalize_target': Starting task run...\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.TaskRunner | Task 'finalize_target': Finished task run for task with final state: 'Success'\n", + "[2021-06-24 17:52:19+0000] INFO - prefect.FlowRunner | Flow run SUCCESS: all reference tasks succeeded\n" ] }, { @@ -2585,7 +2693,7 @@ "" ] }, - "execution_count": 27, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -2605,7 +2713,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -2997,7 +3105,7 @@ " time_coverage_end: 2017-01-31\n", " time_coverage_resolution: P01M\n", " time_coverage_start: 1955-01-01\n", - " title: World Ocean Atlas 2018 : sea_water_salin...