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

v2.0 #323

Merged
merged 24 commits into from Jan 20, 2021
Merged

v2.0 #323

Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 51 additions & 9 deletions .github/workflows/ci-cd-workflow.yml
Expand Up @@ -18,8 +18,8 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dev dependencies
run: |
pip install --upgrade pip
pip install -e .[dev] --use-feature=2020-resolver
pip install --upgrade --user pip wheel
pip install -e .[dev]
# TODO: add `pylint pymagicc`
# TODO: add pydocstyle pymagicc
- name: Formatting and linters
Expand Down Expand Up @@ -86,11 +86,18 @@ jobs:
restore-keys: |
${{ runner.os }}-pip-

# no windows wheel for Python 3.6 cftime 1.3.1
znicholls marked this conversation as resolved.
Show resolved Hide resolved
# https://github.com/Unidata/cftime/issues/224
- name: Install cftime 1.3.0 (${{ runner.os }})
if: startsWith(runner.os, 'Windows') && endsWith(matrix.python-version, '3.6')
run: |
pip install --upgrade --user pip wheel
pip install cftime==1.3.0

- name: Install test dependencies
run: |
pip install --upgrade pip
pip install -e .[tests] --use-feature=2020-resolver
pip install --upgrade --user pip wheel
pip install -e .[tests]


- name: Test with pytest (${{ runner.os }})
Expand All @@ -111,6 +118,10 @@ jobs:
run: |
pytest tests -r a

- name: Test scripts (${{ runner.os }})
run: |
python scripts/plot_example.py


- name: Upload coverage to Codecov
if: startsWith(runner.os, 'Linux') && ${{ matrix.python-version }} == 3.7
Expand Down Expand Up @@ -158,10 +169,18 @@ jobs:
restore-keys: |
${{ runner.os }}-notebooks-pip-

# no windows wheel for Python 3.6 cftime 1.3.1
# https://github.com/Unidata/cftime/issues/224
- name: Install cftime 1.3.0 (${{ runner.os }})
if: startsWith(runner.os, 'Windows') && endsWith(matrix.python-version, '3.6')
run: |
pip install --upgrade --user pip wheel
pip install cftime==1.3.0

- name: Install notebook dependencies
run: |
pip install --upgrade pip
pip install -e .[tests,notebooks] --use-feature=2020-resolver
pip install --upgrade --user pip wheel
pip install -e .[tests,notebooks]
- name: Test notebooks with nbval
if: startsWith(runner.os, 'Linux')
run: |
Expand All @@ -171,8 +190,31 @@ jobs:
run: |
pytest notebooks -r a --nbval --sanitize-with tests/notebook-tests.cfg --no-cov

test-install:
needs: build
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ["ubuntu-latest", "windows-latest"]
python-version: [3.6, 3.7, 3.8]

steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup python
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install (${{ runner.os }})
run: |
pip install --upgrade pip wheel
pip install .
- name: Test installation
run: |
python scripts/test_install.py

deploy-pypi:
needs: test-notebooks
needs: [test-notebooks,test-install]
if: startsWith(github.ref, 'refs/tags/v')

runs-on: ubuntu-latest
Expand All @@ -189,8 +231,8 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -e .[dev] --use-feature=2020-resolver
pip install --upgrade --user pip wheel
pip install -e .[dev]
- name: Create package
run: python setup.py sdist bdist_wheel --universal
- name: Publish package to PyPI
Expand Down
183 changes: 118 additions & 65 deletions CHANGELOG.rst

Large diffs are not rendered by default.

54 changes: 25 additions & 29 deletions README.rst
Expand Up @@ -91,28 +91,25 @@ Basic Usage
import matplotlib.pyplot as plt

import pymagicc
from pymagicc import scenarios
import scmdata
from pymagicc import rcps

for name, scen in scenarios.items():
results = pymagicc.run(scen)
results_df = results.df
results_df.set_index("time", inplace=True)
results = []
for scen in rcps.groupby("scenario"):
results_scen = pymagicc.run(scen)
results.append(results_scen)

global_temp_time_rows = (
(results_df.variable == "Surface Temperature")
& (results_df.region == "World")
)
results = scmdata.run_append(results)

temp = (
results_df.value[global_temp_time_rows].loc[1850:]
- results_df.value[global_temp_time_rows].loc[1850:1900].mean()
)
temp.plot(label=name)
temperature_rel_to_1850_1900 = (
results
.filter(variable="Surface Temperature", region="World")
.relative_to_ref_period_mean(year=range(1850, 1900 + 1))
)

plt.legend()
temperature_rel_to_1850_1900.lineplot()
plt.title("Global Mean Temperature Projection")
plt.ylabel("°C over pre-industrial (1850-1900 mean)");
plt.legend(loc="best")
# Run `plt.show()` to display the plot when running this example
# interactively or add `%matplotlib inline` on top when in a Jupyter Notebook.

Expand Down Expand Up @@ -266,16 +263,16 @@ Use an included scenario

.. code:: python

from pymagicc import rcp26
from pymagicc.scenarios import rcp26

rcp26.df.head()
rcp26.head()

Read a MAGICC scenario file
***************************

.. code:: python

from pymagicc import read_scen_file
from pymagicc.scenarios import read_scen_file

scenario = read_scen_file("PATHWAY.SCEN")

Expand All @@ -284,18 +281,17 @@ Run MAGICC for a scenario

.. code:: python

results = pymagicc.run(scenario)
results_df = results.df
results_df.set_index("time", inplace=True)
import pymagicc
from pymagicc.scenarios import read_scen_file

global_temp_time_rows = (
(results_df.variable == "Surface Temperature")
& (results_df.region == "World")
)
scenario = read_scen_file("PATHWAY.SCEN")

results = pymagicc.run(scenario)

temp = (
results_df.value[global_temp_time_rows].loc[1850:]
- results_df.value[global_temp_time_rows].loc[1850:1900].mean()
temperature_rel_to_1850_1900 = (
results
.filter(variable="Surface Temperature")
.relative_to_ref_period_mean(year=range(1850, 1900 + 1))
)

Using a different MAGICC version
Expand Down
16 changes: 13 additions & 3 deletions pymagicc/io/base.py
Expand Up @@ -743,10 +743,20 @@ def _ensure_file_region_type_consistency(self, regions):
# no checks required except for certain cases
return regions

def _get_data_block(self):
data_block = self.minput.timeseries(
def _get_timeseries_no_nans(self):
out = self.minput.timeseries(
meta=["variable", "todo", "unit", "region"]
).T
).T.dropna(how="all")
if out.isnull().any().any():
raise AssertionError(
"Your data contains timesteps where some values are nan whilst others "
"are not. This will not work in MAGICC."
)

return out

def _get_data_block(self):
data_block = self._get_timeseries_no_nans()
self._check_data_block_column_names(data_block)
self._check_data_filename_variable_consistency(data_block)

Expand Down
4 changes: 1 addition & 3 deletions pymagicc/io/prn_files.py
Expand Up @@ -255,9 +255,7 @@ def _get_unit(self):
return unit

def _get_data_block(self):
data_block = self.minput.timeseries(
meta=["variable", "todo", "unit", "region"]
).T
data_block = self._get_timeseries_no_nans()
self._check_data_block_column_names(data_block)

regions = data_block.columns.get_level_values("region").unique()
Expand Down
2 changes: 1 addition & 1 deletion pymagicc/scenarios/__init__.py
Expand Up @@ -62,7 +62,7 @@ def read_scen_file(

rcps = deepcopy(rcp26)
for rcp in [rcp45, rcp60, rcp85]:
rcps.append(rcp)
rcps = rcps.append(rcp)

zero_emissions = MAGICCData(
join(dirname(abspath(__file__)), "RCP3PD_EMISSIONS.DAT"),
Expand Down
Binary file modified scripts/example-plot.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 15 additions & 19 deletions scripts/plot_example.py
@@ -1,9 +1,9 @@
import os
import matplotlib.pyplot as plt


import matplotlib.pyplot as plt
import pymagicc
from pymagicc import scenarios
import scmdata
from pymagicc import rcps


plt.style.use("ggplot")
Expand All @@ -17,25 +17,21 @@
'./example-plot.png'
)

for name, scen in scenarios.items():
results = pymagicc.run(scen)
results_df = results.df
results_df.set_index("time", inplace=True)
results = []
for scen in rcps.groupby("scenario"):
results_scen = pymagicc.run(scen)
results.append(results_scen)

global_temp_time_rows = (
(results_df.variable == "Surface Temperature")
& (results_df.region == "World")
)
results = scmdata.run_append(results)

temp = (
results_df.value[global_temp_time_rows].loc[1850:]
- results_df.value[global_temp_time_rows].loc[1850:1900].mean()
)
temp.plot(label=name)
temperature_rel_to_1850_1900 = (
results
.filter(variable="Surface Temperature", region="World")
.relative_to_ref_period_mean(year=range(1850, 1900 + 1))
)

plt.legend()
temperature_rel_to_1850_1900.lineplot()
plt.title("Global Mean Temperature Projection")
plt.ylabel("°C over pre-industrial (1850-1900 mean)");
plt.legend(loc="best")
plt.ylabel("°C over pre-industrial (1850-1900 mean)")

plt.savefig(output_path, dpi=96)
2 changes: 2 additions & 0 deletions setup.py
Expand Up @@ -46,6 +46,7 @@
"Programming Language :: Python :: 3.8",
]
REQUIREMENTS_INSTALL = [
"cftime",
"pandas-datapackage-reader",
"f90nml",
"PyYAML",
Expand All @@ -67,6 +68,7 @@
"codecov",
"goodtables",
"scipy",
"seaborn",
]
REQUIREMENTS_DOCS = [
"sphinx>2.1",
Expand Down
55 changes: 54 additions & 1 deletion tests/test_io.py
Expand Up @@ -2907,7 +2907,7 @@ def test_conc_in_reader_get_variable_from_filepath(test_filepath, expected_varia
assert conc_reader._get_variable_from_filepath() == expected_variable


@pytest.mark.parametrize(
ALL_FILE_TYPES = pytest.mark.parametrize(
"magicc_version, starting_fpath, starting_fname, confusing_metadata, old_namelist",
[
(6, MAGICC6_DIR, "HISTRCP_CO2I_EMIS.IN", False, False),
Expand Down Expand Up @@ -2953,6 +2953,9 @@ def test_conc_in_reader_get_variable_from_filepath(test_filepath, expected_varia
(7, TEST_DATA_DIR, "MAG_FORMAT_SAMPLE_TWO.MAG", False, False),
],
)


@ALL_FILE_TYPES
def test_in_file_read_write_functionally_identical(
magicc_version,
starting_fpath,
Expand Down Expand Up @@ -2993,6 +2996,56 @@ def test_in_file_read_write_functionally_identical(
)


@ALL_FILE_TYPES
def test_nans_stripped_before_writing(
magicc_version,
starting_fpath,
starting_fname,
confusing_metadata,
old_namelist,
temp_dir,
):
mi_writer = MAGICCData(join(starting_fpath, starting_fname))

nan_idx = mi_writer.shape[1] // 2
nan_timestep = mi_writer["time"].iloc[nan_idx]

assert nan_timestep in mi_writer["time"].values

mi_writer.values[:, nan_idx] = np.nan

mi_writer.write(join(temp_dir, starting_fname), magicc_version=magicc_version)

mi_written = MAGICCData(join(temp_dir, starting_fname))
assert nan_timestep not in mi_written["time"].values


@ALL_FILE_TYPES
def test_raises_if_nans_not_uniform(
magicc_version,
starting_fpath,
starting_fname,
confusing_metadata,
old_namelist,
temp_dir,
):
mi_writer = MAGICCData(join(starting_fpath, starting_fname))

if mi_writer.shape[0] == 1:
pytest.skip("Only one timeseries so can't create mismatch")

nan_row = mi_writer.shape[0] // 2
nan_col = mi_writer.shape[1] // 2
mi_writer.values[nan_row, nan_col] = np.nan

error_msg = re.escape(
"Your data contains timesteps where some values are nan whilst others "
"are not. This will not work in MAGICC."
)
with pytest.raises(AssertionError, match=error_msg):
mi_writer.write(join(temp_dir, starting_fname), magicc_version=magicc_version)


emissions_valid = [
"CO2I",
"CO2B",
Expand Down