diff --git a/.github/codecov.yml b/.github/codecov.yml index 7b8a515..6adc42c 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -1,2 +1,4 @@ ignore: - - "test/*" \ No newline at end of file + - "test/*" + - "python/**/tests/**" + - "python/generate.py" \ No newline at end of file diff --git a/.github/workflows/build_wheels.yaml b/.github/workflows/build_wheels.yaml new file mode 100644 index 0000000..d1b6c1d --- /dev/null +++ b/.github/workflows/build_wheels.yaml @@ -0,0 +1,56 @@ +name: Build and Publish + +on: + push: + branches: + - main + - pypi + tags: + - 'v*' + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Build distributions + run: pipx run build + + - uses: actions/upload-artifact@v4 + with: + name: sdist + path: dist/* + if-no-files-found: error + + upload_pypi: + needs: [build_sdist] + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + contents: read + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') || github.event_name == 'release' + steps: + - uses: actions/download-artifact@v4 + with: + pattern: sdist + path: dist + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + print-hash: true diff --git a/.github/workflows/python_app.yaml b/.github/workflows/python_app.yaml new file mode 100644 index 0000000..21a41d2 --- /dev/null +++ b/.github/workflows/python_app.yaml @@ -0,0 +1,48 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python application + +on: + workflow_dispatch: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v4 + with: + python-version: "3.12" + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install lcov libhdf5-dev + python -m pip install --upgrade pip + pip install flake8 pytest coverage pytest-cov + pip install -r python/requirements.txt + - name: Lint with flake8 + run: | + cd python + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Install package + run: pip install . + - name: Test with pytest + run: pytest --cov python/ + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 034555e..a690774 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,32 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps + +# Python related gitignore +__pycache__/ +*.pyc +*.pyo +*.pyd +*.egg-info/ +dist/ +build/ +.eggs/ +*.egg +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +.ipynb_checkpoints +.pytest_cache/ +.tox/ +.coverage +htmlcov/ +.nox/ +.pyre/ +.mypy_cache/ +.dmypy.json +.pytype/ +.pyright/ \ No newline at end of file diff --git a/README.md b/README.md index 8a34820..cd5faf9 100644 --- a/README.md +++ b/README.md @@ -41,15 +41,35 @@ ## Dependencies - Python: - - Hiroshi's `sparse_ir` - - `numpy`, `scipy`, `h5py`, `mpmath`, ... + - [`sparse-ir`](https://github.com/SpM-lab/sparse-ir) + - `numpy`, `scipy`, `h5py`, and `mpmath`. - C++: - Green/h5pp: for compatibility with h5py - Green/ndarrays: for compatibility with numpy.ndarray - - Green/params: for comandline parameters + - Green/params: for command-line parameters + - CMake: Version 3.27 or later +## Installation +C++ installation uses CMake in a straightforward manner: +```bash +mkdir build && cd build +cmake .. -DCMAKE_INSTALL_PREFIX=. +make -j 4 +make install +make test # Test the code +``` +The Python package for `green-grids` can be installed using PyPI: +```bash +pip install green-grids +``` +or simply by building from source as: +```bash +git clone https://github.com/Green-Phys/green-grids +cd green-grids +pip install . +``` # Acknowledgements diff --git a/c++/green/grids/common_defs.h b/c++/green/grids/common_defs.h index c483555..7fcc5b6 100644 --- a/c++/green/grids/common_defs.h +++ b/c++/green/grids/common_defs.h @@ -8,12 +8,17 @@ #include #include #include +#include "except.h" #include +#include using namespace std::string_literals; namespace green::grids { + // VERSION INFO + inline const std::string GRIDS_MIN_VERSION = "0.2.4"; + // NDArray types template using itensor = green::ndarray::ndarray; @@ -48,5 +53,40 @@ namespace green::grids { } std::string grid_path(const std::string& path); + + /** + * @brief Check whether a version string satisfies the minimum required GRIDS version. + * + * Compares the given version string against the library's minimum supported + * GRIDS version specified by `GRIDS_MIN_VERSION`. + * + * @param v Version string to check (e.g. "0.2.4"). + * @return true if v is greater than or equal to GRIDS_MIN_VERSION. + * @return false if v is less than GRIDS_MIN_VERSION. + * @throws outdated_grids_file_error if the format of v or GRIDS_MIN_VERSION is incorrect. + */ + inline bool CheckVersion(const std::string& v) { + int major_Vin = 0, minor_Vin = 0, patch_Vin = 0; + int major_Vref = 0, minor_Vref = 0, patch_Vref = 0; + + char suffixV[32] = ""; + char suffixM[32] = ""; + + int parsed_in = std::sscanf(v.c_str(), "%d.%d.%d%30s", &major_Vin, &minor_Vin, &patch_Vin, suffixV); + int parsed_ref = std::sscanf(GRIDS_MIN_VERSION.c_str(), "%d.%d.%d%30s", &major_Vref, &minor_Vref, &patch_Vref, suffixM); + + if (parsed_in < 3 || parsed_ref < 3) { + throw outdated_grids_file_error("Version string format is incorrect. Expected format: major.minor.patch[suffix]"); + } + + if (major_Vin != major_Vref) return major_Vin > major_Vref; + if (minor_Vin != minor_Vref) return minor_Vin > minor_Vref; + if (patch_Vin != patch_Vref) return patch_Vin > patch_Vref; + + // If numeric parts in version are all equal, do not worry about suffix + // e.g., 0.2.4b10 has same integral format as 0.2.4 + return true; + } + } // namespace green::grids #endif // GRIDS_COMMON_DEFS_H diff --git a/c++/green/grids/except.h b/c++/green/grids/except.h index ce3ee05..9fc35ca 100644 --- a/c++/green/grids/except.h +++ b/c++/green/grids/except.h @@ -16,6 +16,11 @@ namespace green::grids { public: explicit grids_file_not_found_error(const std::string& string) : runtime_error(string) {} }; + + class outdated_grids_file_error : public std::runtime_error { + public: + explicit outdated_grids_file_error(const std::string& string) : runtime_error(string) {} + }; } // namespace green::grids #endif // GRIDS_EXCEPT_H diff --git a/c++/green/grids/transformer_t.h b/c++/green/grids/transformer_t.h index a5ab62e..829dd81 100644 --- a/c++/green/grids/transformer_t.h +++ b/c++/green/grids/transformer_t.h @@ -52,8 +52,25 @@ namespace green::grids { sparse_data _sd; + // Version Info + std::string _version = ""; + public: - transformer_t(const green::params::params& p) : _sd(p) { read_trans(p["grid_file"]); } + transformer_t(const green::params::params& p) : _sd(p) { read_trans(p["grid_file"]); } + + /** + * @brief Set the version string + * + * @param v - std::string + */ + void set_version(const std::string& v) { _version = v; } + + /** + * @brief Get the version string + * + * @param v - std::string + */ + const std::string& get_version() const { return _version; } /** * @param n - [INPUT] Matsubara frequency number, omega(n) = iw_n diff --git a/c++/transformer.cpp b/c++/transformer.cpp index 22e37da..a2f73e2 100644 --- a/c++/transformer.cpp +++ b/c++/transformer.cpp @@ -46,6 +46,19 @@ namespace green::grids { void transformer_t::read_trans(const std::string& path) { green::h5pp::archive tnl_file(grid_path(path)); + + // Read version info + if (tnl_file.has_attribute("__grids_version__")) { + std::string v_str = tnl_file.get_attribute("__grids_version__"); + set_version(v_str); + if (!CheckVersion(v_str)) { + throw outdated_grids_file_error("The grids file version " + v_str + + " is outdated. Minimum required version is " + GRIDS_MIN_VERSION + "."); + } + } else { + set_version(GRIDS_MIN_VERSION); + } + read_trans_statistics(tnl_file, 1, _Tnc, _Tcn, _Ttc, _Tct); read_trans_statistics(tnl_file, 0, _Tnc_B, _Tcn_B, _Ttc_B, _Tct_B); diff --git a/data/cheb/100.h5 b/data/cheb/100.h5 index efef95f..44c193e 100644 Binary files a/data/cheb/100.h5 and b/data/cheb/100.h5 differ diff --git a/data/cheb/150.h5 b/data/cheb/150.h5 index a92ec16..9a68d7b 100644 Binary files a/data/cheb/150.h5 and b/data/cheb/150.h5 differ diff --git a/data/cheb/200.h5 b/data/cheb/200.h5 index 2a8d5d8..49d8b07 100644 Binary files a/data/cheb/200.h5 and b/data/cheb/200.h5 differ diff --git a/data/cheb/300.h5 b/data/cheb/300.h5 index c36d5a8..ca5dd26 100644 Binary files a/data/cheb/300.h5 and b/data/cheb/300.h5 differ diff --git a/data/cheb/350.h5 b/data/cheb/350.h5 index 22ee8e8..9794a6a 100644 Binary files a/data/cheb/350.h5 and b/data/cheb/350.h5 differ diff --git a/data/cheb/450.h5 b/data/cheb/450.h5 index facb88f..ff35ac5 100644 Binary files a/data/cheb/450.h5 and b/data/cheb/450.h5 differ diff --git a/data/ir/1e4.h5 b/data/ir/1e4.h5 index b892ffa..f553223 100644 Binary files a/data/ir/1e4.h5 and b/data/ir/1e4.h5 differ diff --git a/data/ir/1e5.h5 b/data/ir/1e5.h5 index 5c88134..aff5072 100644 Binary files a/data/ir/1e5.h5 and b/data/ir/1e5.h5 differ diff --git a/data/ir/1e6.h5 b/data/ir/1e6.h5 index f5c15a8..4a9ae1f 100644 Binary files a/data/ir/1e6.h5 and b/data/ir/1e6.h5 differ diff --git a/data/ir/1e7.h5 b/data/ir/1e7.h5 index 10d8243..5e86242 100644 Binary files a/data/ir/1e7.h5 and b/data/ir/1e7.h5 differ diff --git a/data/ir/1e8.h5 b/data/ir/1e8.h5 index e0df66c..6df5eac 100644 Binary files a/data/ir/1e8.h5 and b/data/ir/1e8.h5 differ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dd6c163 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,90 @@ +[build-system] +requires = ["setuptools>=64", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "green-grids" +dynamic = ["version"] +description = "Sparse-grid tools for Green's function methods in physics" +readme = "README.md" +requires-python = ">=3.9" +license = { text = "MIT" } # or your license +authors = [ + { name = "Sergei Iskakov", email = "siskakov@umich.edu" } +] +maintainers = [ + { name = "Gaurav Harsha", email = "gharsha@umich.edu" }, + { name = "Sergei Iskakov", email = "siskakov@umich.edu" } +] +keywords = [ + "physics", + "greens-functions", + "sparse-grids", + "numerical-methods", + "many-body", + "scientific-computing" +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Physics", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", +] +dependencies = [ + "numpy>=1.19.0", + "scipy>=1.5.0", + "h5py>=3.0.0", + "mpmath>=1.0.0", + "sparse-ir>=1.0.0,<2.0.0", + "xprec>=1.3.0" +] + +[project.urls] +Homepage = "https://green-phys.org" +Repository = "https://github.com/green-phys/green-grids" +Issues = "https://github.com/green-phys/green-grids/issues" +Documentation = "https://github.com/green-phys/green-grids#readme" + +# ------------------------- +# setuptools configuration +# ------------------------- + +[tool.setuptools] +package-dir = {"" = "python"} + +[tool.setuptools.packages.find] +where = ["python"] +include = ["green_grids", "green_grids.*"] + +[tool.setuptools.dynamic] +version = {attr = "green_grids.version.__version__"} + +# ------------------------- +# Optional dev tooling +# ------------------------- + +[project.optional-dependencies] +tests = ["coverage>=5.0.3", "pytest", "pytest-benchmark[histogram]>=3.2.1"] + +# ------------------------- +# Coverage configuration +# ------------------------- +[tool.coverage.run] +branch = true +source = ["python/green_grids"] + +# ------------------------- +# Pytest configuration +# ------------------------- +[tool.pytest.ini_options] +markers = [ + "slow: mark a test that takes a long time to run.", +] diff --git a/python/examples/generate_and_transform.ipynb b/python/examples/generate_and_transform.ipynb index 6d5f0a3..5efc333 100644 --- a/python/examples/generate_and_transform.ipynb +++ b/python/examples/generate_and_transform.ipynb @@ -29,18 +29,16 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "import sys\n", - "sys.path.append('..')\n", - "from sparse_grid import get_generator" + "from green_grids import get_generator" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -56,20 +54,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'type': 'chebyshev', 'ncoeff': 32}" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "cheb_data.metadata" ] @@ -87,16 +74,16 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from sparse_grid import transform_data" + "from green_grids import transform_data" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -106,20 +93,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'type': 'chebyshev', 'ncoeff': 32, 'beta': 10.0}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "cheb_data_ft.metadata" ] @@ -138,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -155,7 +131,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -164,32 +140,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-0.5118378999174271, 0.0)" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "ftau = func_tau(cheb_data_ft.xgrid)\n", "plt.plot(cheb_data_ft.xgrid, ftau, '-+')\n", @@ -205,41 +158,18 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "import sparse_grid.transform as st" + "import green_grids.transform as st" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fl = st.tau_to_l(cheb_data_ft, ftau)\n", "plt.plot(fl, '--+')" @@ -256,32 +186,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fiw = st.l_to_iw(cheb_data_ft, fl)\n", "\n", @@ -318,31 +225,19 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from sparse_grid.sparse_data import PairedSparseData\n", + "from green_grids.sparse_data import PairedSparseData\n", "ir_pair = PairedSparseData.load_hdf5('ir_1e5.h5')" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "({'lambda': 100000.0, 'ncoeff': 136, 'type': 'ir'},\n", - " {'lambda': 100000.0, 'ncoeff': 127, 'type': 'ir'})" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ir_pair.get_grid('fermi').metadata, ir_pair.get_grid('bose').metadata" ] @@ -359,30 +254,19 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from sparse_grid.sparse_data import SparseData\n", + "from green_grids.sparse_data import SparseData\n", "ir_fermi = SparseData.load_hdf5('ir_1e5.h5', basepath='fermi')" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'lambda': 100000.0, 'ncoeff': 136, 'type': 'ir'}" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ir_fermi.metadata" ] diff --git a/python/examples/ir_1e5.h5 b/python/examples/ir_1e5.h5 index e711d43..5c88134 100644 Binary files a/python/examples/ir_1e5.h5 and b/python/examples/ir_1e5.h5 differ diff --git a/python/generate.py b/python/generate.py index 6570692..b8c3bd0 100644 --- a/python/generate.py +++ b/python/generate.py @@ -1,7 +1,7 @@ import argparse -import sparse_grid -import sparse_grid.repn.generator as generator +import green_grids +import green_grids.repn.generator as generator CHEBYSHEV_BASIS = "chebyshev" IR_BASIS = "ir" @@ -53,7 +53,7 @@ def ir_generator(args, stats): ------- generator : sparse_grid.repn.Generator ''' - return sparse_grid.get_generator(args.basis, args.irlambda, args.ncoeff, + return green_grids.get_generator(args.basis, args.irlambda, args.ncoeff, stats, args.trim, args.h5file) @@ -85,7 +85,7 @@ def chebyshev_generator(args, stats): ------- generator : sparse_grid.repn.Generator ''' - return sparse_grid.get_generator(args.basis, args.ncoeff, stats, args.trim, + return green_grids.get_generator(args.basis, args.ncoeff, stats, args.trim, args.prec) diff --git a/python/sparse_grid/__init__.py b/python/green_grids/__init__.py similarity index 95% rename from python/sparse_grid/__init__.py rename to python/green_grids/__init__.py index 37fc252..ca8a5d1 100644 --- a/python/sparse_grid/__init__.py +++ b/python/green_grids/__init__.py @@ -1,5 +1,10 @@ -from sparse_grid.repn import chebyshev, ir, generator -from sparse_grid.sparse_data import SparseData, PairedSparseData +from .repn import chebyshev, ir, generator +from .sparse_data import SparseData, PairedSparseData +from .version import __version__ + + +__all__ = ["__version__",] + ALL_REPNS = { 'chebyshev': chebyshev, diff --git a/python/sparse_grid/repn/__init__.py b/python/green_grids/repn/__init__.py similarity index 100% rename from python/sparse_grid/repn/__init__.py rename to python/green_grids/repn/__init__.py diff --git a/python/sparse_grid/repn/basis.py b/python/green_grids/repn/basis.py similarity index 100% rename from python/sparse_grid/repn/basis.py rename to python/green_grids/repn/basis.py diff --git a/python/sparse_grid/repn/chebyshev.py b/python/green_grids/repn/chebyshev.py similarity index 98% rename from python/sparse_grid/repn/chebyshev.py rename to python/green_grids/repn/chebyshev.py index 4516a25..0808036 100644 --- a/python/sparse_grid/repn/chebyshev.py +++ b/python/green_grids/repn/chebyshev.py @@ -3,9 +3,9 @@ import mpmath as mp import numpy as np -from sparse_grid import utils -from sparse_grid.repn.basis import SparseBasis -from sparse_grid.repn.transformer import SparseTransformer +from .. import utils +from .basis import SparseBasis +from .transformer import SparseTransformer def get_xroot(order): diff --git a/python/sparse_grid/repn/generator.py b/python/green_grids/repn/generator.py similarity index 95% rename from python/sparse_grid/repn/generator.py rename to python/green_grids/repn/generator.py index 3f1f84e..c328de8 100644 --- a/python/sparse_grid/repn/generator.py +++ b/python/green_grids/repn/generator.py @@ -1,6 +1,6 @@ import numpy as np -from sparse_grid.repn.basis import SparseBasis -from sparse_grid.sparse_data import SparseData, PairedSparseData +from .basis import SparseBasis +from ..sparse_data import SparseData, PairedSparseData from warnings import warn _stats_str = {'fermi': 'F', 'bose': 'B'} diff --git a/python/sparse_grid/repn/ir.py b/python/green_grids/repn/ir.py similarity index 85% rename from python/sparse_grid/repn/ir.py rename to python/green_grids/repn/ir.py index 8df2046..b01da38 100644 --- a/python/sparse_grid/repn/ir.py +++ b/python/green_grids/repn/ir.py @@ -1,7 +1,8 @@ import numpy as np import scipy.linalg as la -from sparse_grid.repn.basis import SparseBasis -from sparse_grid.repn.transformer import SparseTransformer +from .basis import SparseBasis +from .transformer import SparseTransformer +from sparse_ir import poly as spir_poly import sparse_ir _stats_str = {'fermi': 'F', 'bose': 'B'} @@ -10,7 +11,9 @@ class Basis(SparseBasis): def __init__(self, lambda_, ncoeff, stats, trim=True, h5file=""): - sparse_ir.poly.PiecewiseLegendreFT._DEFAULT_GRID = np.hstack([np.arange(2**6), (2**np.linspace(6, 30, 16*(30-6)+1)).astype(np.int64)]) + spir_poly.PiecewiseLegendreFT._DEFAULT_GRID = np.hstack( + [np.arange(2**6), (2**np.linspace(6, 30, 16 * (30 - 6) + 1)).astype(np.int64)] + ) self._basis = sparse_ir.FiniteTempBasis(_stats_str[stats], beta=1.0, wmax=int(float(lambda_))) self.Lambda = lambda_ if ncoeff is None: @@ -27,10 +30,10 @@ def _sampling_points_x(self, ncoeff: int): return sparse_ir.basis._default_sampling_points(self._basis.sve_result.u, ncoeff) def _uxl(self, l, x): - return self._basis.u[:self._dim]((np.asarray(x) + 1)/2).T * np.sqrt(1.0/2.0) + return self._basis.u[:self._dim]((np.asarray(x) + 1) / 2).T * np.sqrt(1.0 / 2.0) def compute_unl(self, n, whichl=None): - return self._basis.uhat[:self._dim]((2 * n + (1 if self.stats == 'fermi' else 0))).T + return self._basis.uhat[:self._dim]((2 * n + (1 if self.stats == 'fermi' else 0))).T def metadata(self, ncoeff): return { diff --git a/python/sparse_grid/repn/transformer.py b/python/green_grids/repn/transformer.py similarity index 98% rename from python/sparse_grid/repn/transformer.py rename to python/green_grids/repn/transformer.py index a4ed0f8..2934841 100644 --- a/python/sparse_grid/repn/transformer.py +++ b/python/green_grids/repn/transformer.py @@ -1,6 +1,6 @@ import numpy as np from abc import ABC, abstractmethod -from sparse_grid.sparse_data import SparseData +from ..sparse_data import SparseData from warnings import warn diff --git a/python/sparse_grid/sparse_data.py b/python/green_grids/sparse_data.py similarity index 98% rename from python/sparse_grid/sparse_data.py rename to python/green_grids/sparse_data.py index b91d7bf..0534e7a 100644 --- a/python/sparse_grid/sparse_data.py +++ b/python/green_grids/sparse_data.py @@ -2,7 +2,8 @@ import numpy as np import re from dataclasses import dataclass -from sparse_grid.utils import h5save_dict, h5load_dict +from .utils import h5save_dict, h5load_dict +from .version import __version__ from typing import Optional @@ -281,6 +282,8 @@ def save_hdf5(self, filename: str, basepath='/'): basepath += '/' with h5py.File(filename, 'w') as f: + if basepath == '/': + f.attrs['__grids_version__'] = __version__ grp = f.require_group(basepath) self.save_to(grp) diff --git a/python/sparse_grid/transform.py b/python/green_grids/transform.py similarity index 98% rename from python/sparse_grid/transform.py rename to python/green_grids/transform.py index f6bf4a5..331f2af 100644 --- a/python/sparse_grid/transform.py +++ b/python/green_grids/transform.py @@ -1,6 +1,6 @@ import numpy as np -from sparse_grid.sparse_data import SparseData, PairedSparseData +from .sparse_data import SparseData, PairedSparseData def l_to_tau(data: SparseData, fl: np.ndarray): diff --git a/python/sparse_grid/utils.py b/python/green_grids/utils.py similarity index 100% rename from python/sparse_grid/utils.py rename to python/green_grids/utils.py diff --git a/python/green_grids/version.py b/python/green_grids/version.py new file mode 100644 index 0000000..290d7c6 --- /dev/null +++ b/python/green_grids/version.py @@ -0,0 +1 @@ +__version__ = '0.3.0' \ No newline at end of file diff --git a/python/requirements.txt b/python/requirements.txt index 1392bf4..7fc459d 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -1,8 +1,6 @@ -future h5py>=3.0.0 xprec>=1.3.0 -sparse_ir>=1.0.0 +sparse_ir>=1.0.0,<2.0.0 mpmath>=1.0.0 numpy>=1.19.0 scipy>=1.5.0 -six diff --git a/python/tests/test_basis.py b/python/tests/test_basis.py index 334e0a9..8f4311d 100644 --- a/python/tests/test_basis.py +++ b/python/tests/test_basis.py @@ -1,8 +1,8 @@ import numpy as np import unittest from numpy.testing import assert_allclose -from sparse_grid.repn.chebyshev import Basis as ChebyshevBasis -from sparse_grid.repn.ir import Basis as IRBasis +from green_grids.repn.chebyshev import Basis as ChebyshevBasis +from green_grids.repn.ir import Basis as IRBasis class ChebyshevBasisTest(unittest.TestCase): diff --git a/python/tests/test_generator.py b/python/tests/test_generator.py index d2e17a3..f84c419 100644 --- a/python/tests/test_generator.py +++ b/python/tests/test_generator.py @@ -1,6 +1,6 @@ import numpy as np import unittest -from sparse_grid.repn.generator import Generator +from green_grids.repn.generator import Generator from unittest.mock import Mock diff --git a/python/tests/test_grid_files.py b/python/tests/test_grid_files.py new file mode 100644 index 0000000..b46dbfe --- /dev/null +++ b/python/tests/test_grid_files.py @@ -0,0 +1,89 @@ +import pytest +import h5py +import numpy as np +from pathlib import Path +from green_grids import get_generator, generator + + +def gridfile_diff(file1, file2): + with h5py.File(file1, 'r') as f1, h5py.File(file2, 'r') as f2: + # Compare keys + assert f1.attrs['__grids_version__'] == f2.attrs['__grids_version__'], "Grid file versions do not match." + keys = ["ngrid", "u1l_neg", "u1l_pos", "ulw", "ulx", "uwl", "uxl", "uxl_other", "wgrid", "xgrid"] + stats = ["fermi", "bose"] + for st in stats: + for key in keys: + data1 = f1[f"{st}/{key}"][:] + data2 = f2[f"{st}/{key}"][:] + assert np.allclose(data1, data2, atol=1e-8), f"Difference found in {st}/{key}" + + +@pytest.mark.parametrize( + "ir_lambda, outfile", + [ + (1e4, "1e4.h5"), + (1e5, "1e5.h5"), + pytest.param(1e6, "1e6.h5", marks=pytest.mark.slow), + pytest.param(1e7, "1e7.h5", marks=pytest.mark.slow), + pytest.param(1e8, "1e8.h5", marks=pytest.mark.slow), + ] +) +def test_ir_gridfiles(ir_lambda, outfile, tmp_path): + # create temporary directory for generated files + tmp_outfile = tmp_path / outfile + + # Syntax: get_generator(basis, ir_lambda, ncoeff, stats, trim, h5file to read) + fermi_generator = get_generator("ir", ir_lambda, None, "fermi", True, None) + bose_generator = get_generator("ir", ir_lambda, None, "bose", True, None) + sparse_data = generator.generate_paired_sparse_data(fermi_generator, bose_generator, "fermi", "bose") + # save data + sparse_data.save_hdf5(tmp_outfile) + + # Compare HDF5 files + test_dir = Path(__file__).resolve().parent + repo_dir = test_dir.parent.parent + data_dir = repo_dir / "data" / "ir" + reference_file = data_dir / outfile + + # Check if the generated file matches the reference file + assert reference_file.exists(), f"Reference file {reference_file} does not exist." + assert tmp_outfile.exists(), f"Generated file {tmp_outfile} does not exist." + + # Use the diff_hdf5 function to compare the contents of the HDF5 files + gridfile_diff(reference_file, tmp_outfile) + + +@pytest.mark.parametrize( + "ncoeff, outfile", + [ + (100, "100.h5"), + (150, "150.h5"), + pytest.param(200, "200.h5", marks=pytest.mark.slow), + pytest.param(300, "300.h5", marks=pytest.mark.slow), + pytest.param(350, "350.h5", marks=pytest.mark.slow), + pytest.param(450, "450.h5", marks=pytest.mark.slow), + ] +) +def test_chebyshev_gridfiles(ncoeff, outfile, tmp_path): + # create temporary directory for generated files + tmp_outfile = tmp_path / outfile + + # Syntax: get_generator(basis, ncoeff, stats, trim, precision) + fermi_generator = get_generator("chebyshev", ncoeff, "fermi", True, None) + bose_generator = get_generator("chebyshev", ncoeff, "bose", True, None) + sparse_data = generator.generate_paired_sparse_data(fermi_generator, bose_generator, "fermi", "bose") + # save data + sparse_data.save_hdf5(tmp_outfile) + + # Compare HDF5 files + test_dir = Path(__file__).resolve().parent + repo_dir = test_dir.parent.parent + data_dir = repo_dir / "data" / "cheb" + reference_file = data_dir / outfile + + # Check if the generated file matches the reference file + assert reference_file.exists(), f"Reference file {reference_file} does not exist." + assert tmp_outfile.exists(), f"Generated file {tmp_outfile} does not exist." + + # Use the diff_hdf5 function to compare the contents of the HDF5 files + gridfile_diff(reference_file, tmp_outfile) diff --git a/python/tests/test_module_functions.py b/python/tests/test_module_functions.py index bdf9209..a7d2b16 100644 --- a/python/tests/test_module_functions.py +++ b/python/tests/test_module_functions.py @@ -3,8 +3,8 @@ # import numpy as np # from numpy.testing import assert_allclose -from sparse_grid import get_generator, get_fermi_bose_pair -from sparse_grid import get_transformer, transform_data, transform_paired_data +from green_grids import get_generator, get_fermi_bose_pair +from green_grids import get_transformer, transform_data, transform_paired_data class ModuleFunctionsTest(unittest.TestCase): diff --git a/python/tests/test_repn_transformer.py b/python/tests/test_repn_transformer.py index 35d3600..390dd60 100644 --- a/python/tests/test_repn_transformer.py +++ b/python/tests/test_repn_transformer.py @@ -1,10 +1,10 @@ import numpy as np import unittest from numpy.testing import assert_allclose -from sparse_grid.repn.chebyshev import Transformer as ChebyshevTransformer -from sparse_grid.repn.ir import Transformer as IRTransformer -from sparse_grid.repn.transformer import SparseTransformer -from sparse_grid.sparse_data import SparseData +from green_grids.repn.chebyshev import Transformer as ChebyshevTransformer +from green_grids.repn.ir import Transformer as IRTransformer +from green_grids.repn.transformer import SparseTransformer +from green_grids.sparse_data import SparseData class FakeTransformer(SparseTransformer): diff --git a/python/tests/test_sparse_data.py b/python/tests/test_sparse_data.py index 8b8a9c4..f2a5e31 100644 --- a/python/tests/test_sparse_data.py +++ b/python/tests/test_sparse_data.py @@ -3,8 +3,8 @@ import os import shutil from contextlib import contextmanager -from sparse_grid.sparse_data import PairedSparseData, SparseData -from sparse_grid.utils import h5save_dict +from green_grids.sparse_data import PairedSparseData, SparseData +from green_grids.utils import h5save_dict from .common import HDF5TestCase diff --git a/python/tests/test_transform.py b/python/tests/test_transform.py index 0d13b84..b17c76e 100644 --- a/python/tests/test_transform.py +++ b/python/tests/test_transform.py @@ -1,8 +1,8 @@ import numpy as np -import sparse_grid.transform as tf +import green_grids.transform as tf import unittest from numpy.testing import assert_allclose -from sparse_grid import get_fermi_bose_pair +from green_grids import get_fermi_bose_pair class TransformTest(unittest.TestCase): diff --git a/python/tests/test_utils.py b/python/tests/test_utils.py index 5801cf8..4dfeff6 100644 --- a/python/tests/test_utils.py +++ b/python/tests/test_utils.py @@ -2,7 +2,7 @@ import numpy as np import shutil from numpy.testing import assert_allclose -from sparse_grid import utils +from green_grids import utils from .common import HDF5TestCase diff --git a/test/data/1e4_old_compatible.h5 b/test/data/1e4_old_compatible.h5 new file mode 100644 index 0000000..b892ffa Binary files /dev/null and b/test/data/1e4_old_compatible.h5 differ diff --git a/test/data/1e4_old_incompatible.h5 b/test/data/1e4_old_incompatible.h5 new file mode 100644 index 0000000..b377e25 Binary files /dev/null and b/test/data/1e4_old_incompatible.h5 differ diff --git a/test/grids_test.cpp b/test/grids_test.cpp index 3bf8951..1beba4f 100644 --- a/test/grids_test.cpp +++ b/test/grids_test.cpp @@ -159,6 +159,12 @@ void check_transformer(green::grids::transformer_t& tr) { double leakage = tr.check_chebyshev(X1t, 1); REQUIRE(leakage < 1e-10); } + SECTION("Check Version Info") { + std::string v = tr.get_version(); + std::string v2 = "0.2.0"; // Older version + REQUIRE(green::grids::CheckVersion(v)); + REQUIRE_FALSE(green::grids::CheckVersion(v2)); + } } TEST_CASE("Grids") { @@ -202,6 +208,26 @@ TEST_CASE("Grids") { REQUIRE_THROWS_AS(green::grids::transformer_t(p), green::grids::grids_file_not_found_error); } + SECTION("Outdated grid - compatible") { + auto p = green::params::params("DESCR"); + green::grids::define_parameters(p); + std::string input_file = TEST_PATH + "/1e4_old_compatible.h5"s; + std::string args = "test --BETA 10 --grid_file " + input_file; + auto [argc, argv] = get_argc_argv(args); + p.parse(argc, argv); + REQUIRE_NOTHROW(green::grids::transformer_t(p)); + } + + SECTION("Outdated grid - incompatible") { + auto p = green::params::params("DESCR"); + green::grids::define_parameters(p); + std::string input_file = TEST_PATH + "/1e4_old_incompatible.h5"s; + std::string args = "test --BETA 10 --grid_file " + input_file; + auto [argc, argv] = get_argc_argv(args); + p.parse(argc, argv); + REQUIRE_THROWS_AS(green::grids::transformer_t(p), green::grids::outdated_grids_file_error); + } + #ifndef NDEBUG SECTION("Wrong File") { auto p = green::params::params("DESCR");