diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6e6e765..32d1afc 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,152 +1,68 @@ name: Docs -on: [release] +on: + push: + branches: + - main + - dev + tags: + - "v*" + pull_request: + branches: + - main + - dev + release: + +permissions: + contents: write # 'write' access to repository contents + pull-requests: write # 'write' access to pull requests jobs: - notebooks: + build-notebooks: name: "Build the notebooks for the docs" runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + - name: Set SHA + run: | + SHA="${{ github.event.pull_request.head.sha || github.sha }}" + echo "SHA=$SHA" >> "$GITHUB_ENV" - name: Set up Python uses: actions/setup-python@v6 with: - python-version: 3.11 - - uses: conda-incubator/setup-miniconda@v4 - with: - auto-activate-base: true - activate-environment: "" - auto-update-conda: true - python-version: ${{ matrix.python-version }} - channels: conda-forge, threeml, defaults - + python-version: 3.13 - name: Install dependencies run: | - python -m pip install --upgrade pip wheel - pip install numpy==2.1 - pip install matplotlib==3.8.4 - pip install black - pip install ipython jupyter cython astropy - conda install jupytext jupyterthemes emcee pymultinest ultranest nbconvert ipykernel astropy regions threeML astromodels gammapy - pip install . + pip install black ultranest + pip install -e . + pip install -r docs/requirements.txt - name: Execute the notebooks shell: bash -l {0} run: | - pip install . - export GAMMAPY_DATA=$HOME/data + export GAMMAPY_DATA="/home/runner/work/gammapy_data" mkdir -p $GAMMAPY_DATA git clone https://github.com/gammapy/gammapy-data.git $GAMMAPY_DATA - jupytext --to ipynb --pipe black --execute docs/md/*.md + jupytext --to ipynb --pipe black --execute docs/md_docs/*.md mkdir -p docs/notebooks - mv docs/md/*.ipynb docs/notebooks - + mv docs/md_docs/*.ipynb docs/notebooks + echo "Next - uploading artifacts for sha ${SHA}" - uses: actions/upload-artifact@v6 with: - name: notebooks-for-${{ github.sha }} + name: notebooks-for-${{ env.SHA }} path: docs/notebooks - api_doc: - name: "Create the API stubs" - runs-on: macos-latest - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token - fetch-depth: 0 # otherwise, you will failed to push refs to dest repo - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: 3.11 - - - name: Build the API doc - run: | - - brew install c-blosc - brew install hdf5 - - pip3 install --upgrade pip - pip3 install cython - pip3 install numpy==2.1 - pip3 install --upgrade scipy numba astropy - pip3 install matplotlib==3.8.4 - pip3 install . - - brew install sphinx-doc pandoc - - pip3 install wheel - pip3 install mock recommonmark - pip3 install sphinx_rtd_theme - pip3 install -U sphinx nbsphinx sphinx-gallery - - - - sphinx-apidoc -f -o docs/api/ gammapy_plugin - - - uses: actions/upload-artifact@v6 - with: - name: api-stubs-for-${{ github.sha }} - path: docs/api - - build_docs: - name: "Build the Documentation" - runs-on: macos-latest - needs: [notebooks, api_doc] - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token - fetch-depth: 0 # otherwise, you will failed to push refs to dest repo - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: 3.11 - - - name: Install package + - name: Trigger RTD + shell: bash -l {0} run: | + curl -X POST \ + "https://app.readthedocs.org/api/v3/projects/gammapy-plugin/versions/${PR_NUMBER}/builds/" \ + -H "Authorization: Token $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"branch\": \"${BRANCH}\" + }" - brew install c-blosc - brew install hdf5 - pip3 install numpy scipy numba astropy matplotlib==3.8.4 - brew install sphinx-doc pandoc - - pip3 install wheel - pip3 install mock recommonmark - pip3 install sphinx_rtd_theme - pip3 install -U sphinx nbsphinx sphinx-gallery - pip3 install threeML - pip3 install --upgrade git+https://github.com/threeml/astromodels.git - pip3 install --upgrade git+https://github.com/threeml/threeML.git - pip3 install --upgrade gammapy --use-pep517 - - - pip3 install -e . - - rm -rf docs/md/* env: - ISDEV: ${{contains(github.rev,'dev') || contains(github.base_ref, 'dev')}} - - - uses: actions/download-artifact@master - with: - name: notebooks-for-${{ github.sha }} - path: docs/notebooks - - - uses: actions/download-artifact@master - with: - name: api-stubs-for-${{ github.sha }} - path: docs/notebooks/api - - - name: Build and Commit - uses: sphinx-notes/pages@master - with: - documentation_path: docs - sphinx_version: 5.1.1 - requirements_path: docs/requirements.txt - - - name: Push changes - if: github.event_name == 'push' - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: gh-pages + TOKEN: ${{ secrets.RTD_API }} + BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }} + PR_NUMBER: ${{ github.event.number || 'latest' }} diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b1e9ab8..99ca186 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,34 +1,22 @@ # Read the Docs configuration file for Sphinx projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details -# Required version: 2 -# Set the OS, Python version and other tools you might need build: os: ubuntu-24.04 tools: python: "3.12" - # You can also specify other tool versions: - # nodejs: "20" - # rust: "1.70" - # golang: "1.20" jobs: pre_build: - sphinx-apidoc . -o docs/api - - jupytext --to ipynb --pipe black --execute docs/md_docs/*.md - - mv docs/md_docs/*.ipynb docs/notebooks + - bash docs/download_notebooks.sh # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/conf.py fail_on_warning: false -# Optionally build your docs in additional formats such as PDF and ePub -# formats: -# - pdf -# - epub - python: install: - requirements: docs/requirements.txt diff --git a/docs/download_notebooks.sh b/docs/download_notebooks.sh new file mode 100644 index 0000000..e024a84 --- /dev/null +++ b/docs/download_notebooks.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail + +OWNER="threeML" +REPO="gammapy-plugin" +SHA="${READTHEDOCS_GIT_COMMIT_HASH}" +TOKEN="${GITHUB_TOKEN}" + +API="https://api.github.com/repos/$OWNER/$REPO" + +echo "Searching artifacts for SHA: $SHA" + +ARTIFACT_ID=$( +python3 - < None: for name, source in self._converted_sources.items(): source._update_parameters() + def update(self) -> None: + """Update all parameters of all SkyModels witht the current values from the + astromodels model. Public method for _update_parameters""" + self._update_parameters() + @property def gammapy_models(self) -> list[SkyModel]: """ @@ -221,6 +226,13 @@ def _create_skymodel(self) -> None: ) self._gather_mappings() + def update(self) -> None: + """ + This invokes the updating of all parameters of the converted model in the + gammapy SkyModels + """ + self._update_parameters() + @property def skymodel(self) -> SkyModel: """Returns the Gammapy skymodel for this source. diff --git a/gammapy_plugin/test/test_gammapy_fit.py b/gammapy_plugin/test/test_gammapy_fit.py new file mode 100644 index 0000000..dc11e33 --- /dev/null +++ b/gammapy_plugin/test/test_gammapy_fit.py @@ -0,0 +1,93 @@ +import astropy.units as u +import numpy as np +import pytest +from astromodels.core.model import Model +from astromodels.functions import Powerlaw +from astromodels.sources import PointSource +from gammapy.modeling import Fit +from gammapy.modeling.models import PowerLawSpectralModel, SkyModel + +from gammapy_plugin.converter import AstromodelConverter + + +def test_gammapy_fit(crab_test_data): + datasets = crab_test_data.copy() + datasets_gp = crab_test_data.copy() + np.random.seed(1234) + + pl = Powerlaw() + ps = PointSource("crab", spectral_shape=pl, ra=83.63, dec=22.01) + pl.piv = 1 * u.TeV + pl.K = 1e-12 * u.Unit("TeV-1 cm-2 s-1") + pl.index = -2 + pl.index.min_value = -np.inf + pl.index.max_value = np.inf + + model = Model(ps) + conv = AstromodelConverter(model) + datasets.models = [conv.gammapy_models[0]] # using ReflectedRegionsBackground + fit = Fit() + result = fit.run(datasets=datasets) + + spectral_model = PowerLawSpectralModel( + amplitude=1e-12 * u.Unit("cm-2 s-1 TeV-1"), + index=2, + reference=1 * u.TeV, + ) + model_gp = SkyModel(spectral_model=spectral_model, name="crab") + + datasets_gp.models = [model_gp] + + fit_joint = Fit() + result_joint = fit_joint.run(datasets=datasets_gp) + assert np.isclose( + result.models[0].parameters["crab.spectrum.main.Powerlaw.index"].value, + -result_joint.models[0].parameters["index"].value, + atol=result_joint.models[0].parameters["index"].error, + ) + + +def test_xspec_wrapping(crab_test_data): + + pytest.importorskip("xspec") + + from astromodels.xspec import XS_powerlaw + + datasets = crab_test_data.copy() + datasets = datasets.stack_reduce() + datasets_gp = crab_test_data.copy() + datasets_gp = datasets_gp.stack_reduce() + np.random.seed(1234) + pl = XS_powerlaw() + ps = PointSource("crab", spectral_shape=pl, ra=83.633, dec=22.014) + pl.phoindex = 2 + pl.phoindex.min_value = -np.nan + pl.phoindex.max_value = np.nan + + model = Model(ps) + conv = AstromodelConverter(model) + datasets.models = [conv.gammapy_models[0]] # using ReflectedRegionsBackground + fit = Fit() + result = fit.run(datasets=datasets) + + spectral_model = PowerLawSpectralModel( + amplitude=100 * u.Unit("cm-2 s-1 keV-1"), + index=2, + reference=1 * u.keV, + ) + model_gp = SkyModel(spectral_model=spectral_model, name="crab") + + datasets_gp.models = [model_gp] + + fit_joint = Fit() + result_joint = fit_joint.run(datasets=datasets_gp) + assert np.isclose( + result.models[0].parameters["crab.spectrum.main.XS_powerlaw.norm"].value, + result_joint.models[0].parameters["amplitude"].value, + atol=result_joint.models[0].parameters["amplitude"].error, + ) + assert np.isclose( + result.models[0].parameters["crab.spectrum.main.XS_powerlaw.phoindex"].value, + result_joint.models[0].parameters["index"].value, + atol=result_joint.models[0].parameters["index"].error, + )