From b88509cd236f3be1c85cd0319bd2473ad0ae3eab Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Fri, 27 Sep 2024 19:04:10 +0530 Subject: [PATCH 01/18] basic regression data setup --- .github/actions/setup_lfs/action.yml | 52 ++++++ .github/workflows/tests.yml | 5 +- stardis/conftest.py | 31 ++++ stardis/util/__init__.py | 0 stardis/util/hdf_writer_mixin.py | 244 ++++++++++++++++++++++++++ stardis/util/regression_data.py | 169 ++++++++++++++++++ stardis/util/tests/test_regression.py | 7 + 7 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 .github/actions/setup_lfs/action.yml create mode 100644 stardis/util/__init__.py create mode 100644 stardis/util/hdf_writer_mixin.py create mode 100644 stardis/util/regression_data.py create mode 100644 stardis/util/tests/test_regression.py diff --git a/.github/actions/setup_lfs/action.yml b/.github/actions/setup_lfs/action.yml new file mode 100644 index 00000000..3855931b --- /dev/null +++ b/.github/actions/setup_lfs/action.yml @@ -0,0 +1,52 @@ +name: "Setup LFS" +description: "Pull LFS repositories and caches them" + + +inputs: + regression-data-repo: + description: "stardis regression data repository" + required: false + default: "tardis-sn/stardis-regression-data" + +runs: + using: "composite" + steps: + - name: Clone tardis-sn/stardis-regression-data + uses: actions/checkout@v4 + with: + repository: ${{ inputs.regression-data-repo }} + path: stardis-regression-data + + - name: Create LFS file list + run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id + working-directory: stardis-regression-data + shell: bash + + - name: Restore LFS cache + uses: actions/cache/restore@v4 + id: lfs-cache-regression-data + with: + path: stardis-regression-data/.git/lfs + key: ${{ runner.os }}-lfs-${{ hashFiles('stardis-regression-data/.lfs-assets-id') }}-v1 + + - name: Git LFS Pull + run: git lfs pull + working-directory: stardis-regression-data + if: steps.lfs-cache-regression-data.outputs.cache-hit != 'true' + shell: bash + + - name: Git LFS Checkout + run: git lfs checkout + working-directory: stardis-regression-data + if: steps.lfs-cache-regression-data.outputs.cache-hit == 'true' + shell: bash + + - name: Save LFS cache if not found + # uses fake ternary + # for reference: https://github.com/orgs/community/discussions/26738#discussioncomment-3253176 + if: ${{ steps.lfs-cache-regression-data.outputs.cache-hit != 'true' && !contains(github.ref, 'merge') && always() || false }} + uses: actions/cache/save@v4 + id: lfs-cache-regression-data-save + with: + path: stardis-regression-data/.git/lfs + key: ${{ runner.os }}-lfs-${{ hashFiles('stardis-regression-data/.lfs-assets-id') }}-v1 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f782247b..e81f3565 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ on: env: CACHE_NUMBER: 0 # increase to reset cache manually - PYTEST_FLAGS: --cov=stardis --cov-report=xml --cov-report=html + PYTEST_FLAGS: --cov=stardis --cov-report=xml --cov-report=html --stardis-regression-data=${{ github.workspace }}/stardis-regression-data CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} defaults: @@ -39,6 +39,9 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Setup LFS + uses: ./.github/actions/setup_lfs + - name: Setup Mambaforge uses: conda-incubator/setup-miniconda@v2 with: diff --git a/stardis/conftest.py b/stardis/conftest.py index 4aa591e1..5b12eee4 100644 --- a/stardis/conftest.py +++ b/stardis/conftest.py @@ -1,3 +1,4 @@ +import os import pytest from pathlib import Path import numpy as np @@ -15,6 +16,8 @@ from stardis.radiation_field.source_functions.blackbody import blackbody_flux_at_nu from stardis import STARDISOutput from stardis.io.base import SCHEMA_PATH +from stardis.util import regression_data + EXAMPLE_CONF_PATH = Path(__file__).parent / "tests" / "stardis_test_config.yml" EXAMPLE_CONF_PATH_BROADENING = ( @@ -24,6 +27,22 @@ Path(__file__).parent / "tests" / "stardis_test_config_parallel.yml" ) +# ensuring that regression_data is not removed by ruff +assert regression_data is not None + +def pytest_addoption(parser): + parser.addoption( + "--stardis-regression-data", + default=None, + help="Path to the stardis regression data directory", + ) + parser.addoption( + "--generate-reference", + action="store_true", + default=False, + help="generate reference data instead of testing", + ) + @pytest.fixture(scope="session") def example_tracing_nus(): @@ -281,3 +300,15 @@ def example_stardis_output_parallel( example_stellar_plasma, example_stellar_radiation_field_parallel, ) + +@pytest.fixture(scope="session") +def stardis_regression_path(request): + stardis_regression_path = request.config.getoption( + "--stardis-regression-data" + ) + if stardis_regression_path is None: + pytest.skip("--stardis-regression-data was not specified") + else: + return Path( + os.path.expandvars(os.path.expanduser(stardis_regression_path)) + ) diff --git a/stardis/util/__init__.py b/stardis/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/stardis/util/hdf_writer_mixin.py b/stardis/util/hdf_writer_mixin.py new file mode 100644 index 00000000..73a87e1f --- /dev/null +++ b/stardis/util/hdf_writer_mixin.py @@ -0,0 +1,244 @@ +import hashlib +import os +import logging +import re +import shutil +from functools import lru_cache + +import numpy as np +import pandas as pd +from astropy import units as u +from astropy.utils.data import download_file + +logger = logging.getLogger(__name__) + +class HDFWriterMixin(object): + def __new__(cls, *args, **kwargs): + instance = super(HDFWriterMixin, cls).__new__(cls) + instance.optional_hdf_properties = [] + instance.__init__(*args, **kwargs) + return instance + + @staticmethod + def to_hdf_util( + path_or_buf, path, elements, overwrite, complevel=9, complib="blosc" + ): + """ + A function to uniformly store TARDIS data to an HDF file. + + Scalars will be stored in a Series under path/scalars + 1D arrays will be stored under path/property_name as distinct Series + 2D arrays will be stored under path/property_name as distinct DataFrames + + Units will be stored as their CGS value + + Parameters + ---------- + path_or_buf : str or pandas.io.pytables.HDFStore + Path or buffer to the HDF file + path : str + Path inside the HDF file to store the `elements` + elements : dict + A dict of property names and their values to be + stored. + overwrite : bool + If the HDF file path already exists, whether to overwrite it or not + + Notes + ----- + `overwrite` option doesn't have any effect when `path_or_buf` is an + HDFStore because the user decides on the mode in which they have + opened the HDFStore ('r', 'w' or 'a'). + """ + if ( + isinstance(path_or_buf, str) + and os.path.exists(path_or_buf) + and not overwrite + ): + raise FileExistsError( + "The specified HDF file already exists. If you still want " + "to overwrite it, set function parameter overwrite=True" + ) + + else: + try: # when path_or_buf is a str, the HDFStore should get created + buf = pd.HDFStore( + path_or_buf, complevel=complevel, complib=complib + ) + except TypeError as e: + if str(e) == "Expected bytes, got HDFStore": + # when path_or_buf is an HDFStore buffer instead + logger.debug( + "Expected bytes, got HDFStore. Changing path to HDF buffer" + ) + buf = path_or_buf + else: + raise e + + if not buf.is_open: + buf.open() + + scalars = {} + for key, value in elements.items(): + if value is None: + value = "none" + if hasattr(value, "cgs"): + value = value.cgs.value + if np.isscalar(value): + scalars[key] = value + elif hasattr(value, "shape"): + if value.ndim == 1: + # This try,except block is only for model.plasma.levels + try: + pd.Series(value).to_hdf(buf, os.path.join(path, key)) + except NotImplementedError: + logger.debug( + "Could not convert SERIES to HDF. Converting DATAFRAME to HDF" + ) + pd.DataFrame(value).to_hdf(buf, os.path.join(path, key)) + else: + pd.DataFrame(value).to_hdf(buf, os.path.join(path, key)) + else: # value is a TARDIS object like model, transport or plasma + try: + value.to_hdf(buf, path, name=key, overwrite=overwrite) + except AttributeError: + logger.debug( + "Could not convert VALUE to HDF. Converting DATA (Dataframe) to HDF" + ) + data = pd.DataFrame([value]) + data.to_hdf(buf, os.path.join(path, key)) + + if scalars: + pd.Series(scalars).to_hdf(buf, os.path.join(path, "scalars")) + + if buf.is_open: + buf.close() + + def get_properties(self): + data = {name: getattr(self, name) for name in self.full_hdf_properties} + return data + + @property + def full_hdf_properties(self): + if hasattr(self, "virt_logging") and self.virt_logging: + self.hdf_properties.extend(self.vpacket_hdf_properties) + + return self.optional_hdf_properties + self.hdf_properties + + @staticmethod + def convert_to_snake_case(s): + s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", s) + return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() + + def to_hdf(self, file_path_or_buf, path="", name=None, overwrite=False): + """ + Parameters + ---------- + file_path_or_buf : str or pandas.io.pytables.HDFStore + Path or buffer to the HDF file + path : str + Path inside the HDF file to store the `elements` + name : str + Group inside the HDF file to which the `elements` need to be saved + overwrite : bool + If the HDF file path already exists, whether to overwrite it or not + """ + if name is None: + try: + name = self.hdf_name + except AttributeError: + name = self.convert_to_snake_case(self.__class__.__name__) + logger.debug( + f"self.hdf_name not present, setting name to {name} for HDF" + ) + + data = self.get_properties() + buff_path = os.path.join(path, name) + self.to_hdf_util(file_path_or_buf, buff_path, data, overwrite) + + +class PlasmaWriterMixin(HDFWriterMixin): + def get_properties(self): + data = {} + if self.collection: + properties = [ + name + for name in self.plasma_properties + if isinstance(name, tuple(self.collection)) + ] + else: + properties = self.plasma_properties + for prop in properties: + for output in prop.outputs: + data[output] = getattr(prop, output) + data["atom_data_uuid"] = self.atomic_data.uuid1 + if "atomic_data" in data: + data.pop("atomic_data") + if "nlte_data" in data: + logger.warning("nlte_data can't be saved") + data.pop("nlte_data") + return data + + def to_hdf( + self, + file_path_or_buf, + path="", + name=None, + collection=None, + overwrite=False, + ): + """ + Parameters + ---------- + file_path_or_buf : str or pandas.io.pytables.HDFStore + Path or buffer to the HDF file + path : str + Path inside the HDF file to store the `elements` + name : str + Group inside the HDF file to which the `elements` need to be saved + collection : + `None` or a `PlasmaPropertyCollection` of which members are + the property types which will be stored. If `None` then + all types of properties will be stored. This acts like a filter, + for example if a value of `property_collections.basic_inputs` is + given, only those input parameters will be stored to the HDF file. + overwrite : bool + If the HDF file path already exists, whether to overwrite it or not + """ + self.collection = collection + super(PlasmaWriterMixin, self).to_hdf( + file_path_or_buf, path, name, overwrite + ) + + +@lru_cache(maxsize=None) +def download_from_url(url, dst, checksum, src=None, retries=3): + """Download files from a given URL + + Parameters + ---------- + url : str + URL to download from + dst : str + Destination folder for the downloaded file + src : tuple + List of URLs to use as mirrors + """ + + cached_file_path = download_file(url, sources=src, pkgname="tardis") + + with open(cached_file_path, "rb") as f: + new_checksum = hashlib.md5(f.read()).hexdigest() + + if checksum == new_checksum: + shutil.copy(cached_file_path, dst) + + elif checksum != new_checksum and retries > 0: + retries -= 1 + logger.warning( + f"Incorrect checksum, retrying... ({retries+1} attempts remaining)" + ) + download_from_url(url, dst, checksum, src, retries) + + else: + logger.error("Maximum number of retries reached. Aborting") diff --git a/stardis/util/regression_data.py b/stardis/util/regression_data.py new file mode 100644 index 00000000..6d4dde06 --- /dev/null +++ b/stardis/util/regression_data.py @@ -0,0 +1,169 @@ +import os +import re +from pathlib import Path + +import numpy as np +import pandas as pd +import pytest + +from stardis.util import HDFWriterMixin + + +class RegressionData: + def __init__(self, request) -> None: + self.request = request + if request.config.getoption("--stardis-regression-data") is None: + pytest.skip("--stardis-regression-data was not specified") + regression_data_path = Path( + request.config.getoption("--stardis-regression-data") + ) + self.regression_data_path = Path( + os.path.expandvars(regression_data_path.expanduser()) + ) + self.enable_generate_reference = request.config.getoption( + "--generate-reference" + ) + self.fname = f"{self.fname_prefix}.UNKNOWN_FORMAT" + + @property + def module_name(self): + return self.request.node.module.__name__ + + @property + def test_name(self): + return self.request.node.name + + @property + def fname_prefix(self): + double_under = re.compile(r"[:\[\]{}]") + no_space = re.compile(r'[,"\']') # quotes and commas + + name = double_under.sub("__", self.test_name) + name = no_space.sub("", name) + return name + + @property + def relative_regression_data_dir(self): + relative_data_dir = Path(self.module_name.replace(".", "/")) + if self.request.cls is not None: + relative_data_dir /= HDFWriterMixin.convert_to_snake_case( + self.request.cls.__name__ + ) + return relative_data_dir + + @property + def absolute_regression_data_dir(self): + return self.regression_data_path / self.relative_regression_data_dir + + @property + def fpath(self): + return self.absolute_regression_data_dir / self.fname + + def sync_dataframe(self, data, key="data"): + """ + Synchronizes the dataframe with the regression data. + + Parameters + ---------- + data : DataFrame + The dataframe to be synchronized. + key : str, optional + The key to use for storing the dataframe in the regression data file. Defaults to "data". + + Returns + ------- + DataFrame or None + The synchronized dataframe if `enable_generate_reference` is `False`, otherwise `None`. + """ + self.fname = f"{self.fname_prefix}.h5" + if self.enable_generate_reference: + self.fpath.parent.mkdir(parents=True, exist_ok=True) + data.to_hdf( + self.fpath, + key=key, + ) + pytest.skip("Skipping test to generate reference data") + else: + return pd.read_hdf(self.fpath, key=key) + + def sync_ndarray(self, data): + """ + Synchronizes the ndarray with the regression data. + + Parameters + ---------- + data : ndarray + The ndarray to be synchronized. + + Returns + ------- + ndarray or None + The synchronized ndarray if `enable_generate_reference` is `False`, otherwise `None`. + """ + self.fname = f"{self.fname_prefix}.npy" + if self.enable_generate_reference: + self.fpath.parent.mkdir(parents=True, exist_ok=True) + self.fpath.parent.mkdir(parents=True, exist_ok=True) + np.save(self.fpath, data) + pytest.skip("Skipping test to generate reference data") + else: + return np.load(self.fpath) + + def sync_str(self, data): + """ + Synchronizes the string with the regression data. + + Parameters + ---------- + data : str + The string to be synchronized. + + Returns + ------- + str or None + The synchronized string if `enable_generate_reference` is `False`, otherwise `None`. + """ + self.fname = f"{self.fname_prefix}.txt" + if self.enable_generate_reference: + self.fpath.parent.mkdir(parents=True, exist_ok=True) + with self.fpath.open("w") as fh: + fh.write(data) + pytest.skip( + f"Skipping test to generate regression_data {self.fpath} data" + ) + else: + with self.fpath.open("r") as fh: + return fh.read() + + def sync_hdf_store(self, stardis_module, update_fname=True): + """ + Synchronizes the HDF store with the regression data. + + Parameters + ---------- + stardis_module : object + The module to be synchronized. + update_fname : bool, optional + Whether to update the file name. Defaults to True. + + Returns + ------- + HDFStore or None + The synchronized HDF store if `enable_generate_reference` is `False`, otherwise `None`. + """ + if update_fname: + self.fname = f"{self.fname_prefix}.h5" + if self.enable_generate_reference: + self.fpath.parent.mkdir(parents=True, exist_ok=True) + with pd.HDFStore(self.fpath, mode="w") as store: + stardis_module.to_hdf(store, overwrite=True) + pytest.skip( + f"Skipping test to generate regression data: {self.fpath}" + ) + else: + return pd.HDFStore(self.fpath, mode="r") + + +@pytest.fixture(scope="function") +def regression_data(request): + return RegressionData(request) diff --git a/stardis/util/tests/test_regression.py b/stardis/util/tests/test_regression.py new file mode 100644 index 00000000..738179f6 --- /dev/null +++ b/stardis/util/tests/test_regression.py @@ -0,0 +1,7 @@ +import pandas as pd +import numpy as np + +def test_np_regression(regression_data): + numpy_array = np.array([1, 2, 3, 4, 5]) + expected = regression_data.sync_ndarray(numpy_array) + np.testing.assert_allclose(expected, numpy_array) From 2c324472e3c49e2cd47c409ad76fe90d7ed18a3a Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Tue, 1 Oct 2024 17:42:04 +0530 Subject: [PATCH 02/18] Model regression tests --- stardis/conftest.py | 6 +++++- stardis/model/base.py | 5 ++++- stardis/tests/stardis_test_config.yml | 4 ++++ stardis/tests/test_stardis_regression.py | 6 ++++++ stardis/util/__init__.py | 1 + 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 stardis/tests/test_stardis_regression.py diff --git a/stardis/conftest.py b/stardis/conftest.py index 5b12eee4..2419d818 100644 --- a/stardis/conftest.py +++ b/stardis/conftest.py @@ -5,7 +5,7 @@ from astropy import units as u from tardis.io.atom_data.base import AtomData -from tardis.io.atom_data.util import download_atom_data +from tardis.io.atom_data import download_atom_data from tardis.io.configuration.config_validator import validate_yaml from tardis.io.configuration.config_reader import Configuration from stardis.io.model.marcs import read_marcs_model @@ -30,6 +30,10 @@ # ensuring that regression_data is not removed by ruff assert regression_data is not None +pytest_plugins = [ + "stardis.util.regression_data", + ] + def pytest_addoption(parser): parser.addoption( "--stardis-regression-data", diff --git a/stardis/model/base.py b/stardis/model/base.py index f6b4e285..dad58f88 100644 --- a/stardis/model/base.py +++ b/stardis/model/base.py @@ -1,4 +1,6 @@ -class StellarModel: +from stardis.util import HDFWriterMixin + +class StellarModel(HDFWriterMixin): """ Class containing information about the stellar model. @@ -19,6 +21,7 @@ class StellarModel: no_of_depth_points : int Class attribute to be easily accessible for initializing arrays that need to match the shape of the model. """ + hdf_properties = ["temperatures", "geometry", "composition"] def __init__(self, temperatures, geometry, composition): self.temperatures = temperatures diff --git a/stardis/tests/stardis_test_config.yml b/stardis/tests/stardis_test_config.yml index 7b2c4d5f..71e44ccc 100644 --- a/stardis/tests/stardis_test_config.yml +++ b/stardis/tests/stardis_test_config.yml @@ -14,3 +14,7 @@ opacity: disable: False broadening: [] no_of_thetas: 1 +result_options: + return_model: true + return_plasma: true + return_radiation_field: true \ No newline at end of file diff --git a/stardis/tests/test_stardis_regression.py b/stardis/tests/test_stardis_regression.py new file mode 100644 index 00000000..9ea7581a --- /dev/null +++ b/stardis/tests/test_stardis_regression.py @@ -0,0 +1,6 @@ +import numpy as np +from numpy.testing import assert_allclose + +def test_stardis_output_model(example_stardis_output, regression_data): + expected = regression_data.sync_hdf_store(example_stardis_output.stellar_model) + diff --git a/stardis/util/__init__.py b/stardis/util/__init__.py index e69de29b..335a3c44 100644 --- a/stardis/util/__init__.py +++ b/stardis/util/__init__.py @@ -0,0 +1 @@ +from stardis.util.hdf_writer_mixin import HDFWriterMixin \ No newline at end of file From b7d8586586127719c9391df5ef00a085b2ddda8e Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Tue, 1 Oct 2024 17:57:53 +0530 Subject: [PATCH 03/18] Make geometry hdfwritermixin --- stardis/model/geometry/radial1d.py | 6 ++++-- stardis/tests/test_stardis_regression.py | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/stardis/model/geometry/radial1d.py b/stardis/model/geometry/radial1d.py index 20155a92..de266be9 100644 --- a/stardis/model/geometry/radial1d.py +++ b/stardis/model/geometry/radial1d.py @@ -1,4 +1,6 @@ -class Radial1DGeometry: +from stardis.util import HDFWriterMixin + +class Radial1DGeometry(HDFWriterMixin): """ Holds information about model geometry (distribution of depth points) for radial 1D models. @@ -14,7 +16,7 @@ class Radial1DGeometry: dist_to_next_depth_point : astropy.units.quantity.Quantity distance to the next depth point """ - + hdf_properties = ["r"] def __init__(self, r): self.r = r diff --git a/stardis/tests/test_stardis_regression.py b/stardis/tests/test_stardis_regression.py index 9ea7581a..6654edb9 100644 --- a/stardis/tests/test_stardis_regression.py +++ b/stardis/tests/test_stardis_regression.py @@ -1,6 +1,17 @@ import numpy as np -from numpy.testing import assert_allclose +import pandas as pd def test_stardis_output_model(example_stardis_output, regression_data): - expected = regression_data.sync_hdf_store(example_stardis_output.stellar_model) + actual = example_stardis_output.stellar_model + expected = regression_data.sync_hdf_store(actual) + np.testing.assert_allclose( + actual.temperatures.value, + expected['/stellar_model/temperatures'] + ) + np.testing.assert_allclose( + actual.geometry.r.value, + expected['/stellar_model/geometry/r'] + ) + + From c5b834797a6be578c0bbd5a7e396ced810961623 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Tue, 1 Oct 2024 18:03:24 +0530 Subject: [PATCH 04/18] remove test regression --- stardis/util/tests/test_regression.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 stardis/util/tests/test_regression.py diff --git a/stardis/util/tests/test_regression.py b/stardis/util/tests/test_regression.py deleted file mode 100644 index 738179f6..00000000 --- a/stardis/util/tests/test_regression.py +++ /dev/null @@ -1,7 +0,0 @@ -import pandas as pd -import numpy as np - -def test_np_regression(regression_data): - numpy_array = np.array([1, 2, 3, 4, 5]) - expected = regression_data.sync_ndarray(numpy_array) - np.testing.assert_allclose(expected, numpy_array) From aa315d639fa421677dcd1cc948d67fefea3f0a5a Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Wed, 2 Oct 2024 18:29:23 +0530 Subject: [PATCH 05/18] Add plasma tests and fix HDFWriterMixin imports --- stardis/model/base.py | 2 +- stardis/model/geometry/radial1d.py | 2 +- stardis/radiation_field/base.py | 3 +- stardis/tests/test_stardis_regression.py | 79 +++++++- stardis/util/__init__.py | 1 - stardis/util/hdf_writer_mixin.py | 244 ----------------------- stardis/util/regression_data.py | 3 +- 7 files changed, 77 insertions(+), 257 deletions(-) delete mode 100644 stardis/util/hdf_writer_mixin.py diff --git a/stardis/model/base.py b/stardis/model/base.py index dad58f88..b68bbd22 100644 --- a/stardis/model/base.py +++ b/stardis/model/base.py @@ -1,4 +1,4 @@ -from stardis.util import HDFWriterMixin +from tardis.io.util import HDFWriterMixin class StellarModel(HDFWriterMixin): """ diff --git a/stardis/model/geometry/radial1d.py b/stardis/model/geometry/radial1d.py index de266be9..2128c818 100644 --- a/stardis/model/geometry/radial1d.py +++ b/stardis/model/geometry/radial1d.py @@ -1,4 +1,4 @@ -from stardis.util import HDFWriterMixin +from tardis.io.util import HDFWriterMixin class Radial1DGeometry(HDFWriterMixin): diff --git a/stardis/radiation_field/base.py b/stardis/radiation_field/base.py index 0f5e1680..fb48b8a1 100644 --- a/stardis/radiation_field/base.py +++ b/stardis/radiation_field/base.py @@ -4,9 +4,10 @@ from stardis.radiation_field.opacities.opacities_solvers import calc_alphas from stardis.radiation_field.radiation_field_solvers import raytrace from stardis.radiation_field.source_functions.blackbody import blackbody_flux_at_nu +from tardis.io.util import HDFWriterMixin -class RadiationField: +class RadiationField(HDFWriterMixin): """ Class containing information about the radiation field. ###TODO Radiation field temperature should be a separate attribute, for the case of differing gas and radiation. diff --git a/stardis/tests/test_stardis_regression.py b/stardis/tests/test_stardis_regression.py index 6654edb9..ab78fa32 100644 --- a/stardis/tests/test_stardis_regression.py +++ b/stardis/tests/test_stardis_regression.py @@ -1,7 +1,40 @@ import numpy as np import pandas as pd -def test_stardis_output_model(example_stardis_output, regression_data): +plasma_properties = [ + 'alpha_line', + 'beta_rad', + 'electron_densities', + 'g', + 'g_electron', + 'general_level_boltzmann_factor', + 'ion_number_density', + 'ionization_data', + 'level_boltzmann_factor', + 'level_number_density', + 'levels', + 'lines', + 'lines_lower_level_index', + 'lines_upper_level_index', + 'metastability', + 'nlte_excitation_species', + 'nlte_ionization_species', + 'nu', + 'number_density', + 'partition_function', + 'phi', + 'selected_atoms', + 'stimulated_emission_factor', + 't_electrons', + 't_rad', + 'wavelength_cm' +] + +plasma_properties_complex = [ + +] + +def test_stardis_stellar_model(example_stardis_output, regression_data): actual = example_stardis_output.stellar_model expected = regression_data.sync_hdf_store(actual) @@ -9,9 +42,41 @@ def test_stardis_output_model(example_stardis_output, regression_data): actual.temperatures.value, expected['/stellar_model/temperatures'] ) - np.testing.assert_allclose( - actual.geometry.r.value, - expected['/stellar_model/geometry/r'] - ) - - + +def test_stardis_stellar_model_geometry(example_stardis_output, regression_data): + # test Radial1DGeometry + actual = example_stardis_output.stellar_model.geometry.r.value + expected = regression_data.sync_ndarray(actual) + np.testing.assert_allclose(actual, expected) + +def test_stardis_plasma(example_stardis_output, regression_data): + # test BasePlasma + expected = regression_data.sync_hdf_store(example_stardis_output.stellar_plasma) + actual_plasma = example_stardis_output.stellar_plasma + for item in plasma_properties: + actual_item = getattr(actual_plasma, item) + expected_item = expected[f'plasma/{item}'] + if isinstance(actual_item, list): + actual_item = np.ndarray(actual_item) + + if any(isinstance(actual_item, object_type) for object_type in [pd.MultiIndex, pd.Index]): + expected_item = expected[f'plasma/{item}'].values.flatten() + np.testing.assert_array_equal(actual_item.values, expected_item) + + elif isinstance(actual_item, np.ndarray): + np.testing.assert_allclose( + actual=actual_item, + desired=expected_item, + err_msg=f"Error encountered which comparing regression data for property- {item}" + ) + elif isinstance(actual_item, pd.DataFrame): + pd.testing.assert_frame_equal(actual_item, expected_item) + elif isinstance(actual_item, pd.Series): + pd.testing.assert_series_equal(actual_item, expected_item) + else: + plasma_properties_complex.append(item) + if plasma_properties_complex: + raise AssertionError(plasma_properties_complex) + +def test_stardis_radiation_field(example_stardis_output, regression_data): + expected = regression_data.sync_hdf_store(example_stardis_output.stellar_radiation_field) diff --git a/stardis/util/__init__.py b/stardis/util/__init__.py index 335a3c44..e69de29b 100644 --- a/stardis/util/__init__.py +++ b/stardis/util/__init__.py @@ -1 +0,0 @@ -from stardis.util.hdf_writer_mixin import HDFWriterMixin \ No newline at end of file diff --git a/stardis/util/hdf_writer_mixin.py b/stardis/util/hdf_writer_mixin.py deleted file mode 100644 index 73a87e1f..00000000 --- a/stardis/util/hdf_writer_mixin.py +++ /dev/null @@ -1,244 +0,0 @@ -import hashlib -import os -import logging -import re -import shutil -from functools import lru_cache - -import numpy as np -import pandas as pd -from astropy import units as u -from astropy.utils.data import download_file - -logger = logging.getLogger(__name__) - -class HDFWriterMixin(object): - def __new__(cls, *args, **kwargs): - instance = super(HDFWriterMixin, cls).__new__(cls) - instance.optional_hdf_properties = [] - instance.__init__(*args, **kwargs) - return instance - - @staticmethod - def to_hdf_util( - path_or_buf, path, elements, overwrite, complevel=9, complib="blosc" - ): - """ - A function to uniformly store TARDIS data to an HDF file. - - Scalars will be stored in a Series under path/scalars - 1D arrays will be stored under path/property_name as distinct Series - 2D arrays will be stored under path/property_name as distinct DataFrames - - Units will be stored as their CGS value - - Parameters - ---------- - path_or_buf : str or pandas.io.pytables.HDFStore - Path or buffer to the HDF file - path : str - Path inside the HDF file to store the `elements` - elements : dict - A dict of property names and their values to be - stored. - overwrite : bool - If the HDF file path already exists, whether to overwrite it or not - - Notes - ----- - `overwrite` option doesn't have any effect when `path_or_buf` is an - HDFStore because the user decides on the mode in which they have - opened the HDFStore ('r', 'w' or 'a'). - """ - if ( - isinstance(path_or_buf, str) - and os.path.exists(path_or_buf) - and not overwrite - ): - raise FileExistsError( - "The specified HDF file already exists. If you still want " - "to overwrite it, set function parameter overwrite=True" - ) - - else: - try: # when path_or_buf is a str, the HDFStore should get created - buf = pd.HDFStore( - path_or_buf, complevel=complevel, complib=complib - ) - except TypeError as e: - if str(e) == "Expected bytes, got HDFStore": - # when path_or_buf is an HDFStore buffer instead - logger.debug( - "Expected bytes, got HDFStore. Changing path to HDF buffer" - ) - buf = path_or_buf - else: - raise e - - if not buf.is_open: - buf.open() - - scalars = {} - for key, value in elements.items(): - if value is None: - value = "none" - if hasattr(value, "cgs"): - value = value.cgs.value - if np.isscalar(value): - scalars[key] = value - elif hasattr(value, "shape"): - if value.ndim == 1: - # This try,except block is only for model.plasma.levels - try: - pd.Series(value).to_hdf(buf, os.path.join(path, key)) - except NotImplementedError: - logger.debug( - "Could not convert SERIES to HDF. Converting DATAFRAME to HDF" - ) - pd.DataFrame(value).to_hdf(buf, os.path.join(path, key)) - else: - pd.DataFrame(value).to_hdf(buf, os.path.join(path, key)) - else: # value is a TARDIS object like model, transport or plasma - try: - value.to_hdf(buf, path, name=key, overwrite=overwrite) - except AttributeError: - logger.debug( - "Could not convert VALUE to HDF. Converting DATA (Dataframe) to HDF" - ) - data = pd.DataFrame([value]) - data.to_hdf(buf, os.path.join(path, key)) - - if scalars: - pd.Series(scalars).to_hdf(buf, os.path.join(path, "scalars")) - - if buf.is_open: - buf.close() - - def get_properties(self): - data = {name: getattr(self, name) for name in self.full_hdf_properties} - return data - - @property - def full_hdf_properties(self): - if hasattr(self, "virt_logging") and self.virt_logging: - self.hdf_properties.extend(self.vpacket_hdf_properties) - - return self.optional_hdf_properties + self.hdf_properties - - @staticmethod - def convert_to_snake_case(s): - s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", s) - return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() - - def to_hdf(self, file_path_or_buf, path="", name=None, overwrite=False): - """ - Parameters - ---------- - file_path_or_buf : str or pandas.io.pytables.HDFStore - Path or buffer to the HDF file - path : str - Path inside the HDF file to store the `elements` - name : str - Group inside the HDF file to which the `elements` need to be saved - overwrite : bool - If the HDF file path already exists, whether to overwrite it or not - """ - if name is None: - try: - name = self.hdf_name - except AttributeError: - name = self.convert_to_snake_case(self.__class__.__name__) - logger.debug( - f"self.hdf_name not present, setting name to {name} for HDF" - ) - - data = self.get_properties() - buff_path = os.path.join(path, name) - self.to_hdf_util(file_path_or_buf, buff_path, data, overwrite) - - -class PlasmaWriterMixin(HDFWriterMixin): - def get_properties(self): - data = {} - if self.collection: - properties = [ - name - for name in self.plasma_properties - if isinstance(name, tuple(self.collection)) - ] - else: - properties = self.plasma_properties - for prop in properties: - for output in prop.outputs: - data[output] = getattr(prop, output) - data["atom_data_uuid"] = self.atomic_data.uuid1 - if "atomic_data" in data: - data.pop("atomic_data") - if "nlte_data" in data: - logger.warning("nlte_data can't be saved") - data.pop("nlte_data") - return data - - def to_hdf( - self, - file_path_or_buf, - path="", - name=None, - collection=None, - overwrite=False, - ): - """ - Parameters - ---------- - file_path_or_buf : str or pandas.io.pytables.HDFStore - Path or buffer to the HDF file - path : str - Path inside the HDF file to store the `elements` - name : str - Group inside the HDF file to which the `elements` need to be saved - collection : - `None` or a `PlasmaPropertyCollection` of which members are - the property types which will be stored. If `None` then - all types of properties will be stored. This acts like a filter, - for example if a value of `property_collections.basic_inputs` is - given, only those input parameters will be stored to the HDF file. - overwrite : bool - If the HDF file path already exists, whether to overwrite it or not - """ - self.collection = collection - super(PlasmaWriterMixin, self).to_hdf( - file_path_or_buf, path, name, overwrite - ) - - -@lru_cache(maxsize=None) -def download_from_url(url, dst, checksum, src=None, retries=3): - """Download files from a given URL - - Parameters - ---------- - url : str - URL to download from - dst : str - Destination folder for the downloaded file - src : tuple - List of URLs to use as mirrors - """ - - cached_file_path = download_file(url, sources=src, pkgname="tardis") - - with open(cached_file_path, "rb") as f: - new_checksum = hashlib.md5(f.read()).hexdigest() - - if checksum == new_checksum: - shutil.copy(cached_file_path, dst) - - elif checksum != new_checksum and retries > 0: - retries -= 1 - logger.warning( - f"Incorrect checksum, retrying... ({retries+1} attempts remaining)" - ) - download_from_url(url, dst, checksum, src, retries) - - else: - logger.error("Maximum number of retries reached. Aborting") diff --git a/stardis/util/regression_data.py b/stardis/util/regression_data.py index 6d4dde06..9d08c0bc 100644 --- a/stardis/util/regression_data.py +++ b/stardis/util/regression_data.py @@ -6,8 +6,7 @@ import pandas as pd import pytest -from stardis.util import HDFWriterMixin - +from tardis.io.util import HDFWriterMixin class RegressionData: def __init__(self, request) -> None: From e874306781713759647b6713504f4d090a2ead16 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 17:36:39 +0530 Subject: [PATCH 06/18] Add radiation field tests --- stardis/radiation_field/base.py | 1 + stardis/tests/test_stardis_regression.py | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/stardis/radiation_field/base.py b/stardis/radiation_field/base.py index fb48b8a1..76cd50ff 100644 --- a/stardis/radiation_field/base.py +++ b/stardis/radiation_field/base.py @@ -30,6 +30,7 @@ class RadiationField(HDFWriterMixin): F_nu : numpy.ndarray Radiation field fluxes at each frequency at each depth point. Initialized as zeros and calculated by a solver. """ + hdf_properties = ["frequencies", "opacities", "F_nu"] def __init__(self, frequencies, source_function, stellar_model): self.frequencies = frequencies diff --git a/stardis/tests/test_stardis_regression.py b/stardis/tests/test_stardis_regression.py index ab78fa32..45aea829 100644 --- a/stardis/tests/test_stardis_regression.py +++ b/stardis/tests/test_stardis_regression.py @@ -80,3 +80,14 @@ def test_stardis_plasma(example_stardis_output, regression_data): def test_stardis_radiation_field(example_stardis_output, regression_data): expected = regression_data.sync_hdf_store(example_stardis_output.stellar_radiation_field) + actual = example_stardis_output.stellar_radiation_field + + np.testing.assert_allclose( + expected["/radiation_field/frequencies"].values, + actual.frequencies.value + ) + + np.testing.assert_allclose( + expected["/radiation_field/F_nu"].values, + actual.F_nu + ) From ab9a4c5635681511f382f3f7b7d2424c30961af6 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 17:41:15 +0530 Subject: [PATCH 07/18] Cleanup --- stardis/tests/test_stardis_regression.py | 94 ++++++++++++------------ 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/stardis/tests/test_stardis_regression.py b/stardis/tests/test_stardis_regression.py index 45aea829..eadb8108 100644 --- a/stardis/tests/test_stardis_regression.py +++ b/stardis/tests/test_stardis_regression.py @@ -2,72 +2,73 @@ import pandas as pd plasma_properties = [ - 'alpha_line', - 'beta_rad', - 'electron_densities', - 'g', - 'g_electron', - 'general_level_boltzmann_factor', - 'ion_number_density', - 'ionization_data', - 'level_boltzmann_factor', - 'level_number_density', - 'levels', - 'lines', - 'lines_lower_level_index', - 'lines_upper_level_index', - 'metastability', - 'nlte_excitation_species', - 'nlte_ionization_species', - 'nu', - 'number_density', - 'partition_function', - 'phi', - 'selected_atoms', - 'stimulated_emission_factor', - 't_electrons', - 't_rad', - 'wavelength_cm' + "alpha_line", + "beta_rad", + "electron_densities", + "g", + "g_electron", + "general_level_boltzmann_factor", + "ion_number_density", + "ionization_data", + "level_boltzmann_factor", + "level_number_density", + "levels", + "lines", + "lines_lower_level_index", + "lines_upper_level_index", + "metastability", + "nlte_excitation_species", + "nlte_ionization_species", + "nu", + "number_density", + "partition_function", + "phi", + "selected_atoms", + "stimulated_emission_factor", + "t_electrons", + "t_rad", + "wavelength_cm", ] -plasma_properties_complex = [ +plasma_properties_complex = [] -] def test_stardis_stellar_model(example_stardis_output, regression_data): actual = example_stardis_output.stellar_model expected = regression_data.sync_hdf_store(actual) np.testing.assert_allclose( - actual.temperatures.value, - expected['/stellar_model/temperatures'] + actual.temperatures.value, expected["/stellar_model/temperatures"] ) + def test_stardis_stellar_model_geometry(example_stardis_output, regression_data): - # test Radial1DGeometry actual = example_stardis_output.stellar_model.geometry.r.value expected = regression_data.sync_ndarray(actual) np.testing.assert_allclose(actual, expected) + def test_stardis_plasma(example_stardis_output, regression_data): - # test BasePlasma expected = regression_data.sync_hdf_store(example_stardis_output.stellar_plasma) actual_plasma = example_stardis_output.stellar_plasma for item in plasma_properties: actual_item = getattr(actual_plasma, item) - expected_item = expected[f'plasma/{item}'] + expected_item = expected[f"plasma/{item}"] if isinstance(actual_item, list): actual_item = np.ndarray(actual_item) - - if any(isinstance(actual_item, object_type) for object_type in [pd.MultiIndex, pd.Index]): - expected_item = expected[f'plasma/{item}'].values.flatten() + + if any( + isinstance(actual_item, object_type) + for object_type in [pd.MultiIndex, pd.Index] + ): + expected_item = expected[f"plasma/{item}"].values.flatten() np.testing.assert_array_equal(actual_item.values, expected_item) elif isinstance(actual_item, np.ndarray): np.testing.assert_allclose( actual=actual_item, desired=expected_item, - err_msg=f"Error encountered which comparing regression data for property- {item}" + err_msg=f"Error encountered when comparing regression data for property- {item}", ) elif isinstance(actual_item, pd.DataFrame): pd.testing.assert_frame_equal(actual_item, expected_item) @@ -75,19 +76,20 @@ def test_stardis_plasma(example_stardis_output, regression_data): pd.testing.assert_series_equal(actual_item, expected_item) else: plasma_properties_complex.append(item) - if plasma_properties_complex: - raise AssertionError(plasma_properties_complex) + if plasma_properties_complex: + raise AssertionError( + f"These properties were not tested- {plasma_properties_complex}" + ) + def test_stardis_radiation_field(example_stardis_output, regression_data): - expected = regression_data.sync_hdf_store(example_stardis_output.stellar_radiation_field) + expected = regression_data.sync_hdf_store( + example_stardis_output.stellar_radiation_field + ) actual = example_stardis_output.stellar_radiation_field np.testing.assert_allclose( - expected["/radiation_field/frequencies"].values, - actual.frequencies.value + expected["/radiation_field/frequencies"].values, actual.frequencies.value ) - np.testing.assert_allclose( - expected["/radiation_field/F_nu"].values, - actual.F_nu - ) + np.testing.assert_allclose(expected["/radiation_field/F_nu"].values, actual.F_nu) From 874d26085f198b5bbfe1418cc00360bad2df3799 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 17:47:06 +0530 Subject: [PATCH 08/18] Run tests From ac2c2e1cb2dc3eed99eb8fd08f16d5131c4f15f3 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 17:53:48 +0530 Subject: [PATCH 09/18] Use composite action to setup env --- .github/actions/setup_env/action.yml | 32 ++++++++++++++++++++++++++++ .github/workflows/tests.yml | 27 +++-------------------- 2 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 .github/actions/setup_env/action.yml diff --git a/.github/actions/setup_env/action.yml b/.github/actions/setup_env/action.yml new file mode 100644 index 00000000..a06d7e43 --- /dev/null +++ b/.github/actions/setup_env/action.yml @@ -0,0 +1,32 @@ +name: "Setup environment" +description: "Sets up environment for stardis and caches it" + +inputs: + os-label: + description: "os label for lock file, default linux" + required: true + default: "linux-64" + +runs: + using: "composite" + steps: + - name: Download Lock File + run: wget -q https://raw.githubusercontent.com/tardis-sn/stardis/master/conda-${{ inputs.os-label }}.lock + if: matrix.pip == true + shell: bash + + - name: Generate Cache Key + run: | + file_hash=$(cat conda-${{ inputs.os-label }}.lock | shasum -a 256 | cut -d' ' -f1) + echo "file_hash=$file_hash" >> "${GITHUB_OUTPUT}" + id: cache-environment-key + shell: bash + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: conda-${{ inputs.os-label }}.lock + cache-environment-key: ${{ steps.cache-environment-key.outputs.file_hash }} + cache-downloads-key: ${{ steps.cache-environment-key.outputs.file_hash }} + environment-name: stardis + cache-environment: true + cache-downloads: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e81f3565..be1691e2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,38 +41,17 @@ jobs: - name: Setup LFS uses: ./.github/actions/setup_lfs - - - name: Setup Mambaforge - uses: conda-incubator/setup-miniconda@v2 - with: - miniforge-variant: Mambaforge - miniforge-version: latest - activate-environment: stardis - use-mamba: true - - - - name: Cache lockfile - uses: actions/cache@v2 - with: - path: ${{ matrix.prefix }} - key: conda-${{ matrix.label }}-${{ hashFiles(format('conda-{0}.lock', matrix.label)) }}-${{ env.CACHE_NUMBER }} - id: cache-conda - - - name: Update Conda Environment - id: update-env - run: | - mamba update -n stardis --file conda-${{ matrix.label }}.lock - if: steps.cache-conda.outputs.cache-hit != 'true' + + - name: Setup LFS + uses: ./.github/actions/setup_env - name: Install TARDIS id: install-tardis - # shell: bash -l {0} run: | pip install git+https://github.com/tardis-sn/tardis.git@release-2024.08.25 - name: Install STARDIS id: install-stardis - # shell: bash -l {0} run: | pip install -e .[test] From c4156dd4c634bc9cb22ce27ae4f298e2f4a3d799 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 17:57:33 +0530 Subject: [PATCH 10/18] Modify triggers --- .github/workflows/tests.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index be1691e2..9486fb2d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,11 @@ name: tests on: push: + branches: + - master pull_request: + branches: + - master workflow_dispatch: env: @@ -16,19 +20,16 @@ defaults: jobs: build: - # if: github.repository_owner == 'tardis-sn' + if: github.repository_owner == 'tardis-sn' strategy: matrix: include: - - os: ubuntu-latest label: linux-64 prefix: /usr/share/miniconda3/envs/stardis - # - os: ubuntu-latest # label: linux-64-cuda # prefix: /usr/share/miniconda3/envs/stardis - - os: macos-latest label: osx-64 prefix: /Users/runner/miniconda3/envs/stardis @@ -37,13 +38,15 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup LFS uses: ./.github/actions/setup_lfs - name: Setup LFS uses: ./.github/actions/setup_env + with: + os-label: ${{ matrix.label }} - name: Install TARDIS id: install-tardis From 4e09d5762dd2dc75e982e0b72a15f41ea4bb890b Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 17:58:59 +0530 Subject: [PATCH 11/18] Set default branch to main --- .github/actions/setup_env/action.yml | 2 +- .github/workflows/tests.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup_env/action.yml b/.github/actions/setup_env/action.yml index a06d7e43..ae07fdf2 100644 --- a/.github/actions/setup_env/action.yml +++ b/.github/actions/setup_env/action.yml @@ -11,7 +11,7 @@ runs: using: "composite" steps: - name: Download Lock File - run: wget -q https://raw.githubusercontent.com/tardis-sn/stardis/master/conda-${{ inputs.os-label }}.lock + run: wget -q https://raw.githubusercontent.com/tardis-sn/stardis/main/conda-${{ inputs.os-label }}.lock if: matrix.pip == true shell: bash diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9486fb2d..c591f4f6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,10 +3,10 @@ name: tests on: push: branches: - - master + - main pull_request: branches: - - master + - main workflow_dispatch: env: From 7b77592843f8a2678c260cbe0375359bf561e80c Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 18:05:18 +0530 Subject: [PATCH 12/18] typo fix --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c591f4f6..ca114ef6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,7 +43,7 @@ jobs: - name: Setup LFS uses: ./.github/actions/setup_lfs - - name: Setup LFS + - name: Setup STARDIS uses: ./.github/actions/setup_env with: os-label: ${{ matrix.label }} From a2d005359a115560a34af8d16280f7a342f0a031 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Thu, 3 Oct 2024 18:06:06 +0530 Subject: [PATCH 13/18] Run black --- stardis/conftest.py | 14 ++++++-------- stardis/model/base.py | 2 ++ stardis/model/geometry/radial1d.py | 4 +++- stardis/radiation_field/base.py | 1 + .../opacities/opacities_solvers/base.py | 6 +++--- stardis/util/regression_data.py | 9 +++------ 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/stardis/conftest.py b/stardis/conftest.py index 2419d818..622dfba8 100644 --- a/stardis/conftest.py +++ b/stardis/conftest.py @@ -31,8 +31,9 @@ assert regression_data is not None pytest_plugins = [ - "stardis.util.regression_data", - ] + "stardis.util.regression_data", +] + def pytest_addoption(parser): parser.addoption( @@ -305,14 +306,11 @@ def example_stardis_output_parallel( example_stellar_radiation_field_parallel, ) + @pytest.fixture(scope="session") def stardis_regression_path(request): - stardis_regression_path = request.config.getoption( - "--stardis-regression-data" - ) + stardis_regression_path = request.config.getoption("--stardis-regression-data") if stardis_regression_path is None: pytest.skip("--stardis-regression-data was not specified") else: - return Path( - os.path.expandvars(os.path.expanduser(stardis_regression_path)) - ) + return Path(os.path.expandvars(os.path.expanduser(stardis_regression_path))) diff --git a/stardis/model/base.py b/stardis/model/base.py index b68bbd22..92a1b088 100644 --- a/stardis/model/base.py +++ b/stardis/model/base.py @@ -1,5 +1,6 @@ from tardis.io.util import HDFWriterMixin + class StellarModel(HDFWriterMixin): """ Class containing information about the stellar model. @@ -21,6 +22,7 @@ class StellarModel(HDFWriterMixin): no_of_depth_points : int Class attribute to be easily accessible for initializing arrays that need to match the shape of the model. """ + hdf_properties = ["temperatures", "geometry", "composition"] def __init__(self, temperatures, geometry, composition): diff --git a/stardis/model/geometry/radial1d.py b/stardis/model/geometry/radial1d.py index 2128c818..47891bea 100644 --- a/stardis/model/geometry/radial1d.py +++ b/stardis/model/geometry/radial1d.py @@ -1,7 +1,7 @@ from tardis.io.util import HDFWriterMixin -class Radial1DGeometry(HDFWriterMixin): +class Radial1DGeometry(HDFWriterMixin): """ Holds information about model geometry (distribution of depth points) for radial 1D models. @@ -16,7 +16,9 @@ class Radial1DGeometry(HDFWriterMixin): dist_to_next_depth_point : astropy.units.quantity.Quantity distance to the next depth point """ + hdf_properties = ["r"] + def __init__(self, r): self.r = r diff --git a/stardis/radiation_field/base.py b/stardis/radiation_field/base.py index 76cd50ff..82a7cb12 100644 --- a/stardis/radiation_field/base.py +++ b/stardis/radiation_field/base.py @@ -30,6 +30,7 @@ class RadiationField(HDFWriterMixin): F_nu : numpy.ndarray Radiation field fluxes at each frequency at each depth point. Initialized as zeros and calculated by a solver. """ + hdf_properties = ["frequencies", "opacities", "F_nu"] def __init__(self, frequencies, source_function, stellar_model): diff --git a/stardis/radiation_field/opacities/opacities_solvers/base.py b/stardis/radiation_field/opacities/opacities_solvers/base.py index 6a78804f..a26b1a72 100644 --- a/stardis/radiation_field/opacities/opacities_solvers/base.py +++ b/stardis/radiation_field/opacities/opacities_solvers/base.py @@ -728,9 +728,9 @@ def calc_alphas( opacity_config.line, n_threads, ) - stellar_radiation_field.opacities.opacities_dict[ - "alpha_line_at_nu" - ] = alpha_line_at_nu + stellar_radiation_field.opacities.opacities_dict["alpha_line_at_nu"] = ( + alpha_line_at_nu + ) stellar_radiation_field.opacities.opacities_dict["alpha_line_at_nu_gammas"] = gammas stellar_radiation_field.opacities.opacities_dict[ "alpha_line_at_nu_doppler_widths" diff --git a/stardis/util/regression_data.py b/stardis/util/regression_data.py index 9d08c0bc..65bfb689 100644 --- a/stardis/util/regression_data.py +++ b/stardis/util/regression_data.py @@ -8,6 +8,7 @@ from tardis.io.util import HDFWriterMixin + class RegressionData: def __init__(self, request) -> None: self.request = request @@ -127,9 +128,7 @@ def sync_str(self, data): self.fpath.parent.mkdir(parents=True, exist_ok=True) with self.fpath.open("w") as fh: fh.write(data) - pytest.skip( - f"Skipping test to generate regression_data {self.fpath} data" - ) + pytest.skip(f"Skipping test to generate regression_data {self.fpath} data") else: with self.fpath.open("r") as fh: return fh.read() @@ -156,9 +155,7 @@ def sync_hdf_store(self, stardis_module, update_fname=True): self.fpath.parent.mkdir(parents=True, exist_ok=True) with pd.HDFStore(self.fpath, mode="w") as store: stardis_module.to_hdf(store, overwrite=True) - pytest.skip( - f"Skipping test to generate regression data: {self.fpath}" - ) + pytest.skip(f"Skipping test to generate regression data: {self.fpath}") else: return pd.HDFStore(self.fpath, mode="r") From de10eb66b6e772c3cc6fdce871224ff1425e59b6 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Fri, 4 Oct 2024 13:53:53 +0530 Subject: [PATCH 14/18] Remove HDFWriterMixin from Radial1DGeometry --- stardis/model/geometry/radial1d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stardis/model/geometry/radial1d.py b/stardis/model/geometry/radial1d.py index 47891bea..877a5a56 100644 --- a/stardis/model/geometry/radial1d.py +++ b/stardis/model/geometry/radial1d.py @@ -1,7 +1,7 @@ from tardis.io.util import HDFWriterMixin -class Radial1DGeometry(HDFWriterMixin): +class Radial1DGeometry: """ Holds information about model geometry (distribution of depth points) for radial 1D models. From 1dbce92d58acf9580e30e6c00104a47c72cfc68d Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Fri, 4 Oct 2024 14:38:54 +0530 Subject: [PATCH 15/18] pip matrix not necessary --- .github/actions/setup_env/action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/setup_env/action.yml b/.github/actions/setup_env/action.yml index ae07fdf2..c6d579ce 100644 --- a/.github/actions/setup_env/action.yml +++ b/.github/actions/setup_env/action.yml @@ -12,7 +12,6 @@ runs: steps: - name: Download Lock File run: wget -q https://raw.githubusercontent.com/tardis-sn/stardis/main/conda-${{ inputs.os-label }}.lock - if: matrix.pip == true shell: bash - name: Generate Cache Key From 2358bd03cb31d49c5c156764682794ece261ea7c Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Mon, 7 Oct 2024 18:11:46 +0530 Subject: [PATCH 16/18] black formatting --- stardis/radiation_field/opacities/opacities_solvers/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stardis/radiation_field/opacities/opacities_solvers/base.py b/stardis/radiation_field/opacities/opacities_solvers/base.py index a26b1a72..6a78804f 100644 --- a/stardis/radiation_field/opacities/opacities_solvers/base.py +++ b/stardis/radiation_field/opacities/opacities_solvers/base.py @@ -728,9 +728,9 @@ def calc_alphas( opacity_config.line, n_threads, ) - stellar_radiation_field.opacities.opacities_dict["alpha_line_at_nu"] = ( - alpha_line_at_nu - ) + stellar_radiation_field.opacities.opacities_dict[ + "alpha_line_at_nu" + ] = alpha_line_at_nu stellar_radiation_field.opacities.opacities_dict["alpha_line_at_nu_gammas"] = gammas stellar_radiation_field.opacities.opacities_dict[ "alpha_line_at_nu_doppler_widths" From 140f06b511f1555f4c6f96f469126b24ff35a344 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Mon, 7 Oct 2024 19:43:21 +0530 Subject: [PATCH 17/18] Remove unused import --- stardis/model/geometry/radial1d.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stardis/model/geometry/radial1d.py b/stardis/model/geometry/radial1d.py index 877a5a56..5a967032 100644 --- a/stardis/model/geometry/radial1d.py +++ b/stardis/model/geometry/radial1d.py @@ -1,6 +1,3 @@ -from tardis.io.util import HDFWriterMixin - - class Radial1DGeometry: """ Holds information about model geometry (distribution of depth points) for radial 1D models. @@ -16,9 +13,6 @@ class Radial1DGeometry: dist_to_next_depth_point : astropy.units.quantity.Quantity distance to the next depth point """ - - hdf_properties = ["r"] - def __init__(self, r): self.r = r From 101859eb180fba8c290c087cedb2ddaefce30bb0 Mon Sep 17 00:00:00 2001 From: Atharva Arya Date: Mon, 7 Oct 2024 19:48:03 +0530 Subject: [PATCH 18/18] Run black --- stardis/model/geometry/radial1d.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stardis/model/geometry/radial1d.py b/stardis/model/geometry/radial1d.py index 5a967032..7c752f42 100644 --- a/stardis/model/geometry/radial1d.py +++ b/stardis/model/geometry/radial1d.py @@ -13,6 +13,7 @@ class Radial1DGeometry: dist_to_next_depth_point : astropy.units.quantity.Quantity distance to the next depth point """ + def __init__(self, r): self.r = r