Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add .tools.check() #506

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Next release
All changes
-----------

- Add a tool for :doc:`tools/check` (:pull:`506`).
- Adjust test suite for pyam v1.1.0 compatibility (:pull:`499`).
- Add Westeros :doc:`tutorial <tutorials>` on historical parameters (:pull:`478`).
- Update reference for activity and capacity soft constraints (:pull:`474`).
Expand Down
2 changes: 0 additions & 2 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ Then, continue with the:
tutorials




.. _core:

Mathematical specification
Expand Down
27 changes: 27 additions & 0 deletions doc/tools/check.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Pre-solve checks
****************

.. currentmodule:: message_ix.tools

.. autofunction:: check

.. currentmodule:: message_ix.tools._check

.. _checks-summary:

.. automodule:: message_ix.tools._check
:members: gaps_input, gaps_tl, tl_integer

.. autoclass:: Result

Individual checks
=================

Gaps in certain parameters (:func:`gaps_*` check functions) can cause the GAMS implementation to treat that specific technology to be disabled in one period, between other periods where it *is* enabled.
This may prevent solution of the model.

.. autosummary::

gaps_input
gaps_tl
tl_integer
13 changes: 8 additions & 5 deletions message_ix/reporting/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,14 @@ def from_scenario(cls, scenario, **kwargs):
solved = scenario.has_solution()

if not solved:
log.warning(
f'Scenario "{scenario.model}/{scenario.scenario}" has no solution'
)
log.warning("Some reporting may not function as expected")
fail_action = logging.DEBUG
if kwargs.pop("solved", True):
log.warning(
f'Scenario "{scenario.model}/{scenario.scenario}" has no solution'
)
log.warning("Some reporting may not function as expected")
fail_action = logging.DEBUG
else:
fail_action = logging.NOTSET
else:
fail_action = "raise"

Expand Down
3 changes: 2 additions & 1 deletion message_ix/tests/test_tutorials.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys
from shutil import copyfile
from typing import List, Tuple

import numpy as np
import pytest
Expand All @@ -17,7 +18,7 @@
# 3. Dictionary with extra keyword arguments to run_notebook().

# FIXME check objective function of the rest of tutorials.
tutorials = [
tutorials: List[Tuple] = [
# IPython kernel
(
("westeros", "westeros_baseline"),
Expand Down
96 changes: 96 additions & 0 deletions message_ix/tests/tools/test_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import pytest

from message_ix import Scenario, make_df
from message_ix.testing import make_dantzig, make_westeros
from message_ix.tools import check


def test_check_dantzig(test_mp):
scen = make_dantzig(test_mp)

# Checks all True
results = check(scen)
assert results[0]


@pytest.fixture
def westeros(test_mp):
yield make_westeros(test_mp)


# Minimal config to make Westeros reportable
WESTEROS_CONFIG = {"units": {"replace": {"-": ""}}}


def test_gaps_input(westeros):
# Delete one value
to_delete = make_df(
"input",
node_loc="Westeros",
technology="bulb",
year_vtg=690,
year_act=710,
mode="standard",
node_origin="Westeros",
commodity="electricity",
level="final",
time="year",
time_origin="year",
).dropna(axis=1)
with westeros.transact():
westeros.remove_par("input", to_delete)

# Checks fail
results = check(westeros, config=WESTEROS_CONFIG)
assert not results[0]


def test_check_tl_integer(westeros):
# Change one value
tl = "technical_lifetime"
with westeros.transact():
westeros.add_par(
tl,
make_df(
tl,
node_loc="Westeros",
technology="bulb",
year_vtg=700,
value=1.1,
unit="y",
),
)

# Checks fail
results = check(westeros, config=WESTEROS_CONFIG)
assert not results[0]

assert """FAIL Non-integer values for ``technical_lifetime``:
See https://github.com/iiasa/message_ix/issues/503.
- 1.1 at indices: nl=Westeros t=bulb yv=700""" in map(
str, results
)


@pytest.mark.parametrize(
"url, config",
[
# ("ixmp://platform/model/scenario#version", dict()),
],
)
def test_check_existing(url, config):
"""Check existing scenarios.

For local use only: extend the list of parameters, above, but do not commit
additions to ``main``.
"""
# import pint
# from iam_units import registry
#
# pint.set_application_registry(registry)

scen, mp = Scenario.from_url(url)
results = check(scen, config=config)

Check warning on line 93 in message_ix/tests/tools/test_check.py

View check run for this annotation

Codecov / codecov/patch

message_ix/tests/tools/test_check.py#L92-L93

Added lines #L92 - L93 were not covered by tests

# Checks all pass
assert results[0], "\n".join(map(str, results))

Check warning on line 96 in message_ix/tests/tools/test_check.py

View check run for this annotation

Codecov / codecov/patch

message_ix/tests/tools/test_check.py#L96

Added line #L96 was not covered by tests
5 changes: 5 additions & 0 deletions message_ix/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from ._check import check

__all__ = [
"check",
]
Loading