Kerchunk and Pangeo-Forge

Overview

In this tutorial we are going to use the open-source ETL pipeline named pangeo-forge-recipes to generate Kerchunk references.

Pangeo-Forge is a community project to build reproducible cloud-native ARCO (Analysis-Ready-Cloud-Optimized) datasets. The Python library (pangeo-forge-recipes) is the ETL pipeline to process these datasets or “recipes”. While a majority of the recipes convert a legacy format such as NetCDF to Zarr stores, pangeo-forge-recipes can also use Kerchunk under the hood to create reference recipes.

It is important to note that Kerchunk can be used independently of pangeo-forge-recipes and in this example, pangeo-forge-recipes is acting as the runner for Kerchunk.

Prerequisites

Concepts

Importance

Notes

Kerchunk Basics

Required

Core

Multiple Files and Kerchunk

Required

Core

Multi-File Datasets with Kerchunk

Required

IO/Visualization

  • Time to learn: 45 minutes


Getting to Know The Data

gridMET is a high-resolution daily meteorological dataset covering CONUS from 1979-2023. It is produced by the Climatology Lab at UC Merced. In this example, we are going to look create a virtual Zarr dataset of a derived variable, Burn Index.

Examine a Single File

import xarray as xr

ds = xr.open_dataset(
    "http://thredds.northwestknowledge.net:8080/thredds/dodsC/MET/bi/bi_2021.nc"
)

Plot the Dataset

ds.sel(day="2021-08-01").burning_index_g.plot()
<matplotlib.collections.QuadMesh at 0x7f9ac9933af0>
../../_images/1924f5baf6fc152c3bb7b7b6e9636ad9b7eeba036a2383c1c2dfe18581ab6e7d.png

Create a File Pattern

To build our pangeo-forge pipeline, we need to create a FilePattern object, which is composed of all of our input urls. This dataset ranges from 1979 through 2023 and is composed of one year per file.

To speed up our example, we will prune our recipe to select the first two entries in the FilePattern

from pangeo_forge_recipes.patterns import ConcatDim, FilePattern

years = list(range(1979, 2022 + 1))


time_dim = ConcatDim("time", keys=years)


def format_function(time):
    return f"http://www.northwestknowledge.net/metdata/data/bi_{time}.nc"


pattern = FilePattern(format_function, time_dim, file_type="netcdf4")


pattern = pattern.prune()

pattern
<FilePattern {'time': 2}>

Create a Location For Output

We write to local storage for this example, but the reference file could also be shared via cloud storage.

target_root = "references"
store_name = "Pangeo_Forge"

Build the Pangeo-Forge Beam Pipeline

Next, we will chain together a bunch of methods to create a Pangeo-Forge - Apache Beam pipeline. Processing steps are chained together with the pipe operator (|). Once the pipeline is built, it can be ran in the following cell.

The steps are as follows:

  1. Creates a starting collection of our input file patterns.

  2. Passes those file_patterns to OpenWithKerchunk, which creates references of each file.

  3. Combines the references files into a single reference file and write them with WriteCombineReferences

Just like Kerchunk, you can specify the reference file type as either .json or .parquet.

Note: You can add additional processing steps in this pipeline.

import apache_beam as beam
from pangeo_forge_recipes.transforms import OpenWithKerchunk, WriteCombinedReference

transforms = (
    # Create a beam PCollection from our input file pattern
    beam.Create(pattern.items())
    # Open with Kerchunk and create references for each file
    | OpenWithKerchunk(file_type=pattern.file_type)
    # Use Kerchunk's `MultiZarrToZarr` functionality to combine and
    # then write references. Note: Setting the correct contact_dims
    # and identical_dims is important.
    | WriteCombinedReference(
        target_root=target_root,
        store_name=store_name,
        output_file_name="reference.json",
        concat_dims=["day"],
        identical_dims=["lat", "lon", "crs"],
    )
)
%%time

with beam.Pipeline() as p:
    p | transforms
ERROR:apache_beam.runners.common:No dimension found with name day [while running '[6]: Create|OpenWithKerchunk|WriteCombinedReference/WriteCombinedReference/CombineReferences/Get just the positions']
Traceback (most recent call last):
  File "apache_beam/runners/common.py", line 1435, in apache_beam.runners.common.DoFnRunner.process
  File "apache_beam/runners/common.py", line 637, in apache_beam.runners.common.SimpleInvoker.invoke_process
  File "/home/runner/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/transforms/core.py", line 2040, in <lambda>
    wrapper = lambda x: [fn(*x)]
  File "/home/runner/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/pangeo_forge_recipes/transforms.py", line 525, in <lambda>
    >> beam.MapTuple(lambda k, v: k.find_position(self.sort_dimension))
  File "/home/runner/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/pangeo_forge_recipes/types.py", line 81, in find_position
    raise ValueError(f"No dimension found with name {dim_name}")
ValueError: No dimension found with name day
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1435, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:637, in apache_beam.runners.common.SimpleInvoker.invoke_process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/transforms/core.py:2040, in MapTuple.<locals>.<lambda>(x)
   2039 else:
-> 2040   wrapper = lambda x: [fn(*x)]
   2042 # Proxy the type-hint information from the original function to this new
   2043 # wrapped function.

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/pangeo_forge_recipes/transforms.py:525, in CombineReferences.expand.<locals>.<lambda>(k, v)
    521 def expand(self, reference_lists: beam.PCollection) -> beam.PCollection:
    522     min_max_count_positions = (
    523         reference_lists
    524         | "Get just the positions"
--> 525         >> beam.MapTuple(lambda k, v: k.find_position(self.sort_dimension))
    526         | "Get minimum/maximum positions" >> beam.CombineGlobally(MinMaxCountCombineFn())
    527     )
    528     return (
    529         reference_lists
    530         | "Handle special case of gribs" >> beam.Map(self.handle_gribs)
   (...)
    540         | "Global reduce" >> beam.MapTuple(lambda k, refs: self.global_combine_refs(refs))
    541     )

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/pangeo_forge_recipes/types.py:81, in Index.find_position(self, dim_name)
     80 else:
---> 81     raise ValueError(f"No dimension found with name {dim_name}")

ValueError: No dimension found with name day

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
File <timed exec>:1

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/pipeline.py:612, in Pipeline.__exit__(self, exc_type, exc_val, exc_tb)
    610 try:
    611   if not exc_type:
--> 612     self.result = self.run()
    613     self.result.wait_until_finish()
    614 finally:

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/pipeline.py:586, in Pipeline.run(self, test_runner_api)
    584     finally:
    585       shutil.rmtree(tmpdir)
--> 586   return self.runner.run_pipeline(self, self._options)
    587 finally:
    588   if not is_in_ipython():

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/direct/direct_runner.py:128, in SwitchingDirectRunner.run_pipeline(self, pipeline, options)
    125 else:
    126   runner = BundleBasedDirectRunner()
--> 128 return runner.run_pipeline(pipeline, options)

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/fn_runner.py:203, in FnApiRunner.run_pipeline(self, pipeline, options)
    192   _LOGGER.warning(
    193       'If direct_num_workers is not equal to 1, direct_running_mode '
    194       'should be `multi_processing` or `multi_threading` instead of '
   (...)
    197       self._num_workers,
    198       running_mode)
    200 self._profiler_factory = Profile.factory_from_options(
    201     options.view_as(pipeline_options.ProfilingOptions))
--> 203 self._latest_run_result = self.run_via_runner_api(
    204     pipeline.to_runner_api(default_environment=self._default_environment),
    205     options)
    206 return self._latest_run_result

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/fn_runner.py:226, in FnApiRunner.run_via_runner_api(self, pipeline_proto, options)
    224 pipeline_proto = self.resolve_any_environments(pipeline_proto)
    225 stage_context, stages = self.create_stages(pipeline_proto)
--> 226 return self.run_stages(stage_context, stages)

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/fn_runner.py:481, in FnApiRunner.run_stages(self, stage_context, stages)
    478 assert consuming_stage_name == bundle_context_manager.stage.name
    480 bundle_counter += 1
--> 481 bundle_results = self._execute_bundle(
    482     runner_execution_context, bundle_context_manager, bundle_input)
    484 if consuming_stage_name in monitoring_infos_by_stage:
    485   monitoring_infos_by_stage[
    486       consuming_stage_name] = consolidate_monitoring_infos(
    487           itertools.chain(
    488               bundle_results.process_bundle.monitoring_infos,
    489               monitoring_infos_by_stage[consuming_stage_name]))

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/fn_runner.py:809, in FnApiRunner._execute_bundle(self, runner_execution_context, bundle_context_manager, bundle_input)
    804 # We create the bundle manager here, as it can be reused for bundles of
    805 # the same stage, but it may have to be created by-bundle later on.
    806 bundle_manager = self._get_bundle_manager(bundle_context_manager)
    808 last_result, deferred_inputs, newly_set_timers, watermark_updates = (
--> 809     self._run_bundle(
    810         runner_execution_context,
    811         bundle_context_manager,
    812         bundle_input,
    813         bundle_context_manager.stage_data_outputs,
    814         bundle_context_manager.stage_timer_outputs,
    815         bundle_manager))
    817 for pc_name, watermark in watermark_updates.items():
    818   _BUNDLE_LOGGER.debug('Update: %s %s', pc_name, watermark)

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/fn_runner.py:1046, in FnApiRunner._run_bundle(self, runner_execution_context, bundle_context_manager, bundle_input, data_output, expected_timer_output, bundle_manager)
   1037 input_timers = bundle_input.timers
   1038 self._run_bundle_multiple_times_for_testing(
   1039     runner_execution_context,
   1040     bundle_manager,
   (...)
   1043     input_timers,
   1044     expected_timer_output)
-> 1046 result, splits = bundle_manager.process_bundle(
   1047     data_input, data_output, input_timers, expected_timer_output)
   1048 # Now we collect all the deferred inputs remaining from bundle execution.
   1049 # Deferred inputs can be:
   1050 # - timers
   1051 # - SDK-initiated deferred applications of root elements
   1052 # - Runner-initiated deferred applications of root elements
   1053 deferred_inputs = {}  # type: Dict[str, execution.PartitionableBuffer]

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/fn_runner.py:1382, in BundleManager.process_bundle(self, inputs, expected_outputs, fired_timers, expected_output_timers, dry_run)
   1375 # Actually start the bundle.
   1376 process_bundle_req = beam_fn_api_pb2.InstructionRequest(
   1377     instruction_id=process_bundle_id,
   1378     process_bundle=beam_fn_api_pb2.ProcessBundleRequest(
   1379         process_bundle_descriptor_id=self.bundle_context_manager.
   1380         process_bundle_descriptor.id,
   1381         cache_tokens=[next(self._cache_token_generator)]))
-> 1382 result_future = self._worker_handler.control_conn.push(process_bundle_req)
   1384 split_results = []  # type: List[beam_fn_api_pb2.ProcessBundleSplitResponse]
   1385 with ProgressRequester(self._worker_handler,
   1386                        process_bundle_id,
   1387                        self._progress_frequency):

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/portability/fn_api_runner/worker_handlers.py:384, in EmbeddedWorkerHandler.push(self, request)
    382   self._uid_counter += 1
    383   request.instruction_id = 'control_%s' % self._uid_counter
--> 384 response = self.worker.do_instruction(request)
    385 return ControlFuture(request.instruction_id, response)

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/sdk_worker.py:650, in SdkWorker.do_instruction(self, request)
    647 request_type = request.WhichOneof('request')
    648 if request_type:
    649   # E.g. if register is set, this will call self.register(request.register))
--> 650   return getattr(self, request_type)(
    651       getattr(request, request_type), request.instruction_id)
    652 else:
    653   raise NotImplementedError

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/sdk_worker.py:688, in SdkWorker.process_bundle(self, request, instruction_id)
    684 with bundle_processor.state_handler.process_instruction_id(
    685     instruction_id, request.cache_tokens):
    686   with self.maybe_profile(instruction_id):
    687     delayed_applications, requests_finalization = (
--> 688         bundle_processor.process_bundle(instruction_id))
    689     monitoring_infos = bundle_processor.monitoring_infos()
    690     response = beam_fn_api_pb2.InstructionResponse(
    691         instruction_id=instruction_id,
    692         process_bundle=beam_fn_api_pb2.ProcessBundleResponse(
   (...)
    698             },
    699             requires_finalization=requests_finalization))

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/bundle_processor.py:1113, in BundleProcessor.process_bundle(self, instruction_id)
   1110         self.ops[element.transform_id].process_timer(
   1111             element.timer_family_id, timer_data)
   1112     elif isinstance(element, beam_fn_api_pb2.Elements.Data):
-> 1113       input_op_by_transform_id[element.transform_id].process_encoded(
   1114           element.data)
   1116 # Finish all operations.
   1117 for op in self.ops.values():

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/bundle_processor.py:237, in DataInputOperation.process_encoded(self, encoded_windowed_values)
    233 except Exception as exn:
    234   raise ValueError(
    235       "Error decoding input stream with coder " +
    236       str(self.windowed_coder)) from exn
--> 237 self.output(decoded_value)

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:570, in apache_beam.runners.worker.operations.Operation.output()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:572, in apache_beam.runners.worker.operations.Operation.output()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:263, in apache_beam.runners.worker.operations.SingletonElementConsumerSet.receive()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:266, in apache_beam.runners.worker.operations.SingletonElementConsumerSet.receive()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:953, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:954, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1437, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1526, in apache_beam.runners.common.DoFnRunner._reraise_augmented()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1435, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:636, in apache_beam.runners.common.SimpleInvoker.invoke_process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1621, in apache_beam.runners.common._OutputHandler.handle_process_outputs()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1734, in apache_beam.runners.common._OutputHandler._write_value_to_tag()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:266, in apache_beam.runners.worker.operations.SingletonElementConsumerSet.receive()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:953, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:954, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1437, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1526, in apache_beam.runners.common.DoFnRunner._reraise_augmented()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1435, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:636, in apache_beam.runners.common.SimpleInvoker.invoke_process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1621, in apache_beam.runners.common._OutputHandler.handle_process_outputs()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1734, in apache_beam.runners.common._OutputHandler._write_value_to_tag()

    [... skipping similar frames: apache_beam.runners.common.DoFnRunner._reraise_augmented at line 1526 (1 times), apache_beam.runners.common.DoFnRunner.process at line 1437 (1 times), apache_beam.runners.common.DoFnRunner.process at line 1435 (1 times), apache_beam.runners.common.SimpleInvoker.invoke_process at line 636 (1 times), apache_beam.runners.common._OutputHandler._write_value_to_tag at line 1734 (1 times), apache_beam.runners.common._OutputHandler.handle_process_outputs at line 1621 (1 times), apache_beam.runners.worker.operations.DoOperation.process at line 953 (1 times), apache_beam.runners.worker.operations.DoOperation.process at line 954 (1 times), apache_beam.runners.worker.operations.SingletonElementConsumerSet.receive at line 266 (1 times)]

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:266, in apache_beam.runners.worker.operations.SingletonElementConsumerSet.receive()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:953, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:954, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1437, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1526, in apache_beam.runners.common.DoFnRunner._reraise_augmented()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1435, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:636, in apache_beam.runners.common.SimpleInvoker.invoke_process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1621, in apache_beam.runners.common._OutputHandler.handle_process_outputs()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1734, in apache_beam.runners.common._OutputHandler._write_value_to_tag()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:352, in apache_beam.runners.worker.operations.GeneralPurposeConsumerSet.receive()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:951, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:953, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/worker/operations.py:954, in apache_beam.runners.worker.operations.DoOperation.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1437, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1547, in apache_beam.runners.common.DoFnRunner._reraise_augmented()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:1435, in apache_beam.runners.common.DoFnRunner.process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/runners/common.py:637, in apache_beam.runners.common.SimpleInvoker.invoke_process()

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/apache_beam/transforms/core.py:2040, in MapTuple.<locals>.<lambda>(x)
   2038   wrapper = lambda x, *args, **kwargs: [fn(*(tuple(x) + args), **kwargs)]
   2039 else:
-> 2040   wrapper = lambda x: [fn(*x)]
   2042 # Proxy the type-hint information from the original function to this new
   2043 # wrapped function.
   2044 type_hints = get_type_hints(fn).with_defaults(
   2045     typehints.decorators.IOTypeHints.from_callable(fn))

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/pangeo_forge_recipes/transforms.py:525, in CombineReferences.expand.<locals>.<lambda>(k, v)
    521 def expand(self, reference_lists: beam.PCollection) -> beam.PCollection:
    522     min_max_count_positions = (
    523         reference_lists
    524         | "Get just the positions"
--> 525         >> beam.MapTuple(lambda k, v: k.find_position(self.sort_dimension))
    526         | "Get minimum/maximum positions" >> beam.CombineGlobally(MinMaxCountCombineFn())
    527     )
    528     return (
    529         reference_lists
    530         | "Handle special case of gribs" >> beam.Map(self.handle_gribs)
   (...)
    540         | "Global reduce" >> beam.MapTuple(lambda k, refs: self.global_combine_refs(refs))
    541     )

File ~/miniconda3/envs/kerchunk-cookbook/lib/python3.10/site-packages/pangeo_forge_recipes/types.py:81, in Index.find_position(self, dim_name)
     79     return self[dimension].value
     80 else:
---> 81     raise ValueError(f"No dimension found with name {dim_name}")

ValueError: No dimension found with name day [while running '[6]: Create|OpenWithKerchunk|WriteCombinedReference/WriteCombinedReference/CombineReferences/Get just the positions']