From 3703611bf3dabcd71264480fbcdeec476027dec2 Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Thu, 25 Apr 2024 14:21:37 -0600 Subject: [PATCH 1/9] Added function to load CDF file --- imap_processing/cdf/utils.py | 19 ++++++++++++++++++- imap_processing/tests/cdf/test_utils.py | 12 +++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/imap_processing/cdf/utils.py b/imap_processing/cdf/utils.py index b8bf155cf..2a3b235a5 100644 --- a/imap_processing/cdf/utils.py +++ b/imap_processing/cdf/utils.py @@ -2,11 +2,12 @@ import logging import re +from pathlib import Path import imap_data_access import numpy as np import xarray as xr -from cdflib.xarray import xarray_to_cdf +from cdflib.xarray import cdf_to_xarray, xarray_to_cdf from imap_processing import launch_time @@ -41,6 +42,22 @@ def calc_start_time(shcoarse_time: float) -> np.datetime64: return launch_time + time_delta +def load_cdf(file_path: Path) -> xr.Dataset: + """Load the contents of a CDF file into an ``xarray`` dataset. + + Parameters + ---------- + file_path : Path + The path to the CDF file + + Returns + ------- + dataset : xr.Dataset + The ``xarray`` dataset for the CDF file + """ + return cdf_to_xarray(file_path) + + def write_cdf(dataset: xr.Dataset): """Write the contents of "data" to a CDF file using cdflib.xarray_to_cdf. diff --git a/imap_processing/tests/cdf/test_utils.py b/imap_processing/tests/cdf/test_utils.py index 1c2dc01b1..a54963a5d 100644 --- a/imap_processing/tests/cdf/test_utils.py +++ b/imap_processing/tests/cdf/test_utils.py @@ -1,10 +1,12 @@ +from pathlib import Path + import imap_data_access import numpy as np import xarray as xr from imap_processing import launch_time from imap_processing.cdf.global_attrs import ConstantCoordinates -from imap_processing.cdf.utils import calc_start_time, write_cdf +from imap_processing.cdf.utils import calc_start_time, load_cdf, write_cdf from imap_processing.swe.swe_cdf_attrs import swe_l1a_global_attrs @@ -13,6 +15,14 @@ def test_calc_start_time(): assert calc_start_time(1) == launch_time + np.timedelta64(1, "s") +def test_load_cdf(): + """Tests the ``load_cdf`` function.""" + + file_path = Path("data/imap_codice_l1a_lo-sw-species-counts_20100101_v001.cdf") + dataset = load_cdf(file_path) + assert isinstance(dataset, xr.core.dataset.Dataset) + + def test_write_cdf(): # Set up a fake dataset # lots of requirements on attributes, so depend on SWE for now From d8cb4010c2eeda95b65a3d3e96e9a5748baf2f4b Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Thu, 25 Apr 2024 14:23:41 -0600 Subject: [PATCH 2/9] Added missing docstrings --- imap_processing/tests/cdf/test_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/imap_processing/tests/cdf/test_utils.py b/imap_processing/tests/cdf/test_utils.py index a54963a5d..627774397 100644 --- a/imap_processing/tests/cdf/test_utils.py +++ b/imap_processing/tests/cdf/test_utils.py @@ -1,3 +1,5 @@ +"""Tests for the ``cdf.utils`` module.""" + from pathlib import Path import imap_data_access @@ -11,6 +13,8 @@ def test_calc_start_time(): + """Tests the ``calc_start_time`` function""" + assert calc_start_time(0) == launch_time assert calc_start_time(1) == launch_time + np.timedelta64(1, "s") @@ -24,6 +28,8 @@ def test_load_cdf(): def test_write_cdf(): + """Tests the ``write_cdf`` function.""" + # Set up a fake dataset # lots of requirements on attributes, so depend on SWE for now dataset = xr.Dataset( From 64b85f18e5f9ab0ee107313dc66d4fdda1c873ec Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Thu, 25 Apr 2024 14:33:41 -0600 Subject: [PATCH 3/9] Added CDF file for testing --- .../imap_codice_l1a_hskp_20100101_v001.cdf | Bin 0 -> 276849 bytes imap_processing/tests/cdf/test_utils.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 imap_processing/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf diff --git a/imap_processing/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf b/imap_processing/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf new file mode 100644 index 0000000000000000000000000000000000000000..f0cbec54c689be7e3124a9f50695886e08f59c73 GIT binary patch literal 276849 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 T&)m!NVd;mj><-HP_kaEyyBfGb literal 0 HcmV?d00001 diff --git a/imap_processing/tests/cdf/test_utils.py b/imap_processing/tests/cdf/test_utils.py index 627774397..72e0dd499 100644 --- a/imap_processing/tests/cdf/test_utils.py +++ b/imap_processing/tests/cdf/test_utils.py @@ -22,7 +22,7 @@ def test_calc_start_time(): def test_load_cdf(): """Tests the ``load_cdf`` function.""" - file_path = Path("data/imap_codice_l1a_lo-sw-species-counts_20100101_v001.cdf") + file_path = Path("data/imap_codice_l1a_hskp_20100101_v001.cdf") dataset = load_cdf(file_path) assert isinstance(dataset, xr.core.dataset.Dataset) From 80c6fb806828757ddd2d2cb7156d517cd0119a3a Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Thu, 25 Apr 2024 14:45:48 -0600 Subject: [PATCH 4/9] Fixed issue with path to test data --- imap_processing/tests/cdf/test_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imap_processing/tests/cdf/test_utils.py b/imap_processing/tests/cdf/test_utils.py index 72e0dd499..6f91794c1 100644 --- a/imap_processing/tests/cdf/test_utils.py +++ b/imap_processing/tests/cdf/test_utils.py @@ -6,7 +6,7 @@ import numpy as np import xarray as xr -from imap_processing import launch_time +from imap_processing import imap_module_directory, launch_time from imap_processing.cdf.global_attrs import ConstantCoordinates from imap_processing.cdf.utils import calc_start_time, load_cdf, write_cdf from imap_processing.swe.swe_cdf_attrs import swe_l1a_global_attrs @@ -22,7 +22,9 @@ def test_calc_start_time(): def test_load_cdf(): """Tests the ``load_cdf`` function.""" - file_path = Path("data/imap_codice_l1a_hskp_20100101_v001.cdf") + file_path = Path( + f"{imap_module_directory}/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf" + ) dataset = load_cdf(file_path) assert isinstance(dataset, xr.core.dataset.Dataset) From bc39c14611a1a68281306af854c6b8eea3d6049d Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Fri, 26 Apr 2024 16:48:39 -0600 Subject: [PATCH 5/9] Now using pytest fixture to produce a dataset and writing a CDF file within the testing framework, instead of using an "external" CDF file. Also fixed small docstring formatting issue --- imap_processing/cdf/utils.py | 8 +-- .../imap_codice_l1a_hskp_20100101_v001.cdf | Bin 276849 -> 0 bytes imap_processing/tests/cdf/test_utils.py | 65 +++++++++++------- 3 files changed, 45 insertions(+), 28 deletions(-) delete mode 100644 imap_processing/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf diff --git a/imap_processing/cdf/utils.py b/imap_processing/cdf/utils.py index 2a3b235a5..398ca7984 100644 --- a/imap_processing/cdf/utils.py +++ b/imap_processing/cdf/utils.py @@ -70,13 +70,13 @@ def write_cdf(dataset: xr.Dataset): Parameters ---------- - dataset : xarray.Dataset - The dataset object to convert to a CDF + dataset : xarray.Dataset + The dataset object to convert to a CDF Returns ------- - pathlib.Path - Path to the file created + pathlib.Path + Path to the file created """ # Create the filename from the global attributes # Logical_source looks like "imap_swe_l2_counts-1min" diff --git a/imap_processing/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf b/imap_processing/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf deleted file mode 100644 index f0cbec54c689be7e3124a9f50695886e08f59c73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276849 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 T&)m!NVd;mj><-HP_kaEyyBfGb diff --git a/imap_processing/tests/cdf/test_utils.py b/imap_processing/tests/cdf/test_utils.py index 6f91794c1..306eff796 100644 --- a/imap_processing/tests/cdf/test_utils.py +++ b/imap_processing/tests/cdf/test_utils.py @@ -1,39 +1,26 @@ """Tests for the ``cdf.utils`` module.""" -from pathlib import Path - import imap_data_access import numpy as np +import pytest import xarray as xr -from imap_processing import imap_module_directory, launch_time +from imap_processing import launch_time from imap_processing.cdf.global_attrs import ConstantCoordinates from imap_processing.cdf.utils import calc_start_time, load_cdf, write_cdf from imap_processing.swe.swe_cdf_attrs import swe_l1a_global_attrs -def test_calc_start_time(): - """Tests the ``calc_start_time`` function""" - - assert calc_start_time(0) == launch_time - assert calc_start_time(1) == launch_time + np.timedelta64(1, "s") - - -def test_load_cdf(): - """Tests the ``load_cdf`` function.""" - - file_path = Path( - f"{imap_module_directory}/tests/cdf/data/imap_codice_l1a_hskp_20100101_v001.cdf" - ) - dataset = load_cdf(file_path) - assert isinstance(dataset, xr.core.dataset.Dataset) - +@pytest.fixture() +def test_dataset(): + """Create a simple ``xarray`` dataset to be used in testing -def test_write_cdf(): - """Tests the ``write_cdf`` function.""" + Returns + ------- + dataset : xarray.Dataset + The ``xarray`` dataset object + """ - # Set up a fake dataset - # lots of requirements on attributes, so depend on SWE for now dataset = xr.Dataset( { "epoch": ( @@ -50,7 +37,37 @@ def test_write_cdf(): ) dataset["epoch"].attrs = ConstantCoordinates.EPOCH - file_path = write_cdf(dataset) + return dataset + + +def test_calc_start_time(): + """Tests the ``calc_start_time`` function""" + + assert calc_start_time(0) == launch_time + assert calc_start_time(1) == launch_time + np.timedelta64(1, "s") + + +def test_load_cdf(test_dataset): + """Tests the ``load_cdf`` function.""" + + # Write the dataset to a CDF to be used to test the load function + file_path = write_cdf(test_dataset) + + # Load the CDF and ensure the function returns a dataset + dataset = load_cdf(file_path) + assert isinstance(dataset, xr.core.dataset.Dataset) + + +def test_write_cdf(test_dataset): + """Tests the ``write_cdf`` function. + + Parameters + ---------- + dataset : xarray.Dataset + An ``xarray`` dataset object to test with + """ + + file_path = write_cdf(test_dataset) assert file_path.exists() assert file_path.name == "imap_swe_l1_sci_20100101_v001.cdf" assert file_path.relative_to(imap_data_access.config["DATA_DIR"]) From 513a576b303d8c56f3b682df7edfb9ae57fd6613 Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Mon, 29 Apr 2024 11:15:31 -0600 Subject: [PATCH 6/9] Replaced references to cdf_to_xarray with new load_cdf function --- imap_processing/cli.py | 5 ++--- imap_processing/tests/codice/test_codice_l1a.py | 4 ++-- imap_processing/tests/idex/test_l1_cdfs.py | 7 ++----- imap_processing/tests/mag/test_mag_decom.py | 7 +++---- imap_processing/tests/swe/test_swe_l1b.py | 5 ++--- imap_processing/tests/ultra/unit/test_ultra_l1a.py | 10 +++++----- 6 files changed, 16 insertions(+), 22 deletions(-) diff --git a/imap_processing/cli.py b/imap_processing/cli.py index aface71d9..af7bbd262 100644 --- a/imap_processing/cli.py +++ b/imap_processing/cli.py @@ -19,7 +19,6 @@ from urllib.error import HTTPError import imap_data_access -from cdflib.xarray import cdf_to_xarray import imap_processing @@ -31,7 +30,7 @@ # from imap_processing import cdf # In code: # call cdf.utils.write_cdf -from imap_processing.cdf.utils import write_cdf +from imap_processing.cdf.utils import load_cdf, write_cdf from imap_processing.mag.l1a.mag_l1a import mag_l1a from imap_processing.swe.l1a.swe_l1a import swe_l1a from imap_processing.swe.l1b.swe_l1b import swe_l1b @@ -352,7 +351,7 @@ def process(self): elif self.data_level == "l1b": # read CDF file - l1a_dataset = cdf_to_xarray(dependencies[0]) + l1a_dataset = load_cdf(dependencies[0]) processed_data = swe_l1b(l1a_dataset) # TODO: Pass in the proper version and descriptor cdf_file_path = write_cdf(data=processed_data) diff --git a/imap_processing/tests/codice/test_codice_l1a.py b/imap_processing/tests/codice/test_codice_l1a.py index 5b9c638a6..aa9b80eff 100644 --- a/imap_processing/tests/codice/test_codice_l1a.py +++ b/imap_processing/tests/codice/test_codice_l1a.py @@ -2,12 +2,12 @@ from pathlib import Path -import cdflib import numpy as np import pytest import xarray as xr from imap_processing import imap_module_directory +from imap_processing.cdf.utils import load_cdf from imap_processing.codice.codice_l0 import decom_packets from imap_processing.codice.codice_l1a import process_codice_l1a @@ -140,7 +140,7 @@ def test_l1a_data_array_values(test_l1a_data: xr.Dataset, validation_data: Path) """ generated_dataset = test_l1a_data - validation_dataset = cdflib.xarray.cdf_to_xarray(validation_data) + validation_dataset = load_cdf(validation_data) # Ensure the processed data matches the validation data for variable in validation_dataset: diff --git a/imap_processing/tests/idex/test_l1_cdfs.py b/imap_processing/tests/idex/test_l1_cdfs.py index f659c0c92..82042d3c6 100644 --- a/imap_processing/tests/idex/test_l1_cdfs.py +++ b/imap_processing/tests/idex/test_l1_cdfs.py @@ -5,11 +5,10 @@ import numpy as np import pytest import xarray as xr -from cdflib.xarray import cdf_to_xarray from cdflib.xarray.xarray_to_cdf import ISTPError from imap_processing import imap_module_directory -from imap_processing.cdf.utils import write_cdf +from imap_processing.cdf.utils import load_cdf, write_cdf from imap_processing.idex.idex_packet_parser import PacketParser @@ -74,7 +73,5 @@ def test_idex_tof_high_data_from_cdf(decom_test_data): data = np.array([int(line.rstrip()) for line in f]) file_name = write_cdf(decom_test_data) - l1_data = cdf_to_xarray( - file_name - ) # Read in the data from the CDF file to an xarray object + l1_data = load_cdf(file_name) assert (l1_data["TOF_High"][13].data == data).all() diff --git a/imap_processing/tests/mag/test_mag_decom.py b/imap_processing/tests/mag/test_mag_decom.py index f02c13e6a..e2217275e 100644 --- a/imap_processing/tests/mag/test_mag_decom.py +++ b/imap_processing/tests/mag/test_mag_decom.py @@ -1,10 +1,9 @@ from pathlib import Path import pandas as pd -from cdflib.xarray import cdf_to_xarray from imap_processing.cdf import global_attrs -from imap_processing.cdf.utils import write_cdf +from imap_processing.cdf.utils import load_cdf, write_cdf from imap_processing.mag import mag_cdf_attrs from imap_processing.mag.l0.decom_mag import decom_packets, generate_dataset @@ -91,12 +90,12 @@ def test_mag_raw_cdf_generation(): assert output.exists() assert output.name == "imap_mag_l1a_norm-raw_20231025_v001.cdf" - input_xarray = cdf_to_xarray(output) + input_xarray = load_cdf(output) assert input_xarray.attrs.keys() == norm_data.attrs.keys() output = write_cdf(burst_data) assert output.exists() assert output.name == "imap_mag_l1a_burst-raw_20231025_v001.cdf" - input_xarray = cdf_to_xarray(output) + input_xarray = load_cdf(output) assert input_xarray.attrs.keys() == burst_data.attrs.keys() diff --git a/imap_processing/tests/swe/test_swe_l1b.py b/imap_processing/tests/swe/test_swe_l1b.py index 2effd5f3e..46cdac570 100644 --- a/imap_processing/tests/swe/test_swe_l1b.py +++ b/imap_processing/tests/swe/test_swe_l1b.py @@ -1,9 +1,8 @@ import pandas as pd import pytest -from cdflib.xarray import cdf_to_xarray from imap_processing import imap_module_directory -from imap_processing.cdf.utils import write_cdf +from imap_processing.cdf.utils import load_cdf, write_cdf from imap_processing.swe.l0 import decom_swe from imap_processing.swe.l1a.swe_l1a import swe_l1a from imap_processing.swe.l1a.swe_science import swe_science @@ -132,7 +131,7 @@ def test_cdf_creation(): assert hk_l1a_filepath.name == "imap_swe_l1a_sci_20230927_v001.cdf" # reads data from CDF file and passes to l1b - l1a_cdf_dataset = cdf_to_xarray(hk_l1a_filepath, to_datetime=True) + l1a_cdf_dataset = load_cdf(hk_l1a_filepath, to_datetime=True) l1b_dataset = swe_l1b(l1a_cdf_dataset) hk_l1b_filepath = write_cdf(l1b_dataset) diff --git a/imap_processing/tests/ultra/unit/test_ultra_l1a.py b/imap_processing/tests/ultra/unit/test_ultra_l1a.py index 0c4be375e..8e638f93c 100644 --- a/imap_processing/tests/ultra/unit/test_ultra_l1a.py +++ b/imap_processing/tests/ultra/unit/test_ultra_l1a.py @@ -1,8 +1,8 @@ import dataclasses import pytest -from cdflib.xarray import cdf_to_xarray +from imap_processing.cdf.utils import load_cdf from imap_processing.ultra import ultra_cdf_attrs from imap_processing.ultra.l0.decom_ultra import decom_ultra_apids from imap_processing.ultra.l0.ultra_utils import ( @@ -185,7 +185,7 @@ def test_cdf_aux( assert test_data_path.name == "imap_ultra_l1a_sci_20220530_v001.cdf" dataset_aux = create_dataset({ULTRA_AUX.apid[0]: decom_ultra_aux}) - input_xarray_aux = cdf_to_xarray(test_data_path) + input_xarray_aux = load_cdf(test_data_path) assert input_xarray_aux.attrs.keys() == dataset_aux.attrs.keys() @@ -203,7 +203,7 @@ def test_cdf_rates( assert test_data_path.name == "imap_ultra_l1a_sci_20220530_v001.cdf" dataset_rates = create_dataset({ULTRA_RATES.apid[0]: decom_ultra_rates}) - input_xarray_rates = cdf_to_xarray(test_data_path) + input_xarray_rates = load_cdf(test_data_path) assert input_xarray_rates.attrs.keys() == dataset_rates.attrs.keys() @@ -219,7 +219,7 @@ def test_cdf_tof( assert test_data_path.name == "imap_ultra_l1a_sci_20240124_v001.cdf" dataset_tof = create_dataset({ULTRA_TOF.apid[0]: decom_ultra_tof}) - input_xarray_tof = cdf_to_xarray(test_data_path) + input_xarray_tof = load_cdf(test_data_path) assert input_xarray_tof.attrs.keys() == dataset_tof.attrs.keys() @@ -243,6 +243,6 @@ def test_cdf_events( dataset_events = create_dataset( {ULTRA_EVENTS.apid[0]: decom_ultra_events, ULTRA_AUX.apid[0]: decom_ultra_aux} ) - input_xarray_events = cdf_to_xarray(test_data_path) + input_xarray_events = load_cdf(test_data_path) assert input_xarray_events.attrs.keys() == dataset_events.attrs.keys() From c71ecf0df84e879d8de11142a132e12b79cadfef Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Mon, 29 Apr 2024 11:59:58 -0600 Subject: [PATCH 7/9] Added kwargs support for load_cdf --- imap_processing/cdf/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imap_processing/cdf/utils.py b/imap_processing/cdf/utils.py index 398ca7984..51d42081c 100644 --- a/imap_processing/cdf/utils.py +++ b/imap_processing/cdf/utils.py @@ -42,20 +42,22 @@ def calc_start_time(shcoarse_time: float) -> np.datetime64: return launch_time + time_delta -def load_cdf(file_path: Path) -> xr.Dataset: +def load_cdf(file_path: Path, **kwargs) -> xr.Dataset: """Load the contents of a CDF file into an ``xarray`` dataset. Parameters ---------- file_path : Path The path to the CDF file + kwargs : dict + Keyword arguments for ``cdf_to_xarray`` Returns ------- dataset : xr.Dataset The ``xarray`` dataset for the CDF file """ - return cdf_to_xarray(file_path) + return cdf_to_xarray(file_path, kwargs) def write_cdf(dataset: xr.Dataset): From 2c331c059fe0e325ef136da3235aea7295fe2479 Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Thu, 2 May 2024 09:56:48 -0600 Subject: [PATCH 8/9] Updated docstrings --- imap_processing/cdf/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imap_processing/cdf/utils.py b/imap_processing/cdf/utils.py index 51d42081c..4f584acbf 100644 --- a/imap_processing/cdf/utils.py +++ b/imap_processing/cdf/utils.py @@ -42,19 +42,19 @@ def calc_start_time(shcoarse_time: float) -> np.datetime64: return launch_time + time_delta -def load_cdf(file_path: Path, **kwargs) -> xr.Dataset: +def load_cdf(file_path: Path, **kwargs: dict) -> xr.Dataset: """Load the contents of a CDF file into an ``xarray`` dataset. Parameters ---------- file_path : Path The path to the CDF file - kwargs : dict + **kwargs : dict, optional Keyword arguments for ``cdf_to_xarray`` Returns ------- - dataset : xr.Dataset + xr.Dataset The ``xarray`` dataset for the CDF file """ return cdf_to_xarray(file_path, kwargs) @@ -77,7 +77,7 @@ def write_cdf(dataset: xr.Dataset): Returns ------- - pathlib.Path + file_path: pathlib.Path Path to the file created """ # Create the filename from the global attributes From 6d57ec594d08b02901022f4d6b83eb953d95dbf7 Mon Sep 17 00:00:00 2001 From: Matthew Bourque Date: Mon, 6 May 2024 14:34:52 -0600 Subject: [PATCH 9/9] Added code to convert attribute lists back to single values where applicable --- imap_processing/cdf/utils.py | 13 +++++++++++-- imap_processing/tests/cdf/test_utils.py | 24 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/imap_processing/cdf/utils.py b/imap_processing/cdf/utils.py index 4f584acbf..6dc198113 100644 --- a/imap_processing/cdf/utils.py +++ b/imap_processing/cdf/utils.py @@ -54,10 +54,19 @@ def load_cdf(file_path: Path, **kwargs: dict) -> xr.Dataset: Returns ------- - xr.Dataset + dataset : xr.Dataset The ``xarray`` dataset for the CDF file """ - return cdf_to_xarray(file_path, kwargs) + dataset = cdf_to_xarray(file_path, kwargs) + + # cdf_to_xarray converts single-value attributes to lists + # convert these back to single values where applicable + for attribute in dataset.attrs: + value = dataset.attrs[attribute] + if isinstance(value, list) and len(value) == 1: + dataset.attrs[attribute] = value[0] + + return dataset def write_cdf(dataset: xr.Dataset): diff --git a/imap_processing/tests/cdf/test_utils.py b/imap_processing/tests/cdf/test_utils.py index 306eff796..459dfe13a 100644 --- a/imap_processing/tests/cdf/test_utils.py +++ b/imap_processing/tests/cdf/test_utils.py @@ -33,9 +33,14 @@ def test_dataset(): ) }, attrs=swe_l1a_global_attrs.output() - | {"Logical_source": "imap_swe_l1_sci", "Data_version": "001"}, + | { + "Logical_source": "imap_swe_l1_sci", + "Data_version": "001", + "Logical_file_id": "imap_swe_l1_sci_20100101_v001", + }, ) dataset["epoch"].attrs = ConstantCoordinates.EPOCH + dataset["epoch"].attrs["DEPEND_0"] = "epoch" return dataset @@ -71,3 +76,20 @@ def test_write_cdf(test_dataset): assert file_path.exists() assert file_path.name == "imap_swe_l1_sci_20100101_v001.cdf" assert file_path.relative_to(imap_data_access.config["DATA_DIR"]) + + +def test_written_and_loaded_dataset(test_dataset): + """Tests that a dataset that is written to CDF and then loaded results in + the original dataset. + + Parameters + ---------- + dataset : xarray.Dataset + An ``xarray`` dataset object to test with + """ + + new_dataset = load_cdf(write_cdf(test_dataset), to_datetime=True) + new_dataset.attrs["PI_affiliation"] = tuple( + new_dataset.attrs["PI_affiliation"] + ) # The PI_affiliation attribute should be a tuple + assert str(test_dataset) == str(new_dataset)