Skip to content

Commit

Permalink
Merge branch 'develop' into issue-2322-experiment-steps
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinsulzer committed Jun 9, 2023
2 parents f061dd1 + 51dc280 commit cd84774
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/periodic_benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Install Linux system dependencies
run: |
sudo apt-get update
sudo apt install gfortran gcc libopenblas-dev
sudo apt-get install gfortran gcc libopenblas-dev
- name: Install python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools virtualenv asv wget cmake casadi numpy
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ jobs:
.\bootstrap-vcpkg.bat
- name: Cache packages installed through vcpkg on windows
uses: actions/cache@v2
uses: actions/cache@v3
env:
cache-name: vckpg_binary_cache
with:
path: C:\Users\runneradmin\AppData\Local\vcpkg\archives
key: ${{ runner.os }}-build-VS2022-${{ env.cache-name }}-${{ hashFiles('vcpkg*.json') }}

# Enable tmate debugging of manually-triggered workflows if the input option was provided
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
Expand Down Expand Up @@ -85,7 +85,7 @@ jobs:
- name: Clone pybind11 repo (no history)
run: git clone --depth 1 --branch v2.10.4 https://github.com/pybind/pybind11.git

- name: Install sundials on macOS
- name: Install SUNDIALS on macOS
if: matrix.os == 'macos-latest'
run: |
# https://github.com/actions/virtual-environments/issues/1280
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/run_periodic_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,16 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: tox -e pybamm-requires

- name: Run unit tests for GNU/Linux with Python 3.8, 3.10, and 3.11
if: matrix.os == 'ubuntu-latest' && matrix.python-version != 3.9
- name: Run unit tests for GNU/Linux with Python 3.8, 3.9, and 3.10
if: matrix.os == 'ubuntu-latest' && matrix.python-version != 3.11
run: python -m tox -e unit

- name: Run unit tests for GNU/Linux with Python 3.9 and generate coverage report
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.9
- name: Run unit tests for GNU/Linux with Python 3.11 and generate coverage report
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.11
run: python -m tox -e coverage

- name: Upload coverage report
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.9
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.11
uses: codecov/[email protected]

- name: Run integration tests for GNU/Linux
Expand Down
33 changes: 25 additions & 8 deletions .github/workflows/test_on_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,35 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

# Install and cache apt packages
- name: Install Linux system dependencies
uses: awalsh128/[email protected]
if: matrix.os == 'ubuntu-latest'
with:
packages: gfortran gcc graphviz
execute_install_scripts: true

# dot -c is for registering graphviz fonts and plugins
- name: Install OpenBLAS and TexLive for Linux
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt install gfortran gcc libopenblas-dev graphviz
sudo apt install texlive-full
sudo dot -c
sudo apt-get install libopenblas-dev texlive-latex-extra dvipng
# Added fixes to homebrew installs:
# rm -f /usr/local/bin/2to3
# (see https://github.com/actions/virtual-environments/issues/2322)
- name: Install MacOS system dependencies
if: matrix.os == 'macos-latest'
env:
# Homebrew environment variables
HOMEBREW_NO_INSTALL_CLEANUP: 1
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_GOOGLE_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
# Speed up CI
NONINTERACTIVE: 1
run: |
rm -f /usr/local/bin/2to3*
rm -f /usr/local/bin/idle3*
Expand All @@ -76,7 +93,7 @@ jobs:
if: matrix.os == 'windows-latest'
run: choco install graphviz --version=2.38.0.20190211

- name: Install standard python dependencies
- name: Install standard Python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools
python -m pip install "tox<4"
Expand All @@ -85,16 +102,16 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: tox -e pybamm-requires

- name: Run unit tests for GNU/Linux with Python 3.8, 3.10, and 3.11
if: matrix.os == 'ubuntu-latest' && matrix.python-version != 3.9
- name: Run unit tests for GNU/Linux with Python 3.8, 3.9, and 3.10
if: matrix.os == 'ubuntu-latest' && matrix.python-version != 3.11
run: python -m tox -e unit

- name: Run unit tests for GNU/Linux with Python 3.9 and generate coverage report
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.9
- name: Run unit tests for GNU/Linux with Python 3.11 and generate coverage report
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.11
run: python -m tox -e coverage

- name: Upload coverage report
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.9
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.11
uses: codecov/[email protected]

- name: Run integration tests for GNU/Linux with Python 3.11
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repos:
- id: black

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.0.269"
rev: "v0.0.270"
hooks:
- id: ruff
args: [--ignore=E741, --exclude=__init__.py]
164 changes: 137 additions & 27 deletions pybamm/citations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import warnings
import pybtex
from sys import _getframe
from pybtex.database import parse_file, parse_string, Entry
from pybtex.scanner import PybtexError

Expand Down Expand Up @@ -35,6 +36,12 @@ def __init__(self):
# Dict mapping citations keys to BibTex entries
self._all_citations: dict[str, str] = dict()

# Set of unknown citations to parse with pybtex
self._unknown_citations = set()

# Dict mapping citation tags for use when registering citations
self._citation_tags = dict()

# store citation error
self._citation_err_msg = None

Expand All @@ -48,10 +55,23 @@ def _reset(self):
"""Reset citations to default only (only for testing purposes)"""
# Initialize empty papers to cite
self._papers_to_cite = set()
# Register the PyBaMM paper and the numpy paper
# Initialize empty set of unknown citations
self._unknown_citations = set()
# Initialize empty citation tags
self._citation_tags = dict()
# Register the PyBaMM paper and the NumPy paper
self.register("Sulzer2021")
self.register("Harris2020")

def _caller_name():
"""
Returns the qualified name of classes that call :meth:`register` internally.
Gets cached in order to reduce the number of calls.
"""
# Attributed to https://stackoverflow.com/a/53490973
caller_name = _getframe().f_back.f_back.f_locals["self"].__class__.__qualname__
return caller_name

def read_citations(self):
"""Reads the citations in `pybamm.CITATIONS.txt`. Other works can be cited
by passing a BibTeX citation to :meth:`register`.
Expand All @@ -70,22 +90,28 @@ def _add_citation(self, key, entry):
if not isinstance(key, str) or not isinstance(entry, Entry):
raise TypeError()

# Warn if overwriting an previous citation
# Warn if overwriting a previous citation
new_citation = entry.to_string("bibtex")
if key in self._all_citations and new_citation != self._all_citations[key]:
warnings.warn(f"Replacing citation for {key}")

# Add to database
self._all_citations[key] = new_citation

def _add_citation_tag(self, key, entry):
"""Adds a tag for a citation key in the dict, which represents the name of the
class that called :meth:`register`"""
self._citation_tags[key] = entry

@property
def _cited(self):
"""Return a list of the BibTeX entries that have been cited"""
return [self._all_citations[key] for key in self._papers_to_cite]

def register(self, key):
"""Register a paper to be cited. The intended use is that :meth:`register`
should be called only when the referenced functionality is actually being used.
"""Register a paper to be cited, one at a time. The intended use is that
:meth:`register` should be called only when the referenced functionality is
actually being used.
.. warning::
Registering a BibTeX citation, with the same key as an existing citation,
Expand All @@ -95,39 +121,113 @@ def register(self, key):
----------
key : str
- The citation key for an entry in `pybamm/CITATIONS.txt` or
- One or more BibTeX formatted citations
- A BibTeX formatted citation
"""
if self._citation_err_msg is None:
# Check if citation is a known key
if key in self._all_citations:
self._papers_to_cite.add(key)
# Add citation tags for the key for verbose output, but
# don't if they already exist in _citation_tags dict
if key not in self._citation_tags:
try:
caller = Citations._caller_name()
self._add_citation_tag(key, entry=caller)
# Don't add citation tags if the citation is registered manually
except KeyError: # pragma: no cover
pass
else:
# If citation is unknown, parse it later with pybtex
self._unknown_citations.add(key)
return

def _parse_citation(self, key):
"""
Parses a citation with pybtex and adds it to the _papers_to_cite set. This
method is called when a citation is unknown at the time of registration.
Parameters
----------
key: str
A BibTeX formatted citation
"""
try:
# Parse string as a bibtex citation, and check that a citation was found
bib_data = parse_string(key, bib_format="bibtex")
if not bib_data.entries:
raise PybtexError("no entries found")

# Add and register all citations
for key, entry in bib_data.entries.items():
# Add to _all_citations dictionary
self._add_citation(key, entry)
# Add to _papers_to_cite set
self._papers_to_cite.add(key)
return
except PybtexError:
# Unable to parse / unknown key
raise KeyError(f"Not a bibtex citation or known citation: {key}")

# Try to parse the citation using pybtex
try:
# Parse string as a bibtex citation, and check that a citation was found
bib_data = parse_string(key, bib_format="bibtex")
if not bib_data.entries:
raise PybtexError("no entries found")

# Add and register all citations
for key, entry in bib_data.entries.items():
self._add_citation(key, entry)
self.register(key)
return
except PybtexError:
# Unable to parse / unknown key
raise KeyError(f"Not a bibtex citation or known citation: {key}")

def print(self, filename=None, output_format="text"):
"""Print all citations that were used for running simulations.
def _tag_citations(self):
"""Prints the citation tags for the citations that have been registered
(non-manually) in the code, for verbose output purposes
"""
if self._citation_tags: # pragma: no cover
print("\nCitations registered: \n")
for key, entry in self._citation_tags.items():
print(f"{key} was cited due to the use of {entry}")

def print(self, filename=None, output_format="text", verbose=False):
"""Print all citations that were used for running simulations. The verbose
option is provided to print tags for citations in the output such that it can
can be seen where the citations were registered due to the use of PyBaMM models
and solvers in the code.
.. note::
If a citation is registered manually, it will not be tagged.
.. warning::
This function will notify the user if a citation that has been previously
registered is invalid or cannot be parsed.
Parameters
----------
filename : str, optional
Filename to which to print citations. If None, citations are printed to the
terminal.
Filename to which to print citations. If None, citations are printed
to the terminal.
verbose: bool, optional
If True, prints the citation tags for the citations that have been
registered. An example of the output is shown below.
Examples
--------
.. code-block:: python
pybamm.lithium_ion.SPM()
pybamm.Citations.print(verbose=True) or pybamm.print_citations(verbose=True)
will append the following at the end of the list of citations:
.. code-block::
Citations registered:
Marquis2019 was cited due to the use of SPM
"""
# Parse citations that were not known keys at registration, but do not
# fail if they cannot be parsed
try:
for key in self._unknown_citations:
self._parse_citation(key)
except KeyError: # pragma: no cover
warnings.warn(
message=f'\nCitation with key "{key}" is invalid. Please try again\n',
category=UserWarning,
)
# delete the invalid citation from the set
self._unknown_citations.remove(key)

if output_format == "text":
citations = pybtex.format_from_strings(
self._cited, style="plain", output_backend="plaintext"
Expand All @@ -142,12 +242,14 @@ def print(self, filename=None, output_format="text"):

if filename is None:
print(citations)
if verbose:
self._tag_citations() # pragma: no cover
else:
with open(filename, "w") as f:
f.write(citations)


def print_citations(filename=None, output_format="text"):
def print_citations(filename=None, output_format="text", verbose=False):
"""See :meth:`Citations.print`"""
if citations._citation_err_msg is not None:
raise ImportError(
Expand All @@ -159,7 +261,15 @@ def print_citations(filename=None, output_format="text"):
f"{citations._citation_err_msg}"
)
else:
pybamm.citations.print(filename, output_format)
if verbose: # pragma: no cover
if filename is not None: # pragma: no cover
raise Exception(
"Verbose output is available only for the terminal and not for printing to files", # noqa: E501
)
else:
citations.print(filename, output_format, verbose=True)
else:
pybamm.citations.print(filename, output_format)


citations = Citations()
Loading

0 comments on commit cd84774

Please sign in to comment.