diff --git a/.github/actions/r2x-check/action.yaml b/.github/actions/r2x-check/action.yaml deleted file mode 100644 index 8b726751..00000000 --- a/.github/actions/r2x-check/action.yaml +++ /dev/null @@ -1,100 +0,0 @@ -name: r2x-compatibility -description: "Action to run R2X." -inputs: - reeds-run-path: - required: true - type: string - scenario: - type: string - python-version: - type: string - default: "3.11" - weather-year: - type: int - default: 2012 - solve-year: - type: int - default: 2035 - -outputs: - scenario: - description: Resolved scenario name used for export. - value: ${{ steps.resolve.outputs.scenario }} - system-json: - description: Filename of the exported R2X system JSON. - value: ${{ steps.resolve.outputs.system_json }} - -runs: - using: composite - steps: - - name: Resolve scenario name - id: resolve - shell: bash -le {0} - env: - INPUT_SCENARIO: ${{ inputs.scenario }} - INPUT_RUN_PATH: ${{ inputs.reeds-run-path }} - run: | - scenario="${INPUT_SCENARIO}" - if [ -z "$scenario" ]; then - scenario="$(basename "$INPUT_RUN_PATH")" - fi - system_json="${scenario}_system.json" - echo "scenario=$scenario" >> "$GITHUB_OUTPUT" - echo "system_json=$system_json" >> "$GITHUB_OUTPUT" - - - name: Install uv and set the python version - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 - with: - python-version: ${{ inputs.python-version }} - enable-cache: true - restore-cache: true - save-cache: true - ignore-nothing-to-cache: true - - - name: Run R2X translation - shell: bash -le {0} - env: - R2X_RUN_PATH: ${{ inputs.reeds-run-path }} - R2X_SOLVE_YEAR: ${{ inputs.solve-year }} - R2X_WEATHER_YEAR: ${{ inputs.weather-year }} - R2X_SCENARIO: ${{ steps.resolve.outputs.scenario }} - R2X_SYSTEM_JSON: ${{ steps.resolve.outputs.system_json }} - run: | - uv run --with "r2x-reeds>=0.3.5" python - <<'PY' - import os - from pathlib import Path - - from loguru import logger - from r2x_core import DataStore, PluginContext - from r2x_core.logger import setup_logging - from r2x_reeds import ReEDSConfig, ReEDSParser - - run_path = Path(os.environ["R2X_RUN_PATH"]).expanduser().resolve() - solve_year = int(os.environ["R2X_SOLVE_YEAR"]) - weather_year = int(os.environ["R2X_WEATHER_YEAR"]) - scenario = os.environ["R2X_SCENARIO"] - system_json = os.environ["R2X_SYSTEM_JSON"] - - setup_logging() - - config = ReEDSConfig( - weather_year=weather_year, - solve_year=solve_year, - scenario=scenario, - ) - - store = DataStore.from_plugin_config(config, path=run_path) - ctx = PluginContext(config=config, store=store) - parser = ReEDSParser.from_context(ctx) - result_ctx = parser.run() - result_ctx.system.to_json(system_json) - logger.info("Built R2X system for scenario '{}' at '{}'", scenario, system_json) - PY - - - name: Save R2X system - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: r2x-${{ steps.resolve.outputs.scenario }} - compression-level: 9 - retention-days: 1 - path: ${{ steps.resolve.outputs.system_json }} diff --git a/.github/actions/setup-reeds-env/action.yml b/.github/actions/setup-reeds-env/action.yml new file mode 100644 index 00000000..0818d3c8 --- /dev/null +++ b/.github/actions/setup-reeds-env/action.yml @@ -0,0 +1,61 @@ +name: Setup ReEDS Environment +description: Setup cached micromamba Python and/or Julia environment for ReEDS CI. + +inputs: + setup-python: + description: Setup micromamba environment from environment.yml. + required: false + default: "true" + setup-julia: + description: Setup Julia toolchain. + required: false + default: "true" + julia-version: + description: Julia version to install. + required: false + default: "1.12.1" + instantiate-julia: + description: Run julia --project=. instantiate.jl. + required: false + default: "true" + +outputs: + mamba-env-path: + description: Micromamba environment path. + value: ${{ steps.mamba.outputs.environment-path }} + julia-bindir: + description: Julia binary directory. + value: ${{ steps.setup-julia.outputs.julia-bindir }} + +runs: + using: composite + steps: + - name: Setup micromamba env + if: ${{ fromJSON(inputs.setup-python) }} + id: mamba + uses: mamba-org/setup-micromamba@add3a49764cedee8ee24e82dfde87f5bc2914462 # v2 + with: + environment-file: environment.yml + cache-environment: true + post-cleanup: "all" + cache-environment-key: ${{ runner.os }}-conda-${{ hashFiles('environment.yml') }} + + - name: Restore Julia cache + if: ${{ fromJSON(inputs.setup-julia) }} + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 + with: + path: ~/.julia + key: julia-${{ runner.os }}-${{ hashFiles('Project.toml') }} + restore-keys: julia-${{ runner.os }}- + + - name: Setup Julia + if: ${{ fromJSON(inputs.setup-julia) }} + id: setup-julia + uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2 + with: + version: ${{ inputs.julia-version }} + + - name: Instantiate Julia project + if: ${{ fromJSON(inputs.setup-julia) && fromJSON(inputs.instantiate-julia) }} + shell: bash -le {0} + run: julia --project=. instantiate.jl diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..f48eaf06 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,65 @@ +version: 2 + +updates: + - package-ecosystem: "conda" + directory: / + schedule: + interval: "weekly" + cooldown: + default-days: 7 + open-pull-requests-limit: 2 + labels: + - "dependencies" + reviewers: + - "kennedy-mindermann" + commit-message: + prefix: "build" + include: "scope" + rebase-strategy: "auto" + + - package-ecosystem: "pip" + directory: / + schedule: + interval: "weekly" + cooldown: + default-days: 7 + open-pull-requests-limit: 2 + labels: + - "dependencies" + reviewers: + - "kennedy-mindermann" + commit-message: + prefix: "build" + include: "scope" + rebase-strategy: "auto" + + - package-ecosystem: "julia" + directory: / + schedule: + interval: "weekly" + cooldown: + default-days: 7 + open-pull-requests-limit: 2 + labels: + - "dependencies" + reviewers: + - "kennedy-mindermann" + commit-message: + prefix: "build" + include: "scope" + rebase-strategy: "auto" + + - package-ecosystem: "github-actions" + directory: / + schedule: + interval: "weekly" + cooldown: + default-days: 7 + labels: + - "dependencies" + reviewers: + - "kennedy-mindermann" + commit-message: + prefix: "build" + include: "scope" + rebase-strategy: "auto" diff --git a/.github/labeler.yaml b/.github/labeler.yaml new file mode 100644 index 00000000..e0558a5b --- /dev/null +++ b/.github/labeler.yaml @@ -0,0 +1,87 @@ +dependencies: + - head-branch: + - '^dependabot/.+' + - changed-files: + - any-glob-to-any-file: + - "environment.yml" + - "pyproject.toml" + - "requirements*.txt" + - "Project.toml" + - "Manifest.toml" + - ".github/dependabot.yml" + +github_actions: + - changed-files: + - any-glob-to-any-file: + - ".github/workflows/**" + - ".github/actions/**" + - ".github/scripts/**" + +docs: + - changed-files: + - any-glob-to-any-file: + - "docs/**" + - "**/*.md" + - "CITATION.cff" + +release: + - changed-files: + - any-glob-to-any-file: + - "CHANGELOG.md" + - "README.md" + +tests: + - changed-files: + - any-glob-to-any-file: + - "tests/**" + - "hourlize/tests/**" + - "reeds2pras/test/**" + - "**/test_*.py" + - "**/*_test.py" + +model_changes: + - changed-files: + - any-glob-to-any-file: + - "*.gms" + - "**/*.gms" + - "runbatch.py" + - "d_solve*.py" + - "reeds/**" + - "ReEDS_Augur/**" + - "Augur.py" + - "instantiate.jl" + - "reeds2pras/**" + +data_changes: + - changed-files: + - any-glob-to-any-file: + - "inputs/**" + - "hourlize/inputs/**" + - "postprocessing/**/inputs/**" + - "**/*.csv" + - "**/*.h5" + - "sources.csv" + - "sources_documentation.md" + +hourlize: + - changed-files: + - any-glob-to-any-file: "hourlize/**" + +input_processing: + - changed-files: + - any-glob-to-any-file: + - "input_processing/**" + - "preprocessing/**" + +postprocessing: + - changed-files: + - any-glob-to-any-file: "postprocessing/**" + +reeds2pras: + - changed-files: + - any-glob-to-any-file: "reeds2pras/**" + +switches: + - changed-files: + - any-glob-to-any-file: + - "cases.csv" diff --git a/.github/workflows/build-docs.yaml b/.github/workflows/build-docs.yaml index fac37fb5..24f72ed6 100644 --- a/.github/workflows/build-docs.yaml +++ b/.github/workflows/build-docs.yaml @@ -17,16 +17,20 @@ on: - main permissions: - contents: write + contents: read jobs: build: + name: build runs-on: ubuntu-latest + permissions: + contents: write # Required for peaceiris/actions-gh-pages publish to gh-pages. steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 1 lfs: true + persist-credentials: false - name: Set up Python 3.12 uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 @@ -48,11 +52,11 @@ jobs: - name: Set variables for internal github repo run: | - echo "BASE_URL=https://github.com/ReEDS-Model/ReEDS" >> $GITHUB_ENV - cd ${GITHUB_WORKSPACE}/docs/source/documentation_tools/ + echo "BASE_URL=https://github.com/ReEDS-Model/ReEDS" >> "$GITHUB_ENV" + cd "$GITHUB_WORKSPACE/docs/source/documentation_tools/" sh generate_sources_md_file.sh - cd ${GITHUB_WORKSPACE} - python docs/source/documentation_tools/generate_markdown.py --githubURL "https://github.com/ReEDS-Model/ReEDS/blob/main" --reedsPath "${GITHUB_WORKSPACE}" + cd "$GITHUB_WORKSPACE" + python docs/source/documentation_tools/generate_markdown.py --githubURL "https://github.com/ReEDS-Model/ReEDS/blob/main" --reedsPath "$GITHUB_WORKSPACE" - name: Build Sphinx documentation env: diff --git a/.github/workflows/cache.yaml b/.github/workflows/cache.yaml deleted file mode 100644 index b44aa9f3..00000000 --- a/.github/workflows/cache.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# This Workflow creates caches for the Python and Julia environments every time -# someone merges a PR. Subsequent PRs reuse these caches if the dependency -# files have not changed. -name: update-cache - -on: - push: - branches: - - main - workflow_dispatch: - -permissions: - contents: read - -# To reset the CACHE, change the environment variable: CACHE_NUMBER. -# Either you increment the number or decrement it, but also reflect the changes -# on the other workflows that reutilize the Python environment -env: - CACHE_NUMBER: 1 - JULIA_VERSION: '1.12.1' - -jobs: - python-cache: - name: Python Cache - runs-on: ubuntu-latest - permissions: - contents: read - actions: write - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - uses: mamba-org/setup-micromamba@add3a49764cedee8ee24e82dfde87f5bc2914462 # v2 - with: - environment-file: environment.yml - cache-environment: true - post-cleanup: 'all' - cache-environment-key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('environment.yml') }} - env: - ACTIONS_STEP_DEBUG: true - - julia-cache: - name: Julia Cache - runs-on: ubuntu-latest - permissions: - contents: read - actions: write - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Restore Julia cache - id: julia-cache - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 - with: - path: ~/.julia - key: julia-${{ runner.os }}-${{ hashFiles('Project.toml') }} - restore-keys: julia-${{ runner.os }}- - - - uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2 - with: - version: ${{ env.JULIA_VERSION }} - env: - NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/nrel_ca_chain.crt - - - run: julia --project=. instantiate.jl diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml new file mode 100644 index 00000000..a1bcfcbf --- /dev/null +++ b/.github/workflows/labeler.yaml @@ -0,0 +1,29 @@ +name: labeler + +on: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + labeler: + name: apply labels + permissions: + contents: read + pull-requests: write # Required to add/remove pull-request labels. + issues: write # Required because PR labels are issue labels in the API. + if: github.event.pull_request.draft == false + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + configuration-path: .github/labeler.yaml + sync-labels: true diff --git a/.github/workflows/python-app.yaml b/.github/workflows/python-app.yaml index 69efc6ff..5f69a91d 100644 --- a/.github/workflows/python-app.yaml +++ b/.github/workflows/python-app.yaml @@ -23,57 +23,34 @@ defaults: shell: bash -le {0} env: - CACHE_NUMBER: 1 JULIA_VERSION: '1.12.1' - REEDS_ENV_NAME: reeds2 jobs: - julia-setup: - name: "Julia environment" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Restore Julia cache - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 - with: - path: ~/.julia - key: julia-${{ runner.os }}-${{ hashFiles('Project.toml') }} - restore-keys: julia-${{ runner.os }}- - - - uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2 - with: - version: ${{ env.JULIA_VERSION }} - - - run: julia --project=. instantiate.jl - - python-setup: - name: "Python environment" + reeds-env: + name: ReEDS Python and Julia env runs-on: ubuntu-latest + timeout-minutes: 15 permissions: contents: read - actions: write + actions: write # Required to save/update micromamba cache. steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: mamba-org/setup-micromamba@add3a49764cedee8ee24e82dfde87f5bc2914462 # v2 + - name: Setup ReEDS environments + uses: ./.github/actions/setup-reeds-env with: - environment-file: environment.yml - cache-environment: true - post-cleanup: 'all' - cache-environment-key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('environment.yml') }} + julia-version: ${{ env.JULIA_VERSION }} zenodo-setup: name: "Get Zenodo files" needs: - - python-setup + - reeds-env runs-on: ubuntu-latest + timeout-minutes: 15 permissions: contents: read - actions: write + actions: write # Required to save/update Zenodo data cache. steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: @@ -91,7 +68,7 @@ jobs: - name: Restore Zenodo files from cache id: cache-zenodo - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 with: path: | inputs/remote/ @@ -104,27 +81,25 @@ jobs: zenodo-files-${{ steps.zenodo-files.outputs.files-hash }}- zenodo-files- - - uses: mamba-org/setup-micromamba@add3a49764cedee8ee24e82dfde87f5bc2914462 # v2 - id: mamba + - name: Setup Python environment + uses: ./.github/actions/setup-reeds-env with: - environment-file: environment.yml - cache-environment: true - post-cleanup: 'all' - cache-environment-key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('environment.yml') }} + setup-julia: false - name: Download Zenodo files if not cached if: steps.cache-zenodo.outputs.cache-hit != 'true' run: python .github/scripts/download_test_zenodo_files.py run-ReEDS: + name: run ReEDS model matrix runs-on: ubuntu-latest + timeout-minutes: 60 needs: - - julia-setup - - python-setup + - reeds-env - zenodo-setup permissions: contents: read - actions: write + actions: write # Required to save/update LFS and Zenodo caches. strategy: fail-fast: false max-parallel: 4 @@ -173,7 +148,7 @@ jobs: - name: Restore Zenodo files from cache id: cache-zenodo - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 with: path: | inputs/remote/ @@ -186,59 +161,44 @@ jobs: zenodo-files-${{ steps.zenodo-files.outputs.files-hash }}- zenodo-files- - - uses: mamba-org/setup-micromamba@add3a49764cedee8ee24e82dfde87f5bc2914462 # v2 - id: mamba - with: - environment-file: environment.yml - cache-environment: true - post-cleanup: 'all' - cache-environment-key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('environment.yml') }} - - - name: Removing julia from python - run: micromamba remove -y julia - - - uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2 - id: setup-julia - with: - version: ${{ env.JULIA_VERSION }} - - - name: Restore Julia cache - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 + - name: Setup Python and Julia environments + id: setup-env + uses: ./.github/actions/setup-reeds-env with: - path: ~/.julia - key: julia-${{ runner.os }}-${{ hashFiles('Project.toml') }} - restore-keys: julia-${{ runner.os }}- - - - run: julia --project=. instantiate.jl + julia-version: ${{ env.JULIA_VERSION }} - name: Prepend Julia install to PATH env: - JULIA_BINDIR: ${{ steps.setup-julia.outputs.julia-bindir }} - run: echo "$JULIA_BINDIR" >> $GITHUB_PATH + JULIA_BINDIR: ${{ steps.setup-env.outputs.julia-bindir }} + run: printf '%s\n' "$JULIA_BINDIR" >> "$GITHUB_PATH" - name: Setup environment variables run: | - echo "GAMSDIR=$(python -c 'from gamspy_base import directory;print(directory)')" >> "$GITHUB_ENV" - echo "$(python -c 'from gamspy_base import directory;print(directory)')" >> "$GITHUB_PATH" + GAMSDIR="$(python -c 'from gamspy_base import directory;print(directory)')" + echo "GAMSDIR=$GAMSDIR" >> "$GITHUB_ENV" + echo "$GAMSDIR" >> "$GITHUB_PATH" echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GAMSDIR" >> "$GITHUB_ENV" - name: Setup licence env: GAMSLICE_CONTENT: ${{ secrets.GAMSLICE }} - MAMBA_ENV_PATH: ${{ steps.mamba.outputs.environment-path }} + MAMBA_ENV_PATH: ${{ steps.setup-env.outputs.mamba-env-path }} run: | echo "$GAMSLICE_CONTENT" > "${MAMBA_ENV_PATH}/lib/python3.11/site-packages/gamspy_base/gamslice.txt" + - name: Set run folder + env: + SCENARIO: ${{ matrix.scenario }} + run: echo "RUN_FOLDER=$GITHUB_WORKSPACE/runs/${batch}_${SCENARIO}" >> "$GITHUB_ENV" + - name: Run ReEDS model env: SCENARIO: ${{ matrix.scenario }} - run: | - python runbatch.py -b "$batch" -c test -s "$SCENARIO" - echo "RUN_FOLDER=$GITHUB_WORKSPACE/runs/${batch}_${SCENARIO}" >> "$GITHUB_ENV" + run: python runbatch.py -b "$batch" -c test -s "$SCENARIO" - name: Print GAMS log if: runner.debug == '1' - run: cat $RUN_FOLDER/gamslog.txt + run: cat "$RUN_FOLDER/gamslog.txt" - name: Check ReEDS outputs if: ${{ hashFiles(format('{0}/outputs/cap_ivrt.csv', env.RUN_FOLDER)) == '' }} @@ -252,6 +212,22 @@ jobs: SCENARIO: ${{ matrix.scenario }} run: python -m pytest tests/test_outputs.py --casepath "$GITHUB_WORKSPACE/runs/${batch}_${SCENARIO}" + - name: Upload ReEDS failure diagnostics + if: ${{ failure() }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: ${{ format('{0}-failure-diagnostics', matrix.scenario) }} + compression-level: 9 + retention-days: 7 + if-no-files-found: ignore + path: | + ${{ env.RUN_FOLDER }}/gamslog.txt + ${{ env.RUN_FOLDER }}/meta.csv + ${{ env.RUN_FOLDER }}/lstfiles/1_Inputs.lst + ${{ env.RUN_FOLDER }}/lstfiles/${{ matrix.scenario }}_*i*.lst + ${{ env.RUN_FOLDER }}/lstfiles/report_${{ matrix.scenario }}.lst + ${{ env.RUN_FOLDER }}/ReEDS_Augur/PRAS/PRAS_*i*.log + - name: Save ReEDS run uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 with: @@ -266,7 +242,9 @@ jobs: ${{ env.RUN_FOLDER }}/outputs/**/*.h5 run-R2X: + name: run R2X compatibility matrix runs-on: ubuntu-latest + timeout-minutes: 30 needs: - run-ReEDS permissions: @@ -292,10 +270,35 @@ jobs: with: name: ${{ matrix.scenario }} path: ${{ format('{0}-{1}', matrix.scenario, matrix.solve-year) }} - - name: R2X compatibility - uses: ./.github/actions/r2x-check - id: r2x-check + + - name: Install uv and set Python version + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: - reeds-run-path: ${{ format('{0}-{1}', matrix.scenario, matrix.solve-year) }} - scenario: ${{ matrix.scenario }} - solve-year: ${{ matrix.solve-year }} + python-version: "3.11" + enable-cache: true + restore-cache: true + save-cache: true + ignore-nothing-to-cache: true + + - name: Run R2X compatibility + env: + R2X_REEDS_RUN_PATH: ${{ format('{0}-{1}', matrix.scenario, matrix.solve-year) }} + R2X_SCENARIO: ${{ matrix.scenario }} + R2X_SOLVE_YEAR: ${{ matrix.solve-year }} + R2X_WEATHER_YEAR: "2012" + R2X_SYSTEM_JSON: ${{ format('{0}_system.json', matrix.scenario) }} + run: | + uvx --from "r2x-reeds>=0.3.5" python scripts/run_r2x.py \ + --reeds-run-path "$R2X_REEDS_RUN_PATH" \ + --scenario "$R2X_SCENARIO" \ + --solve-year "$R2X_SOLVE_YEAR" \ + --weather-year "$R2X_WEATHER_YEAR" \ + --system-json "$R2X_SYSTEM_JSON" + + - name: Save R2X system + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: r2x-${{ matrix.scenario }} + compression-level: 9 + retention-days: 1 + path: ${{ format('{0}_system.json', matrix.scenario) }} diff --git a/.github/workflows/workflow-quality.yaml b/.github/workflows/workflow-quality.yaml new file mode 100644 index 00000000..d35249e9 --- /dev/null +++ b/.github/workflows/workflow-quality.yaml @@ -0,0 +1,53 @@ +name: GitHub Actions Quality + +on: + pull_request: + paths: + - ".github/**" + push: + branches: + - main + paths: + - ".github/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + zizmor: + name: zizmor + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Install uv + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 + with: + version: "0.9.4" + + - name: Run zizmor + run: uvx zizmor --pedantic .github + + actionlint: + name: actionlint + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run actionlint + run: | + ACTIONLINT_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/rhysd/actionlint/e7d448ef7507c20fc4c88a95d0c448b848cd6127/scripts/download-actionlint.bash" + curl -fsSL "$ACTIONLINT_INSTALL_SCRIPT_URL" -o download-actionlint.bash + echo "28a0e78b3230372051c5a77840125aa2c8dc7804fce3696ef29dd52001ec3a8f download-actionlint.bash" | sha256sum -c - + bash download-actionlint.bash + ./actionlint diff --git a/scripts/run_r2x.py b/scripts/run_r2x.py new file mode 100644 index 00000000..0d215acd --- /dev/null +++ b/scripts/run_r2x.py @@ -0,0 +1,54 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "r2x-reeds>=0.3.5", +# ] +# /// + +from __future__ import annotations + +import argparse +from pathlib import Path + +from loguru import logger +from r2x_core import DataStore, PluginContext +from r2x_core.logger import setup_logging +from r2x_reeds import ReEDSConfig, ReEDSParser + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Run R2X translation for a ReEDS case.") + parser.add_argument("--reeds-run-path", required=True, type=Path) + parser.add_argument("--scenario", required=True) + parser.add_argument("--solve-year", required=True, type=int) + parser.add_argument("--weather-year", required=True, type=int) + parser.add_argument("--system-json", required=True, type=Path) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + + run_path = args.reeds_run_path.expanduser().resolve() + + setup_logging() + + config = ReEDSConfig( + weather_year=args.weather_year, + solve_year=args.solve_year, + scenario=args.scenario, + ) + + store = DataStore.from_plugin_config(config, path=run_path) + ctx = PluginContext(config=config, store=store) + parser = ReEDSParser.from_context(ctx) + result_ctx = parser.run() + + system_json = args.system_json.expanduser().resolve() + result_ctx.system.to_json(system_json) + logger.info("Built R2X system for scenario '{}' at '{}'", args.scenario, system_json) + + +if __name__ == "__main__": + main()