diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 000000000..2be30620d
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,59 @@
+{
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "commitType": "docs",
+ "commitConvention": "angular",
+ "contributors": [
+ {
+ "login": "BradyPlanden",
+ "name": "Brady Planden",
+ "avatar_url": "https://avatars.githubusercontent.com/u/55357039?v=4",
+ "profile": "http://bradyplanden.github.io",
+ "contributions": [
+ "infra",
+ "test",
+ "code",
+ "example"
+ ]
+ },
+ {
+ "login": "NicolaCourtier",
+ "name": "NicolaCourtier",
+ "avatar_url": "https://avatars.githubusercontent.com/u/45851982?v=4",
+ "profile": "https://github.com/NicolaCourtier",
+ "contributions": [
+ "code",
+ "review"
+ ]
+ },
+ {
+ "login": "davidhowey",
+ "name": "David Howey",
+ "avatar_url": "https://avatars.githubusercontent.com/u/2247552?v=4",
+ "profile": "http://howey.eng.ox.ac.uk",
+ "contributions": [
+ "ideas",
+ "mentoring"
+ ]
+ },
+ {
+ "login": "martinjrobins",
+ "name": "Martin Robinson",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1148404?v=4",
+ "profile": "http://www.rse.ox.ac.uk",
+ "contributions": [
+ "ideas",
+ "mentoring"
+ ]
+ }
+ ],
+ "contributorsPerLine": 7,
+ "skipCi": true,
+ "repoType": "github",
+ "repoHost": "https://github.com",
+ "projectName": "PyBOP",
+ "projectOwner": "pybop-team"
+}
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..dfe077042
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000..0b95cd9a8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,37 @@
+name: Bug Report
+description: Create a bug report
+title: "[Bug]: "
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for filling out this report to help us improve!
+ - type: input
+ id: python-version
+ attributes:
+ label: Python Version
+ description: What python version are you using?
+ placeholder: python version
+ validations:
+ required: true
+ - type: textarea
+ id: bug-description
+ attributes:
+ label: Describe the bug
+ description: A clear and concise description of the bug.
+ validations:
+ required: true
+ - type: textarea
+ id: reproduce
+ attributes:
+ label: Steps to reproduce the behaviour
+ description: Tell us how to reproduce this behaviour. Please try to include a [Minimum Workable Example](https://stackoverflow.com/help/minimal-reproducible-example)
+ validations:
+ required: true
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output
+ description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
+ render: shell
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 000000000..5821d4f5c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,30 @@
+name: Feature request
+description: Suggest a feature
+labels: ["enhancement"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for filling out this report to help us improve!
+ - type: textarea
+ id: feature
+ attributes:
+ label: Feature description
+ description: Describe the feature you'd like.
+ validations:
+ required: true
+ - type: textarea
+ id: motivation
+ attributes:
+ label: Motivation
+ description: Please enter the motivation for this feature i.e (problem, performance, etc).
+ - type: textarea
+ id: possible-implementation
+ attributes:
+ label: Possible implementation
+ description: Please enter any possible implementation for this feature.
+ - type: textarea
+ id: context
+ attributes:
+ label: Additional context
+ description: Add any additional context about the feature request.
diff --git a/.github/workflows/release-action.yaml b/.github/workflows/release-action.yaml
new file mode 100644
index 000000000..c2cd834b2
--- /dev/null
+++ b/.github/workflows/release-action.yaml
@@ -0,0 +1,110 @@
+name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI
+
+on: push
+
+jobs:
+ build:
+ name: Build distribution 📦
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.8"
+ - name: Install pypa/build
+ run: >-
+ python3 -m
+ pip install
+ build
+ --user
+ - name: Build a binary wheel and a source tarball
+ run: python3 -m build
+ - name: Store the distribution packages
+ uses: actions/upload-artifact@v3
+ with:
+ name: python-package-distributions
+ path: dist/
+
+ publish-to-pypi:
+ name: >-
+ Publish Python 🐍 distribution 📦 to PyPI
+ if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
+ needs:
+ - build
+ runs-on: ubuntu-latest
+ environment:
+ name: pypi
+ url: https://pypi.org/p/pybop
+ permissions:
+ id-token: write # IMPORTANT: mandatory for trusted publishing
+
+ steps:
+ - name: Download all the dists
+ uses: actions/download-artifact@v3
+ with:
+ name: python-package-distributions
+ path: dist/
+ - name: Publish distribution 📦 to PyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
+
+ github-release:
+ name: >-
+ Sign the Python 🐍 distribution 📦 with Sigstore
+ and upload them to GitHub Release
+ needs:
+ - publish-to-pypi
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: write # IMPORTANT: mandatory for making GitHub Releases
+ id-token: write # IMPORTANT: mandatory for sigstore
+
+ steps:
+ - name: Download all the dists
+ uses: actions/download-artifact@v3
+ with:
+ name: python-package-distributions
+ path: dist/
+ - name: Sign the dists with Sigstore
+ uses: sigstore/gh-action-sigstore-python@v1.2.3
+ with:
+ inputs: >-
+ ./dist/*.tar.gz
+ ./dist/*.whl
+ - name: Upload artifact signatures to GitHub Release
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ # Upload to GitHub Release using the `gh` CLI.
+ # `dist/` contains the built packages, and the
+ # sigstore-produced signatures and certificates.
+ run: >-
+ gh release upload
+ '${{ github.ref_name }}' dist/**
+ --repo '${{ github.repository }}'
+
+ publish-to-testpypi:
+ name: Publish Python 🐍 distribution 📦 to TestPyPI
+ if: contains(github.ref, 'rc') # only publish to TestPyPI for rc tags
+ needs:
+ - build
+ runs-on: ubuntu-latest
+
+ environment:
+ name: testpypi
+ url: https://test.pypi.org/project/pybop/
+
+ permissions:
+ id-token: write # IMPORTANT: mandatory for trusted publishing
+
+ steps:
+ - name: Download all the dists
+ uses: actions/download-artifact@v3
+ with:
+ name: python-package-distributions
+ path: dist/
+ - name: Publish distribution 📦 to TestPyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ repository-url: https://test.pypi.org/legacy/
diff --git a/.github/workflows/scheduled_tests.yaml b/.github/workflows/scheduled_tests.yaml
new file mode 100644
index 000000000..2de1a0f83
--- /dev/null
+++ b/.github/workflows/scheduled_tests.yaml
@@ -0,0 +1,69 @@
+name: Scheduled
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches:
+ - main
+
+ # runs every day at 09:00 UTC
+ schedule:
+ - cron: '0 9 * * *'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: ["3.8", "3.9", "3.10", "3.11"]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip nox
+ - name: Unit tests with nox
+ run: |
+ python -m nox -s unit
+ python -m nox -s notebooks
+
+ #M-series Mac Mini
+ build-apple-mseries:
+ runs-on: [self-hosted, macOS, ARM64]
+ env:
+ GITHUB_PATH: ${PYENV_ROOT/bin:$PATH}
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: ["3.10"]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install python & create virtualenv
+ shell: bash
+ run: |
+ eval "$(pyenv init -)"
+ pyenv install ${{ matrix.python-version }} -s
+ pyenv virtualenv ${{ matrix.python-version }} pybop-${{ matrix.python-version }}
+
+ - name: Install dependencies & run unit tests
+ shell: bash
+ run: |
+ eval "$(pyenv init -)"
+ pyenv activate pybop-${{ matrix.python-version }}
+ python -m pip install --upgrade pip wheel setuptools nox
+ python -m nox -s unit
+ python -m nox -s notebooks
+
+ - name: Uninstall pyenv-virtualenv & python
+ if: always()
+ shell: bash
+ run: |
+ eval "$(pyenv init -)"
+ pyenv activate pybop-${{ matrix.python-version }}
+ pyenv uninstall -f $( python --version )
diff --git a/.github/workflows/test_on_push.yaml b/.github/workflows/test_on_push.yaml
new file mode 100644
index 000000000..959e4c826
--- /dev/null
+++ b/.github/workflows/test_on_push.yaml
@@ -0,0 +1,79 @@
+name: test_on_push
+
+on:
+ push:
+ workflow_dispatch:
+ pull_request:
+
+concurrency:
+ # github.workflow: name of the workflow, so that we don't cancel other workflows
+ # github.event.pull_request.number || github.ref: pull request number or branch name if not a pull request
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ # Cancel in-progress runs when a new workflow with the same group name is triggered
+ # This avoids workflow runs on both pushes and PRs
+ cancel-in-progress: true
+
+jobs:
+ style:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.11
+
+ - name: Check formatting with pre-commit
+ run: |
+ python -m pip install pre-commit
+ pre-commit run ruff
+
+
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: ["3.8", "3.9", "3.10", "3.11"]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip nox
+ - name: Unit tests with nox
+ run: |
+ nox -s unit
+
+ # Runs only on Ubuntu with Python 3.11
+ check_coverage:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ name: Coverage tests (ubuntu-latest / Python 3.11)
+
+ steps:
+ - name: Check out PyBOP repository
+ uses: actions/checkout@v4
+ - name: Set up Python 3.11
+ id: setup-python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.11
+ cache: 'pip'
+ cache-dependency-path: setup.py
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip nox
+ - name: Run coverage tests for Ubuntu with Python 3.11 and generate report
+ run: nox -s coverage
+
+ - name: Upload coverage report
+ uses: codecov/codecov-action@v3
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 7978daaa3..838f372b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -301,3 +301,6 @@ $RECYCLE.BIN/
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/python,macos,windows,linux,c
+
+# Visual Studio Code settings
+.vscode/*
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000..5270e26ff
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,32 @@
+ci:
+ autoupdate_commit_msg: "chore: update pre-commit hooks"
+ autofix_commit_msg: "style: pre-commit fixes"
+
+repos:
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: "v0.1.5"
+ hooks:
+ - id: ruff
+ args: [--fix, --show-fixes]
+ types_or: [python, pyi, jupyter]
+ - id: ruff-format
+
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.5.0
+ hooks:
+ - id: check-added-large-files
+ - id: check-case-conflict
+ - id: check-merge-conflict
+ - id: check-yaml
+ - id: debug-statements
+ - id: end-of-file-fixer
+ - id: mixed-line-ending
+ - id: trailing-whitespace
+
+ - repo: https://github.com/pre-commit/pygrep-hooks
+ rev: v1.10.0
+ hooks:
+ - id: python-check-blanket-type-ignore
+ - id: rst-backticks
+ - id: rst-directive-colons
+ - id: rst-inline-touching-normal
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 000000000..e1efab891
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,14 @@
+cff-version: 1.2.0
+title: 'Python Battery Optimisation and Parameterisation (PyBOP)'
+message: >-
+ If you use this software, please cite it using the
+ metadata from this file.
+type: software
+authors:
+ - given-names: Brady
+ family-names: Planden
+ - given-names: Nicola
+ family-names: Courtier
+ - given-names: David
+ family-names: Howey
+repository-code: 'https://www.github.com/pybop-team/pybop'
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..d1ea9db24
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,303 @@
+# Contributing to PyBOP
+
+If you'd like to contribute to PyBOP, please have a look at the [pre-commit](#pre-commit-checks) and the [workflow](#workflow) guidelines below.
+
+## Pre-commit checks
+
+Before you commit any code, please perform the following checks:
+
+- [All tests pass](#testing): `$ nox -s unit`
+
+### Installing and using pre-commit
+
+`PyBOP` uses a set of `pre-commit` hooks and the `pre-commit` bot to format and prettify the codebase. The hooks can be installed locally using -
+
+```bash
+pip install pre-commit
+pre-commit install
+```
+
+This would run the checks every time a commit is created locally. The checks will only run on the files modified by that commit, but the checks can be triggered for all the files using -
+
+```bash
+pre-commit run --all-files
+```
+
+If you would like to skip the failing checks and push the code for further discussion, use the `--no-verify` option with `git commit`.
+
+## Workflow
+
+We use [GIT](https://en.wikipedia.org/wiki/Git) and [GitHub](https://en.wikipedia.org/wiki/GitHub) to coordinate our work. When making any kind of update, we try to follow the procedure below.
+
+### A. Before you begin
+
+1. Create an [issue](https://guides.github.com/features/issues/) where new proposals can be discussed before any coding is done.
+2. Create a [branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/) of this repo (ideally on your own [fork](https://help.github.com/articles/fork-a-repo/)), where all changes will be made
+3. Download the source code onto your local system, by [cloning](https://help.github.com/articles/cloning-a-repository/) the repository (or your fork of the repository).
+4. [Install](Developer-Install) PyBOP with the developer options.
+5. [Test](#testing) if your installation worked: `$ pytest --unit -v`.
+
+You now have everything you need to start making changes!
+
+### B. Writing your code
+
+6. PyBOP is developed in [Python](https://en.wikipedia.org/wiki/Python_(programming_language)), and makes heavy use of [NumPy](https://en.wikipedia.org/wiki/NumPy) (see also [NumPy for MatLab users](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html) and [Python for R users](http://blog.hackerearth.com/how-can-r-users-learn-python-for-data-science)).
+7. Make sure to follow our [coding style guidelines](#coding-style-guidelines).
+8. Commit your changes to your branch with [useful, descriptive commit messages](https://chris.beams.io/posts/git-commit/): Remember these are publicly visible and should still make sense a few months ahead in time. While developing, you can keep using the GitHub issue you're working on as a place for discussion. [Refer to your commits](https://stackoverflow.com/questions/8910271/how-can-i-reference-a-commit-in-an-issue-comment-on-github) when discussing specific lines of code.
+9. If you want to add a dependency on another library, or re-use code you found somewhere else, have a look at [these guidelines](#dependencies-and-reusing-code).
+
+### C. Merging your changes with PyBOP
+
+10. [Test your code!](#testing)
+12. If you added a major new feature, perhaps it should be showcased in an [example notebook](#example-notebooks).
+13. If you've added new functionality, please add additional tests to ensure ample code coverage in PyBOP.
+13. When you feel your code is finished, or at least warrants serious discussion, create a [pull request](https://help.github.com/articles/about-pull-requests/) (PR) on [PyBOP's GitHub page](https://github.com/pybop-team/PyBOP).
+14. Once a PR has been created, it will be reviewed by any member of the community. Changes might be suggested which you can make by simply adding new commits to the branch. When everything's finished, someone with the right GitHub permissions will merge your changes into PyBOP main repository.
+
+Finally, if you really, really, _really_ love developing PyBOP, have a look at the current [project infrastructure](#infrastructure).
+
+## Coding style guidelines
+
+PyBOP follows the [PEP8 recommendations](https://www.python.org/dev/peps/pep-0008/) for coding style. These are very common guidelines, and community tools have been developed to check how well projects implement them.
+
+### Ruff
+
+We use [ruff](https://github.com/charliermarsh/ruff) to check our PEP8 adherence. To try this on your system, navigate to the PyBOP directory in a console and type
+
+```bash
+python -m pip install pre-commit
+pre-commit run ruff
+```
+
+ruff is configured inside the file `pre-commit-config.yaml`, allowing us to ignore some errors. If you think this should be added or removed, please submit an [issue](#issues)
+
+When you commit your changes they will be checked against ruff automatically (see [Pre-commit checks](#pre-commit-checks)).
+
+### Naming
+
+Naming is hard. In general, we aim for descriptive class, method, and argument names. Avoid abbreviations when possible without making names overly long, so `mean` is better than `mu`, but a class name like `MyClass` is fine.
+
+Class names are CamelCase, and start with an upper case letter, for example `MyOtherClass`. Method and variable names are lower-case, and use underscores for word separation, for example, `x` or `iteration_count`.
+
+## Dependencies and reusing code
+
+While it's a bad idea for developers to "reinvent the wheel", it's important for users to get a _reasonably sized download and an easy install_. In addition, external libraries can sometimes cease to be supported, and when they contain bugs it might take a while before fixes become available as automatic downloads to PyBOP users.
+For these reasons, all dependencies in PyBOP should be thought about carefully and discussed on GitHub.
+
+Direct inclusion of code from other packages is possible, as long as their license permits it and is compatible with ours, but again should be considered carefully and discussed in the group. Snippets from blogs and [stackoverflow](https://stackoverflow.com/) can often be included but must include attribution to the original by commenting with a link in the source code.
+
+### Separating dependencies
+
+On the other hand... We _do_ want to compare several tools, to generate documentation, and speed up development. For this reason, the dependency structure is split into 4 parts:
+
+1. Core PyBOP: A minimal set, including things like NumPy, SciPy, etc. All infrastructure should run against this set of dependencies, as well as any numerical methods we implement ourselves.
+2. Extras: Other inference packages and their dependencies. Methods we don't want to implement ourselves, but do want to provide an interface to can have their dependencies added here.
+3. Documentation generating code: Everything you need to generate and work on the docs.
+4. Development code: Everything you need to do PyBOP development (so all of the above packages, plus ruff and other testing tools).
+
+Only 'core pybop' is installed by default. The others have to be specified explicitly when running the installation command.
+
+### Matplotlib
+
+We use Matplotlib in PyBOP, but with two caveats:
+
+First, Matplotlib should only be used in plotting methods, and these should _never_ be called by other PyBOP methods. So users who don't like Matplotlib will not be forced to use it in any way. Use in notebooks is OK and encouraged.
+
+Second, Matplotlib should never be imported at the module level, but always inside methods. For example:
+
+```
+def plot_great_things(self, x, y, z):
+ import matplotlib.pyplot as pl
+ ...
+```
+
+This allows people to (1) use PyBOP without ever importing Matplotlib and (2) configure Matplotlib's back-end in their scripts, which _must_ be done before e.g. `pyplot` is first imported.
+
+## Testing
+
+All code requires testing. We use the [pytest](https://docs.pytest.org/en/) package for our tests. (These tests typically just check that the code runs without error, and so, are more _debugging_ than _testing_ in a strict sense. Nevertheless, they are very useful to have!)
+
+If you have nox installed, to run unit tests, type
+
+```bash
+nox -s unit
+```
+
+else, type
+
+```bash
+pytest --unit -v
+```
+
+To run individual test files, you can use
+
+```bash
+pytest tests/unit/path/to/test --unit -v
+```
+
+And for individual tests,
+
+```bash
+pytest tests/unit/path/to/test.py::TestClass:test_name --unit -v
+```
+where `--unit` is a flag to run only unit tests and `-v` is a flag to display verbose output.
+
+### Writing tests
+
+Every new feature should have its own test. To create ones, have a look at the `test` directory and see if there's a test for a similar method. Copy-pasting is a good way to start.
+
+Next, add some simple (and speedy!) tests of your main features. If these run without exceptions that's a good start! Next, check the output of your methods using any of these [functions](https://docs.pytest.org/en/7.4.x/reference/reference.html#functions).
+
+### Debugging
+
+Often, the code you write won't pass the tests straight away, at which stage it will become necessary to debug.
+The key to successful debugging is to isolate the problem by finding the smallest possible example that causes the bug.
+In practice, there are a few tricks to help you do this, which we give below.
+Once you've isolated the issue, it's a good idea to add a unit test that replicates this issue, so that you can easily check whether it's been fixed, and make sure that it's easily picked up if it crops up again.
+This also means that, if you can't fix the bug yourself, it will be much easier to ask for help (by opening a [bug-report issue](https://github.com/pybop-team/PyBOP/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D%3A+)).
+
+1. Run individual test scripts instead of the whole test suite:
+
+ ```bash
+ pytest tests/unit/path/to/test --unit -v
+ ```
+
+ You can also run an individual test from a particular script, e.g.
+
+ ```bash
+ pytest tests/unit/path/to/test.py::TestClass:test_name --unit -v
+ ```
+ where `--unit` is a flag to run only unit tests and `-v` is a flag to display verbose output.
+
+2. Set break-points, either in your IDE or using the Python debugging module. To use the latter, add the following line where you want to set the break point
+
+ ```python
+ import ipdb
+
+ ipdb.set_trace()
+ ```
+
+ This will start the [Python interactive debugger](https://gist.github.com/mono0926/6326015). If you want to be able to use magic commands from `ipython`, such as `%timeit`, then set
+
+ ```python
+ from IPython import embed
+
+ embed()
+ import ipdb
+
+ ipdb.set_trace()
+ ```
+
+ at the break point instead.
+ Figuring out where to start the debugger is the real challenge. Some good ways to set debugging break points are:
+
+ 1. Try-except blocks. Suppose the line `do_something_complicated()` is raising a `ValueError`. Then you can put a try-except block around that line as:
+
+ ```python
+ try:
+ do_something_complicated()
+ except ValueError:
+ import ipdb
+
+ ipdb.set_trace()
+ ```
+
+ This will start the debugger at the point where the `ValueError` was raised, and allow you to investigate further. Sometimes, it is more informative to put the try-except block further up the call stack than exactly where the error is raised.
+ 2. Warnings. If functions are raising warnings instead of errors, it can be hard to pinpoint where this is coming from. Here, you can use the `warnings` module to convert warnings to errors:
+
+ ```python
+ import warnings
+
+ warnings.simplefilter("error")
+ ```
+
+ Then you can use a try-except block, as in a., but with, for example, `RuntimeWarning` instead of `ValueError`.
+
+3. To isolate whether a bug is in a model, its Jacobian or its simplified version, you can set the `use_jacobian` and/or `use_simplify` attributes of the model to `False` (they are both `True` by default for most models).
+4. If a model isn't giving the answer you expect, you can try comparing it to other models. For example, you can investigate parameter limits in which two models should give the same answer by setting some parameters to be small or zero. The `StandardOutputComparison` class can be used to compare some standard outputs from battery models.
+5. To get more information about what is going on under the hood, and hence understand what is causing the bug, you can set the [logging](https://realpython.com/python-logging/) level to `DEBUG` by adding the following line to your test or script:
+
+ ```python3
+ pybop.set_logging_level("DEBUG")
+ ```
+
+### Profiling
+
+Sometimes, a bit of code will take much longer than you expect to run. In this case, you can set
+
+```python
+from IPython import embed
+
+embed()
+import ipdb
+
+ipdb.set_trace()
+```
+
+as above, and then use some of the profiling tools. In order of increasing detail:
+
+1. Simple timer. In ipython, the command
+
+ ```
+ %time command_to_time()
+ ```
+
+ tells you how long the line `command_to_time()` takes. You can use `%timeit` instead to run the command several times and obtain more accurate timings.
+2. Simple profiler. Using `%prun` instead of `%time` will give a brief profiling report 3. Detailed profiler. You can install the detailed profiler `snakeviz` through pip:
+
+ ```bash
+ pip install snakeviz
+ ```
+
+ and then, in ipython, run
+
+ ```
+ %load_ext snakeviz
+ %snakeviz command_to_time()
+ ```
+
+ This will open a window in your browser with detailed profiling information.
+
+## Infrastructure
+
+### Setuptools
+
+Installation of PyBOP _and dependencies_ is handled via [setuptools](http://setuptools.readthedocs.io/)
+
+Configuration files:
+
+```
+setup.py
+```
+
+Note that this file must be kept in sync with the version number in [pybop/**init**.py](pybop/__init__.py).
+
+### Continuous Integration using GitHub actions
+
+Each change pushed to the PyBOP GitHub repository will trigger the test and benchmark suites to be run, using [GitHub actions](https://github.com/features/actions).
+
+Tests are run for different operating systems, and for all Python versions officially supported by PyBOP. If you opened a Pull Request, feedback is directly available on the corresponding page. If all tests pass, a green tick will be displayed next to the corresponding test run. If one or more test(s) fail, a red cross will be displayed instead.
+
+Similarly, the benchmark suite is automatically run for the most recently pushed commit. Benchmark results are compared to the results available for the latest commit on the `develop` branch. Should any significant performance regression be found, a red cross will be displayed next to the benchmark run.
+
+In all cases, more details can be obtained by clicking on a specific run.
+
+Configuration files for various GitHub actions workflow can be found in `.github/workflows`.
+
+### Codecov
+
+Code coverage (how much of our code is seen by the (Linux) unit tests) is tested using [Codecov](https://docs.codecov.io/), a report is visible on https://codecov.io/gh/pybop-team/PyBOP.
+
+
+### GitHub
+
+GitHub does some magic with particular filenames. In particular:
+
+- The first page people see when they go to [our GitHub page](https://github.com/pybop-team/PyBOP) displays the contents of [README.md](README.md), which is written in the [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) format. Some guidelines can be found [here](https://help.github.com/articles/about-readmes/).
+- The license for using PyBOP is stored in [LICENSE](LICENSE.txt), and [automatically](https://help.github.com/articles/adding-a-license-to-a-repository/) linked to by GitHub.
+- This file, [CONTRIBUTING.md](CONTRIBUTING.md) is recognised as the contribution guidelines and a link is [automatically](https://github.com/blog/1184-contributing-guidelines) displayed when new issues or pull requests are created.
+
+## Acknowledgements
+
+This CONTRIBUTING.md file, along with large sections of the code infrastructure,
+was copied from the excellent [Pints repo](https://github.com/pints-team/pints), and [PyBaMM repo](https://github.com/pybamm-team/PyBaMM)
diff --git a/LICENSE b/LICENSE
index c7c3f30fd..160abed72 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,28 @@
-MIT License
+BSD 3-Clause License
-Copyright (c) 2023 PRISM-Organisation
+Copyright (c) 2023, pybop-team
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/PyBOP/cost_functions/MLE.py b/PyBOP/cost_functions/MLE.py
deleted file mode 100644
index 48f8b48da..000000000
--- a/PyBOP/cost_functions/MLE.py
+++ /dev/null
@@ -1,18 +0,0 @@
-class CostFunction():
- """
- Base class for cost function definition.
- """
-
- def __init__():
- """"
-
- Init.
-
- """
-
- def MLE(self, x0, x_hat, theta):
- """
-
- Function for Maximum Likelihood Estimation
-
- """
diff --git a/PyBOP/models/base_model.py b/PyBOP/models/base_model.py
deleted file mode 100644
index 46e314ce1..000000000
--- a/PyBOP/models/base_model.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pybamm.models.base_model import PyBaMMBaseModel
-import numpy as np
-
-class BaseModel(PyBaMMBaseModel):
- """
-
- This is a wrapper class for the PyBaMM Model class.
-
- """
-
- def __init__(self):
- """
-
- Insert initialisation code as needed.
-
- """
-
- self.name = "Base Model"
-
-
- def update(self, k):
- """
- Updater
- """
- print(k)
\ No newline at end of file
diff --git a/PyBOP/optimisation/base_optimisation.py b/PyBOP/optimisation/base_optimisation.py
deleted file mode 100644
index a77348b2f..000000000
--- a/PyBOP/optimisation/base_optimisation.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import botorch
-import scipy
-import numpy
-
-class BaseOptimisation():
- """
-
- Base class for the optimisation methods.
-
- """
-
- def __init__(self):
-
- """
-
- Initialise and name class.
-
- """
- self.name = "Base Optimisation"
-
-
-
- def NelderMead(self, fun, x0, options):
- """
- PRISM optimiser using Nelder-Mead.
- """
- res = scipy.optimize(fun, x0, method='nelder-mead',
- options={'xatol': 1e-8, 'disp': True})
\ No newline at end of file
diff --git a/PyBOP/simulation/base_simulation.py b/PyBOP/simulation/base_simulation.py
deleted file mode 100644
index 0595b6577..000000000
--- a/PyBOP/simulation/base_simulation.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import pybamm.simulation.Simulation as pybamm_simulation
-
-class BaseSimulation(pybamm_simulation):
- """
-
- This class solves the optimisation / estimation problem.
-
- Parameters:
- ================
- pybamm_simulation: argument for PyBaMM simulation that will be updated.
-
- """
-
- def __init__(self):
- """
- Initialise and name class
- """
-
- self.name = "Base Simulation"
-
- def Simulation(self, simulation, optimise, cost, data):
- """
-
-
-
- """
\ No newline at end of file
diff --git a/README.md b/README.md
index 2f0a61069..11d7e9be8 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,152 @@
-# PyBOP - A *Py*thon toolbox for *B*attery *O*ptimisation and *P*arameterisation
+
+
+
+## PyBOP
+PyBOP offers a full range of tools for the parameterisation and optimisation of battery models, utilising both Bayesian and frequentist approaches with example workflows to assist the user. PyBOP can be used to parameterise various battery models, which include electrochemical and equivalent circuit models that are present in [PyBaMM](https://pybamm.org/). PyBOP prioritises clear and informative diagnostics for users, while also allowing for advanced probabilistic methods.
+
+The diagram below presents PyBOP's conceptual framework. The PyBOP software specification is available at [this link](https://github.com/pybop-team/software-spec). This product is currently undergoing development, and users can expect the API to evolve with future releases.
+
+
+
+
+
+
+## Getting Started
+
+
+### Prerequisites
+To use and/or contribute to PyBOP, first install Python (3.8-3.11). On a Debian-based distribution, this looks like:
+
+```bash
+sudo apt update
+sudo apt install python3 python3-virtualenv
+```
+
+For further information, please refer to the similar [installation instructions for PyBaMM](https://docs.pybamm.org/en/latest/source/user_guide/installation/GNU-linux.html).
+
+### Installation
+
+Create a virtual environment called `pybop-env` within your current directory:
+
+```bash
+virtualenv pybop-env
+```
+
+Activate the environment:
+
+```bash
+source pybop-env/bin/activate
+```
+
+Later, you can deactivate the environment:
+
+```bash
+deactivate
+```
+
+Within your virtual environment, install the `develop` branch of PyBOP:
+
+```bash
+pip install git+https://github.com/pybop-team/PyBOP.git@develop
+```
+
+To alternatively install PyBOP from a local directory, use the following template, substituting in the relevant path:
+
+```bash
+pip install -e "PATH_TO_PYBOP"
+```
+
+To check whether PyBOP has been installed correctly, run one of the examples in the following section or the full set of unit tests:
+
+```bash
+pytest --unit -v
+```
+
+### Using PyBOP
+PyBOP has two general types of intended use cases:
+1. parameter estimation from battery test data
+2. design optimisation subject to battery manufacturing/usage constraints
+
+These general cases encompass a wide variety of optimisation problems that require careful consideration based on the choice of battery model, the available data and/or the choice of design parameters.
+
+PyBOP comes with a number of [example notebooks and scripts](https://github.com/pybop-team/PyBOP/blob/develop/examples) which can be found in the examples folder.
+
+The [spm_descent.py](https://github.com/pybop-team/PyBOP/blob/develop/examples/scripts/spm_descent.py) script illustrates a straightforward example that starts by generating artificial data from a single particle model (SPM). The unknown parameter values are identified by implementing a sum-of-square error cost function using the terminal voltage as the observed signal and a gradient descent optimiser. To run this example:
+
+```bash
+python examples/scripts/spm_descent.py
+```
+
+In addition, [spm_nlopt.ipynb](https://github.com/pybop-team/PyBOP/blob/develop/examples/notebooks/spm_nlopt.ipynb) provides a second example in notebook form. This example estimates the SPM parameters based on an RMSE cost function and a BOBYQA optimiser.
+
+
+## Code of Conduct
+
+PyBOP aims to foster a broad consortium of developers and users, building on and learning from the success of the [PyBaMM](https://pybamm.org/) community. Our values are:
+
+- Inclusivity and fairness (those who wish to contribute may do so, and their input is appropriately recognised)
+
+- Interoperability (modularity for maximum impact and inclusivity)
+
+- User-friendliness (putting user requirements first via user-assistance & workflows)
+
+
+
+## Contributors ✨
+
+Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+
+
+
+
+
+
+
+
+
+
+
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specifications. Contributions of any kind are welcome! See `contributing.md` for ways to get started.
diff --git a/assets/BayOpt_Arch.pdf b/assets/BayOpt_Arch.pdf
new file mode 100644
index 000000000..5332b82b2
Binary files /dev/null and b/assets/BayOpt_Arch.pdf differ
diff --git a/assets/BayesOpt_Arch.svg b/assets/BayesOpt_Arch.svg
new file mode 100644
index 000000000..e9340ab6d
--- /dev/null
+++ b/assets/BayesOpt_Arch.svg
@@ -0,0 +1,1731 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/PyBOP_Architecture.drawio b/assets/PyBOP_Architecture.drawio
new file mode 100644
index 000000000..9045249c2
--- /dev/null
+++ b/assets/PyBOP_Architecture.drawio
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/PyBOP_Architecture.png b/assets/PyBOP_Architecture.png
new file mode 100644
index 000000000..25ea6d42f
Binary files /dev/null and b/assets/PyBOP_Architecture.png differ
diff --git a/assets/Temp_Logo.png b/assets/Temp_Logo.png
new file mode 100644
index 000000000..4ef2853b3
Binary files /dev/null and b/assets/Temp_Logo.png differ
diff --git a/conftest.py b/conftest.py
new file mode 100644
index 000000000..b37cbd0f5
--- /dev/null
+++ b/conftest.py
@@ -0,0 +1,24 @@
+import pytest
+import matplotlib
+
+matplotlib.use("Template")
+
+
+def pytest_addoption(parser):
+ parser.addoption(
+ "--unit", action="store_true", default=False, help="run unit tests"
+ )
+
+
+def pytest_configure(config):
+ config.addinivalue_line("markers", "unit: mark test as a unit test")
+
+
+def pytest_collection_modifyitems(config, items):
+ if config.getoption("--unit"):
+ # --unit given in cli: do not skip unit tests
+ return
+ skip_unit = pytest.mark.skip(reason="need --unit option to run")
+ for item in items:
+ if "unit" in item.keywords:
+ item.add_marker(skip_unit)
diff --git a/examples/notebooks/spm_nlopt.ipynb b/examples/notebooks/spm_nlopt.ipynb
new file mode 100644
index 000000000..811575160
--- /dev/null
+++ b/examples/notebooks/spm_nlopt.ipynb
@@ -0,0 +1,793 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "expmkveO04pw"
+ },
+ "source": [
+ "## A NMC/Gr parameterisation example using PyBOP\n",
+ "\n",
+ "This notebook introduces a synthetic re-parameterisation of the single-particle model with corrupted observations. To start, we import the PyBOP package for parameterisation and the PyBaMM package to generate the initial synethic data,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "X87NUGPW04py",
+ "outputId": "0d785b07-7cff-4aeb-e60a-4ff5a669afbf"
+ },
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m19.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m139.4/139.4 kB\u001b[0m \u001b[31m14.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m15.9/15.9 MB\u001b[0m \u001b[31m78.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.3/2.3 MB\u001b[0m \u001b[31m79.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m44.9/44.9 kB\u001b[0m \u001b[31m5.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m160.1/160.1 kB\u001b[0m \u001b[31m17.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.3/75.3 MB\u001b[0m \u001b[31m8.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m561.4/561.4 kB\u001b[0m \u001b[31m27.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m51.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m423.7/423.7 kB\u001b[0m \u001b[31m6.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m260.7/260.7 kB\u001b[0m \u001b[31m15.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m284.9/284.9 kB\u001b[0m \u001b[31m15.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25h Building wheel for pybop (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+ "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
+ "\u001b[0m"
+ ]
+ }
+ ],
+ "source": [
+ "%pip install --upgrade pip ipywidgets pybamm -q\n",
+ "%pip install git+https://github.com/pybop-team/PyBOP.git@develop -q"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jAvD5fk104p0"
+ },
+ "source": [
+ "Next, we import the added packages plus any additional dependencies,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "id": "SQdt4brD04p1"
+ },
+ "outputs": [],
+ "source": [
+ "import pybop\n",
+ "import pybamm\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "5XU-dMtU04p2"
+ },
+ "source": [
+ "## Generate Synthetic Data"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "MlBYO-xK04p3"
+ },
+ "source": [
+ "We need to generate the synthetic data required for later reparameterisation. To do this we will run the PyBaMM forward model and store the generated data. This will be integrated into PyBOP in a future release for fast synthetic generation. For now, we define the PyBaMM model with a default parameter set,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "id": "sBasxv8U04p3"
+ },
+ "outputs": [],
+ "source": [
+ "synthetic_model = pybamm.lithium_ion.SPM()\n",
+ "params = synthetic_model.default_parameter_values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "wRDiC_dj04p5"
+ },
+ "source": [
+ "We can now modify individual parameters with the bespoke values and run the simulation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "id": "JgN4C76x04p6"
+ },
+ "outputs": [],
+ "source": [
+ "params.update(\n",
+ " {\n",
+ " \"Negative electrode active material volume fraction\": 0.52,\n",
+ " \"Positive electrode active material volume fraction\": 0.63,\n",
+ " }\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "KWA5Fmbv04p7"
+ },
+ "source": [
+ "Define the experiment and run the forward model to capture the synthetic data."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "id": "LvQ7eXGf04p7"
+ },
+ "outputs": [],
+ "source": [
+ "experiment = pybamm.Experiment(\n",
+ " [\n",
+ " (\n",
+ " \"Discharge at 1C for 15 minutes (1 second period)\",\n",
+ " \"Rest for 2 minutes (1 second period)\",\n",
+ " \"Charge at 1C for 15 minutes (1 second period)\",\n",
+ " \"Rest for 2 minutes (1 second period)\",\n",
+ " ),\n",
+ " ]\n",
+ " * 2\n",
+ ")\n",
+ "sim = pybamm.Simulation(synthetic_model, experiment=experiment, parameter_values=params)\n",
+ "synthetic_sol = sim.solve()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "u6QbgzJD04p-"
+ },
+ "source": [
+ "Plot the synthetic data,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 602,
+ "referenced_widgets": [
+ "8d003c14da5f4fa68284b28c15cee6e6",
+ "aef2fa7adcc14ad0854b73d5910ae3b4",
+ "7d46516469314b88be3500e2afcafcf6",
+ "423bffea3a1c42b49a9ad71218e5811b",
+ "06f2374f91c8455bb63252092512f2ed",
+ "56ff19291e464d63b23e63b8e2ac9ea3",
+ "646a8670cb204a31bb56bc2380898093"
+ ]
+ },
+ "id": "_F-7UPUl04p-",
+ "outputId": "cf548842-64ae-4389-b16d-d3cf3239ce8f"
+ },
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ "interactive(children=(FloatSlider(value=0.0, description='t', max=1.1333333333333333, step=0.01133333333333333…"
+ ],
+ "application/vnd.jupyter.widget-view+json": {
+ "version_major": 2,
+ "version_minor": 0,
+ "model_id": "8d003c14da5f4fa68284b28c15cee6e6"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "execution_count": 25
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ ""
+ ],
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAKxCAYAAAC8BuXeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeVxU1f8/8NeADKsDorIlAqYhmIDiRxzLHRnQj2n5KRdS3D8aaEhp8ckItcJc0ST5mAtW8nGpNFMDCUNccENHccMN0xIwU0BQAeH8/vDH/ToybIoMwuv5eNxH3Xve9973PTNzOZ65c45MCCFARERERERERERERETl6Ok6ASIiIiIiIiIiIiKi+oqd6EREREREREREREREFWAnOhERERERERERERFRBdiJTkRERERERERERERUAXaiExERERERERERERFVgJ3oREREREREREREREQVYCc6EREREREREREREVEF2IlORERERERERERERFQBdqITEREREREREREREVWAnehPyNHREZGRkbpOo1ZduXIFMpkMarW6WvFjxozBkCFDnmlOT2r//v3o2LEjDAwM6m2OpEkmk2Hr1q3P9Bzh4eGQyWSQyWR18vmti2uqrrq+9sasPr3ujwsPD4eHh4eu06Aq1EUbIyYmRronBAcHP9NzAfWr3VTX1061JykpCTKZDDk5OZXG1af3W21hO510ie30Z4vtdKL6o+zvrUwme6J/N5Xta2FhUeu5ke7Vu070MWPGQCaTYd68eRrbt27dCplMVuf5xMTEaH3zHzlyBJMmTarzfGqLtoa1vb09MjMz8fLLL+smqVoUEhICDw8PZGRkICYmRtfpPNcq+gw8qYo68TIzM+Hn51dr56lIhw4dkJmZ+Vx/fh+Xnp6OPn36wNraGkZGRmjTpg1mzZqF4uJiKeb9999HZmYmWrVqpcNMn39lf6MeX3x9fZ/ZOXX5j7za/vw/76rbgVddum5jKBQKZGZmYu7cuc/8XHXl77//hq+vL+zs7GBoaAh7e3sEBQUhLy9Pihk2bBgyMzOhVCp1mGnD9eh9Ui6Xo23btpgzZw4ePHjw1Mfu3r07MjMzYW5uDkD3n6Fnhe10qi620+s/ttOpIcrKysLUqVPRpk0bqb01aNAgJCYm6jq1StXk31W//vqr1uv5448/IJfLK/x7nJmZyS/DGrAmuk5A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SdsyMzMFAJGSklLhccoolUphaGgoAIhJkyaJkpKScjFsnD+dgIAAoa+vL0xNTTWWzz77TIp59HX/9ttvhbOzs9TZKMTDzlNjY2MRHx8vhKj83vP48cp88sknwsDAQKPxt2vXLqGvry+uXr0qbSv7PB8+fFja79HPwBdffCFcXFyk9R9++EGYmZlJnz1tn//ff/9d6Ovriz///FNje79+/URoaKjWa4iPjxd6enoiPT1da/nIkSNF//79NbbNmDFDuLq6SusODg7i7bffltZLS0uFlZWVWLFihRCi6ntuv379yjX4v/32W2FrayutV3XPfbQD71G9evUSnTp10nreRz1JG6O6r6uJiYnG39MZM2YILy+vCnOp7NyP1nPZPejjjz+WtpXdIzMzM4UQ1X/9qupEd3Bw0LhvOTs7ix49ekjrZffI//3vfxUep8zw4cOFsbGxACAGDRok7t27Vy6GnejPxqPtw9LSUpGQkCAMDQ3F+++/L86fPy8AiP3790vxN2/eFMbGxmLTpk1CCCE6duyo8eXWox7/DLKdzna6EGyns53OdjpRXTl06JAAIH788cdK42rSib5161aNfbW1q+fOnSt8fHw0tl27dk16uKVsv0c/s0II8Y9//EN88MEH0npVn/uKci8zcuRIjb9r7u7uWv+esRO94aqXw7mU+eKLL7Bu3TqcPXu2XNmJEycQExMjjR9mZmYGlUqF0tJSZGRkID09HU2aNEHnzp2lfdq2bVvuJ/e//vor+vXrhxdeeAFNmzbFqFGj8Pfff+Pu3bvVzrNJkyZ46623sH79egBAQUEBfvrpJ/j7+wMALl68iLt376J///4a+X7zzTcV/uSyzOOTXimVSo36qE7+crkcbm5u1b6eMmq1Gj169ICBgUGVsU9yjf3794eDgwPatGmDUaNGYf369TWq9zJdunSpVlxUVBQ8PT3RsmVLmJmZYeXKlbh69SoA4MaNG7h+/Tr69eundd8TJ04gPz8fzZs317i+jIyMCq9PrVajU6dOsLS01Fp+9uxZvPLKKxrbXnnllXLv90dfO1NTUygUCty4cUM6R0WvUUFBAS5duoTx48dr5Pzpp5+Wy/nRc9ja2kp1UhVtdb9x40a88sorsLGxgZmZGWbNmiXVc3WdPXsW7u7uMDU1lba98sorKC0tRXp6urStQ4cOGmMH2traVitvbR6t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9x3y8vIejuMOoGXLltDX18fPP/+M7OxsdOvWDUZGRkhISMDnn3+O999/XzrH5MmTsXz5csycORPjxo3D7t27sWnTJuzYsUOKCQkJQUBAALp06YKuXbsiMjJSo1OGiIjqh2HDhuGvv/5CWFgYsrKy4OHhgbi4OGlei6tXr0JP7/+exezevTtiY2Mxa9Ys/Oc//0G7du2wdetWvPzyy7q6BGpohNB1BkQSdqITETUwvXv3hqiksSGTyTBnzhyNzuvHWVpaIjY2ttLzuLm5Ye/evRWWjxkzBmPGjNHY5uDggJ07d1Z63N69e+P48eOVxhARUdVu3LiB0aNHIzMzE+bm5nBzc0N8fDz69++PpKQkHDp0CADQtm1bjf0yMjLg6OgIAwMDREVFYfr06RBCoG3btli8eDEmTpwoxVbny8+qOmWIiKj+CAoKqvBJ8qSkpHLb3nzzTbz55pvPOCtiZzI9tcb6HqrF62YnOhERERFRA7R69eoKy6r6whUAfH194evrW+V5qvPlZ2WdMkRERERE9R3HRCciIiIiIiIiIp2oalLrRk0m03UG9QPr4cmx7h6qhXpgJzoREREREREREemEXC7XdQpERFViJzoRERERERERERERUQXYiU5ERERERERERDpRWlqq6xSIiKrETnQiIiIiIiIiItKJe/fu6TqF+q+KycAbrMZ63c9CY63LWrxudqITEREREREREREREVWAnehERERERERERET1jUym6wzqB9bDk2PdPVQL9cBOdCIiIiIiIiIiIiKiCrATnYiIiIiIiIiIiIioAuxEJyIiIiIiIiIiIiKqADvRiYiIiIiIiIiIqH4RQtcZEEnYiU5ERERERERERDrRpEkTXadQ/7EzmZ5WY30P1eJ1sxOdiIiIiIiIiIh0wtDQUNcpEBFViZ3oRERERERERERE9Y1MpusM6gfWw5Nj3T1UC/XATnQiIiIiIiIiItIJ0ViHmSCi5wo70YmIiIiIiIiISCfu3r2r6xSIiKrETnQiIiIiIiIiIiKqX/grBapH2IlORERERERERERUX7EzmZ5WY30P1eJ1sxOdiIiIiKgBWrFiBdzc3KBQKKBQKKBUKvHLL78AAG7duoWpU6fC2dkZxsbGaN26NaZNm4bc3FyNY1y9ehUDBw6EiYkJrKysMGPGDDx48EAjJikpCZ07d4ahoSHatm2LmJiY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Rb1D5ERENU+l1kQvKCjAkSNH8P7778PR0RFNmjSBra2tQsmXmJgY5ObmwsHBQZxnaWmJZs2aITo6GoC8HleHDh1gbGwstnF0dERGRgauX78utnm9j8I2hX0Uh/W3iIiIiIiIiKg+MDIygqWlZamThoYG7OzskJaWhpiYGHHdyMhIFBQUwNbWtti+586diytXriAuLk6cAHlpxm3btlXH7tUPEomyI6gZeBzeHo+dXCUch0pNoqekpCAzMxNLly6Fk5MTfv/9dwwbNgzDhw/H8ePHAchrbWloaBT5tNLY2FistZWUlKSQQC9cXristDYZGRl4+fJlsfGx/hYRERERERER0f9YWVnByckJXl5eOH/+PE6fPg1vb2+MGTMGpqamAIBHjx7B0tIS58+fBwDIZDK0b99eYQKAZs2aoUWLFhXavopKpaamqC6pryVIqEaqcDmX0hQUFAAAhg4dCl9fXwBAp06dcObMGQQFBaF3796VubkKY/0tIiIiIiIiIiJFu3btgre3N/r37w8VFRWMGDEC69atE5fn5uYiPj4eL168qPRta2lpVXqfRESVrVKT6I0bN4aamhratm2rML+wXjkg/7QyJycHaWlpClejJycni7W2ZDKZ+Onm68sLlxX+LJz3ehs9PT0OwERERERERERE5WRoaIiQkJASl5ubm0Mo46rgspYTEdVmlfqdGQ0NDXTr1g3x8fEK82/duoXmzZsDAGxsbKCuro6IiAhxeXx8PB48eAA7OzsAgJ2dHa5evapwY4vw8HDo6emJCXo7OzuFPgrbFPZBRERERERERERERPSuKnwlemZmJu7cuSM+v3fvHuLi4mBoaIhmzZph9uzZGD16NHr16oW+ffvi6NGjOHTokHhnZn19fXh6esLPzw+GhobQ09PDtGnTYGdnhx49egAABgwYgLZt22L8+PFYvnw5kpKS8OWXX2Lq1KliOZbJkydjw4YN+PzzzzFhwgRERkZi7969OHLkSCUcFiIiIiIiIiIiqmovXryAnp6essOo2XiVP72r+vo7VIn7XeEk+sWLF9G3b1/xuZ+fHwDAzc0NwcHBGDZsGIKCghAYGIjp06fDwsIC+/btQ8+ePcV1Vq9eLdbYys7OhqOjI7799ltxuaqqKg4fPowpU6bAzs4O2tracHNzw1dffSW2adGiBY4cOQJfX1+sXbsWTZs2xfff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6h6O7UREVJIuXbrg+vXrMDc3R+vWrRUmbW1tZYdHdRCT6FSv5OTk4JNPPsHo0aOxePFiTJw4scJXlMTHx+PVq1cwNTUV50VHR+PRo0cKJ+NERFQ9OLYTEdU9HNuJiKg0U6dORWpqKsaOHYsLFy4gISEBYWFh8PDwQH5+vrLDozqISXSqV+bNm4f09HSsW7cOc+bMwfvvv48JEyZUqI+4uDgAwPr163H79m389ttvcHV1BSA/2SciourFsZ2IqO7h2E5ERKUxNTXF6dOnkZ+fjwEDBqBDhw7w8fGBgYEBVFSY7qTKx5roVG9ERUVhzZo1OHbsGPT09AAAO3fuhLW1NTZt2oQpU6aUq5+4uDg4Ojri7t276NChA9q2bYtFixZhypQpWLduHXbu3FmVu0FERK/h2E5EVPdwbCciqhvc3d3h7u5eZH5wcLDC86ioqCJtiivjJQiCwvM2bdrg559/focIS95W4QexRIWYRKd6o0+fPsjNzVWYZ25ujvT09Ar1c/nyZXTr1g3/+c9/FOa/fsOit30DICKiiuHYTkRU93BsJyKiqpKeng4dHR1MnTq12JuSlkRHRwd5eXnQ1NSswuioJuP3G4jK8O2330JHRwdXr14FID8Z79ChQ5Vsa/LkydDR0amSvomI6H84thMR1T0c24mIqDQjRozA7du3ERcXh9mzZ1do3bi4OFy7dg2xsbFVFB3VdBKBH6kTlejRo0d4+fIlAKBZs2ZITU2FiYkJrl+/jrZt21b69lJSUpCRkQEAMDEx4R2liYiqAMd2IqK6h2M7ERERVSUm0YmIiIiIiIiIiIiISsByLkREREREREREREREJWASnYiIiIiIiIiIiIioBEyiExERERERERERERGVgEl0IiIiIiIiIiIiIqISMIlORERERERERERERFQCJtGJiIiIiIiIiIiIiErAJDoRERERERERERERUQmYRCciIiIiIiIiIiIiKgGT6EREREREREREREREJWASnYiIiIiIiIiIiIioBEyiExERERERERERERGVgEl0IiIiIiIiIiIiIqISMIlORERERERERERERFQCJtGJiIiIiIiIiIiIiErAJDoRERERERERERERUQmYRCciIiIiIiIiIiIiKgGT6FQh5ubmWLNmjVJjCA4OhoGBgVJjqKiacNyUISAgAJ06darQOhKJBPv37y9xeZ8+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IiKq+xo0aKDsEIiIysQkOhERERERERERKYVEIlF2CEREZWISnYiIiIiIiIiIiIioBEyiExERERERERGRUmRnZys7BKqpnjwBLl1SdhRUm+XlASdOALm579wVk+hERERERERERKQUeXl5yg6BaqIXLwBbW6BrV+DuXWVHQ7WVhwfQuzewY8c7d8UkOhEREREREREREdUcgYHy5LkgAI8fKzsaqo2iooAffpA//vvvd+6OSXQiIiIiIiIiIiKqGe7cAZYvV3YUVJvl5gLe3pXaJZPoREREREREREREpHyCAEyfDuTkKDsSqs02bACuX6/ULplEJyIiIiIiIiIiIuU7eBD47TdAXR3Q15fPEwTlxkS1S2IisHCh/LGRkfxnJfwOMYlOREREREREREREyvXyJeDjI388cyZgbKzUcKiWmj0beP4c6N4dGDGi0rplEp2IiIiIiIiIiIiUKzAQuH8faNoU+PJLZUdDtdHx48CuXYBEAmzcCKhUXuqbSXQiIiIiIiIiIlKKBg0aKDsEqgni44Fly+SPV60CtLWVGw/VPjk5wJQp8seTJgFdu1Zq90yiExERERERERGRUkgkEmWHQMomCPLkZ04OMHAg8O9/F11OVJYVK4AbN4AmTeTfangda6ITERERERERERFRrfXDD8CxY4CmJrBhg7wUB/C/n0RlSUgAFi+WP161CmjYUP64En+HmEQnIiIiIiIiIiKlyM7OVnYIpEypqfKbiALAggVAy5bKjYdqH0EApk4FXr0C+vcHxo2rks0wiU5EREREREREREqRl5en7BBImebOBf75B2jb9n/JdKKKCA0FwsIADQ3g22+r7BsMTKITERERERERERFR9TpzBvjvf+WPg4LkSdDXFSZDWROdSpKeDsyYIX/8xRfA++8X34410YmIiIiIiIiIiKhWyc0FPv1U/njCBODDD5UbD9VO8+YBSUny5PncuUWXsyY6ERERERERERER1Upr1gDXrgGNGgHLlys7GqqNLlyQl28BgE2bAKm0SjfHJDoRERERERERERFVj7/+AgIC5I9XrJAn0okqIi9P/k0GQQA++QTo16/KN8kkOhFRPZOamgoXFxfo6enBwMAAnp6eyMzMLHWdzZs3o0+fPtDT04NEIkFaWlqx7Y4cOQJbW1toaWmhYcOGcHZ2FpcFBwdDIpEUO6WkpAAAoqKiil2e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5AQsXqzsiIpXm2qiExERERERERERFUcqlSo7hPrl/n15HfS8PGDcOHk9a6KKyMmR/w49fAi8/z7w44+Aqqqyo6pyTKITEREREREREZFSqKlVW5EEysqSXz389CnQpQvw/fe82psqbsYM4ORJQE8POHBAfkPReoBJdCIiIiIiIiIiorpMEAB3d+DKFaBJE2D/fkBLS9lRlQ9rotccQUHyqbCWvqWlsiMqn0r4HWISnYiIiIiIiIiIlCI3N1fZIdQPS5YAP/0EqKsD+/YBZmbKjqhsvEq+Zjl5Epg2Tf54yRJg8GDlxlMerIlORERERERERES1XU5OjrJDqPv27QPmz5c/3rgR6NlTufFQ7XP3LjB8uLyW/ujRwJw5yo6o2jGJTkREREREREREVBedOwd88om8nMXUqYCXl7Ijotrm2TNg0CDgyRN5Lf2tW+vltwSYRCciIiIiIiIiIqpr7t8HPv4YePVKngRds0bZEb0d1kRXnpwc+RXo8fHyEkCHDgENGig7qopjTXQiIiIiIiIiIiJSkJYmr1mdkgJYWwO7dwNqasqOqmLq4dXONYogAJ9+CkRFAbq6wOHDgKmpsqOqGNZEJyIiIiIiIiIioiJyc4GRI4E//5QnPQ8flidBiSpiyRIgOBhQVQX27gU6dlR2RErFJDoREREREREREVFdIAjAlCnAH38A2tryBHrTpsqOimqbH38EvvxS/nj9esDJSbnx1ABMohMREREREREREdUFy5cDW7YAKiryEi6dOys7orenqSn/+fy5cuOob06fBtzd5Y9nzpR/KFNbVeLvEJPoRERERERERESkFFKpVNkh1B179wJz58ofr10L/Otfyo3nXbVpI/9586Zy46hPbt8Ghg6V31B02DD5hzK1WeHv0I0b79wVk+hERERERERERKQUarXtZpc11YkTwPjx8sfTpwPe3sqNpzIUXkUfEaHcOOqLlBR52ZanT4GuXYEffpB/o6E269JF/vPiRfnNdt9BLT8SRERERERERERE9diNG4pXD69apeyIKsfQoYBEApw5A5w/r+xo6rasLGDIEODuXaBFC3kt/QYNlB3Vu3v/faBtW/nNdr/77p26YhKdiIiIiIiIiIiUIi8vT9kh1G6JicDAgfKrbO3sgF27AFVVZUdVOd57D/jkE/njTz6R7ytVvrw8YOxY+QcVhobAb78BxsbK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d+nSpTKZTDKZTBo5cqRlfoMGDTRr1qxC1726no+PT5nGCMflZu8AAAAAAAAAADg/k8lU6PKJEyfqzTfflGEYNorImpeXlw4ePKiqVave0HrJycn64IMPNHHixDKKDI6OkehAITp06GC52piUlFTm+xs4cKBlf5988kmZ7w8AKiL6dgAof+jbAcAxJCcnW6ZZs2bJy8vLat4zzzwjb29vu43oNplMCggIUPXq1W9ovYCAAHl7e5dRVHAGJNGBIkRFRSk5OVm33357me/rzTffVHJycpnvBwAqOvp2ACh/6NsBwP4CAgIsk7e3tyVpfXWqVq1annIuHTp00JNPPqmRI0eqRo0a8vf31zvvvKPMzEwNGjRI1atXV5MmTfTf//7Xal979+5Vly5dVK1aNfn7++uxxx7T2bNnixV3VlaWHn/8cVWvXl3169fXggULSvIyoBwiiQ4UoUqVKgoICJCbW9lXP/L29lZAQECZ7wcAKjr6dgAof+jbAcB5LVu2TL6+vtq+fbuefPJJDR8+XH379lW7du20c+dO3X///XrssceUlZUlSUpLS1PHjh0VFBSk77//XnFxcTp9+rQefvjhYu3/tddeU9u2bbVr1y498cQTGj58uA4ePFiahwgnRxIdFcZvv/2mgIAATZ061TJv8+bNcnd31/r1629oW99++60qVaqkixcvWuYdP35cJpNJP//8c7GvogIAbgx9OwCUP/TtAFDxtGrVSuPGjdMtt9yisWPHytPTU76+voqKitItt9yiCRMm6Ny5c/rhhx8kSW+99ZaCgoI0depUBQYGKigoSIsXL9bGjRv1008/3fD+u3btqieeeEJNmjTR888/L19fX23cuLG0DxNOjCQ6KoxatWpp8eLFmjRpkr7//nudP39ejz32mKKjo9WpU6cb2lZSUpKaNWsmT09Py7xdu3apRo0auvnmmyXd+FVUAMCNo28HgPKHvh0AKp6WLVtaHru6uuqmm25SixYtLPP8/f0lSWfOnJEk7d69Wxs3blS1atUsU2BgoCTpyJEjJdr/1RI0V/cFSCTRUcF07dpVUVFRCg8P17Bhw1S1alVNmzbthreze/duBQUFWc1LSkpSq1atLM9v9CoqAKB46NsBoPyhbweAiqVSpUpWz00mk9U8k8kkScrNzZUkXbhwQT169FBSUpLVdOjQId17772lsv+r+wIkkuiogGbOnKkrV65o9erVWr58uTw8PG54G0lJSWrdurXVvF27dlnNu9GrqACA4qNvB4Dyh74dAFCQO+64Q/v27VODBg3UpEkTq6lq1ar2Dg/lEEl0VDhHjhzRqVOnlJubq+PHj9/w+jk5Odq7d2+eES07d+60+jB+o1dRAQDFR98OAOUPfTsAoCAjRoxQamqq+vfvrx07dujIkSNat26dBg0apJycHHuHh3Ko7G9bDjiQS5cuacCAAXrkkUfUtGlTDRkyRHv27JGfn991b+PgwYO6ePGi6tSpY5m3ZcsW/frrr3lGuQAAyh59OwCUP/TtAIDC1KlTR999952ef/553X///crOztbNN9+ssLAwubgwZhiljyQ6KpQXX3xR6enpmj17tqpVq6YvvvhCjz/+uNauXXvd20hKSpIkzZkzR0899ZQOHz6sp556SpL5wz4AwLbo2wGg/KFvBwDnN3DgQA0cODDP/KVLl1o9T0hIyNMmv28gGYZh9fyWW27RRx99VIIIC97X1b8hwFVcmkGFkZCQoFmzZum9996Tl5eXXFxc9N577+mbb77R/Pnzr3s7SUlJCg0N1dGjR9WiRQu9+OKLeumll+Tl5aXZs2eX4REAAP6Kvh0Ayh/6dgBAWUlPT1e1atX0/PPP39B61apV07Bhw8ooKjgDRqKjwujQoYMuX75sNa9BgwZKT0+/oe3s3r1bd955p/71r39ZzX/00Uctj4t7FRUAcGPo2wGg/KFvBwCUhT59+qh9+/aSJB8fnxta9+rIdFdX11KOCs6CkehAEebNm6dq1appz549kswfxlu0aFEm+xo2bJiqVatWJtsGAPyJvh0Ayh/6dgBAYapXr64mTZqoSZMm8vX1vaF1r67XsGHDMooOjs5kcEkdKNCvv/6qP/74Q5JUv359paamqnbt2tq3b5+aN29e6vs7c+aMMjIyJEm1a9dW1apVS30fAFDR0bcDQPlD3w4AAMoSSXQAAAAAAAAAAApAORcAAAAAAAAAAApAEh0AAAAAAAAAgAKQRAcAAAAAAAAAoAAk0QEAAAAAAAAAKABJdAAAAAAAAAAACkASHQAAAAAAAACAApBEBwAAAAAAAACgACTRAQAAAAAAAAAoAEl0AAAAAAAAAAAKQBIdAAAAAAAAAIAC/D9pNV++FzK5QwAAAABJRU5ErkJggg==\n"
+ },
+ "metadata": {}
+ }
+ ],
+ "source": [
+ "sim.plot()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "kPlPy2oo04p-"
+ },
+ "source": [
+ "Now, let's corrupt the synthetic data with 1mV of gaussian noise centered around zero,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "id": "IW9PFOV904p-"
+ },
+ "outputs": [],
+ "source": [
+ "corrupt_V = synthetic_sol[\"Terminal voltage [V]\"].data\n",
+ "corrupt_V += np.random.normal(0, 0.001, len(corrupt_V))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "X8-tubYY04p_"
+ },
+ "source": [
+ "## Identify the Parameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "PQqhvSZN04p_"
+ },
+ "source": [
+ "Now, to blind fit the synthetic parameters we need to define the observation variables as well as update the forward model to be of PyBOP type (This composes PyBaMM's model class). For the observed voltage variable, we used the newly corrupted voltage array,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "metadata": {
+ "id": "zuvGHWID04p_"
+ },
+ "outputs": [],
+ "source": [
+ "pyb_model = pybop.lithium_ion.SPM()\n",
+ "dataset = [\n",
+ " pybop.Dataset(\"Time [s]\", synthetic_sol[\"Time [s]\"].data),\n",
+ " pybop.Dataset(\"Current function [A]\", synthetic_sol[\"Current [A]\"].data),\n",
+ " pybop.Dataset(\"Terminal voltage [V]\", corrupt_V),\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ffS3CF_704qA"
+ },
+ "source": [
+ "Next, we define the targeted forward model parameters for estimation. Furthermore, PyBOP provides functionality to define a prior for the parameters. The initial parameters values used in the estimiation will be randomly drawn from the prior distribution."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {
+ "id": "WPCybXIJ04qA"
+ },
+ "outputs": [],
+ "source": [
+ "parameters = [\n",
+ " pybop.Parameter(\n",
+ " \"Negative electrode active material volume fraction\",\n",
+ " prior=pybop.Gaussian(0.5, 0.02),\n",
+ " bounds=[0.48, 0.625],\n",
+ " ),\n",
+ " pybop.Parameter(\n",
+ " \"Positive electrode active material volume fraction\",\n",
+ " prior=pybop.Gaussian(0.65, 0.02),\n",
+ " bounds=[0.525, 0.75],\n",
+ " ),\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "n4OHa-aF04qA"
+ },
+ "source": [
+ "We can now define the fitting signal, a problem (which combines the model with the dataset) and construct a cost function."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {
+ "id": "etMzRtx404qA"
+ },
+ "outputs": [],
+ "source": [
+ "# Define the cost to optimise\n",
+ "signal = \"Terminal voltage [V]\"\n",
+ "problem = pybop.Problem(pyb_model, parameters, dataset, signal=signal)\n",
+ "cost = pybop.RootMeanSquaredError(problem)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "eQiGurUV04qB"
+ },
+ "source": [
+ "Let's construct PyBOP's optimisation class. This class provides the methods needed to fit the forward model. For this example, we use a root-mean square cost function with the BOBYQA algorithm implemented in NLOpt."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "metadata": {
+ "id": "N3FtAhrT04qB"
+ },
+ "outputs": [],
+ "source": [
+ "parameterisation = pybop.Optimisation(\n",
+ " cost=cost,\n",
+ " optimiser=pybop.NLoptOptimize,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "caprp-bV04qB"
+ },
+ "source": [
+ "Finally, we run the estimation algorithm."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {
+ "id": "-9OVt0EQ04qB"
+ },
+ "outputs": [],
+ "source": [
+ "x, final_cost = parameterisation.run()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "-4pZsDmS04qC"
+ },
+ "source": [
+ "Let's view the identified parameters:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "Hgz8SV4i04qC",
+ "outputId": "e1e42ae7-5075-4c47-dd68-1b22ecc170f6"
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "array([0.48367449, 0.63380314])"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 69
+ }
+ ],
+ "source": [
+ "x"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "KxKURtH704qC"
+ },
+ "source": [
+ "## Plotting"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "-cWCOiqR04qC"
+ },
+ "source": [
+ "First, run the SPM forward model with the estimated parameters,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 70,
+ "metadata": {
+ "id": "ZVfozY0A04qC"
+ },
+ "outputs": [],
+ "source": [
+ "params.update(\n",
+ " {\n",
+ " \"Negative electrode active material volume fraction\": x[0],\n",
+ " \"Positive electrode active material volume fraction\": x[1],\n",
+ " }\n",
+ ")\n",
+ "optsol = sim.solve()[\"Terminal voltage [V]\"].data"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ntIvAJmA04qD"
+ },
+ "source": [
+ "Now, we plot the estimated forward model against the corrupted synthetic observation,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 467
+ },
+ "id": "tJUJ80Ve04qD",
+ "outputId": "855fbaa2-1e09-4935-eb1a-8caf7f99eb75"
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "execution_count": 71
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ ""
+ ],
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAGwCAYAAABB4NqyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACJ4ElEQVR4nOzddXxV9RvA8c+5tWQjRtcoR4fkAAkZUiKoP0VECekQkVBGSUiHhLSEggiiYNAhA5FGkG5GbjQbbGy7cX5/DK5MaoNt557teb9e0+3ec899vpx7zn3ONxVVVVWEEEIIIdIRg9YBCCGEEEKkNkmAhBBCCJHuSAIkhBBCiHRHEiAhhBBCpDuSAAkhhBAi3ZEESAghhBDpjiRAQgghhEh3TFoH4IocDgeXL18mQ4YMKIqidThCCCGESARVVblz5w65cuXCYHh6HY8kQI9x+fJl8ubNq3UYQgghhHgOFy5cIE+ePE/dRhKgx8iQIQMQ/w/o4+OjcTRCCCGESIzIyEjy5s3r/B5/GkmAHuNBs5ePj48kQEIIIYTOJKb7inSCFkIIIUS6IwmQEEIIIdIdSYCEEEIIke5IH6AXYLfbsVqtWochXITFYnnmsEshhBCuQRKg56CqKuHh4dy+fVvrUIQLMRgMFChQAIvFonUoQgghnkESoOfwIPnJli0bnp6eMlmicE6eGRYWRr58+eQzIYQQLk4SoCSy2+3O5CdLlixahyNcSNasWbl8+TI2mw2z2ax1OEIIIZ5COiwk0YM+P56enhpHIlzNg6Yvu92ucSRCCCGeRRKg5yRNHOK/5DMhhBD6IQmQEEIIIdIdSYCEEEIIke5IAiRc3uDBgylbtmyqvmdoaCiKorB///5UfV8hhBCpQxKgdCY8PJxPPvmEwoUL4+7uTvbs2alWrRrTp08nOjpa6/ASpXXr1jRt2tRl9ydSz7046XAuhHg+Mgw+HTlz5gzVqlUjY8aMjBgxglKlSuHm5sbBgweZNWsWuXPn5o033njkdVarVZfDuvUat0icFQcu023RPsa8XZp3K+bVOhwhhM5IDVAyUFWV6Dhbqv+oqpqkOLt06YLJZGLPnj28++67FCtWjIIFC9KkSRNWrlxJ48aNgfjRTNOnT+eNN97Ay8uL4cOHAzB9+nQKFSqExWIhICCABQsWOPf9uCaj27dvoygKISEhAISEhKAoChs3bqRChQp4enpStWpVjh8/niDOUaNGkT17djJkyEDbtm2JiYlxPjd48GC+/fZbfv31VxRFce7/wfsvWbKEmjVr4u7uzvfff//Y5rOJEyfi7+//1P09cObMGWrXro2npydlypRh+/btSfo3Fymn26J9AHz28wGNIxFC6JHUACWDe1Y7xQetTfX3PTK0Hp6WxB3CGzdusG7dOkaMGIGXl9djt3l4GPfgwYMZNWoUEydOxGQysXz5cj755BMmTpxIUFAQK1asoE2bNuTJk4fatWsnKe7+/fszfvx4smbNSqdOnfjoo4/466+/APjxxx8ZPHgwU6dOpXr16ixYsIDJkydTsGBBAHr37s3Ro0eJjIxk3rx5AGTOnJnLly8D0LdvX8aPH0+5cuVwd3dn5syZT43lWfvr378/48aNo0iRIvTv35/mzZtz6tQpTCY5dbR0+tpdrUMQIl3749gVft57idAbUdyLs7Pqk1dwNxu1DitJ5CqeTpw6dQpVVQkICEjwuJ+fn7OGpWvXrowePRqA999/nzZt2ji3a968Oa1bt6ZLly4A9OzZkx07djBu3LgkJ0DDhw+nZs2aQHzC0qhRI2JiYnB3d2fixIm0bduWtm3bAvDll1+yYcMGZ4ze3t54eHgQGxtLjhw5Htl3jx49eOuttxIdy7P217t3bxo1agTAkCFDKFGiBKdOnaJo0aJJKrNIXnXGbyYbt+huWsZie9I+f0KIF/fR/D0AvG3Ygr8hnC3HA3itZE6No0oaSYCSgYfZyJGh9TR53xe1a9cuHA4HLVq0IDY21vl4hQoVEmx39OhROnTokOCxatWqMWnSpCS/Z+nSpZ2/58wZf8JcvXqVfPnycfToUTp16pRg+8DAQDZt2pSoff837hf1pFglAdLOvTg7Cg4mmqdS1XgELyUG+FjrsIRIN25GxQFQSTnKeMsMAHbFdAEkAUp3FEVJdFOUVgoXLoyiKI/0t3nQtOTh4ZHg8Sc1kz2JwRDfnezhfkkPlg35r4c7Jj9odnM4HEl6vyf5b9wGg+GRvlJPiutxUjJWkXRDfj/MvL9CaWH8g6rGIwCYsWkclRDpx91YGy8PW487sYwxz3I+nslNw6Cek3SCTieyZMlC3bp1+frrr4mKikry64sVK+bsp/PAX3/9RfHixYH4hUABwsLCnM8/zxw6xYoVY+fOnQke27FjR4K/LRZLotfbypo1K+Hh4QmSoP/GlZT9Ce1cuBnNvL9CyaNcI9i0yPm4xShLkAiRWqZuOgVAH9OP+BuuOB/XYzLh2tUWIllNmzaNatWqUaFCBQYPHkzp0qUxGAzs3r2bY8eOUb58+Se+tk+fPrz77ruUK1eOoKAgfv/9d5YtW8aGDRuA+BqkKlWqMGrUKAoUKMDVq1cZMGBAkmP85JNPaN26NRUqVKBatWp8//33HD582FlTBeDv78/atWs5fvw4WbJkwdfX94n7q1WrFteuXWPMmDH873//Y82aNaxevRofH5/n2p/QTotvdgIqo0yz8FZisKkGTIoDP2+L1qEJkW78uPsCFZRjtDGuAcCuKhgVFUjaqGRXoMekTTynQoUKsW/fPoKCgggODqZMmTJUqFCBKVOm0Lt3b4YNG/bE1zZt2pRJkyYxbtw4SpQowcyZM5k3bx61atVybjN37lxsNhvly5enR48efPnll0mOsVmzZgwcOJDPPvuM8uXLc+7cOTp37pxgm/bt2xMQEECFChXImjXrIzVTDytWrBjTpk1j6tSplClThl27dtG7d+/n3p/Qxt5zNzl/M5rmxj+objxMjGpmvj31+90JkZ51XfQ3UVF3GGOehUFRWWKrxQ3ibxhVHSZAiprUyWTSgcjISHx9fYmIiEhQUwAQExPD2bNnKVCgAO7u7hpFKFyRfDZSRnScjeKD1pKba6x1+xxvJYZh1g+IxcyX5nns83qFcn1WaB2mEGma3aFSqN8q+psW0t60ijA1M/ViR7PBrQ/ZlNucfms1hUpX1TrMp35//5fUAAkhXNq5G9GAykjzN3grMexxvMQ8e31eK6GvESdC6Nm1O7GUV47T1rgagGBrWyLxcg4O0WNNiiRAQgiXdfZ6FA0m/UkzYwg1jAeJUc18Zu3A0s7VsJgeXL70eOkVQj8mbzxJzZGrGWueiUFRWWqrQYijXMKNdNiYJAmQEMJlLdl9gVxcZ4BpIQDjbO/yfsM6lM+fGZDRX0KkNFVVmbD+BL1NP1LQEE64molhtg8A+Kvvq6g6Pg9lFJgQwmXN3HySheaZZFDusddRhLn2BhyolA/4N/1RpAZIiBSz9nA4lZWjDzV9tSMSb0582QCLycBV55b6Ow8lARJCuJSIe1YW7jjH2LXHaWVcTzXjYaJVN3pZO7G1bxDebvGXLfXB2nX6u+4K4fJirHZGrT7G0m1HWWOZgUFRWWyrxSZHOf4eWPehJuh4OmwBkwRICOFahq04wk97L1JQueyc8HCkrTmhak5yZfR4xquFEC8qItpKmaHrABhhWkhewzUuqn58afuANtX8yez179xb/zaB6S8Dkj5AQgiX8tPeixixM8E8HXfFyhZ7KRbag9jZr84TXqG/C68Qrmz90fgZnmsb9vG+aRMOVaFXXGfu4snARsUf/yIdVgFJAiSEcBmHL0cA0Mn4O2UNp4lUPfnM2gGzyUR2n//MraTot/OlEK5s+MojZOQOo82zAZhrr89OtRij3iqFwZDwvHtQA6TD/EcSIPH85s+fT8aMGbUOI0n0GHN6ER1no9XcXZRQQulh+hmAL6ytCCcLfw+s+8TXSSdoIZJPVKyNW9FWhpnnkU25zUlHbsbamgHw3v0BCI+nv/NQEqB0pHXr1iiK8shP/fr1n/laf39/Jk6cmOCxZs2aceLEiRSK9l+StKR9t6PjKD5oLZF3oxhvno5ZsbPaXpHljurkzujh7PickNQACZGcbHYHJb5YS2PDNhobd2BTDfS0dqZAjqfdhOh3IkTpBJ3O1K9fn3nz5iV4zM3N7bn25eHhgYeHdEoVL+6tadsA6Gn6iaKGC1xTfehvbUufekVpUjbXE16l386XQrii+dtCycYthpnjvyO+tjfloFqQ0B41nvlaPdbESg1QOuPm5kaOHDkS/GTKlAlVVRk8eDD58uXDzc2NXLly0b17dyB+RfVz587x6aefOmuN4NGamcGDB1O2bFnmzp1Lvnz58Pb2pkuXLtjtdsaMGUOOHDnIli0bw4cPTxDThAkTKFWqFF5eXuTNm5cuXbpw9+5dAEJCQmjTpg0RERHO9x48eDAAsbGx9O7dm9y5c+Pl5UXlypUJCQlJsO/58+eTL18+PD09efPNN7lx40bK/MOKF3LmehQVlGN0MMav6dXP2o63qpeha+3C5Mnk+YRXKff/q78LrxCu5uz1KL5ceYTR5llkVKI44CjA17amNH3iDUi8B2efHpcVlRqg5KCqYI1O/fc1eyZbR9Cff/6Zr776isWLF1OiRAnCw8P5559/AFi2bBllypShQ4cOtG/f/qn7OX36NKtXr2bNmjWcPn2a//3vf5w5c4aXXnqJzZs3s23bNj766COCgoKoXLkyAAaDgcmTJ1OgQAHOnDlDly5d+Oyzz5g2bRpVq1Zl4sSJDBo0iOPHjwPg7e0NQLdu3Thy5AiLFy8mV65cLF++nPr163Pw4EGKFCnCzp07adu2LSNHjqRp06asWbOGL774Iln+vUTyCY+IwZMYxptnOKfZX++oQOjrTxhtIoRIdrXHhfCecRO1jf8Qq5rpae2MDROj/1f6qa9TFSU+C5IEKJ2yRsOIp2fJKaLfZbB4JeklK1ascCYQzt3064e7uzs5cuQgKCgIs9lMvnz5qFSpEgCZM2fGaDSSIUMGcuTI8dT9OxwO5s6dS4YMGShevDi1a9fm+PHjrFq1CoPBQEBAAKNHj2bTpk3OBKhHjx7O1/v7+/Pll1/SqVMnpk2bhsViwdfXF0VRErz3+fPnmTdvHufPnydXrvh/+969e7NmzRrmzZvHiBEjmDRpEvXr1+ezzz4D4KWXXmLbtm2sWbMmSf9mImVExlj55s+zTN54ki9N35PfcJWLqh9DbS0J6V3r2TuQFjAhkkXwsgPkVa44l5wZY3uXU2oeFrWvjJvJmKh9qDo8ESUBSmdq167N9OnTEzyWOXNmoqKimDhxIgULFqR+/fo0bNiQxo0bYzIl7SPi7+9PhgwZnH9nz54do9GIwWBI8NjVq/9OoL5hwwZGjhzJsWPHiIyMxGazERMTQ3R0NJ6ej2/+OHjwIHa7nZdeeinB47GxsWTJkgWAo0eP8uabbyZ4PjAwUBIgFxAdZ6PF7J0cvBRBTcM/fGDaCEAfa0f+V604/n6JSOxlGLwQL0xVVZbsOscPlpl4KzHscBRjrr0BAFUL+SViD/o9DyUBSg5mz/jaGC3eN4m8vLwoXLjwI49nzpyZ48ePs2HDBtavX0+XLl0YO3Ysmzdvxmw2Jz6k/2yrKMpjH3M4HACEhoby+uuv07lzZ4YPH07mzJnZunUrbdu2JS4u7okJ0N27dzEajezduxejMeEdyn9ruIRrUVWV4oPWApCJSMaaZwIwz1aP7Y4S/NC4RJL2J32AhHg+kTFWSg9eRyfjCiobjnFXdae3tSNVC2cluEGxpO1MmsDSKUVJclOUK/Lw8KBx48Y0btyYrl27UrRoUQ4ePMjLL7+MxWLBbrcn+3vu3bsXh8PB+PHjnbVEP/74Y4JtHvfe5cqVw263c/XqVV555ZXH7rtYsWLs3LkzwWM7duxIxujF81h35Mr931RGmb9xzjUyytacPz+rnYQ96ffOUwit3YyK4+Vh6ymhnKWnaSkAQ2wtuahmY8tHlR+Z8PBJ9Jf2/EsSoHQmNjaW8PDwBI+ZTCZWrFiB3W6ncuXKeHp6snDhQjw8PMifPz8Q37S1ZcsW3nvvPdzc3PDzS0zV6LMVLlwYq9XKlClTaNy4MX/99RczZsxIsI2/vz93795l48aNlClTBk9PT1566SVatGhBy5YtGT9+POXKlePatWts3LiR0qVL06hRI7p37061atUYN24cTZo0Ye3atdL85QImbjgJQDNjCPWMe4hTjXxi7UosFvJmTnqtpr4vwUJo4+Vh63Enlsnmr7EodlbZK7HUXhMg0clPAjqsAZJh8OnMmjVryJkzZ4Kf6tWrkzFjRmbPnk21atUoXbo0GzZs4Pfff3f2pxk6dCihoaEUKlSIrFmzJls8ZcqUYcKECYwePZqSJUvy/fffM3LkyATbVK1alU6dOtGsWTOyZs3KmDFjAJg3bx4tW7akV69eBAQE0LRpU3bv3k2+fPGzlVapUoXZs2czadIkypQpw7p16xgwYECyxS6ez9GwSPyVML4wfQfAONu7HFH9af7UWWYfR3nov0KIpOpv+p5ChjDC1Uz0s7YFFL5vVzlJ+1B1PBGioupx8H4Ki4yMxNfXl4iICHx8fBI8FxMTw9mzZylQoADu7u5P2INIj+Sz8XSHLkUwbMUR9p69yk+WwZQ1nGGbvTgtrP3I5OXOhp41E6wy/Sw7ln1NlQP9OeRRkZKfb0jByIVIG25Hx/HJ4v3UKZaNkN8XMNcyDoAWccH85ShFu+oFGJDE6ScuDilKHjWMYw2WUrTyaykRdpI87fv7v6QJTAiRKl6fshWAnqZllDWcIUL1pJe1MyqGp6719UTOUWCO5AtSiDSsw4K97Dp7k8MnTrHGbRYAs20N+ctRirMjGzonuX0eeqxJkSYwIUSKi46zAVBBOUZX468A9Le2JYwsfNFYJjwUIqWFXo9i19mbgMoY80z8lEiOOvIyzvYuO/vVee7kR9XxhFySAAkhUtyYNcfJQDRfmadjVFR+tldnhSOQ9q8UoE21Ai+0b0V/110hUtWyvy9Sa1wIAB8YN/CqcT+xqplPrN2IxYKPe+KnOnkSPfamkSYwIUSKUlWV+dtCGW+eT17DNS44svKFtTWhoxq92I5lIkQhEmXqplMAFFIuOWd7HmV7jxNqXgDczemzLiR9ljoZ6DHbFSlLPhOPV3rIOl43bOdt41bsqkIPaxf2D387Gd9B/t2FeJpLt+9hxsYk81TcFStb7KWYb68HQIvK+V6o74+TDq9/UgOURA9mNY6OjsbDw0PjaIQriYuLA3hkZur0zjvmCsPd5gAw1d6EvWoAJmNy3HvF70Nmghbi6WKsDj43LaWkIZSbqje9rJ3oUrsIfeoVfeF9P1gMVY9noSRASWQ0GsmYMaNzLStPT8/kyZ6FrjkcDq5du4anp2eS109LqyJjrHibDYw3T8dXiWa/oxCTbW9pHZYQ6crJK3eoYjhCR+MKAPpa23ONTLSrXjBZ9u/sBC01QEkzffp0pk+fTmhoKAAlSpRg0KBBNGjQ4LHbW61WRo4cybfffsulS5ecK4vXr18/wXZTp05l7NixhIeHU6ZMGaZMmeJc2Tw5PFiV/OEFPYUwGAzky5dM1ck6t+5wOB0W7KWz8Tc+Nx8hSnWjh7ULNkz4erx4h0t4ePSJEOJxgpcdYPWuI6xym4ZBUfnBVpuBvT9j1nPNuJ72aJoA5cmTh1GjRlGkSBFUVeXbb7+lSZMm7Nu3jxIlHl0QccCAASxcuJDZs2dTtGhR1q5dy5tvvsm2bdsoV64cAEuWLKFnz57MmDGDypUrM3HiROrVq8fx48fJli1bssStKAo5c+YkW7ZsWK3WZNmn0D+LxZJg1fv0ymZ30GHBXsopJ+llil/XbYitJaFqTt6tkId2ryTPnafkP0I83vSQ0+y/cIu1h8OZZZ5FLuUmpx05WZOnO82TPfmRGqDn0rhx4wR/Dx8+nOnTp7Njx47HJkALFiygf//+NGzYEIDOnTuzYcMGxo8fz8KF8T3bJ0yYQPv27WnTpg0AM2bMYOXKlcydO5e+ffs+No7Y2FhiY2Odf0dGRiYqfqPRKP09hPiPfy7exocoJpu/xqQ4+N1ehR/ttXi1aDbG/K9Msr+f9AESIqHRa44B8KFxPa8Z9xKrmuhu/Zhp7yRtmYukUHV4HrrM7ardbmfx4sVERUURGBj42G1iY2MfWWLAw8ODrVvjZ5iNi4tj7969BAUFOZ83GAwEBQWxffv2J773yJEj8fX1df7kzZs3GUokRPoTej2Kt6dvY7h5DnkN1zjvyEo/aztAYdw7yZz8SFOjEI94MBq1mHKOAabvARhla87SIR3Jn8Ur+d/vMb/pheYJ0MGDB/H29sbNzY1OnTqxfPlyihd//Myw9erVY8KECZw8eRKHw8H69etZtmwZYWFhAFy/fh273U727NkTvC579uyPrID+sODgYCIiIpw/Fy5cSL4CCpFOHLoUQa1xIbxrDKGxcQdW1Uh368fcwZPQUY2StM5Xkuiw6l2IlPLz35fwIIYp5im4KVY22ssxz14fT0sKN/jo8DzUPAEKCAhg//797Ny5k86dO9OqVSuOHDny2G0nTZpEkSJFKFq0KBaLhW7dutGmTZsX7nfh5uaGj49Pgh8hRNK8PmUrhZRLDDF9C8B42zvsVwun4Ds+WA1efxdeIVJK76X/MMi0gMKGy1xRM9LH2pHQUa+n4DvqtyZW8wTIYrFQuHBhypcvz8iRIylTpgyTJk167LZZs2bll19+ISoqinPnznHs2DG8vb0pWDC+U6Wfnx9Go5ErV64keN2VK1ecI7eEEMlLVVX8+67EjTi+Nk/BQ4njT3tJZtpfx9fDzIaeNbQOUYh0Yebm07xu2E5z0yYcqkIPa1c8MmZ/9gtfgJ6HwWueAP2Xw+FI0CH5cdzd3cmdOzc2m42ff/6ZJk2aAPHJVPny5dm4cWOC/W3cuPGJ/YqEEC9m0/H46SCCTYsoZjjPddWHnvdXed/Zrw6Fs2VIoXfW7yKMQiS34+F3WLBmCyPM3wDxk45ud5TA30+GvD+JpqPAgoODadCgAfny5ePOnTssWrSIkJAQ1q5dC0DLli3JnTs3I0eOBGDnzp1cunSJsmXLcunSJQYPHozD4eCzzz5z7rNnz560atWKChUqUKlSJSZOnEhUVJRzVJgQIvks2HGOgb8coq5hD61N6wDoZe3MNTLxUbUCuJtTcJSkdIIWgvVHrrD6YBi/7TvHUsvX+Cj32OsowqT7k44aU3xqjvjzUIcVQNomQFevXqVly5aEhYXh6+tL6dKlWbt2LXXr1gXg/PnzCfr3xMTEMGDAAM6cOYO3tzcNGzZkwYIFZMyY0blNs2bNuHbtGoMGDSI8PJyyZcuyZs2aRzpGCyFe3MBfDpGDG4wxzwJglq0Rmx1lmN+mIrUCkmferWeRNEikV1tOXKP9d3sA6GP6iXKGU0Sqnnxi7Ybt/td7cIMXX+4icfSXAWmaAM2ZM+epz4eEhCT4u2bNmk/sIP2wbt260a1btxcJTQiRCAYcTLRMI5NylwOOAoy1NePMiIYYDJKWCJHSFu8+D0BVwyE6G38HoK+1HRfVrLxSxI+5rStiTpZ1955Mz8PgZdEiIUSSRcfZuH4nju6mZVQxHOWu6s7H1o+xYkrF5Ef6AIn0zeGArNxmojl+qYtFttqsclQBoGiODCme/CSgwzYwSYCEEElyKyqOcsPWU91wkO/MywHob/2Ic2oOhjV5dAb3FKPIMHiRfsVY7aw7fJmF5q/JptzmuCMPQ20tyeRp5r1K+ehWOyWnoPiXquO+eJIACSGSZN62ULJxi4nmqc67zl8d1anon4kPA/21Dk+IdKHowDV8alpGVWP8YsNdrJ8QgxuH+gdhSs2aH2cnaP3diEgCJIRItBirnakbj7HIMgU/JZIjjvwMsbUC4J7VnsrR6Hf+ESFexLbT16luOMjHxgc1sG05rebm2LD6qZz86JskQEKIRNsdepOepqVUNhzjjupBV2t3Yolf4sKSyhdeHde8C/HcrkTG0GP2Gla5/VsD+4ujOkDKTjvxBHqeCFESICFEomw5cY2582cx3/IbAH2t7SkYUIY+5fMwccMJRr1dOlXjUZ1LYQiRPty4G8vMkONM+U8N7PuV81EspyzhlFSSAAkhnmn5vouMWfIHK92mAfCdrS4rHVUIUqBhqZw0LJVT4wiFSNu+33mO/ssP0ce0mMqmY9xV3Z01sCPeLKV1eKg6HIwgCZAQ4qkG/3aYhdtOscQymczKXQ46/PnS9gEATcvl1jAyGQYv0oebUXH0X36IWob9dDX9WwN7VpUbjxchCZAQ4on+OnWd+dtCCTYtobzhJJGqB12tn/Bzt9rE2uyUz59Js9ge9AGSYfAirZu88SQ5ucEEc3wN7AJbECsc8etbtqicT8vQpA+QECJtavHNToIMe+loWglAH2tHXipailJ5fDWOTOp9RNrncKi8N2sHf4defWwNbM+6L9Gmmr+2QTprYh2aRvE8JAESQjwi4p6VhpP+JK9yhfHm6QDMtdVnraMSZz6soHF098lEiCKNm7HlNLtCb9LvPzWwpfJnp2vtwtQumjrr7T2VjkchSAIkhHhEmSHrcCOOZZaJ+CrR7HcUYqTtfQCXWedL0fOVV4hEGLPmOA0NO+jwUA3snB7vUCR7Bo0j+5eq49XgZcYkIUQC205dB1SGm+dSwnCO66oPneN6YMXE4g5VtA7PSZUESKRhNruDwspFxppnAjDD9jprHZVcKvnRO6kBEkI42R0q73+zkxbGjfzPuAW7qvCx9WPCyMJffV8ld0YPrUMUIs0LvR7F6+NW8avlK7yUWLbZizPW1oyyeTNqHdqT6bAKSBIgIQQAUzedYuza45RTTvKF6VsAxtjeo0PL1ix8KStGF2n6+tf9PkA6vPAK8Th3YqzsPXeL1vN2Md08k0KGMMLUzHxs/Zhe9YvTtnoBrUNMUyQBEkIQFWtj7NrjZCGCaZZJWBQ7q+0VmWl/nWBX6Gj5GP8uhSEJkEgb2s7fw67Qm3Q0rqCBcTdxqpEucZ9wA1+61Eqd1d2TSs/D4KUPkBDpnMOhMnPzaYzYmWKeQk7lJqcdOelj7YgrD/HQ3+VWiCeLsdrZFXqTQMNhPjMtBmCIrRX71CIaR/Z0qo4nJJUaICHSsRNX7vDaV1sA6GtaQlXjEaJUNzpaP+UuntQOyKpxhE8hw+BFGtJj8X5ycoOvzZMxKio/2Wvwvb0OAN99VEnj6J7Mmf7osAZIEiAh0rEHyU99wy46mVYA8UNtT6l52B78KtkyuGsZnhDpxh+HL/CjZSJZlDscduSnv/UjTg5viNno2g01eh6NKQmQEOlcIeUS48wzAJhla0R0kcacaVXRZeb7eTJXj0+IxIm4Z+UL03eUNZzmtupFR+unvF25sMsnP3onCZAQ6dT6I1fw4S6zzePxVmLYbi/OaNt7HG9ZQQfJjxBpw5Ld5znwy1cMN2/EoSr0sHblopqNwY1LaB1a4igPJkKUJjAhhA7E2ux0/G4X88xfU9AQzkXVj27Wj/n145qYdHLX+aDqXfoACT3aE3qTP45dZffmlSyyxE87Mc72LiGOsvz5WW0sJn2ch3omCZAQ6Yiqqqw9HE6nhX8TbPqBmsYD3FMtdIjrSeOqZSiZW/tFThNLUfQ7+kSkX/2WH+RqZCwbjl4hN9f41W0iZsXO7/YqTLO/wa9dq5E3s6fWYSbag7NPkcVQhRCubMbmM4xec4ymhq3OFd57WzvRsO5rdHbReUaeTJrphL6oqsqinecBcCeWWZYJ+CmRHHL408fakWPDGuBuNmocZVLp9zyUOjYh0onf/rnM6DXHKK2cZrR5NgBf25qw0lGFygWzuOBMz4kjM0ELvbA7HnxWVcaaZzrX2usQ15N3A1/SYfLzLz32AZIESIh0ovsP+8jKLWZZJuCmWFlvf5nxtncAyKejKncnfeZrIh27fc8KQBfjbzQ27sCqGukc14PL+DG0SUmNo3s+qo6XpJEESIg0TlVVOi7YgwUrMywTyaHc4qQjN59au6BiYFmXqmT30eN8P8pD/xXCtR24eJsKX27gVcPf9Db9CMAXttbsVosyp1UFjaN7cfpLf6QPkBBp2qFLEbw+ZSugMto0j/KGk0SonrS39uQunpwd2fChzsRCiJSweNd5+i47SCHlEpPMUzEoKgtsQSyy18HP2406xbJrHeIL0O/1QxIgIdIoq91xP/mBj4xraGYKwa4qdLN2J1TNyVfNyug8+ZFRYMK1Xb8bS4NJf3LtTiwZucM35nFkUO6x01GUobaWBBbMwtzWFbUO88Xody1USYCESKvuWe0AvGr4mwGmhQCMsL3Pn47SrOxenRK59DPk/bGUB//T4ZVXpHkOh8qwFUe4dicWMzZmWCZSwHCFi6ofneN6UCxPFha1r6zzm5CHh8Hr7zyUBEiINGri+pMUU84xxTwFg6KyyFabJp2G857FRJHsGbQOLxno+4tDpF1XI2OoNGLj/b9URpi+oYrhKHdUDz6K68NNfPi7W3VNY0w+92eClgRICKG1a3diqTh8A1m5xa9uY/FSYtlqL8EgWxtO5c2kdXgpQH8XXpG2zdl61vl7Z+PvvGPa4mx+PqHmZcXHaSX5eYgO28AkARIiDem26G9WHAjDnVi+sYwnl3KT046cdLF+gi2tne46bzoQade1O7EANDDs5HPzYiB+xNdmRxlmt6ygqxnXn0VWgxdCaO7cjShWHAhDwcEE83TKGM5wU/WmjfUzIvGmc61CWoeYrJT//F8IV7Fs3yVKK6f5yjwNgHm2eiy01+XwkHp4uaWtr91/hyJIDZAQQiO/7b8MQB/TjzQ07iJWNdExrifn1eyMebs071bMq3GEyUvPd54ibZqw7jiT/zhFLq7zjWU87oqVP+xlGWb7kOktXk5zyQ88PBGixoE8h7R3NIRIh9YcCmP8+hO8Ywyhi+k3AD63dmC3WpRjw+rreor9J9Px+FuR5py7EcXkP07hxT3mWMaSTbnNUUdePrZ+zNctKtCgVE6tQ0wZD05DHdYAyUzQQujcnRgrnRb+TaDhMMNNcwCYbGvKL474jpZpM/n5twuQHoffirRny8nrGLEzxTyFYoYLXFN9aRvXhyg8aJhWk5+H6fBGRGqAhNCp8IgYfv/nMsNXHaWocp6Z5glYFDu/26vwle1/AHz3USWNo0w50gQmXMGcrWeZ99dZLt6KZpRpDq8a93NPtdAurheX8aNKwcxah5ii9HweSgIkhE69O3M7529Gk5MbzLOMwef+DLO9rZ14Kbsvy7pUTZN9Dv5LaoCEVk5eucOwFUcA6G5cznv3Z1v/2Pox/6iF+ax+AJ1qpK3BB0+ix/Mw7V8dhUiDYm12zt+Mxoco5ltGk1O5yQlHbtrH9SQWC2t6vKL7GWafKa2XT7i06Dgbdb/aAsA7xhB6mn8CYJCtDfcKvkZouyoaRpea7k+EqL/8RxIgIfRm3NrjfL3pFBaszLJMIMBwkXA1E63jPsdq9mXme2XTfvKDDH8X2io+aC0AtQz7GWn6BoCvbU343h6UjpKfh+kvA5IESAgduRNj5etNp1BwMN483Tm9fpu4z3g3KJCPXy2C0ZBeUoP0Uk7hSlRVpcU3OwEopZxhqnkSJsXBz/ZXGGd7lwGNimkcYepSFf0uSiyjwITQkUrD49cXCjb9QGPjDuJUIx2tn3JUzU9QsezpKPn5lx77Hgj92nziGttO3yCvcoW5ljF4KbFssZeir7U9WbzcaPdKQa1D1IQ0gQkhkp2qqiiKwokrd7hntdPGuJoOppUA9LF2ZJujJAD5snhqGWbqu3/nKQmQSA2qqhJy4hp/n7tFJiL51jyarEokhx356WL9BCsmOtVMHx2eE9LveSgJkBAu7MbdWBpM+pOGpXIyf1sobxj+4gvzAgBGW9/jV0d1mpTNRXCDYvi4mzWOVoi0a8WBMD7+YR9e3ON7yxgKGsK5qPrRJu4z7hJ/8/FR9QIaR6kdPdYASROYEC7su+3nuHonlvnbQqll2Md48wwA5tteY7q9MQAGRSGHr7uWYWpMh1deoTuf/XQAC1ZmmidQ9v46e63iPucqmQAY0KhYumyCVtFvHyCpARLChan3b6sqKMeYYZ6IWbGz3F6NIbaWPKh6rls8u4YRaigdjHQT2ouOsxFxz0qs1crX5qlUNx7mrupO67jPOa3mJoePO0s7BZI3czprgk4DJAESwsWEHL+KfxYv9p67xeQ/TlFMOcdcyzjcFSsb7eXoY+3I0WENibU6OHH1DhXyZ9I6ZI0oD/1XiJRRafhG7sZaGWX6xrnIcAdrTw6o8f19fuocSJ5MkvxIDZAQ4oXsCb1J63m7nX/nV8L5zjIKHyWaXY4Aulq7079xadzNRtzNRir6p+1p9p9Gz1PwC30Ii7jH3VgbfU2LnbM8d7d+7Bx40KJyPkl+FJkIUQiRDNYfueL8PTs3WWgeSVYlgiOO/LSL600MbrSpln47Wj6WHq+8wqXZ7A7enr6Nfy5G0NH4O51MvwPQ19aetY6KAJz4sgEWk3SjfUBGgQkhXsjMLWcA8OUu31lGkddwjbOO7LSM60skXnzTsoLGEboORYbBixRSdOAabA6VZsZNBJt/AGC49X2W2muxtkcNAnJk0DhC1+GsidXhjYgkQEK4iB93XwDAi3vMt4xxLnHxobUf1/EFoGy+jBpG6Foc96+3cXaHtoGINCPO5uBenB2bQ6WhYQcj7i9xMd3WmNn21/mlazVJfv5Dzw3RkgAJ4QIG/3aY+dtC8SCGuZaxlDOc4pbqzYdxwVxUs6IosLt/EH7eblqH6jK2nrpOVa2DEGlGjNVOzbGbuBIZS13DHiaZp2JUVBbZajPa9h6L2lWmbN6MWofpcvRcAyQNmEJobNvp68zfFoobcXxjHk9lwzEiVQ8+jOtL13dfp3hOH5Z3qSbJz38UzeGjdQgiDdl49CpXImOpZdjPVPMk55QTA2xtmde6ElUL+2kdoou63wla4yieh9QACaGx/ssPYcHKDPNXVHtojpFv+3cgi7cbTcvl1jpEl1S5YBbYLX2AxIu7eCuarov+pqrhEDPMX2FR7KywV6a3tRMODNQumk3rEF2eHs9DqQESQmMXrkfwtXkytY3/cE+18FFcH277lSOL1Pg8lZvZ6PzdJv2AxHPae+4m1UdvoqJyjG/M43FXrKyzl6eHtSt2jLz9ch6tQ3Rp0VY7AOduRGscSdJJDZAQqchqd6AAJqOBsIh7TF53lInmqbxm3EusaqadtRe71GJU9UnPS1skjpt7/Pwr3txj2d6LvFspn8YRCT25dPse+87fotuifZRTTjLPMgZPJZYQexm6Wbvzxsv5aRnoT/Gc0tT6NDdjDWCEo+cuYbU7MBv1U6+in0iF0Dm7QyVowmaKf7GWe3F2qo3cQMUDA3nduJM41UhHaw/+cpQCYPTbpTWO1vW5ZS2EQ1XwVaIZs2yr1uEInak26g+6LdpHCeUs31pG463E8Je9BB2tnxKHmRFvlqJs3owy188znFFzAFBIucyYNcc0jiZp5MgKkUpuRsVx7kY0cTYHxQetYrhpDm8Zt2JVjXS1fkKIoxw5fNw5MrSerCuUCAY3T0LV+HXQyhpO4XDorw+C0MaFm/HNNQHKeRZaRjpnWm9n7UUsFgDcH2piFU92Qs0LQDnDaWb/eVbjaJJGEiAhUonqHCaqMtj0Lc1Nm7CrCj2sXVnviJ/gcEnHKnhapGU6sTY7ygDwmmEPBfut4ps/z2CV/kDiGV4Zs4lCyiW+t4wgk3KXfY7CfBTXh3tI03NSla3ZFLuqUMxwnrzKFfz7riTinlXrsBJFEiAhUkmszQGo9Dd9TyvTehyqQi9rZ1Y6qlDAz4uJzcqSP4uX1mHqyk6PVwB4w7iNbNziy5VHmXV/Nm0hHmf4yiPkV8JZZBmOnxLJQYc/reI+5y7/1rq2qCz9yRLr9col2eYoAUBb42oAei/9h8gYK7vO3nzoxs/1KKorR6eRyMhIfH19iYiIwMdHOsCJF7fp2FXazN9Fb9OPdDP9CsDn1vYssdcG4I9eNSmY1VvLEHXpWFgEd6YHUdFwgvX28nSwfoqKgY41ChLcsBgOh4rB8GCxRpVeS//Bw2xk+JulNI5cpLY9oTcZs/Y4l0OPs8QylNzKDY468tI8bgC3yUCZvBlZ2LYS3m4m5zIrInGa9xvDD5bh2FQD78YN4m/1JedzHWsWZP2RK/h5uzG8aUmKZE/ZmbST8v0tNUBCpLAYq50283fT3bjcmfwMtLZ2Jj9j/ldakp/nVDSnL4OtrYlVTdQ17mW4aS5G7MzccoaP5u+mYL9VtJ63i6//OElYRAzL/r7E9zvPc/VOjNahi1S05lAY/5uxnQtnT/KD+UtyKzc45cjFB3H9KFm4AMu7VOXXrtXI4G6W5Oc5bHeU4Dd7ICbFwTeWcZRU/q2Fnbn5DGeuRbHr7E3qfrVFwygfJZ0NhEghkTFWSg9eB0An42/0NP8EwDBrCxbYXwNg5oflqVcih2YxpgWHVX/6Wtsz3jyD901/UNRwnoHWNvxxf0BKyPFrhBy/Rpzt375BdcZv5uDgehpFLFKD3aHSbdHflMzty9i1x8nGLRZZvnQuMPx+XH+mdqhHlYJZtA5V99Z9WoO3voomn3KVsobT/GwZzCTb28y11yeGhPOZjVt7nMxeFt4sl5tMXhaNIo4nNUBCpJAlu+IXN21rXEVf82IAxlibMcfeCIDsPm6S/CST5Y5X6GL9hEjVg5cNp1jp1p/55tE0NmwjA/Ejfib/ccq5/Z0Ym1ahilSy9dR1Vh8KZ+za4/gRwSLLcAoYrnDekZX34wZwlUyS/CSTl7Jn4C6efBgXzHr7y7gpNj4zL+FPtx58bvqBosp5HiyW8fWmUwxdcYTui/dpGzRSAyREsguLuMfFW/f4etMpPjCuZ6B5IQATbW8xzd6EygUy87/yeaheRNYWSg55Mnlw8dY91jgqcTC2AL3NP9LEsI1axn+oZfwHu6pwUC3IfkchTqh5OeHIzSG1gNZhixRmvV/jl4lIFlpGUNhwmUtqFt63DiAMSXySW+dahdh8/Brtw3rxlv1PPjX9TF7DNTqbfqez6XeuqT7schTlmCMfJ9Q8nD6Viy2Hc1KjhHYdzqUT9GNIJ2jxvO7F2Sk2aA0AzYybGG2eDcA02xuMsTUjsKAfC9tVxmiQfgbJJcZq5/d/LlMzICvTQ04z769Q8ivhvG3cwuuGHRQ0hD/ympOO3BQZchikv0eatfnENbrP/YNFluGUMJwjXM1Es7iBnLs/cd/c1hV4tWh2jaNMWxwOlYL9VgFgxsarhr/5n/FPqhsO4qHEPbL939nf5uXOc5M1Bt10gp4+fTqlS5fGx8cHHx8fAgMDWb169VNfM3HiRAICAvDw8CBv3rx8+umnxMT826Fx8ODBKIqS4Kdo0aIpXRQhADh59Q4Abxm2MNL0DQDf2BowxtYMUPimVQVJfpKZu9nIOxXyki2DO4NeL05mLwvn1BxMsL3Lq3ETCIyZQo+4Lsy0NWK/oxAARQyXwGHXOHKREiKirRy4eJtuc0P4zjKKEoZzXFN9aRHXj6um3PzStRqnRzSU5CcFGAwKx7+sTwZ3E1ZMrHVUor21F6Vjv+F/sYMYYW3OT/YaHHAU4I7qwUW0PQaaNoHlyZOHUaNGUaRIEVRV5dtvv6VJkybs27ePEiVKPLL9okWL6Nu3L3PnzqVq1aqcOHGC1q1boygKEyZMcG5XokQJNmzY4PzbZJKWPpHyvlp/gkkbT1LfsIux5pkYFJVvbXX50vYBEJ/0eLnJZzElKYrCzn51mP3nGVQVrkTG8N12+MVRnV8c1fHlLv+4dwDA4XBgkMl+05wqIzeiWqNZYBlDGcMZbqretIjrx2k1N6HD6msdXprnZjKytkcN+vz0D++Uz0vWDG60+GYne9Si7LEXBed9h0rxGC/e0DBWTa/GjRs3TvD38OHDmT59Ojt27HhsArRt2zaqVavG+++/D4C/vz/Nmzdn586dCbYzmUzkyCGdS0XquXYnlkkbTxJoOMwk89cYFZXFtloMtrXiQfIztMmjn2mR/MxGA11qFQbim8fyZfbky5VHAfB2//eS51BVGQWSBlmtscw0T6ai4QQRqicfxPXjhJqXr98vp3Vo6UaujB58366K8+/DQ+rRddHfhBy/9tBWCmXya9sP0mVuR+12O0uXLiUqKorAwMDHblO1alUWLlzIrl27qFSpEmfOnGHVqlV8+OGHCbY7efIkuXLlwt3dncDAQEaOHEm+fE/uaBUbG0tsbKzz78jIyOQplEjzDl6MYPDvh7kdHUdJ5QyzzeNxU2ystlekn60dGdwtRMbY+KlTIBX8M2sdbrrjbjbS7pWCeFpMLNp1jnnvlYep8c+pSPfHtGL5votk8XLDy2JgtHkWdYz7iFHNfBTXhyOqP8eG1Ze1vTTk5WZiYrOyDFtxlJ//vsiHVfLjYTHS9f6NilY07wR98OBBAgMDiYmJwdvbm0WLFtGwYcMnbj958mR69+6NqqrYbDY6derE9OnTnc+vXr2au3fvEhAQQFhYGEOGDOHSpUscOnSIDBkePwPl4MGDGTJkyCOPSydo8TS3ouIoN2w9AAWUMJZahuCnRLLNXpw21s+IxcLhIfUIi7hH4WwpO/upSJyIm9fxnRzfD8ja7wpmi6z9pHenrt4laMJmAPqZvqeDaSU21UB7ay82OeJrfUJHNdIyRPGQh2dnTwm66QQNEBAQwP79+9m5cyedO3emVatWHDly5LHbhoSEMGLECKZNm8bff//NsmXLWLlyJcOGDXNu06BBA9555x1Kly5NvXr1WLVqFbdv3+bHH398YgzBwcFEREQ4fy5cuJDs5RRpS4zV7kx+fLnLXPMY57pCHaw9icVC5QKZ8XIzSfLjolRZPV73tp687kx+PjCup4NpJQCfWTs4k58cPpLkupKUTH6SSvMmMIvFQuHC8dVg5cuXZ/fu3UyaNImZM2c+su3AgQP58MMPadeuHQClSpUiKiqKDh060L9/fwyGR/O5jBkz8tJLL3Hq1KlHnnvAzc0NNze3Jz4vxH+FR8SPPDRhY6p5EgUMV7io+tHm/qKKY/9XmvolpR+ay3no4qsiq8br3Qdz4vt/BhoOM9j0LRA/2egyRw2yeFloUjY3Hwbm1zJE4cI0T4D+y+FwJOiP87Do6OhHkhyjMb5d90kteXfv3uX06dOP9BMS4kU8mD6mv+l7qhsPE6W60S6uN9fxZVPvWhTwk1XdXZGs85R23IqKn1cmr3KF6eaJmBQHy+zVmWaPH1e0s18dTEbNGzmEC9M0AQoODqZBgwbky5ePO3fusGjRIkJCQli7di0ALVu2JHfu3IwcORKIHzU2YcIEypUrR+XKlTl16hQDBw6kcePGzkSod+/eNG7cmPz583P58mW++OILjEYjzZs316ycIu1xqFDXsIc2pvjP6qfWLhxT82ExGST50QlpAtO3ehO3YMLGZPNUMipR7HMUJtjaDj9vd/YMCNI6PKEDmiZAV69epWXLloSFheHr60vp0qVZu3YtdevWBeD8+fMJanwGDBiAoigMGDCAS5cukTVrVho3bszw4cOd21y8eJHmzZtz48YNsmbNSvXq1dmxYwdZs2ZN9fKJtOnX/ZcYvngTa9xmATDT1oh1jop0q12YN1/OrXF04mmk/iftuHonlp6mZZQznCJS9aRrXHdisbCzZw2tQxM6ofkoMFckS2GIp/Hvu5JJ5q9pYtzGIYc/b8YN5cTIN6R5RQfuRNwkw1fx64DFfHYRd0/poK5XdYJnscbSF7Nip2tcd1Y6qtCr7kt8XKeI1qEJDelqFJgQenLhZjQVlGM0MW7DoSp8bu2AFZMkPzqhPGaghNCfbaev84XpO8yKnXX28qx0xE+6J8mPSAq5GgiRBMv+vkQ3068ALLbX4rDqr21AIkkeTlOlD5B+jfpmETWMB4lTjQyzfQBAd0l+RBK53CgwIVzZ0o1b+cTtHxyqwoz7o022fl5b46hE4j08DF4SIL1qYdwIwO+OQPzyBrCwWVnyZ5HBByJpJAESIglqGA4CsFsN4LyanTU9XiFPJk+NoxKJpSSYhE0SIF1SVWoa/wHgD8urLO9STeOAhF5JE5gQSVBCCQVgtyOADjUKUjSHdJLXK2kC06eYiCvkUG4B0Oo9md5EPD9JgIRIgly+ZgCiVTdeLZpN42hEUilyydO9LcfDAbCpBtzcpfZVPD+5GgiRBA8aUErl9qVKwSyaxiKS7uHBetIHSJ/cTf9+bRXK5q1hJELvktQH6Pbt2yxfvpw///yTc+fOER0dTdasWSlXrhz16tWjatWqKRWnEC5Buf+lmVc6XOrTQxmQzICmT1m8LACoKHi7STdW8fwSVQN0+fJl2rVrR86cOfnyyy+5d+8eZcuWpU6dOuTJk4dNmzZRt25dihcvzpIlS1I6ZiGEeHGSAemaTL0lXlSi0udy5crRqlUr9u7dS/HixR+7zb179/jll1+YOHEiFy5coHfv3skaqBBCvLiHh8ELfVLv/1cyIPFiEpUAHTlyhCxZnt7fwcPDg+bNmzvX4RIibZOLrx7JMPi0Q46eeFGJagLLkiULK1aswOFwJGqnz0qWhNAr5UGzieQ/uqQ8XAMkTWD6JMdNJJNEjwJr2rQpefPmpX///pw6dSolYxJCByQD0qcEw8CEDj1IXKUJTLyoRCdAZ8+epWPHjixevJiAgABq1qzJggULuHfvXkrGJ4RLUeRbU9ce7jirSE2CTslxE8kj0QlQ3rx5GTRoEKdPn2bDhg34+/vTuXNncubMSadOndi9e3dKximEi3hw8ZW7T11SZC0w/ZNzUCSP55oIsXbt2nz77beEhYUxduxYDh48SJUqVShTpkxyxyeEEMkm4VemJEBCpGcvNItUhgwZqFOnDufOnePYsWMcOXIkueISwrXJJCS6pCj/3vNJC5hOOfsACfFinqsG6N69e3z33XfUqlWLIkWKsHjxYnr27EloaGgyhyeEq5Hqd11LsBaGfIXqmXSCFi8qSTVAO3bsYO7cufz444/ExcXx1ltvsWHDBmrXrp1S8QnhUuSSq28yC5AQ4oFEJ0DFixfn+PHjlCtXjpEjR/L+++/j6+ubkrEJ4bqkCUynHp4HKHHzmgnX8qDiTmqAxItKdAIUFBTEDz/8IB2dRTon9QZ6liBvlSYwnZLjJpJHohOgyZMnp2QcQuiD3H3qmmJ4qBO0hnEIIbSXqE7Q9evXZ8eOHc/c7s6dO4wePZqpU6e+cGBCuCKZCDEtkWOpS9J0KZJJomqA3nnnHd5++218fX1p3LgxFSpUIFeuXLi7u3Pr1i2OHDnC1q1bWbVqFY0aNWLs2LEpHbcQGpFRYGmFtIDpkyKrwYtkkqgEqG3btnzwwQcsXbqUJUuWMGvWLCIiIgBQFIXixYtTr149du/eTbFixVI0YCFcgnSC1i2HqmBQVKQGSIj0LdF9gNzc3Pjggw/44IMPAIiIiODevXtkyZIFs9mcYgEK4Uok7RFCY7IYqkgmzz0TtK+vrwyDF+mX1ADplrPexyE1QHokR00kl+eaCVqIdEs6jqQhcix1SZV+eCJ5SAIkxHORi69ePWg6kfRH3+T4iRclCZAQSSDD4NMOVWrzdEqOm0gekgAJkSRS/a530nlW52QyUpFMnisBun37Nt988w3BwcHcvHkTgL///ptLly4la3BCuCy59urWgxRW1gITIn1L8iiwAwcOEBQUhK+vL6GhobRv357MmTOzbNkyzp8/z3fffZcScQrhEqQJTAityTB4kTySXAPUs2dPWrduzcmTJ3F3d3c+3rBhQ7Zs2ZKswQnhuuTiq1/3O0FLHyBdksMmkkuSE6Ddu3fTsWPHRx7PnTs34eHhyRKUEEII8Xj3MyC5BxEvKMkJkJubG5GRkY88fuLECbJmzZosQQnh8mQiRN1yNp1IVYKuSROYeFFJToDeeOMNhg4ditVqBeLXAjt//jyff/45b7/9drIHKIQrUWQUWJohnaD1SZHEVSSTJCdA48eP5+7du2TLlo179+5Rs2ZNChcuTIYMGRg+fHhKxCiE65BZaHVPvj717UHiKjVA4kUleRSYr68v69evZ+vWrRw4cIC7d+/y8ssvExQUlBLxCSFEsnLOBC2ZkBDp2nMvhlq9enWqV6+enLEI4fKUR34RQqQuyVxF8khyAjR58uTHPq4oCu7u7hQuXJgaNWpgNBpfODghXJdkQHolnaD1TY6aSC5JToC++uorrl27RnR0NJkyZQLg1q1beHp64u3tzdWrVylYsCCbNm0ib968yR6wEFqSiRDTDsl/9EmRiRBFMklyJ+gRI0ZQsWJFTp48yY0bN7hx4wYnTpygcuXKTJo0ifPnz5MjRw4+/fTTlIhXCNcgw+DTAMmA9EwSIPGiklwDNGDAAH7++WcKFSrkfKxw4cKMGzeOt99+mzNnzjBmzBgZEi/SKPnSTDtkGLwuySkokkmSa4DCwsKw2WyPPG6z2ZwzQefKlYs7d+68eHRCuBiZB0j/pOZA3x4sYSLHUbyoJCdAtWvXpmPHjuzbt8/52L59++jcuTOvvvoqAAcPHqRAgQLJF6UQLkcuvnrlHAbvkKoEPZMzULyoJCdAc+bMIXPmzJQvXx43Nzfc3NyoUKECmTNnZs6cOQB4e3szfvz4ZA9WCO3JOkRphaQ/eqU+9F8hnl+S+wDlyJGD9evXc+zYMU6cOAFAQEAAAQEBzm1q166dfBEK4UqcV13JgPRKfcxvQk/kuInk8dwTIRYtWpSiRYsmZyxCuDxJe9IA5zRA8kWqS9IHSCST50qALl68yG+//cb58+eJi4tL8NyECROSJTAhXJpce3XrwRenzOkkRPqW5ARo48aNvPHGGxQsWJBjx45RsmRJQkNDUVWVl19+OSViFMKFyCiwtELSH72Sc1AkjyR3gg4ODqZ3794cPHgQd3d3fv75Zy5cuEDNmjV55513UiJGIVyQXHz1S5bC0DU1wf+EeG5JToCOHj1Ky5YtATCZTNy7dw9vb2+GDh3K6NGjkz1AIVyJTMOvfw++OCX/0Ss5cCJ5JDkB8vLycvb7yZkzJ6dPn3Y+d/369eSLTAgXJithpAXyRapHirMGSE5C8WKS3AeoSpUqbN26lWLFitGwYUN69erFwYMHWbZsGVWqVEmJGIVwIdL/QO9kNXh9k6MmkkuSE6AJEyZw9+5dAIYMGcLdu3dZsmQJRYoUkRFgIs2TtCftkC9SvZKbEJE8kpwAFSxY0Pm7l5cXM2bMSNaAhNADVa69uuUcBi81QEKka0nuA1SwYEFu3LjxyOO3b99OkBwJkTbFf2lK/qN/kv7o1f2BCHISiheU5AQoNDQUu93+yOOxsbFcunQpWYISwvXJ1Ve/7i+GKjVAuqRKJ2iRTBLdBPbbb785f1+7di2+vr7Ov+12Oxs3bsTf3z9ZgxPC1SgyDb/uyVpg+iYzeIvkkugEqGnTpgAoikKrVq0SPGc2m/H395cV4EU6cL8JTMbB654qX6T6JDchIpkkOgFyOBwAFChQgN27d+Pn55diQQnh+uTiq1fSCVrfJHEVySXJo8DOnj2bEnEIoQuS9qQdkv/onZyN4sUkKgGaPHlyonfYvXv35w5GCN2QJjAde9AJWuMwhBCaSlQC9NVXXyVqZ4qiSAIk0jTpgCmEtv4diCDEi0lUAiTNXkLEk4uu/jkXQ8WhaRzi+cg5KJJLkucBepiqqjKXhkhXFJmGX/dk9JDOqXIOiuTxXAnQd999R6lSpfDw8MDDw4PSpUuzYMGCJO9n+vTplC5dGh8fH3x8fAgMDGT16tVPfc3EiRMJCAjAw8ODvHnz8umnnxITE5Ngm6lTp+Lv74+7uzuVK1dm165dSY5NiMdRHvlF6JbcvOmUDIMXyeO5FkMdOHAg3bp1o1q1agBs3bqVTp06cf36dT799NNE7ytPnjyMGjWKIkWKoKoq3377LU2aNGHfvn2UKFHike0XLVpE3759mTt3LlWrVuXEiRO0bt0aRVGcC7EuWbKEnj17MmPGDCpXrszEiROpV68ex48fJ1u2bEktrhBPIBdfvZLV4IUQ8BwJ0JQpU5g+fTotW7Z0PvbGG29QokQJBg8enKQEqHHjxgn+Hj58ONOnT2fHjh2PTYC2bdtGtWrVeP/99wHw9/enefPm7Ny507nNhAkTaN++PW3atAFgxowZrFy5krlz59K3b98klVWIR8iXphAakxogkTyS3AQWFhZG1apVH3m8atWqhIWFPXcgdrudxYsXExUVRWBg4GO3qVq1Knv37nU2aZ05c4ZVq1bRsGFDAOLi4ti7dy9BQUHO1xgMBoKCgti+ffsT3zs2NpbIyMgEP0I8lQyD1z3pvyhE+pbkBKhw4cL8+OOPjzy+ZMkSihQpkuQADh48iLe3N25ubnTq1Inly5dTvHjxx277/vvvM3ToUKpXr47ZbKZQoULUqlWLfv36AXD9+nXsdjvZs2dP8Lrs2bMTHh7+xBhGjhyJr6+v8ydv3rxJLodIH5ydoCUBEkIbkriKZJLkJrAhQ4bQrFkztmzZ4uwD9Ndff7Fx48bHJkbPEhAQwP79+4mIiOCnn36iVatWbN68+bFJUEhICCNGjGDatGlUrlyZU6dO8cknnzBs2DAGDhyY5Pd+IDg4mJ49ezr/joyMlCRIiDTq36YT+SLVI1kKQySXRCdAhw4domTJkrz99tvs3LmTr776il9++QWAYsWKsWvXLsqVK5fkACwWC4ULFwagfPny7N69m0mTJjFz5sxHth04cCAffvgh7dq1A6BUqVJERUXRoUMH+vfvj5+fH0ajkStXriR43ZUrV8iRI8cTY3Bzc8PNzS3JsYv0R4bB65/0HdE35f4pqEotrHhBiU6ASpcuTcWKFWnXrh3vvfceCxcuTJGAHA4HsbGxj30uOjoagyFhq53RaATi2/MtFgvly5dn48aNztXrHQ4HGzdupFu3bikSr0if5NKrf6pDahL0TBJZ8aIS3Qdo8+bNlChRgl69epEzZ05at27Nn3/++UJvHhwczJYtWwgNDeXgwYMEBwcTEhJCixYtAGjZsiXBwcHO7Rs3bsz06dNZvHgxZ8+eZf369QwcOJDGjRs7E6GePXsye/Zsvv32W44ePUrnzp2JiopyjgoTIjnIxVfP7q8FJk0pOiXHTSSPRNcAvfLKK7zyyitMmTKFH3/8kfnz51OzZk0KFy5M27ZtadWq1VObmR7n6tWrtGzZkrCwMHx9fSldujRr166lbt26AJw/fz5Bjc+AAQNQFIUBAwZw6dIlsmbNSuPGjRk+fLhzm2bNmnHt2jUGDRpEeHg4ZcuWZc2aNY90jBbiechaYEJoS0bvieSiqC/waTp16hTz5s1jwYIFhIeHU79+fX777bfkjE8TkZGR+Pr6EhERgY+Pj9bhCBdy5MtAituOcLD6VEoFfaB1OOI5hA0pTE71Gscb/0JA+dpahyOSaN/mXym3qSXnjPnJP/CA1uEIF5OU7+8XWguscOHC9OvXjwEDBpAhQwZWrlz5IrsTQgdkGLzeSfOlvinIavAieSR5GPwDW7ZsYe7cufz8888YDAbeffdd2rZtm5yxCSFEipGmFJ2SwyaSSZISoMuXLzN//nzmz5/PqVOnqFq1KpMnT+bdd9/Fy8srpWIUwmXIMPi04EEnaKFPcg6K5JHoBKhBgwZs2LABPz8/WrZsyUcffURAQEBKxiaEEClGkRogIdK1RCdAZrOZn376iddff9055FyI9EZqgPRP0h69k8VQRfJIdAKUFkZ3CfHC5NszDZGDqUuqdIIWyeOFRoEJkW7JzaeO3e8DJE1gQqRrkgAJkQT/rgYvp45eSdOJ3kkztEgezz0MXiRdrM1ORFQMJkccmTNl0jocIdIlRQFUsNntWocinoNU3InkIrexqWjPgv5knpCHo99/pnUo4rnJ3af+xR87q02+SfXpfh8gmYxUvCBJgFKR4pYBk+LAKzZc61CESLdUJX4Uqy02WuNIhBBakgQoFTky5AIgQ+xVjSMRz0t5zG9CX66bcwJgjgzVNhDxXBQZBi+SiSRAqeieR/yFN4PUAOmWrAavf5dMeQCICT+ucSTiecjoPZFcJAFKRWfVHDhUhWzKbTb/fVjrcMRzcF56pf+Bbm2+lQUAQ/g/GkcihNCSJECpqFm1EpxUcwOwZo1MLKlHD2qAJP/Rr8hslQAoq5zijwPnNI5GJJkqTWAieUgClIp8Pc3sdRQBoEj0fmKsMgxXiNRW8KVShKmZcVNszFu8iEU7z2sdkhBCA5IApbJNjnIAvGbcw897L2gcjUgq6YCpf1FxdkLsZQBoaNhJv+UHNY5IPB85B8WLkQQolQ3o3pVo1Y08ynWW/Pob9+KkFkiI1PRG2Vz85qgKQAPjLixYpWOtEOmQJECpLH8OP9Y7ygPwnvEP+v8id596pMhSGLpVPn9mdjqKEa5mIqMSxauGfRy+HKl1WCLRZDFUkTzkKq6B7211AGhi3Mb6v09qHI1ICkVqCtKEr957mZ/sNQBobVpLeESMxhGJRFMdWkcg0ghJgDSwSy3KSUduvJRY3jVu0joc8Vyk/4GeuZmMLLQFYVMNVDEc5fLxXdIM5qK+Wn+C7j/sw+H47/GRc1C8GEmANNC8Uj6+sTcEoINpJUOW7dU4IpFY/64GLxdfPasVkJVwsrDaET8k3uvvGRQIXsWm41clEXIxkzae5Ld/LrPn3K34B2QYvEgmkgBpoF/DYuz1fY1LahayK7ex7l1ARLRV67DSvRirHavdwfkb0Yxfd5zKIzbQ9fu/uRIZg8OhEhFtlX4HaYS72cjpEQ2ZZXsdgKaGvyighNFm3m5mbjmjcXTigYeT0Tsx8ddIOQdFcpEESAMZ3M2s7hXEDFtjALqYfqXS0BUaR5W+nbxyh6ID11Ck/2pqjN3ElD9OcSUylpUHw6g8YiPNZm2nzNB1xNlk1F5aYTQoNKjXgPX28hgVle6mZQCMWn1M48jSt6hYG7//c5k/T17jRlSc8/G23+7h6z9OMiPkFCCJkHhxJq0DSK/MRgM/2mvR0bSCPMp12hpXsSe0JhX8M2sdWrpyMyqO4+F3aD57x1O32x16K8HfcvFNG1oG+tNs7dvUNe6liWEb05U3OKHm1TqsdOvLFUf4ZuvZJz4/bt0JXrt/2x4lU4iIFyQJkIZyZMnImFvNmGyZShfTb9SaUZs9o97XOqx05eVh6x/7uA9RFFPO428IJwc3yaHcJJtym/zKVQCi42QkSlrgZTFyWPVnlb0SDY27GGBaSEtrX2JtdtxMRq3DSxduRcXx/c5zfL3pFDHWf88rAw78lXBeUi6SW7lODiX+PCykhAHSB0i8OEmANPRHr1oU7neXjxyrKWs4Q0/TUvz7+rKpdy0K+HlpHV6adyTB3C8qgYYj1DfsoqbhAP6GK099bRhZUjY4kSoURWHGBy+zIqQzda79TQ3jQV617+P8jZoUyZ5B6/DShfJfrufBAK9MRNLEuI3ahv1UNBzHU4l94usuqX5USKUYRdokCZCGjAaFxR2q8uXsD/jJbSjvGTexxF6L2uMgdFQjrcNL8xbvjl8DqpJylCHmbylmSLgm1EXVj5OO3ISpWQhXM3OFTNxWvTmp5qadt78GEYuUUL9kTuqXfIvpA5bR2fQ7A0wL+eXvN+nZoKTWoaULDhU8iOFT08+0NK7DXfl3QMg91cJxNQ/n1ezx56CaiWuqL7fxZqejGE00jFvonyRAGqtcMAuvv/4WP6/5g7eNWxlhnsMbcV/i33clw5qU4MNAf61DTLOOhkXyvnEjI8xzAIhS3fjNXpWNjpfZ5QggEu8nvvatl3OnVpgilSzzbs7/7m2hoCGcuK1TaHGpDd+3q6J1WGlanM1BJiJZaBlJCcM5AA46/PnNXpUtjtKcVPPgeMJYnQYlc6RmqCINklFgLqB1tQIMt37ALdWbEoZztDauAWDgr4c1jixtK+Y4xZemuQAstdUgMHYKwbb2bHCUT5D89KkX4Px9c59ahI5qhLtZ+oekNV+8XZlR1uYAfGJaxvnTR4iVUX8p6p+Ltxltnk0JwzmuqT60jutD47jhzLa/znE132OTn+w+bgxuXJxx75TRIGKRlkgC5CJGt3yVkbb4i28v00/k5hoAZ67d1TKsNK3J3SUYFJXf7IH0sXV8pMZn9Nul2DMgiK61C7Opdy029qpJ/izSNyutql7Ej5w12rDNXhwPJY4RpjkEDFjNoUsRWoeWZu3dvY3XjHuxqkZaxgUT4ijHwzM8Z3A3EdK7lvPvE182YGe/IFpXK4CXmzRgiBcjnyAXUeMlPzrYa/K28U8qG44x0vwNLa19eXX8ZukPlEIKRe0DBb6xNeS/0+r/r3wemlXM5/xbOqWnD80q5ePDzW1Za+jLK8ZDvGnfyutTFDkHU8il/evBDNscJShf+RWmVy9IFm8LVrvKhiNXqFbEj9wZPVjxcXWyeFuwmOSeXSQfSYBchNlgQMVAP2tbVlr6UcN4kOaOP/jBXocjlyMpnstH6xDTlIh7VizYALiJDwvbVqZ6ET9UVeXcjWjyZvbUOEKhhbyZPQlVczLJ9hafmZcw0LyAzbHS1JJS8vuaIBpu4MOXTUsleO7div/Ox1Qyt29qhybSAUmnXYTBEF8DcVrNzVjbuwD0N31PHuUqDSf/KatVJzf133W9fulalepF/ID4YdH+fl4YDTLHSHpVuUBmZtkbcdSRj8zKXb40z8UmfYFSRIlc8VMNZM/gpnEkIj2SBMiFFMwa38wyz96AXY4AvJUYxplnouCg3Xe7NY4u7croYdE6BOFCZn5YnqVdatDb2hGraqShcRcbfpwqi6SmIIsMKhAakATIhazrUYPfu1XHgYHe1k5Eq25UMRyllXEdhy5FPnsHItFU1H9XdhfiIRk9LZTLl4nDagEm2d4CoOrxkQQGL6Dnkv3aBpfGyDkotCQJkAsxGQ2UyuPL0k6BnFezM8IWvyxGX9MPFFEuMmLVUY0jTFseNHIpBjkNxKMWta/MdPsb7HcUwkeJZqx5Jsv3XdA6rLTFWasmTc4i9cmV3wVVvL8g6vf2Omy2l8ZdsTLZPIVvtxxj07GrGkcnRPpQtZAfdoz0tHbmnmrhFeMhPjBuYP2Rpy+TIhLv3/ofSYBE6pMEyEWVyOWDer8p7LrqQzHDBfqafqDNfOkLlHzk7lM82xk1F6Puz9HVz7SI0Qt+4eSVOxpHlTYoD2qA5BQUGpAEyEXNalmBHD7uXCMjva0dAWhjWkttwz6Clx2QDpkvKME/nyJXX/F4zSvFD8X+zl6XLfZSeChxTDFP4fWvNnAzKk7j6PRPaoCEliQBclG5M3qwo18dutUuTIijHHNt9QEYZ57Bhl0HqDrqD8asOaZxlPr2oAOmXHrFkwxtUpIVH1fnhw5V6WXtzLX7tbH9TN/z8rD1HL4ss0QLoVeSALm47nWKADDK1pwjjvxkUe4w3jyD8IhopoWc1ji6tEJSIPF4ZqOBkrl9qVIwC6+UK0Eva2cAWpnW85phN40mb8XhkNrY56fe/6+cgyL1SQLk4iwmA6GjGhGHmY+t3binWqhhPEgH40qtQ9M1FUl7RNK0e6UgWxxlmGmLXxZjjHkWObnByoNhGkemY6rUwgrtSAKkEy0D83Nazc0QW0sA+piWUF45TnScTePI9MvZBCazPotEcDPHXy7H2Zrxj6MgGZUoJlqm8skPe7FLLdBzUh/6rxCpSxIgnejXsBhfNSvDYnttfrFXxaQ4+NoyheqDlvLd9lDpkClECsubyZMM7iay+nrT3dqNu6o7lQ3H+Ni4nEL9VrFBhsc/PxmIIDQgCZBOuJuNvFkuD7kzetLP2o7TjpzkVG7ylXkaX/x6kPbf7dE6RN1RZBi8SAKLycDu/kGE9KnNOTUH/a0fAfCJaRlVDYdo990eIqKtGkepL4qMghcakgRIZ37pWo1o3Oli/YR7qoWaxgN0Mf7G3nO3uCW1QImWYBoBufsUieRuNmIxGfixYyC/Oqqz2FYLg6Iyyfw12blJmaHrWH/kCqHXo7QOVRdU6QQtNCQJkM5kzeBGRk8zx9V8DLS1AaCnaSmBhsNMCzmlcXT64lwKQy6+IokqFYifrf0LW2uOOPKTVYlkimUKJmy0/24PtcaFsOLAZY2j1AOpAhLakQRIh5Z3qQbAT/aa/GiriVFRmWSeyi9/7mP2ljPcjZWO0UkiNUDiOdQrkZ1YLHS2fkKk6kElw3F6m350Pj9h3QkNo9MJZ0WsnIMi9UkCpEMF/LxY1K4yb5XLzSBba4458pJNuc0k89eMXHWYil9u0DpEl6cCBkXGnojn1yPoJQDOqTnoc3+29k6mFdQ1xPfHOyPNYIkg56DQjiRAOlW1sB8TmpUlBje6WrsTpbpR1XiET00/cc9qJ8ZqZ/OJa8RY7VqHqgNy9ymSrlhOHw4Mfg2AtY5KfGNrAMB48wzyKjIiLCmkD5DQgiRAOhdULDun1dwEW9sD8LHpF4IMeyk6cA2t5u5i0K+HNI5QiLTLx93Mio+rA/Gzte91FMFHiWaaeRJuxHE0LFLjCF2ccyCmJEAi9UkCpHNfv1+OHzsGcjBzXebZ6gEwwTwNfyV+dtof91zUMjzXJaPARDIpmduX0yMaYsNEt7ju3FAzUMoQyiDTAub/Fap1eC5OZoIW2pEESOfczUYqFchM/4bFGG5rwS5HAD7KPWaYJ+JJjNbhuSxVuh6IZGQ0KPyvfB7CyEIPa1ccqkIL00bs+xbi33clF25Gax2ii5Jh8EI7kgClEUHFs2PDRNe47lxVM1LUcIHR5llIJ8MnefjfRS6+4sUNfqMEDUrm4E9HaSba3gZguGkupZQzNJz8p8bRCSH+SxKgNGTFx9W5RiY6x32CVTXS2LiDtsbVTNpwUuvQXJs0gYlk4O1mYvoH5QGYYm/KevvLuClWZli+whxzk/HrjnPp9j2No3Qxcn8mNCQJUBpSMrcvi9pXZq8awDDbBwAEmxax/Y9ftA3MFUkbmEghHWsURMVAT2sXTjtyklu5wRTzFKb9cZxqo/4gMkaWy/iXLEcjtCMJUBpTtZAfGdxNfGd/jWX26pgUB1PMk6nS9zv8+67kamSMrFfEv1PwC5HcghsW4+TwBtzBk47WT7mrulPNeJjPTYsB2Hf+trYBupQHM0FLAiRSnyRAadCvXasBCv2sbZ3T9E+3TMKClUojNlJm6DpOXb2jdZgakwRIpByz0cC81hU5peaht7UTAB1MK3nDsI0fd1/QODoXIqeh0JAkQGlQwazeNCqVkxjc6GjtwW3Vi3KGU3xh+s65zfc7z2sYoQuQYfAihZmN8ZfXNY5KTLO9AcBo8yxOH9pJdJwsVwOgSAYkNCQJUBo1tcXLjH+nDBfU7AmG5b5v3AhAdGw6nyFarrsihQUWysKrRbPx9st5GGd7ly32Ungoccw0TyBw0M/UGR+idYia+/c0lJsQkfokAUrD3i6fB4AQR1nG2d4BYIhpPpWUo6w/mt6n6pdh8CJlGQ0Kc1tXZPy7ZXBg4GPrx5x3ZCW/4SqTzFM5e+0O/n1XcvFWep4jSPoACe1IApTGfdWsDADT7E343V4Fs2JnumUiHlGXGLbiiMbRuQi5+IoUVtE/ExF409Hak3uqhVrGf5wrx1cfvQk1vY5KTKfFFq5BEqA07s1yedjVvw4F/LzpY+3IIYc/WZQ7zLZMYNHWo1y/G6t1iNpIr184QhOL2ldhW99XOarm5/P76/Z1Mf3GG4a/ACgQvErL8DQk56HQjiRA6UC2DO7MblmBGNzoENeTa6oPxQ3nGGueSYUv17Pp+NV0N1V/wsuu1ACJlGU2GsiV0YN/vniN3xzVnJ2ix5pnUUY5BcCZa3e1DFEjshSG0I4kQOlEAT8vAC7jR+e4HsSpRl437qSb8RfazNvNK2M2aRxhapM7T5H6fD3MAIy1veucKXqWZQLZuUnfnw9qHJ0GZDV4oSFJgNIJo0Hhn0GvAbBHLcogWxsAepuXUtewBwD/viuZHnJasxg1IxdfkcpUDPSwduW4Iw/ZldvMskzgn9Bw2n+3J531B0pPZRWuRhKgdMTX0+z8fbH9Vb611QXgK/M0XlLiJ2cbveaYJrGltvT1JSNcSdOyuQCIwoN21l7cVL0pYzjDGPMs1h8JZ/BvhzWOUAtyEyJSn6YJ0PTp0yldujQ+Pj74+PgQGBjI6tWrn7h9rVq1UBTlkZ9GjRo5t2nduvUjz9evXz81iqMLf/SqyeIOVQAYZvuQbfbieCsxzDaPJyPxs0Nb7Q4tQ0wdqgyDF9r4qllZDg2pB8AFNTtdrD2wqkaaGLfRxfgb324/p3GEqUluRIR2NE2A8uTJw6hRo9i7dy979uzh1VdfpUmTJhw+/Pg7oGXLlhEWFub8OXToEEajkXfeeSfBdvXr10+w3Q8//JAaxdGFglm9qVIwC22rF8CGia7W7ly4PzfJdPMkzNj4+o9TWocpRJqlKArebibqFs8OwA5HcQbbWgHQ2/QjQYa97Dp7U8sQU4/0ARIaMmn55o0bN07w9/Dhw5k+fTo7duygRIkSj2yfOXPmBH8vXrwYT0/PRxIgNzc3cuTIkeg4YmNjiY39dzh4ZGRkol+rVwNfL87L+TIxeeNJ2l7tzc+WwQQaj/ClOpfPN7bn07ovaR1iikowBb9cfIUGZn5Qntv3rBy5HMkHcyBAuUBL03ommqfy9qysxGYuSstAfyr4Z6J0noxahytEmuMyfYDsdjuLFy8mKiqKwMDARL1mzpw5vPfee3h5eSV4PCQkhGzZshEQEEDnzp25cePGU/czcuRIfH19nT958+Z97nLoSaPSOVn7aQ26NmvMx9aPsasKzUwhdDSu4Os/TmJ3pN3qaVVmghYaMxgUMntZqF7Ej6ND6zP0oSbpb8zjibwRztAVR3jj67/469R1rkTGaB1yCnjQ3C7noEh9midABw8exNvbGzc3Nzp16sTy5cspXrz4M1+3a9cuDh06RLt27RI8Xr9+fb777js2btzI6NGj2bx5Mw0aNMBuf/LaV8HBwURERDh/LlxIX6s1v1EmFyGOsgyxtQQg2PwDBzcspFC/VWw7fV3j6FJI2s3thA55WIw0KpuPLtZPCHVkJ6/hGrMt43EjDoAW3+wkcORGjaMUIm3RPAEKCAhg//797Ny5k86dO9OqVSuOHHn2Eg1z5syhVKlSVKpUKcHj7733Hm+88QalSpWiadOmrFixgt27dxMSEvLEfbm5uTk7Yj/4SU8URaFwNm++s9djvi1+qPxE8zRKKWd4f/bOtD9iSprAhAtoXDoXt8lAW2tvIlRPyhtOMs48A+V+LUlarJBV0vq1Rbg0zRMgi8VC4cKFKV++PCNHjqRMmTJMmjTpqa+Jiopi8eLFtG3b9pn7L1iwIH5+fpw6JR17n+bbj+ITyWG2D9lkL4OHEsc3lnHk4AYFgleluflJ0lJZRNpQp1g2utcpwmk1Nx2tPYlTjTQ27qCXaalzm7TWLO0sjaL5V5FIh1zuU+dwOBJ0SH6cpUuXEhsbywcffPDM/V28eJEbN26QM2fO5AoxTcqd0YNhTUpgx8jH1o855shLduU2cy3j8CSG9UeucP5mNDHWJzcl6ooMgxcuRlEUetZ9iXL5MrLDUZzg+2uGdTP9yjvGEAC6fv+3dgGmADnzhJY0TYCCg4PZsmULoaGhHDx4kODgYEJCQmjRogUALVu2JDg4+JHXzZkzh6ZNm5IlS5YEj9+9e5c+ffqwY8cOQkND2bhxI02aNKFw4cLUq1cvVcqkZx8G+rP189rcxZO2cb2da4ZNNk/BgIMxa49TdOAa/j5/S+tQhUizlnepRpFs3vzsqMFkW1MARpjmEGg4zJrD4aw9HK5tgMlIlc54QkOaJkBXr16lZcuWBAQEUKdOHXbv3s3atWupWzd+huLz588TFhaW4DXHjx9n69atj23+MhqNHDhwgDfeeIOXXnqJtm3bUr58ef7880/c3NxSpUx6lyeTJy/ny8g9r9y0j+tNjGomyLiPfqbvWXkg/lgM/f3ZfbRcnwyDF65rdssKAEywvcNv9kDMip2Z5q8opFyi44K9aWZEmLMPkJyCQgOazgM0Z86cpz7/uI7LAQEBT+y/4eHhwdq1a5MjtHRtaaeqOFSVIv3j6GXtzFTLZNqZVnNRzcp8e332X7iN3aFiNOj3qiWrwQtX5u/nxXsV87J49wX6WDuSS7lBBcMJ5pnH8GbcUCqP2EjoqEbP3pFOyGrwQgsu1wdIaM9oUDAb4z8aKx1VGG19D4BBpgXUM+wCYOEOnU/XL52ghYsb9XZpDg2pRwZvbzrE9eScIxv5HhoefysqjqAJm3W9dti/Z6F8FYnUJ5868UzT7Y1ZYAvCoKhMMk+lvHKcL347zLkbUVqHljykCUy4KG83E3sG1OUmPnxk7UOE6snLhlN8ZZ5G+WFrOXX1LvO3hWod5nNTpA+Q0JAkQCIRFL6wtWa9vTzuipVvLOMpqFym5tgQLt2+x66zN4m16Wt0mKqmgwVfRZpR46WszuHxsaqJhsZdDDJ9x4M6FN1O6+BcC0zTKEQ6JQmQeKKQ3rUY83ZpfulaDQcGPrZ2Y5+jMJmUu3xrHk1WblNt1B+8O3M7wcsOah3uC5Crr3BtrxT2A+IXTu1l7QxAa9M6Oht/B+DAxQjNYnsx8RmQnIFCC5IAiSfy9/Pi3Yp5KZs3Iy0D8xODG23jenP2/lT9cy1j8CR+NMqyvy+x4cgVouNsGkedWDq9Yxbp0oeB+WleKR9j3i6NX5XmDLPGz4H2uXkxbxm20GTqXyzdc4F/LtzWNtDnJJ2ghRYkARKJMrRJSQBu4kNr6+fcUDNQyhDKNPMkTMQnPe2+20OfpQe0DDPREkzBL32AhItzNxsZ+VYp3q2Yly8aF2eOvSGzbPGjwEabZ1PD8A99fjpAk6l/cfLKHY2jTYr7NUByCgoNSAIkEm39pzUAOKfmoG1cH+6pFmoZ/+FL01weXMhWHgx7yh5ch167TAih3M8WRtqa84u9KmbFznTzREoqZwCYuumUfmZsv38iSg2Q0IIkQCLRimTPwPh3ygCwXy3Mx9aPsasK75lCEqxXZLProYOxLIUh9CuzlwUVA32sndhqL4GXEss8yxjyKlf4Zf9lui3S25IZcg6K1CcJkEiSt17OzS9dq7G8S1U2OMoz0PYRAB+bfuEj42oACvdf7Zw1Whek/l3ozPpPa/Bz50CsmOhk/ZQjjvxkVSL5zjyKzESy4ehVrUNMFBkGL7QkCZBIEkVRKJs3I+XyZWJOqwosstdhrPVdAAaZF/Cm4U8Aurr6Hai0gQkdy+LtRvn8mfmr76vcxZNWcZ9xUfWjgOEK8yxj8CaaD77ZydaT17UO9an+XQ1ebkJE6pMESDy3OsWys6RDFabamzDH1gCAseaZ1DHsBWDf+VvcibFqGWLiyMVX6FTujB4AXCMTLeP6ckPNQBnDGWabJ7D71GU+mLOT7advsPPMDY0jfbwHgxHkDBRakARIvJDKBbPwboW8fGlrwc/26pgUB1PNk6moHOPNadsoNXid1iEKkaat6v4KlQtk5oyai1Zxn3NH9SDQeISvzVMwYaP57B00m7XDJScr/bceVlIgkfokARIvbMz/ytC5VhE+t3Zgg70c7oqVOZaxFFdCtQ7tKaQJTKQNxXP5MLtV/Orxh9SCtIvrTaxqpq5xL2PMs1CIH5QQa3O9wQnSB0hoSRIgkSw+rfsSNkx0tX7CTkdRfJR7fGsZTX4lHP++K7UO7xHSBUikJT7uZrb0qQ3ATrUYXazdsakG3jJuZZBpAaBSevA6l+2bp0oztNCAJEAiWZiNBv78rDYenl60j+t1f1RKBAvNI8nGLfz7rnSt9Yrux+JQ5cIr0oZ8WTzZOyAIgI2O8vSydsKhKrQxreVT088ArDwQxpcrjrA79KaWoT6GnIci9UkCJJJN3sye7BtYl0i8aBnX17lkxiLLcLIQQYHgVSzfd5E4F6yKFyItyOLtxj9fvAbAr47qDLK1BuAT0zLnNBXfbD3LOzO2axViQrIosdCQJEAiWSmKgsVk4Dq+fGjtx2U1M4UNl1loGYkvd/l0yT/M/vOM1mHiXEVb4yiESG5eFqPz94X2ugmmqXjHGKJNUM8iTWBCA5IAiWS3f1Bd/vniNS6qWXk/rj9X1YwUM5znO8soMhDN2LXHqTthMxHRWg6Rlyn4RdpkMhrYOyCInf3qADDV3oTZtoYAjDbN5g3DXwBUHbmRi7eiNYvzYXIWCi1IAiSSnafFhK+HmQ09axCq5uT9uH7O+Unm3V9B/uTVu3y96aR2QbpSfyQhklkWbzey+7jf/0thuK0F39vqYFBUJpin08Cwk8sRMYxcfUzTOB+QGxGhBUmARIopnC0Dy7pU5ZSahw/jgolQPalgOME35nG4EcfsP89qHaJceEWatqBtJUa+VYoZH5RngK0NP9pqYlIcTDZ/TV3DHlYeCKPs0HVcuxOrUYQyEaLQjiRAIkW9nC8TtQOyckT1p2VcX+6oHlQ1HmGm+SssWGkzb5cmTWEuNSJNiBTySpGsNK+Uj3olcvBZ/eL0tbVnub0aZsXOVPMkahn2cTvaSsXhG3A4NDgnHqwGL32AhAYkARIpbk6rilQqkJl/1MK0ietDtOpGLeM/fG2ezJ/HwwhefkCDqCQBEumHoih0rlWI6R9WpLe1EyvslbEodmaaJ1LdcBCAzSeuaRylEKlLEiCR4gwGheFNSwKwRy1KO2svYlUzrxn3Mtn8NesOXsS/70qKD1pDjNX1pusXIq2o5J8ZO0Z6WLuy1l4BN8XKbPN4qhiO0Gb+bvz7rsSeijVBMhO00JIkQCJVFMmege3Br1I2b0a2OUrS0dqDWNVEQ+Muptxfsyg6zs6yvy+lTkCqjAIT6U8mLwv1S+TAhomPrR+z0V4ODyWOOeaxVFDiO0RP3ph6gxOcLdHSBCY0IAmQSDU5fT34pWs1AEIc5eho/ZRY1UQD426+Nk/BjI17qVQDpDr/Lxdekb7M+LA8AxoVIw4zXayfsMVeCi8llm8to6mkHGXSxpNUG/UHZ69HpXgsirMTtJyHIvVJAiQ0E+IoR4f7zWH1jbuZap7EqBUHOHHlDlGxthR+9/spkFx3RTrUuqo/ALFY6GDtyZ/2kngpscy3jCHQcJhLt+9Re1xIKkYkJ6JIfZIACU1tdpShvbWns0/QNPNEXv9qIyW+WMueVFivSHogiPTIZDTQuEwuAGJwo521NyH2Mngqscwzj3F2jIaUHjEpZ6DQjiRAItUtal+ZYU1LkieTBwBbHGVoZ+1FjGqmrvFvppknYsHK/1JyvSIthvwK4UJGvx0/P1ABPy9isdDR+ikb7eVwV6zMMY+jlmE/VUZspEDwKn7753LKBOEcBp8yuxfiaSQBEqmuaiE/PqySny19ajO4cXEA/nSUpq21NzGqmSDjPmaYv8KNOH7ccyGFopBO0CJ987SYqF8yB7Nblgfim8M6WT9lnb08boqVmeYJlLgbv2xG9x/2pXA0ch6K1CcJkNCMwaDQuloBXi2aDYC/HKX4yNqHe6qFV437mW0ezxc/7eLv87cIvR7FmWt3NY5YiLSncLYMhI5qxOEh9WhS3p8u1k9YZa+Em2Jjunki9Qy7ARi9xjWWzRAiuZi0DkCIOa0qEGN1EGO1M/DXnHx0SOEb8zhqGA/ynTKKVtMc3METgKND6+Px0GrXz885/jYZ9iWE/nm5mRj3Thl+2nuR7tZu2JlGY+MOvjZPpoe1K9NDYPXBMH7tWh1fT3Pyvrki9+Ii9cmnTmhOURQ8LEYyeVmY0rwc2x0l+CCuHxGqJxUNJ1hk+ZLMRAJQc+wmLtx88RWspQeQEI8368Py2DDRw9rVuWzGZPMU3jGGEHojmjJD1zF3a/Ks46fIWmBCQ5IACZeiKArVC/uxTy1C87gBXFd9KGUIZYllGNm4xdU7sbScu+vF38g5EaIQ4mGvlcgBgB0jvaydWWSrjVFRGWueRVvjKgCGrjjCnydffOkMWZJPaEkSIOFyFrStxJkRDTmhFKBZ3EDC1MwUMVxiqWUIeZSrnL0exYLtocnyXtIJWohHhfSuRccaBXFgoJ+tHTNsrwMw0LyQT00/ASofzom/EXmRYfKyFIbQkiRAwuUoioLBoPB9u8qcVnPzTtwgzjmykd9wlaWWoRRSLjHw18Mv9B6yGrwQT+bv50Vww2KEjmpE80r5GGVrzhhrMwA+MS3jC9N3KDjw77uSAsGrOHQp4jnf6cGEpHIjIlKfJEDCZZXLl4kCfl6EKdl5J+4LTjhyk1O5yRLLMEoooaw7HE65oev449iVJO9bkWHwQiRK79cCAIVp9iYMsLYBoI1pLWPNszASv3TN61O28vPei8//JpIACQ1IAiRclsVkYEPPmpwa3oACBQrRLG4gBx3++CmRLLYMY97333Er2spH8/dgtTu0DleINCmLtxu/d6vOO+XzsNBelx5xXbCpBv5n3MJU82QsWAHotfSf59i71MQK7UgCJFya0aCgKAq9XgvgFj68HzeA7fbiZFDu8a15FI0MOwAoP2x90pq1pBO0EIlWKo8vI98qRc+6L/GLozqdrT2IVU3UN+5mnnkM3sSPzIyMsT7nO0gNkEh9kgAJXajon4nmlfJxB09aWz9jpb0SFsXOFPMUWhnXEhljY9SaY9yLs3P+RmKGyUvqI0RSmIwGutcpwokvG7DeUYHW1s+5q7pTzXiYHy3DyMotSg9eR7/lBxN5DoKiyjB4oR1JgIQuKIrCyLdK8U3LCpQrmIOPrd351lYXg6IyxPwtvU1LmLn5NMUGraHG2E38lOj+CHLpFSIpLCYDx4bVZ7ujBM3iBnJN9aW44RzL3b6goHKZRTvPU2PsJmKs9mfu68FtiCp9gIQGJAESuhJUPDutAv1xYOALW2vGWd8BoJvpV0abZjs7ZQ5feSRR+5NO0EIknbvZSI+gIhxWC/BW3GDOOHKQR7nOz5bBvKycAOD63dhn7keGwQstSQIkdOeVl7Le/03ha/ubfG5tj11VaGYKYYb5K9yJ5Va0le93nnviPlRZDV6IF9KhRkHer5yPC2p2/hc3mP2OQmRS7vK9ZQR1DHupPnpTEobHy42ISH2SAAnd8XYzsbFXTeffS+y16WT9lBjVTF3j3yyyDCcLEfRffoi7sban7ktqgIR4Pp4WEyPeLEXhbN7cxIfmcf35w14WDyWOWeYJNDNu4vUpW9lx5sazdyZNYEIDkgAJXSqU1Zv1n9ZgfpuKAKx3VOCDuGBuq168bDjFcssgCimXKPnFWn775zKHL//3TlRqgIRIDht61iR0VCPu4U57ay+W2GphVFRGm2fTw/QT783ajn/flfRffvDR6SpkQlKhIUmAhG4VyZ6BWgHZnEnQHrUob8UN4ZwjG/kM1/jZMpjKylG6/7CPRpO3cvra3YdeLcPghUhOX79fDjtGPre1Z7KtKQA9TMuYYJ6OBSvf7zxP2SHrGPr74/rnSQ2QSH2SAAndqxWQjdBRjZjXuiJn1Fy8GTeUvx2FyahEscAygqaGrQDUGb8Zh/T9ESJFvF46FwcGv8aY/5Vhgu1dPre2x6YaeMu4lQWWkWTkDlFxdub+9e9K8s7V4CX/ERqQBEikGcVy+gDc748wwDlX0ETLNLoblwEqEzec4Nf9l4h29g2SK68QycXH3cw75fMwu2UFlthr08r6OZGqJ5UNx1huGUQBJQwAq91BrM1OrC2+SUz64gktSAIk0owcvu7M+rA8ZfNmJBYL3azdmWFrDEBP80+MM89k+h/H+GTxfrov3qdxtEKkTYqiUNE/EwB/OUrxVtxgLjiyUsBwheWWQVRWjjJ85VFe+2oLN+7GxL9Gy4BFuiUJkEhTXiuRg1+6VmNZl6qoGBhla04/a1vn2kXfmUfhy13nBVfuPIVIfhk9LXSsWRCAU2qeR5qlI3d8x7kb0XIeCk1JAiTSpFy+Hs7fF9nr0M7am7uqO4HGIyy3DKLg/ap4u3QJEiJFBDcoxvpPa/BZ/QCu40vzuAGssFfBotiZYJlBT9OPKMQ3gSnSCUhowKR1AEKkhBy+7nzfrjKrD4XhZTExcwv8L24w31jGUdAQzhTzZK1DFCLNK5I9A0WyZ+BKRAzfbj/Hx9ZuhKrZ6Wb6le6mX7QOT6RzkgCJNKtaYT+qFfZDVVVCjl/j2JV8NI0dxkzLBMobTgIyDF6I1NC/UXHuWe38uOci42zNCFVzMML0DRbl2euFCZFSpAlMpHmKorD20xqEjmrEdXx5P64/y+3VAIhUvTSOToi0z2IyMOZ/ZVjZvToAP9lr8kFcP+fzdouvVqGJdExqgES6smdAEH+evManS8ystlfigpqN1VoHJUQ6USKXLxPeLUPPH/9hl1qMKjFTqGI4yqA6H2odmkiHJAES6YqftxtvlstD+XyZaTPfmw+q5Nc6JCHSlbdezkO1wn50XriXfJlzMfG9llqHJNIpRVVlMZb/ioyMxNfXl4iICHx8fLQORwghhBCJkJTvb+kDJIQQQoh0RxIgIYQQQqQ7kgAJIYQQIt2RBEgIIYQQ6Y4kQEIIIYRIdyQBEkIIIUS6IwmQEEIIIdIdSYCEEEIIke5IAiSEEEKIdEcSICGEEEKkO5IACSGEECLd0TQBmj59OqVLl8bHxwcfHx8CAwNZvfrJa3PXqlULRVEe+WnUqJFzG1VVGTRoEDlz5sTDw4OgoCBOnjyZGsURQgghhE5omgDlyZOHUaNGsXfvXvbs2cOrr75KkyZNOHz48GO3X7ZsGWFhYc6fQ4cOYTQaeeedd5zbjBkzhsmTJzNjxgx27tyJl5cX9erVIyYmJrWKJYQQQggX53KrwWfOnJmxY8fStm3bZ247ceJEBg0aRFhYGF5eXqiqSq5cuejVqxe9e/cGICIiguzZszN//nzee++9RMUgq8ELIYQQ+pOU729TKsX0THa7naVLlxIVFUVgYGCiXjNnzhzee+89vLy8ADh79izh4eEEBQU5t/H19aVy5cps3779iQlQbGwssbGxzr8jIiKA+H9IIYQQQujDg+/txNTtaJ4AHTx4kMDAQGJiYvD29mb58uUUL178ma/btWsXhw4dYs6cOc7HwsPDAciePXuCbbNnz+587nFGjhzJkCFDHnk8b968iS2GEEIIIVzEnTt38PX1feo2midAAQEB7N+/n4iICH766SdatWrF5s2bn5kEzZkzh1KlSlGpUqUXjiE4OJiePXs6/3Y4HNy8eZMsWbKgKMoL7/9hkZGR5M2blwsXLqS55jUpmz5J2fQpLZcN0nb5pGwpR1VV7ty5Q65cuZ65reYJkMVioXDhwgCUL1+e3bt3M2nSJGbOnPnE10RFRbF48WKGDh2a4PEcOXIAcOXKFXLmzOl8/MqVK5QtW/aJ+3Nzc8PNzS3BYxkzZkxiSZLmwci3tEjKpk9SNn1Ky2WDtF0+KVvKeFbNzwMuNw+Qw+FI0B/ncZYuXUpsbCwffPBBgscLFChAjhw52Lhxo/OxyMhIdu7cmeh+RUIIIYRI+zStAQoODqZBgwbky5ePO3fusGjRIkJCQli7di0ALVu2JHfu3IwcOTLB6+bMmUPTpk3JkiVLgscVRaFHjx58+eWXFClShAIFCjBw4EBy5cpF06ZNU6tYQgghhHBxmiZAV69epWXLloSFheHr60vp0qVZu3YtdevWBeD8+fMYDAkrqY4fP87WrVtZt27dY/f52WefERUVRYcOHbh9+zbVq1dnzZo1uLu7p3h5EsPNzY0vvvjikSa3tEDKpk9SNn1Ky2WDtF0+KZtrcLl5gIQQQgghUprL9QESQgghhEhpkgAJIYQQIt2RBEgIIYQQ6Y4kQEIIIYRIdyQBSkVTp07F398fd3d3KleuzK5du7QO6ZkGDx6MoigJfooWLep8PiYmhq5du5IlSxa8vb15++23uXLlSoJ9nD9/nkaNGuHp6Um2bNno06cPNpsttYvCli1baNy4Mbly5UJRFH755ZcEz6uqyqBBg8iZMyceHh4EBQVx8uTJBNvcvHmTFi1a4OPjQ8aMGWnbti13795NsM2BAwd45ZVXcHd3J2/evIwZMyali/bMsrVu3fqR41i/fv0E27hq2UaOHEnFihXJkCED2bJlo2nTphw/fjzBNsn1OQwJCeHll1/Gzc2NwoULM3/+fM3LVqtWrUeOXadOnVy+bNOnT6d06dLOCfECAwNZvXq183m9HrPElE2vx+xxRo0a5Zxi5gE9H7sEVJEqFi9erFosFnXu3Lnq4cOH1fbt26sZM2ZUr1y5onVoT/XFF1+oJUqUUMPCwpw/165dcz7fqVMnNW/evOrGjRvVPXv2qFWqVFGrVq3qfN5ms6klS5ZUg4KC1H379qmrVq1S/fz81ODg4FQvy6pVq9T+/fury5YtUwF1+fLlCZ4fNWqU6uvrq/7yyy/qP//8o77xxhtqgQIF1Hv37jm3qV+/vlqmTBl1x44d6p9//qkWLlxYbd68ufP5iIgINXv27GqLFi3UQ4cOqT/88IPq4eGhzpw5U9OytWrVSq1fv36C43jz5s0E27hq2erVq6fOmzdPPXTokLp//361YcOGar58+dS7d+86t0mOz+GZM2dUT09PtWfPnuqRI0fUKVOmqEajUV2zZo2mZatZs6bavn37BMcuIiLC5cv222+/qStXrlRPnDihHj9+XO3Xr59qNpvVQ4cOqaqq32OWmLLp9Zj9165du1R/f3+1dOnS6ieffOJ8XM/H7mGSAKWSSpUqqV27dnX+bbfb1Vy5cqkjR47UMKpn++KLL9QyZco89rnbt2+rZrNZXbp0qfOxo0ePqoC6fft2VVXjv5gNBoMaHh7u3Gb69Omqj4+PGhsbm6KxP81/kwSHw6HmyJFDHTt2rPOx27dvq25ubuoPP/ygqqqqHjlyRAXU3bt3O7dZvXq1qiiKeunSJVVVVXXatGlqpkyZEpTt888/VwMCAlK4RP96UgLUpEmTJ75GL2VTVVW9evWqCqibN29WVTX5PoefffaZWqJEiQTv1axZM7VevXopXSSn/5ZNVeO/TB/+8vkvvZRNVVU1U6ZM6jfffJOmjtkDD8qmqmnjmN25c0ctUqSIun79+gTlSUvHTprAUkFcXBx79+4lKCjI+ZjBYCAoKIjt27drGFninDx5kly5clGwYEFatGjB+fPnAdi7dy9WqzVBuYoWLUq+fPmc5dq+fTulSpUie/bszm3q1atHZGQkhw8fTt2CPMXZs2cJDw9PUBZfX18qV66coCwZM2akQoUKzm2CgoIwGAzs3LnTuU2NGjWwWCzOberVq8fx48e5detWKpXm8UJCQsiWLRsBAQF07tyZGzduOJ/TU9kiIiIAyJw5M5B8n8Pt27cn2MeDbVLzHP1v2R74/vvv8fPzo2TJkgQHBxMdHe18Tg9ls9vtLF68mKioKAIDA9PUMftv2R7Q+zHr2rUrjRo1eiSGtHTsNF8MNT24fv06drs9wYcBIHv27Bw7dkyjqBKncuXKzJ8/n4CAAMLCwhgyZAivvPIKhw4dIjw8HIvF8sjCsdmzZyc8PByA8PDwx5b7wXOu4kEsj4v14bJky5YtwfMmk4nMmTMn2KZAgQKP7OPBc5kyZUqR+J+lfv36vPXWWxQoUIDTp0/Tr18/GjRowPbt2zEajbopm8PhoEePHlSrVo2SJUs63zs5PodP2iYyMpJ79+7h4eGREkVyelzZAN5//33y589Prly5OHDgAJ9//jnHjx9n2bJlT437wXNP2yaly3bw4EECAwOJiYnB29ub5cuXU7x4cfbv36/7Y/aksoG+jxnA4sWL+fvvv9m9e/cjz6WV8w0kARLP0KBBA+fvpUuXpnLlyuTPn58ff/wxVT6gInm89957zt9LlSpF6dKlKVSoECEhIdSpU0fDyJKma9euHDp0iK1bt2odSrJ7Utk6dOjg/L1UqVLkzJmTOnXqcPr0aQoVKpTaYSZJQEAA+/fvJyIigp9++olWrVqxefNmrcNKFk8qW/HixXV9zC5cuMAnn3zC+vXrXWYJqZQiTWCpwM/PD6PR+Egv+StXrpAjRw6Nono+GTNm5KWXXuLUqVPkyJGDuLg4bt++nWCbh8uVI0eOx5b7wXOu4kEsTztGOXLk4OrVqwmet9ls3Lx5U3flLViwIH5+fpw6dQrQR9m6devGihUr2LRpE3ny5HE+nlyfwydt4+Pjk+LJ/pPK9jiVK1cGSHDsXLVsFouFwoULU758eUaOHEmZMmWYNGlSmjhmTyrb4+jpmO3du5erV6/y8ssvYzKZMJlMbN68mcmTJ2MymciePbvuj90DkgClAovFQvny5dm4caPzMYfDwcaNGxO0GevB3bt3OX36NDlz5qR8+fKYzeYE5Tp+/Djnz593liswMJCDBw8m+HJdv349Pj4+zupiV1CgQAFy5MiRoCyRkZHs3LkzQVlu377N3r17ndv88ccfOBwO5wUuMDCQLVu2YLVandusX7+egIAAzZq/HufixYvcuHGDnDlzAq5dNlVV6datG8uXL+ePP/54pBkuuT6HgYGBCfbxYJuUPEefVbbH2b9/P0CCY+eKZXsch8NBbGysro/Zkzwo2+Po6ZjVqVOHgwcPsn//fudPhQoVaNGihfP3NHPsUq27dTq3ePFi1c3NTZ0/f7565MgRtUOHDmrGjBkT9JJ3Rb169VJDQkLUs2fPqn/99ZcaFBSk+vn5qVevXlVVNX44ZL58+dQ//vhD3bNnjxoYGKgGBgY6X/9gOORrr72m7t+/X12zZo2aNWtWTYbB37lzR923b5+6b98+FVAnTJig7tu3Tz137pyqqvHD4DNmzKj++uuv6oEDB9QmTZo8dhh8uXLl1J07d6pbt25VixQpkmCo+O3bt9Xs2bOrH374oXro0CF18eLFqqenZ4oPFX9a2e7cuaP27t1b3b59u3r27Fl1w4YN6ssvv6wWKVJEjYmJcfmyde7cWfX19VVDQkISDCuOjo52bpMcn8MHw3L79OmjHj16VJ06dWqKD8t9VtlOnTqlDh06VN2zZ4969uxZ9ddff1ULFiyo1qhRw+XL1rdvX3Xz5s3q2bNn1QMHDqh9+/ZVFUVR161bp6qqfo/Zs8qm52P2JP8d1abnY/cwSYBS0ZQpU9R8+fKpFotFrVSpkrpjxw6tQ3qmZs2aqTlz5lQtFouaO3dutVmzZuqpU6ecz9+7d0/t0qWLmilTJtXT01N988031bCwsAT7CA0NVRv8v507DGnijeMA/l065/DMWbeuLFjIhkaYTipIYsSsgdDAFxb5YuTCvQhRjOhFUAt6IRH4xiKFwEgQE6J6EWS9aC+qNyaiYwZTpOarihSlmmXMpxfh0f3V7K/NOe77gYPtd8/5PD8n48vdeVVVwmw2C1mWxfnz58WPHz/WuxURCoUEgEXb6dOnhRC//hX+8uXLQlEUYTKZRGVlpYhGo5qfMTk5KWpra4UkSWLz5s3C7/eLz58/a8YMDw+Lw4cPC5PJJHbu3CmuXbuW0t7i8bjweDzCarUKo9EobDabCAQCi8L3Ru1tqb4AiDt37qhj/tXfYSgUEmVlZSIrK0sUFhZq5khFbxMTE8LlcoktW7YIk8kk7Ha7uHDhguaZMhu1tzNnzgibzSaysrKE1WoVlZWVavgRIn0/s5V6S+fPbDn/DUDp/Nn9ziCEEOt3vomIiIgo9XgPEBEREekOAxARERHpDgMQERER6Q4DEBEREekOAxARERHpDgMQERER6Q4DEBEREekOAxARERHpDgMQEaWFuro6VFdXp2x+n8+HlpaWvxp76tQptLa2JnlFRLQWfBI0EaWcwWD44/4rV67g3LlzEELAYrGsz6J+Mzw8DLfbjVgsBkmSVhwfiUTgcrnw9u1b5OXlrcMKiej/YgAiopR7//69+rq3txfBYBDRaFStSZL0V8EjWerr65GZmYmOjo6/PubAgQOoq6tDQ0NDEldGRKvFS2BElHLbt29Xt7y8PBgMBk1NkqRFl8COHDmCxsZGNDc3Iz8/H4qi4Pbt2/j69Sv8fj9yc3Nht9vx5MkTzVyRSARVVVWQJAmKosDn8+HTp0/Lri2RSOD+/fvwer2a+q1bt+BwOJCdnQ1FUVBTU6PZ7/V6ce/evbX/cogoKRiAiCht3b17F7Iso7+/H42NjTh79ixOnDiBiooKDA4OwuPxwOfzIR6PAwCmp6fhdrvhdDoxMDCAvr4+fPjwASdPnlx2jnA4jJmZGezfv1+tDQwMoKmpCVevXkU0GkVfXx9cLpfmuIMHD6K/vx/fv39PTvNEtCYMQESUtkpLS3Hp0iU4HA5cvHgR2dnZkGUZgUAADocDwWAQk5OTCIfDAICbN2/C6XSipaUFxcXFcDqd6OzsRCgUwujo6JJzxGIxZGRkYNu2bWptYmICOTk5OH78OGw2G5xOJ5qamjTHFRQUYG5uTnN5j4g2DgYgIkpb+/btU19nZGRg69atKCkpUWuKogAAPn78CODXzcyhUEi9p0iSJBQXFwMAxsfHl5xjdnYWJpNJc6P2sWPHYLPZUFhYCJ/Ph+7ubvUs0wKz2QwAi+pEtDEwABFR2jIajZr3BoNBU1sILfPz8wCAL1++wOv1YmhoSLONjY0tuoS1QJZlxONxzM3NqbXc3FwMDg6ip6cHO3bsQDAYRGlpKaanp9UxU1NTAACr1fpPeiWif4sBiIh0o7y8HCMjI9i9ezfsdrtmy8nJWfKYsrIyAMCbN2809czMTBw9ehTXr19HOBzGu3fv8Pz5c3V/JBLBrl27IMty0vohotVjACIi3WhoaMDU1BRqa2vx+vVrjI+P4+nTp/D7/UgkEkseY7VaUV5ejpcvX6q1x48fo62tDUNDQ4jFYujq6sL8/DyKiorUMS9evIDH40l6T0S0OgxARKQbBQUFePXqFRKJBDweD0pKStDc3AyLxYJNm5b/Oqyvr0d3d7f63mKx4MGDB3C73dizZw86OjrQ09ODvXv3AgC+ffuGR48eIRAIJL0nIlodPgiRiGgFs7OzKCoqQm9vLw4dOrTi+Pb2djx8+BDPnj1bh9UR0WrwDBAR0QrMZjO6urr++MDE3xmNRty4cSPJqyKiteAZICIiItIdngEiIiIi3WEAIiIiIt1hACIiIiLdYQAiIiIi3WEAIiIiIt1hACIiIiLdYQAiIiIi3WEAIiIiIt1hACIiIiLd+QlcEJ4J8Wpn6wAAAABJRU5ErkJggg==\n"
+ },
+ "metadata": {}
+ }
+ ],
+ "source": [
+ "plt.plot(corrupt_V, label=\"Groundtruth\")\n",
+ "plt.plot(optsol, label=\"Estimated\")\n",
+ "plt.xlabel(\"Time (s)\")\n",
+ "plt.ylabel(\"Voltage (V)\")\n",
+ "plt.legend()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {
+ "id": "N5XYkevi04qD"
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.12"
+ },
+ "colab": {
+ "provenance": []
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "8d003c14da5f4fa68284b28c15cee6e6": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "VBoxModel",
+ "model_module_version": "2.0.0",
+ "state": {
+ "_dom_classes": [
+ "widget-interact"
+ ],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "2.0.0",
+ "_model_name": "VBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "2.0.0",
+ "_view_name": "VBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_aef2fa7adcc14ad0854b73d5910ae3b4",
+ "IPY_MODEL_7d46516469314b88be3500e2afcafcf6"
+ ],
+ "layout": "IPY_MODEL_423bffea3a1c42b49a9ad71218e5811b",
+ "tabbable": null,
+ "tooltip": null
+ }
+ },
+ "aef2fa7adcc14ad0854b73d5910ae3b4": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "FloatSliderModel",
+ "model_module_version": "2.0.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "2.0.0",
+ "_model_name": "FloatSliderModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "2.0.0",
+ "_view_name": "FloatSliderView",
+ "behavior": "drag-tap",
+ "continuous_update": true,
+ "description": "t",
+ "description_allow_html": false,
+ "disabled": false,
+ "layout": "IPY_MODEL_06f2374f91c8455bb63252092512f2ed",
+ "max": 1.1333333333333333,
+ "min": 0,
+ "orientation": "horizontal",
+ "readout": true,
+ "readout_format": ".2f",
+ "step": 0.011333333333333332,
+ "style": "IPY_MODEL_56ff19291e464d63b23e63b8e2ac9ea3",
+ "tabbable": null,
+ "tooltip": null,
+ "value": 0
+ }
+ },
+ "7d46516469314b88be3500e2afcafcf6": {
+ "model_module": "@jupyter-widgets/output",
+ "model_name": "OutputModel",
+ "model_module_version": "1.0.0",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/output",
+ "_model_module_version": "1.0.0",
+ "_model_name": "OutputModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/output",
+ "_view_module_version": "1.0.0",
+ "_view_name": "OutputView",
+ "layout": "IPY_MODEL_646a8670cb204a31bb56bc2380898093",
+ "msg_id": "",
+ "outputs": [],
+ "tabbable": null,
+ "tooltip": null
+ }
+ },
+ "423bffea3a1c42b49a9ad71218e5811b": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "2.0.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "2.0.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "2.0.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border_bottom": null,
+ "border_left": null,
+ "border_right": null,
+ "border_top": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "06f2374f91c8455bb63252092512f2ed": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "2.0.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "2.0.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "2.0.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border_bottom": null,
+ "border_left": null,
+ "border_right": null,
+ "border_top": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "56ff19291e464d63b23e63b8e2ac9ea3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_name": "SliderStyleModel",
+ "model_module_version": "2.0.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "2.0.0",
+ "_model_name": "SliderStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "2.0.0",
+ "_view_name": "StyleView",
+ "description_width": "",
+ "handle_color": null
+ }
+ },
+ "646a8670cb204a31bb56bc2380898093": {
+ "model_module": "@jupyter-widgets/base",
+ "model_name": "LayoutModel",
+ "model_module_version": "2.0.0",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "2.0.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "2.0.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border_bottom": null,
+ "border_left": null,
+ "border_right": null,
+ "border_top": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ }
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/scripts/CMAES.py b/examples/scripts/CMAES.py
new file mode 100644
index 000000000..65315b41e
--- /dev/null
+++ b/examples/scripts/CMAES.py
@@ -0,0 +1,55 @@
+import pybop
+import numpy as np
+import matplotlib.pyplot as plt
+
+parameter_set = pybop.ParameterSet("pybamm", "Chen2020")
+model = pybop.lithium_ion.SPMe(parameter_set=parameter_set)
+
+# Fitting parameters
+parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.7, 0.05),
+ bounds=[0.6, 0.9],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.58, 0.05),
+ bounds=[0.5, 0.8],
+ ),
+]
+
+sigma = 0.001
+t_eval = np.arange(0, 900, 2)
+values = model.predict(t_eval=t_eval)
+CorruptValues = values["Terminal voltage [V]"].data + np.random.normal(
+ 0, sigma, len(t_eval)
+)
+
+dataset = [
+ pybop.Dataset("Time [s]", t_eval),
+ pybop.Dataset("Current function [A]", values["Current [A]"].data),
+ pybop.Dataset("Terminal voltage [V]", CorruptValues),
+]
+
+# Generate problem, cost function, and optimisation class
+problem = pybop.Problem(model, parameters, dataset)
+cost = pybop.SumSquaredError(problem)
+optim = pybop.Optimisation(cost, optimiser=pybop.CMAES)
+optim.set_max_iterations(100)
+
+x, final_cost = optim.run()
+print("Estimated parameters:", x)
+
+# Show the generated data
+simulated_values = problem.evaluate(x)
+
+plt.figure(dpi=100)
+plt.xlabel("Time", fontsize=12)
+plt.ylabel("Values", fontsize=12)
+plt.plot(t_eval, CorruptValues, label="Measured")
+plt.fill_between(t_eval, simulated_values - sigma, simulated_values + sigma, alpha=0.2)
+plt.plot(t_eval, simulated_values, label="Simulated")
+plt.legend(bbox_to_anchor=(0.6, 1), loc="upper left", fontsize=12)
+plt.tick_params(axis="both", labelsize=12)
+plt.show()
diff --git a/examples/scripts/Chen_example.csv b/examples/scripts/Chen_example.csv
new file mode 100644
index 000000000..99d509e37
--- /dev/null
+++ b/examples/scripts/Chen_example.csv
@@ -0,0 +1,1389 @@
+Time [s],Current [A],Terminal voltage [V],Cycle,Step
+0.0,2.5,4.160927753511467,0.0,0.0
+1.0,2.5,4.157601075676489,0.0,0.0
+2.0,2.5,4.154490994259158,0.0,0.0
+3.0,2.5,4.151579735777284,0.0,0.0
+4.0,2.5,4.148849144222897,0.0,0.0
+5.0,2.5,4.146282844054771,0.0,0.0
+6.0,2.5,4.143866411877354,0.0,0.0
+7.0,2.5,4.14158685882251,0.0,0.0
+8.0,2.5,4.139432527584678,0.0,0.0
+9.0,2.5,4.1373935777586475,0.0,0.0
+10.0,2.5,4.135460207732003,0.0,0.0
+11.0,2.5,4.133623207865335,0.0,0.0
+12.0,2.5,4.131876288053798,0.0,0.0
+13.0,2.5,4.130210715881797,0.0,0.0
+14.0,2.5,4.128621343373044,0.0,0.0
+15.0,2.5,4.127102372425127,0.0,0.0
+16.0,2.5,4.1256486435085735,0.0,0.0
+17.0,2.5,4.124255949522701,0.0,0.0
+18.0,2.5,4.122920513753348,0.0,0.0
+19.0,2.5,4.121637691133036,0.0,0.0
+20.0,2.5,4.1204045357969346,0.0,0.0
+21.0,2.5,4.11921859787859,0.0,0.0
+22.0,2.5,4.118077799023512,0.0,0.0
+23.0,2.5,4.116977284631903,0.0,0.0
+24.0,2.5,4.115915940608523,0.0,0.0
+25.0,2.5,4.1148922144992515,0.0,0.0
+26.0,2.5,4.113904682884345,0.0,0.0
+27.0,2.5,4.112949360973445,0.0,0.0
+28.0,2.5,4.1120256982856205,0.0,0.0
+29.0,2.5,4.1111323466687715,0.0,0.0
+30.0,2.5,4.11026804945668,0.0,0.0
+31.0,2.5,4.109430366615028,0.0,0.0
+32.0,2.5,4.10861857427313,0.0,0.0
+33.0,2.5,4.1078315059979635,0.0,0.0
+34.0,2.5,4.107068078631514,0.0,0.0
+35.0,2.5,4.106326974076594,0.0,0.0
+36.0,2.5,4.105607359218209,0.0,0.0
+37.0,2.5,4.104908336227618,0.0,0.0
+38.0,2.5,4.1042290586599,0.0,0.0
+39.0,2.5,4.1035685421348544,0.0,0.0
+40.0,2.5,4.1029261716599965,0.0,0.0
+41.0,2.5,4.10230128451634,0.0,0.0
+42.0,2.5,4.101693276866006,0.0,0.0
+43.0,2.5,4.101101600597589,0.0,0.0
+44.0,2.5,4.100525726267815,0.0,0.0
+45.0,2.5,4.099964502197802,0.0,0.0
+46.0,2.5,4.099417847146635,0.0,0.0
+47.0,2.5,4.098885319974872,0.0,0.0
+48.0,2.5,4.098366517541476,0.0,0.0
+49.0,2.5,4.097861072571672,0.0,0.0
+50.0,2.5,4.097368645549943,0.0,0.0
+51.0,2.5,4.09688808870161,0.0,0.0
+52.0,2.5,4.0964195142422435,0.0,0.0
+53.0,2.5,4.095962581548417,0.0,0.0
+54.0,2.5,4.095516971816701,0.0,0.0
+55.0,2.5,4.095082386937095,0.0,0.0
+56.0,2.5,4.094658548400727,0.0,0.0
+57.0,2.5,4.09424471783567,0.0,0.0
+58.0,2.5,4.093840843122007,0.0,0.0
+59.0,2.5,4.093446656829645,0.0,0.0
+60.0,2.5,4.093061889347226,0.0,0.0
+61.0,2.5,4.092686283528498,0.0,0.0
+62.0,2.5,4.092319594146908,0.0,0.0
+63.0,2.5,4.091961442559183,0.0,0.0
+64.0,2.5,4.091611652591053,0.0,0.0
+65.0,2.5,4.091270004239898,0.0,0.0
+66.0,2.5,4.090936275768548,0.0,0.0
+67.0,2.5,4.090610254161096,0.0,0.0
+68.0,2.5,4.090291734778852,0.0,0.0
+69.0,2.5,4.089980493354697,0.0,0.0
+70.0,2.5,4.089676347645338,0.0,0.0
+71.0,2.5,4.089379115842617,0.0,0.0
+72.0,2.5,4.089088619679142,0.0,0.0
+73.0,2.5,4.088804687536027,0.0,0.0
+74.0,2.5,4.088527154174912,0.0,0.0
+75.0,2.5,4.088255804667979,0.0,0.0
+76.0,2.5,4.087990501979117,0.0,0.0
+77.0,2.5,4.087731105819368,0.0,0.0
+78.0,2.5,4.087477471187321,0.0,0.0
+79.0,2.5,4.08722945847457,0.0,0.0
+80.0,2.5,4.086986933232946,0.0,0.0
+81.0,2.5,4.086749765949343,0.0,0.0
+82.0,2.5,4.0865178318285365,0.0,0.0
+83.0,2.5,4.086291010583731,0.0,0.0
+84.0,2.5,4.0860691862348055,0.0,0.0
+85.0,2.5,4.085852132426833,0.0,0.0
+86.0,2.5,4.085639716421859,0.0,0.0
+87.0,2.5,4.085431899989458,0.0,0.0
+88.0,2.5,4.085228574804643,0.0,0.0
+89.0,2.5,4.0850296359704155,0.0,0.0
+90.0,2.5,4.084834981878631,0.0,0.0
+91.0,2.5,4.084644514076079,0.0,0.0
+92.0,2.5,4.0844581371360364,0.0,0.0
+93.0,2.5,4.084275758534926,0.0,0.0
+94.0,2.5,4.084097288534272,0.0,0.0
+95.0,2.5,4.083922580111833,0.0,0.0
+96.0,2.5,4.083751443484631,0.0,0.0
+97.0,2.5,4.083583895147556,0.0,0.0
+98.0,2.5,4.083419848098537,0.0,0.0
+99.0,2.5,4.083259217539309,0.0,0.0
+100.0,2.5,4.083101920805127,0.0,0.0
+101.0,2.5,4.082947877296784,0.0,0.0
+102.0,2.5,4.08279700841526,0.0,0.0
+103.0,2.5,4.0826492374987975,0.0,0.0
+104.0,2.5,4.082504489762482,0.0,0.0
+105.0,2.5,4.0823626853081025,0.0,0.0
+106.0,2.5,4.082223665259328,0.0,0.0
+107.0,2.5,4.082087423199833,0.0,0.0
+108.0,2.5,4.0819538876851205,0.0,0.0
+109.0,2.5,4.081822988827989,0.0,0.0
+110.0,2.5,4.081694658258913,0.0,0.0
+111.0,2.5,4.081568829087869,0.0,0.0
+112.0,2.5,4.081445435866936,0.0,0.0
+113.0,2.5,4.081324414554147,0.0,0.0
+114.0,2.5,4.0812057024784885,0.0,0.0
+115.0,2.5,4.081089238305971,0.0,0.0
+116.0,2.5,4.08097494232456,0.0,0.0
+117.0,2.5,4.080862764679917,0.0,0.0
+118.0,2.5,4.080752650215037,0.0,0.0
+119.0,2.5,4.080644541698893,0.0,0.0
+120.0,2.5,4.080538383064326,0.0,0.0
+121.0,2.5,4.080434119381322,0.0,0.0
+122.0,2.5,4.080331696830786,0.0,0.0
+123.0,2.5,4.080231062679405,0.0,0.0
+124.0,2.5,4.080132165254847,0.0,0.0
+125.0,2.5,4.0800349539220875,0.0,0.0
+126.0,2.5,4.079939376720904,0.0,0.0
+127.0,2.5,4.0798453847155685,0.0,0.0
+128.0,2.5,4.079752931441735,0.0,0.0
+129.0,2.5,4.079661970018632,0.0,0.0
+130.0,2.5,4.079572454489028,0.0,0.0
+131.0,2.5,4.0794843397994525,0.0,0.0
+132.0,2.5,4.079397581781398,0.0,0.0
+133.0,2.5,4.079312137132995,0.0,0.0
+134.0,2.5,4.079227963401337,0.0,0.0
+135.0,2.5,4.079145018965368,0.0,0.0
+136.0,2.5,4.0790632581457285,0.0,0.0
+137.0,2.5,4.078982634181892,0.0,0.0
+138.0,2.5,4.07890311548313,0.0,0.0
+139.0,2.5,4.078824663331393,0.0,0.0
+140.0,2.5,4.078747239768525,0.0,0.0
+141.0,2.5,4.078670807581731,0.0,0.0
+142.0,2.5,4.078595330289514,0.0,0.0
+143.0,2.5,4.078520772128148,0.0,0.0
+144.0,2.5,4.078447098038876,0.0,0.0
+145.0,2.5,4.078374273655544,0.0,0.0
+146.0,2.5,4.078302265292856,0.0,0.0
+147.0,2.5,4.078231039935201,0.0,0.0
+148.0,2.5,4.078160565225972,0.0,0.0
+149.0,2.5,4.078090809457463,0.0,0.0
+150.0,2.5,4.0780217415612645,0.0,0.0
+151.0,2.5,4.077953331099245,0.0,0.0
+152.0,2.5,4.077885548254853,0.0,0.0
+153.0,2.5,4.0778183457825286,0.0,0.0
+154.0,2.5,4.077751683756053,0.0,0.0
+155.0,2.5,4.077685554179354,0.0,0.0
+156.0,2.5,4.077619928841112,0.0,0.0
+157.0,2.5,4.077554780081825,0.0,0.0
+158.0,2.5,4.077490080785911,0.0,0.0
+159.0,2.5,4.07742580437427,0.0,0.0
+160.0,2.5,4.077361924797133,0.0,0.0
+161.0,2.5,4.077298416527288,0.0,0.0
+162.0,2.5,4.077235254553625,0.0,0.0
+163.0,2.5,4.077172414375023,0.0,0.0
+164.0,2.5,4.077109871994523,0.0,0.0
+165.0,2.5,4.077047603913931,0.0,0.0
+166.0,2.5,4.076985587128584,0.0,0.0
+167.0,2.5,4.0769237991225085,0.0,0.0
+168.0,2.5,4.0768622178638925,0.0,0.0
+169.0,2.5,4.076800821800829,0.0,0.0
+170.0,2.5,4.076739567832886,0.0,0.0
+171.0,2.5,4.076678430698656,0.0,0.0
+172.0,2.5,4.076617407022613,0.0,0.0
+173.0,2.5,4.076556476171565,0.0,0.0
+174.0,2.5,4.076495617921502,0.0,0.0
+175.0,2.5,4.076434812452586,0.0,0.0
+176.0,2.5,4.076374040344133,0.0,0.0
+177.0,2.5,4.076313282569893,0.0,0.0
+178.0,2.5,4.076252520493434,0.0,0.0
+179.0,2.5,4.0761917358636595,0.0,0.0
+180.0,2.5,4.076130910810625,0.0,0.0
+181.0,2.5,4.076070027841338,0.0,0.0
+182.0,2.5,4.076009069835855,0.0,0.0
+183.0,2.5,4.075948020043392,0.0,0.0
+184.0,2.5,4.075886862078759,0.0,0.0
+185.0,2.5,4.075825579918716,0.0,0.0
+186.0,2.5,4.075764157898728,0.0,0.0
+187.0,2.5,4.075702566041725,0.0,0.0
+188.0,2.5,4.075640790574839,0.0,0.0
+189.0,2.5,4.075578824437293,0.0,0.0
+190.0,2.5,4.075516652749117,0.0,0.0
+191.0,2.5,4.07545426093731,0.0,0.0
+192.0,2.5,4.075391634731802,0.0,0.0
+193.0,2.5,4.075328760161517,0.0,0.0
+194.0,2.5,4.075265623550525,0.0,0.0
+195.0,2.5,4.0752022115142985,0.0,0.0
+196.0,2.5,4.075138510956072,0.0,0.0
+197.0,2.5,4.075074509063162,0.0,0.0
+198.0,2.5,4.075010193303642,0.0,0.0
+199.0,2.5,4.074945551422783,0.0,0.0
+200.0,2.5,4.074880571439843,0.0,0.0
+201.0,2.5,4.0748152416447745,0.0,0.0
+202.0,2.5,4.074749550595088,0.0,0.0
+203.0,2.5,4.074683487112824,0.0,0.0
+204.0,2.5,4.074617034797386,0.0,0.0
+205.0,2.5,4.074550184650403,0.0,0.0
+206.0,2.5,4.074482928099226,0.0,0.0
+207.0,2.5,4.074415254780117,0.0,0.0
+208.0,2.5,4.074347154566803,0.0,0.0
+209.0,2.5,4.074278617567291,0.0,0.0
+210.0,2.5,4.074209634120945,0.0,0.0
+211.0,2.5,4.074140194795576,0.0,0.0
+212.0,2.5,4.074070290384515,0.0,0.0
+213.0,2.5,4.073999911903955,0.0,0.0
+214.0,2.5,4.0739290505900705,0.0,0.0
+215.0,2.5,4.073857697896411,0.0,0.0
+216.0,2.5,4.073785845491324,0.0,0.0
+217.0,2.5,4.073713485255321,0.0,0.0
+218.0,2.5,4.0736406092786925,0.0,0.0
+219.0,2.5,4.073567209858991,0.0,0.0
+220.0,2.5,4.073493279498674,0.0,0.0
+221.0,2.5,4.073418808567246,0.0,0.0
+222.0,2.5,4.07334379108645,0.0,0.0
+223.0,2.5,4.073268220616229,0.0,0.0
+224.0,2.5,4.07319209037358,0.0,0.0
+225.0,2.5,4.073115393764511,0.0,0.0
+226.0,2.5,4.073038124381744,0.0,0.0
+227.0,2.5,4.072960276002726,0.0,0.0
+228.0,2.5,4.072881842587348,0.0,0.0
+229.0,2.5,4.072802818276068,0.0,0.0
+230.0,2.5,4.072723197387714,0.0,0.0
+231.0,2.5,4.0726429744177235,0.0,0.0
+232.0,2.5,4.072562144036067,0.0,0.0
+233.0,2.5,4.072480701085468,0.0,0.0
+234.0,2.5,4.072398640579519,0.0,0.0
+235.0,2.5,4.072315957700959,0.0,0.0
+236.0,2.5,4.072232647799895,0.0,0.0
+237.0,2.5,4.072148706392074,0.0,0.0
+238.0,2.5,4.072064120134619,0.0,0.0
+239.0,2.5,4.071978890849423,0.0,0.0
+240.0,2.5,4.0718930154476585,0.0,0.0
+241.0,2.5,4.071806489930813,0.0,0.0
+242.0,2.5,4.07171931045325,0.0,0.0
+243.0,2.5,4.071631473320771,0.0,0.0
+244.0,2.5,4.071542974989084,0.0,0.0
+245.0,2.5,4.071453812062383,0.0,0.0
+246.0,2.5,4.071363981291887,0.0,0.0
+247.0,2.5,4.0712734795745265,0.0,0.0
+248.0,2.5,4.0711823039515815,0.0,0.0
+249.0,2.5,4.071090451607358,0.0,0.0
+250.0,2.5,4.070997919867907,0.0,0.0
+251.0,2.5,4.070904706199816,0.0,0.0
+252.0,2.5,4.070810808208975,0.0,0.0
+253.0,2.5,4.070716223639418,0.0,0.0
+254.0,2.5,4.070620950372149,0.0,0.0
+255.0,2.5,4.070524986424056,0.0,0.0
+256.0,2.5,4.07042832994678,0.0,0.0
+257.0,2.5,4.070330979225705,0.0,0.0
+258.0,2.5,4.070232932678884,0.0,0.0
+259.0,2.5,4.070134188856022,0.0,0.0
+260.0,2.5,4.070034746437567,0.0,0.0
+261.0,2.5,4.069934604233671,0.0,0.0
+262.0,2.5,4.069833761183301,0.0,0.0
+263.0,2.5,4.069732216353356,0.0,0.0
+264.0,2.5,4.069629962608646,0.0,0.0
+265.0,2.5,4.069526974796968,0.0,0.0
+266.0,2.5,4.069423277465929,0.0,0.0
+267.0,2.5,4.06931886975559,0.0,0.0
+268.0,2.5,4.0692137509128425,0.0,0.0
+269.0,2.5,4.069107920290343,0.0,0.0
+270.0,2.5,4.069001377345511,0.0,0.0
+271.0,2.5,4.0688941216394525,0.0,0.0
+272.0,2.5,4.068786152836081,0.0,0.0
+273.0,2.5,4.068677470701036,0.0,0.0
+274.0,2.5,4.068568075100781,0.0,0.0
+275.0,2.5,4.068457966001725,0.0,0.0
+276.0,2.5,4.068347143469275,0.0,0.0
+277.0,2.5,4.068235607666899,0.0,0.0
+278.0,2.5,4.0681233588553765,0.0,0.0
+279.0,2.5,4.068010397391818,0.0,0.0
+280.0,2.5,4.067896723728946,0.0,0.0
+281.0,2.5,4.067782338414229,0.0,0.0
+282.0,2.5,4.067667242089039,0.0,0.0
+283.0,2.5,4.067551435487968,0.0,0.0
+284.0,2.5,4.0674349194379875,0.0,0.0
+285.0,2.5,4.067317694857721,0.0,0.0
+286.0,2.5,4.067199762756734,0.0,0.0
+287.0,2.5,4.067081124234777,0.0,0.0
+288.0,2.5,4.066961780481108,0.0,0.0
+289.0,2.5,4.066841732773772,0.0,0.0
+290.0,2.5,4.066720982478961,0.0,0.0
+291.0,2.5,4.0665995265560175,0.0,0.0
+292.0,2.5,4.066477362635106,0.0,0.0
+293.0,2.5,4.066354495157822,0.0,0.0
+294.0,2.5,4.066230925036236,0.0,0.0
+295.0,2.5,4.066106653219106,0.0,0.0
+296.0,2.5,4.065981680690279,0.0,0.0
+297.0,2.5,4.065856008467152,0.0,0.0
+298.0,2.5,4.065729637599162,0.0,0.0
+299.0,2.5,4.065602569166355,0.0,0.0
+300.0,2.5,4.065474804277807,0.0,0.0
+300.000000001,0.0,4.083337104220067,0.0,1.0
+301.0,0.0,4.08411857143703,0.0,1.0
+302.0,0.0,4.084823935791453,0.0,1.0
+303.0,0.0,4.085462722054559,0.0,1.0
+304.0,0.0,4.086043182007179,0.0,1.0
+305.0,0.0,4.0865724051017125,0.0,1.0
+306.0,0.0,4.087056427997617,0.0,1.0
+307.0,0.0,4.087500374077019,0.0,1.0
+308.0,0.0,4.08790902639921,0.0,1.0
+309.0,0.0,4.088286058882586,0.0,1.0
+310.0,0.0,4.088635268080958,0.0,1.0
+311.0,0.0,4.088959341219949,0.0,1.0
+312.0,0.0,4.089261112677142,0.0,1.0
+313.0,0.0,4.089542668887757,0.0,1.0
+314.0,0.0,4.089806112806356,0.0,1.0
+315.0,0.0,4.090053122784463,0.0,1.0
+316.0,0.0,4.090285221354024,0.0,1.0
+317.0,0.0,4.090503745704817,0.0,1.0
+318.0,0.0,4.090710046396893,0.0,1.0
+319.0,0.0,4.090905114792385,0.0,1.0
+320.0,0.0,4.091089906030976,0.0,1.0
+321.0,0.0,4.091265371880813,0.0,1.0
+322.0,0.0,4.0914322422960385,0.0,1.0
+323.0,0.0,4.091591184363877,0.0,1.0
+324.0,0.0,4.0917428222357195,0.0,1.0
+325.0,0.0,4.091887766010014,0.0,1.0
+326.0,0.0,4.092026518729413,0.0,1.0
+327.0,0.0,4.0921594814565765,0.0,1.0
+328.0,0.0,4.092287017515516,0.0,1.0
+329.0,0.0,4.09240944878535,0.0,1.0
+330.0,0.0,4.092527417454655,0.0,1.0
+331.0,0.0,4.092641028661417,0.0,1.0
+332.0,0.0,4.092750526981569,0.0,1.0
+333.0,0.0,4.092856120722325,0.0,1.0
+334.0,0.0,4.092958108470949,0.0,1.0
+335.0,0.0,4.093056869083674,0.0,1.0
+336.0,0.0,4.093152462953598,0.0,1.0
+337.0,0.0,4.09324505576939,0.0,1.0
+338.0,0.0,4.093334793123759,0.0,1.0
+339.0,0.0,4.093421944422245,0.0,1.0
+340.0,0.0,4.093506649887989,0.0,1.0
+341.0,0.0,4.093589011210733,0.0,1.0
+342.0,0.0,4.093669150941425,0.0,1.0
+343.0,0.0,4.093747185325492,0.0,1.0
+344.0,0.0,4.093823278769266,0.0,1.0
+345.0,0.0,4.093897505111239,0.0,1.0
+346.0,0.0,4.09396995992965,0.0,1.0
+347.0,0.0,4.094040730949751,0.0,1.0
+348.0,0.0,4.09410990799957,0.0,1.0
+349.0,0.0,4.094177578696497,0.0,1.0
+350.0,0.0,4.094243806711216,0.0,1.0
+351.0,0.0,4.094308657608522,0.0,1.0
+352.0,0.0,4.094372191189041,0.0,1.0
+353.0,0.0,4.094434507708313,0.0,1.0
+354.0,0.0,4.094495651938244,0.0,1.0
+355.0,0.0,4.094555664953677,0.0,1.0
+356.0,0.0,4.094614591157936,0.0,1.0
+357.0,0.0,4.094672469999011,0.0,1.0
+358.0,0.0,4.094729336096383,0.0,1.0
+359.0,0.0,4.0947852193522305,0.0,1.0
+360.0,0.0,4.094840145048124,0.0,1.0
+361.0,0.0,4.094894277223266,0.0,1.0
+362.0,0.0,4.0949475944493345,0.0,1.0
+363.0,0.0,4.0950000983298045,0.0,1.0
+364.0,0.0,4.095051812803234,0.0,1.0
+365.0,0.0,4.095102758594911,0.0,1.0
+366.0,0.0,4.0951529532665045,0.0,1.0
+367.0,0.0,4.095202411257952,0.0,1.0
+368.0,0.0,4.095251143922228,0.0,1.0
+369.0,0.0,4.095299315797117,0.0,1.0
+370.0,0.0,4.09534688558349,0.0,1.0
+371.0,0.0,4.0953938468241775,0.0,1.0
+372.0,0.0,4.095440216551898,0.0,1.0
+373.0,0.0,4.095486010140206,0.0,1.0
+374.0,0.0,4.095531241327584,0.0,1.0
+375.0,0.0,4.095575922238512,0.0,1.0
+376.0,0.0,4.095620063401408,0.0,1.0
+377.0,0.0,4.095663760543893,0.0,1.0
+378.0,0.0,4.095706993028133,0.0,1.0
+379.0,0.0,4.095749763336209,0.0,1.0
+380.0,0.0,4.095792085594328,0.0,1.0
+381.0,0.0,4.095833973140304,0.0,1.0
+382.0,0.0,4.095875438539559,0.0,1.0
+383.0,0.0,4.09591649359953,0.0,1.0
+384.0,0.0,4.0959571493826985,0.0,1.0
+385.0,0.0,4.095997438202164,0.0,1.0
+386.0,0.0,4.096037362024716,0.0,1.0
+387.0,0.0,4.0960769292507475,0.0,1.0
+388.0,0.0,4.096116150545187,0.0,1.0
+389.0,0.0,4.096155036066913,0.0,1.0
+390.0,0.0,4.096193595477757,0.0,1.0
+391.0,0.0,4.096231837950833,0.0,1.0
+392.0,0.0,4.096269772177853,0.0,1.0
+393.0,0.0,4.096307408860641,0.0,1.0
+394.0,0.0,4.096344754822972,0.0,1.0
+395.0,0.0,4.096381817330585,0.0,1.0
+396.0,0.0,4.096418603484685,0.0,1.0
+397.0,0.0,4.096455119952227,0.0,1.0
+398.0,0.0,4.096491372969539,0.0,1.0
+399.0,0.0,4.096527368345044,0.0,1.0
+400.0,0.0,4.096563111461736,0.0,1.0
+401.0,0.0,4.096598627108964,0.0,1.0
+402.0,0.0,4.09663391003031,0.0,1.0
+403.0,0.0,4.096668963385099,0.0,1.0
+404.0,0.0,4.096703791876213,0.0,1.0
+405.0,0.0,4.096738399802303,0.0,1.0
+406.0,0.0,4.096772791057752,0.0,1.0
+407.0,0.0,4.096806969132171,0.0,1.0
+408.0,0.0,4.096840937109579,0.0,1.0
+409.0,0.0,4.0968746976672685,0.0,1.0
+410.0,0.0,4.096908253074219,0.0,1.0
+411.0,0.0,4.096941605189362,0.0,1.0
+412.0,0.0,4.096974755459436,0.0,1.0
+413.0,0.0,4.097007704916578,0.0,1.0
+414.0,0.0,4.097040480435536,0.0,1.0
+415.0,0.0,4.097073076123438,0.0,1.0
+416.0,0.0,4.097105491844794,0.0,1.0
+417.0,0.0,4.097137731121214,0.0,1.0
+418.0,0.0,4.09716979741555,0.0,1.0
+419.0,0.0,4.0972016941341565,0.0,1.0
+420.0,0.0,4.097233424628999,0.0,1.0
+420.000000001,-2.5,4.115314153407617,0.0,2.0
+421.0,-2.5,4.11580126816336,0.0,2.0
+422.0,-2.5,4.116287981535286,0.0,2.0
+423.0,-2.5,4.116777990744232,0.0,2.0
+424.0,-2.5,4.117273191364564,0.0,2.0
+425.0,-2.5,4.117774915639592,0.0,2.0
+426.0,-2.5,4.118284040604012,0.0,2.0
+427.0,-2.5,4.118801048057358,0.0,2.0
+428.0,-2.5,4.119326515995133,0.0,2.0
+429.0,-2.5,4.119860399527127,0.0,2.0
+430.0,-2.5,4.120403180460219,0.0,2.0
+431.0,-2.5,4.120954562276548,0.0,2.0
+432.0,-2.5,4.121514781148596,0.0,2.0
+433.0,-2.5,4.122083516198534,0.0,2.0
+434.0,-2.5,4.1226607942227185,0.0,2.0
+435.0,-2.5,4.123246364371904,0.0,2.0
+436.0,-2.5,4.123840020969835,0.0,2.0
+437.0,-2.5,4.124441526266611,0.0,2.0
+438.0,-2.5,4.125050951332003,0.0,2.0
+439.0,-2.5,4.125667962076965,0.0,2.0
+440.0,-2.5,4.126292367649658,0.0,2.0
+441.0,-2.5,4.126924195444504,0.0,2.0
+442.0,-2.5,4.127563200844878,0.0,2.0
+443.0,-2.5,4.12820917027299,0.0,2.0
+444.0,-2.5,4.128861945806709,0.0,2.0
+445.0,-2.5,4.129521510767318,0.0,2.0
+446.0,-2.5,4.130187710940636,0.0,2.0
+447.0,-2.5,4.130860241429103,0.0,2.0
+448.0,-2.5,4.131538785425746,0.0,2.0
+449.0,-2.5,4.132223012474197,0.0,2.0
+450.0,-2.5,4.1329137060465575,0.0,2.0
+451.0,-2.5,4.1336100747288285,0.0,2.0
+452.0,-2.5,4.134311816352641,0.0,2.0
+453.0,-2.5,4.135018566209412,0.0,2.0
+454.0,-2.5,4.135730402582563,0.0,2.0
+455.0,-2.5,4.136447738344287,0.0,2.0
+456.0,-2.5,4.137169913020526,0.0,2.0
+457.0,-2.5,4.137896687838134,0.0,2.0
+458.0,-2.5,4.13862779190947,0.0,2.0
+459.0,-2.5,4.139363583911809,0.0,2.0
+460.0,-2.5,4.140103858101116,0.0,2.0
+461.0,-2.5,4.140848348950613,0.0,2.0
+462.0,-2.5,4.1415969032465085,0.0,2.0
+463.0,-2.5,4.142349392150335,0.0,2.0
+464.0,-2.5,4.14310594336973,0.0,2.0
+465.0,-2.5,4.143866307267678,0.0,2.0
+466.0,-2.5,4.144630367242537,0.0,2.0
+467.0,-2.5,4.14539800048952,0.0,2.0
+468.0,-2.5,4.146169135105322,0.0,2.0
+469.0,-2.5,4.1469437054342855,0.0,2.0
+470.0,-2.5,4.147721556947632,0.0,2.0
+471.0,-2.5,4.148502566664649,0.0,2.0
+472.0,-2.5,4.149286603209791,0.0,2.0
+473.0,-2.5,4.150073818632925,0.0,2.0
+474.0,-2.5,4.150864013380658,0.0,2.0
+475.0,-2.5,4.151657032252208,0.0,2.0
+476.0,-2.5,4.152452742603151,0.0,2.0
+477.0,-2.5,4.153250998409786,0.0,2.0
+478.0,-2.5,4.154051639048997,0.0,2.0
+479.0,-2.5,4.154854488114104,0.0,2.0
+480.0,-2.5,4.155659352267687,0.0,2.0
+481.0,-2.5,4.156467062646512,0.0,2.0
+482.0,-2.5,4.157276995734728,0.0,2.0
+483.0,-2.5,4.158088929742623,0.0,2.0
+484.0,-2.5,4.158902722580855,0.0,2.0
+485.0,-2.5,4.159718220883334,0.0,2.0
+486.0,-2.5,4.160535259263556,0.0,2.0
+487.0,-2.5,4.161353659596958,0.0,2.0
+488.0,-2.5,4.162173230329908,0.0,2.0
+489.0,-2.5,4.162995033345934,0.0,2.0
+490.0,-2.5,4.163818275506938,0.0,2.0
+491.0,-2.5,4.1646427911171955,0.0,2.0
+492.0,-2.5,4.165468472838174,0.0,2.0
+493.0,-2.5,4.166295209164681,0.0,2.0
+494.0,-2.5,4.167122884071705,0.0,2.0
+495.0,-2.5,4.16795137667258,0.0,2.0
+496.0,-2.5,4.168780560888696,0.0,2.0
+497.0,-2.5,4.1696110735551075,0.0,2.0
+498.0,-2.5,4.170442384273522,0.0,2.0
+499.0,-2.5,4.171274413467192,0.0,2.0
+500.0,-2.5,4.1721070926304,0.0,2.0
+501.0,-2.5,4.172940353307712,0.0,2.0
+502.0,-2.5,4.173774126914772,0.0,2.0
+503.0,-2.5,4.17460834456357,0.0,2.0
+504.0,-2.5,4.175442940725014,0.0,2.0
+505.0,-2.5,4.176278044626564,0.0,2.0
+506.0,-2.5,4.17711347773185,0.0,2.0
+507.0,-2.5,4.177949187515572,0.0,2.0
+508.0,-2.5,4.178785121997135,0.0,2.0
+509.0,-2.5,4.179621229611505,0.0,2.0
+510.0,-2.5,4.180457459083005,0.0,2.0
+511.0,-2.5,4.181293759302215,0.0,2.0
+512.0,-2.5,4.182130080544206,0.0,2.0
+513.0,-2.5,4.182966395471069,0.0,2.0
+514.0,-2.5,4.1838026396555374,0.0,2.0
+515.0,-2.5,4.184638763875634,0.0,2.0
+516.0,-2.5,4.185474718707162,0.0,2.0
+517.0,-2.5,4.186310454421232,0.0,2.0
+518.0,-2.5,4.187145920884718,0.0,2.0
+519.0,-2.5,4.187981067463743,0.0,2.0
+520.0,-2.5,4.188815859287128,0.0,2.0
+521.0,-2.5,4.1896504023686605,0.0,2.0
+522.0,-2.5,4.190484538000852,0.0,2.0
+523.0,-2.5,4.191318220929476,0.0,2.0
+524.0,-2.5,4.192151405074641,0.0,2.0
+525.0,-2.5,4.1929840434470975,0.0,2.0
+526.0,-2.5,4.19381608806758,0.0,2.0
+527.0,-2.5,4.1946474898890145,0.0,2.0
+528.0,-2.5,4.195478198721599,0.0,2.0
+529.0,-2.5,4.196308163160786,0.0,2.0
+530.0,-2.5,4.197137330518019,0.0,2.0
+531.0,-2.5,4.197965646754283,0.0,2.0
+532.0,-2.5,4.198793056416422,0.0,2.0
+533.0,-2.5,4.1996195697873056,0.0,2.0
+534.0,-2.5,4.200445644043602,0.0,2.0
+535.0,-2.5,4.201270821156214,0.0,2.0
+536.0,-2.5,4.20209506239229,0.0,2.0
+537.0,-2.5,4.202918328424658,0.0,2.0
+538.0,-2.5,4.203740579283007,0.0,2.0
+539.0,-2.5,4.2045617743068116,0.0,2.0
+540.0,-2.5,4.205381872100225,0.0,2.0
+541.0,-2.5,4.206200830488596,0.0,2.0
+542.0,-2.5,4.207018606476822,0.0,2.0
+543.0,-2.5,4.207835156209456,0.0,2.0
+544.0,-2.5,4.208650434932421,0.0,2.0
+545.0,-2.5,4.209464396956459,0.0,2.0
+546.0,-2.5,4.210277075901499,0.0,2.0
+547.0,-2.5,4.211088946655144,0.0,2.0
+548.0,-2.5,4.211899546903226,0.0,2.0
+549.0,-2.5,4.212708850053829,0.0,2.0
+550.0,-2.5,4.213516829576945,0.0,2.0
+551.0,-2.5,4.2143234589756196,0.0,2.0
+552.0,-2.5,4.215128711758133,0.0,2.0
+553.0,-2.5,4.215932561410892,0.0,2.0
+554.0,-2.5,4.216734981372289,0.0,2.0
+555.0,-2.5,4.217535945007451,0.0,2.0
+556.0,-2.5,4.218335425583666,0.0,2.0
+557.0,-2.5,4.219133396246829,0.0,2.0
+558.0,-2.5,4.219929829998552,0.0,2.0
+559.0,-2.5,4.220724737110144,0.0,2.0
+560.0,-2.5,4.221518305656589,0.0,2.0
+561.0,-2.5,4.222310344723525,0.0,2.0
+562.0,-2.5,4.223100839241547,0.0,2.0
+563.0,-2.5,4.223889774647726,0.0,2.0
+564.0,-2.5,4.224677136866221,0.0,2.0
+565.0,-2.5,4.2254629122892915,0.0,2.0
+566.0,-2.5,4.226247087758805,0.0,2.0
+567.0,-2.5,4.227029650547929,0.0,2.0
+568.0,-2.5,4.227810588343391,0.0,2.0
+569.0,-2.5,4.228589889227962,0.0,2.0
+570.0,-2.5,4.229367541663446,0.0,2.0
+570.000000001,0.0,4.210029284710582,0.0,3.0
+571.0,0.0,4.207213583314949,0.0,3.0
+572.0,0.0,4.2045971631097725,0.0,3.0
+573.0,0.0,4.202161839008122,0.0,3.0
+574.0,0.0,4.199890898745848,0.0,3.0
+575.0,0.0,4.197769335614359,0.0,3.0
+576.0,0.0,4.195783879691244,0.0,3.0
+577.0,0.0,4.193922813568967,0.0,3.0
+578.0,0.0,4.19217522692314,0.0,3.0
+579.0,0.0,4.1905311507282805,0.0,3.0
+580.0,0.0,4.1889814120405005,0.0,3.0
+581.0,0.0,4.187518661668531,0.0,3.0
+582.0,0.0,4.186134907137069,0.0,3.0
+583.0,0.0,4.184824930563117,0.0,3.0
+584.0,0.0,4.1835819030923505,0.0,3.0
+585.0,0.0,4.182401580048656,0.0,3.0
+586.0,0.0,4.181278703809178,0.0,3.0
+587.0,0.0,4.180209910457267,0.0,3.0
+588.0,0.0,4.179190532538634,0.0,3.0
+589.0,0.0,4.178216902784102,0.0,3.0
+590.0,0.0,4.177286614461846,0.0,3.0
+591.0,0.0,4.176396007237823,0.0,3.0
+592.0,0.0,4.175542354184778,0.0,3.0
+593.0,0.0,4.17472364073388,0.0,3.0
+594.0,0.0,4.17393750941874,0.0,3.0
+595.0,0.0,4.173181867365283,0.0,3.0
+596.0,0.0,4.172454471651524,0.0,3.0
+597.0,0.0,4.171754031090117,0.0,3.0
+598.0,0.0,4.171079263572318,0.0,3.0
+599.0,0.0,4.17042913754243,0.0,3.0
+600.0,0.0,4.16980120491864,0.0,3.0
+601.0,0.0,4.169194204224323,0.0,3.0
+602.0,0.0,4.168607759644541,0.0,3.0
+603.0,0.0,4.168041150823556,0.0,3.0
+604.0,0.0,4.167493774627918,0.0,3.0
+605.0,0.0,4.166962625224374,0.0,3.0
+606.0,0.0,4.166448148159899,0.0,3.0
+607.0,0.0,4.165949685934117,0.0,3.0
+608.0,0.0,4.165466676378533,0.0,3.0
+609.0,0.0,4.164998206772577,0.0,3.0
+610.0,0.0,4.1645429199915345,0.0,3.0
+611.0,0.0,4.1641007216410015,0.0,3.0
+612.0,0.0,4.1636710663369385,0.0,3.0
+613.0,0.0,4.16325346065624,0.0,3.0
+614.0,0.0,4.1628471299862,0.0,3.0
+615.0,0.0,4.162451571498087,0.0,3.0
+616.0,0.0,4.162066421723589,0.0,3.0
+617.0,0.0,4.16169126270297,0.0,3.0
+618.0,0.0,4.161325704401287,0.0,3.0
+619.0,0.0,4.1609692153506135,0.0,3.0
+620.0,0.0,4.160621529491947,0.0,3.0
+621.0,0.0,4.160282325457457,0.0,3.0
+622.0,0.0,4.159951311130621,0.0,3.0
+623.0,0.0,4.159628069141708,0.0,3.0
+624.0,0.0,4.159312117980469,0.0,3.0
+625.0,0.0,4.159003373346276,0.0,3.0
+626.0,0.0,4.158701613036827,0.0,3.0
+627.0,0.0,4.158406643057931,0.0,3.0
+628.0,0.0,4.158118297327637,0.0,3.0
+629.0,0.0,4.157836437392334,0.0,3.0
+630.0,0.0,4.157560952154421,0.0,3.0
+631.0,0.0,4.157291261979277,0.0,3.0
+632.0,0.0,4.157026688466741,0.0,3.0
+633.0,0.0,4.156767652572423,0.0,3.0
+634.0,0.0,4.156514032810383,0.0,3.0
+635.0,0.0,4.156265726685805,0.0,3.0
+636.0,0.0,4.15602265052153,0.0,3.0
+637.0,0.0,4.155784739291854,0.0,3.0
+638.0,0.0,4.155551946463349,0.0,3.0
+639.0,0.0,4.1553237049393745,0.0,3.0
+640.0,0.0,4.155099377411003,0.0,3.0
+641.0,0.0,4.154879446227916,0.0,3.0
+642.0,0.0,4.154663814247297,0.0,3.0
+643.0,0.0,4.154452393741274,0.0,3.0
+644.0,0.0,4.154245106315513,0.0,3.0
+645.0,0.0,4.154041882830858,0.0,3.0
+646.0,0.0,4.153842663327825,0.0,3.0
+647.0,0.0,4.153647101167119,0.0,3.0
+648.0,0.0,4.153454830558504,0.0,3.0
+649.0,0.0,4.153266067313362,0.0,3.0
+650.0,0.0,4.153080721404211,0.0,3.0
+651.0,0.0,4.152898707130987,0.0,3.0
+652.0,0.0,4.152719943082192,0.0,3.0
+653.0,0.0,4.152544352097112,0.0,3.0
+654.0,0.0,4.152371861229269,0.0,3.0
+655.0,0.0,4.1522023277734,0.0,3.0
+656.0,0.0,4.152035610979901,0.0,3.0
+657.0,0.0,4.1518717097175015,0.0,3.0
+658.0,0.0,4.151710551395647,0.0,3.0
+659.0,0.0,4.151552066364199,0.0,3.0
+660.0,0.0,4.1513961878880865,0.0,3.0
+661.0,0.0,4.15124285212288,0.0,3.0
+662.0,0.0,4.151091998090975,0.0,3.0
+663.0,0.0,4.1509435592345785,0.0,3.0
+664.0,0.0,4.150797472097141,0.0,3.0
+665.0,0.0,4.150653690629847,0.0,3.0
+666.0,0.0,4.150512163297496,0.0,3.0
+667.0,0.0,4.1503728411991965,0.0,3.0
+668.0,0.0,4.15023567804895,0.0,3.0
+669.0,0.0,4.150100630156968,0.0,3.0
+670.0,0.0,4.149967656411437,0.0,3.0
+671.0,0.0,4.1498366540695955,0.0,3.0
+672.0,0.0,4.1497075385471796,0.0,3.0
+673.0,0.0,4.149580332413257,0.0,3.0
+674.0,0.0,4.149454998704056,0.0,3.0
+675.0,0.0,4.14933150294905,0.0,3.0
+676.0,0.0,4.149209813155258,0.0,3.0
+677.0,0.0,4.149089899791887,0.0,3.0
+678.0,0.0,4.148971735775508,0.0,3.0
+679.0,0.0,4.148855296455618,0.0,3.0
+680.0,0.0,4.1487405596006734,0.0,3.0
+681.0,0.0,4.148627505384641,0.0,3.0
+682.0,0.0,4.14851611637379,0.0,3.0
+683.0,0.0,4.148406377514072,0.0,3.0
+684.0,0.0,4.148298213522299,0.0,3.0
+685.0,0.0,4.148191511522451,0.0,3.0
+686.0,0.0,4.148086312994496,0.0,3.0
+687.0,0.0,4.1479825873201,0.0,3.0
+688.0,0.0,4.147880304164437,0.0,3.0
+689.0,0.0,4.147779433472801,0.0,3.0
+690.0,0.0,4.147679945467388,0.0,3.0
+690.000000001,2.5,4.128614765545601,1.0,0.0
+691.0,2.5,4.125806121237927,1.0,0.0
+692.0,2.5,4.123215794986313,1.0,0.0
+693.0,2.5,4.1208229134493735,1.0,0.0
+694.0,2.5,4.118607471025524,1.0,0.0
+695.0,2.5,4.116551784497935,1.0,0.0
+696.0,2.5,4.114640381218213,1.0,0.0
+697.0,2.5,4.112859689636109,1.0,0.0
+698.0,2.5,4.111197424781445,1.0,0.0
+699.0,2.5,4.1096425953611275,1.0,0.0
+700.0,2.5,4.108185319207477,1.0,0.0
+701.0,2.5,4.106817367636223,1.0,0.0
+702.0,2.5,4.105530584404381,1.0,0.0
+703.0,2.5,4.104318858718375,1.0,0.0
+704.0,2.5,4.103175499004113,1.0,0.0
+705.0,2.5,4.102095597490596,1.0,0.0
+706.0,2.5,4.101073956789457,1.0,0.0
+707.0,2.5,4.100106646480028,1.0,0.0
+708.0,2.5,4.099189265075946,1.0,0.0
+709.0,2.5,4.0983181499111465,1.0,0.0
+710.0,2.5,4.0974904450012435,1.0,0.0
+711.0,2.5,4.096702826328648,1.0,0.0
+712.0,2.5,4.095952583807382,1.0,0.0
+713.0,2.5,4.0952374707757215,1.0,0.0
+714.0,2.5,4.094555187694315,1.0,0.0
+715.0,2.5,4.093903667889831,1.0,0.0
+716.0,2.5,4.093280877078022,1.0,0.0
+717.0,2.5,4.092685281272766,1.0,0.0
+718.0,2.5,4.092115414449436,1.0,0.0
+719.0,2.5,4.091569972939239,1.0,0.0
+720.0,2.5,4.09104717147136,1.0,0.0
+721.0,2.5,4.090545739714515,1.0,0.0
+722.0,2.5,4.0900648204169885,1.0,0.0
+723.0,2.5,4.089603449382283,1.0,0.0
+724.0,2.5,4.089160753388908,1.0,0.0
+725.0,2.5,4.088735029900462,1.0,0.0
+726.0,2.5,4.0883258737423,1.0,0.0
+727.0,2.5,4.0879325054599285,1.0,0.0
+728.0,2.5,4.087554207133284,1.0,0.0
+729.0,2.5,4.087190186810957,1.0,0.0
+730.0,2.5,4.086839527158593,1.0,0.0
+731.0,2.5,4.086501759926133,1.0,0.0
+732.0,2.5,4.0861762895157385,1.0,0.0
+733.0,2.5,4.085862558779947,1.0,0.0
+734.0,2.5,4.085559956599416,1.0,0.0
+735.0,2.5,4.08526796397757,1.0,0.0
+736.0,2.5,4.084986129068984,1.0,0.0
+737.0,2.5,4.084713999265481,1.0,0.0
+738.0,2.5,4.084451147597297,1.0,0.0
+739.0,2.5,4.08419712400763,1.0,0.0
+740.0,2.5,4.083951565539416,1.0,0.0
+741.0,2.5,4.083714107407066,1.0,0.0
+742.0,2.5,4.083484404949723,1.0,0.0
+743.0,2.5,4.083262100125357,1.0,0.0
+744.0,2.5,4.083046824275364,1.0,0.0
+745.0,2.5,4.08283832164241,1.0,0.0
+746.0,2.5,4.082636310723714,1.0,0.0
+747.0,2.5,4.0824405255597345,1.0,0.0
+748.0,2.5,4.082250714809793,1.0,0.0
+749.0,2.5,4.082066640890373,1.0,0.0
+750.0,2.5,4.0818880791738374,1.0,0.0
+751.0,2.5,4.08171473227161,1.0,0.0
+752.0,2.5,4.08154625823742,1.0,0.0
+753.0,2.5,4.081382576608256,1.0,0.0
+754.0,2.5,4.081223491802858,1.0,0.0
+755.0,2.5,4.0810688177970835,1.0,0.0
+756.0,2.5,4.080918377636783,1.0,0.0
+757.0,2.5,4.080772002987455,1.0,0.0
+758.0,2.5,4.08062953371918,1.0,0.0
+759.0,2.5,4.080490740915204,1.0,0.0
+760.0,2.5,4.080355347942114,1.0,0.0
+761.0,2.5,4.080223318596588,1.0,0.0
+762.0,2.5,4.080094506404174,1.0,0.0
+763.0,2.5,4.079968770905705,1.0,0.0
+764.0,2.5,4.0798459774126865,1.0,0.0
+765.0,2.5,4.0797259967792545,1.0,0.0
+766.0,2.5,4.079608705189785,1.0,0.0
+767.0,2.5,4.079493948205887,1.0,0.0
+768.0,2.5,4.079381547473939,1.0,0.0
+769.0,2.5,4.079271442100604,1.0,0.0
+770.0,2.5,4.079163519575337,1.0,0.0
+771.0,2.5,4.079057671435461,1.0,0.0
+772.0,2.5,4.078953793119238,1.0,0.0
+773.0,2.5,4.078851783826287,1.0,0.0
+774.0,2.5,4.07875154638534,1.0,0.0
+775.0,2.5,4.0786529792242465,1.0,0.0
+776.0,2.5,4.078555977035114,1.0,0.0
+777.0,2.5,4.078460463561321,1.0,0.0
+778.0,2.5,4.0783663529236325,1.0,0.0
+779.0,2.5,4.078273562173607,1.0,0.0
+780.0,2.5,4.078182011193613,1.0,0.0
+781.0,2.5,4.078091622601979,1.0,0.0
+782.0,2.5,4.078002321662702,1.0,0.0
+783.0,2.5,4.077914035307862,1.0,0.0
+784.0,2.5,4.077826692056932,1.0,0.0
+785.0,2.5,4.0777402258409134,1.0,0.0
+786.0,2.5,4.077654571435659,1.0,0.0
+787.0,2.5,4.077569665857292,1.0,0.0
+788.0,2.5,4.077485448296463,1.0,0.0
+789.0,2.5,4.077401860056638,1.0,0.0
+790.0,2.5,4.077318844495759,1.0,0.0
+791.0,2.5,4.077236341050073,1.0,0.0
+792.0,2.5,4.0771542857423775,1.0,0.0
+793.0,2.5,4.0770726373132895,1.0,0.0
+794.0,2.5,4.076991345937895,1.0,0.0
+795.0,2.5,4.076910363576668,1.0,0.0
+796.0,2.5,4.076829643933492,1.0,0.0
+797.0,2.5,4.076749142416511,1.0,0.0
+798.0,2.5,4.076668816102087,1.0,0.0
+799.0,2.5,4.076588623701528,1.0,0.0
+800.0,2.5,4.07650852553042,1.0,0.0
+801.0,2.5,4.076428483480787,1.0,0.0
+802.0,2.5,4.076348460995688,1.0,0.0
+803.0,2.5,4.076268423046131,1.0,0.0
+804.0,2.5,4.076188320415346,1.0,0.0
+805.0,2.5,4.076108076853919,1.0,0.0
+806.0,2.5,4.076027700246825,1.0,0.0
+807.0,2.5,4.075947158610126,1.0,0.0
+808.0,2.5,4.075866421197667,1.0,0.0
+809.0,2.5,4.075785458480302,1.0,0.0
+810.0,2.5,4.075704242126962,1.0,0.0
+811.0,2.5,4.075622744987126,1.0,0.0
+812.0,2.5,4.07554094107501,1.0,0.0
+813.0,2.5,4.075458805555057,1.0,0.0
+814.0,2.5,4.0753763147289055,1.0,0.0
+815.0,2.5,4.075293446023828,1.0,0.0
+816.0,2.5,4.075210177982228,1.0,0.0
+817.0,2.5,4.075126478009019,1.0,0.0
+818.0,2.5,4.075042268381398,1.0,0.0
+819.0,2.5,4.0749575776201485,1.0,0.0
+820.0,2.5,4.074872385282608,1.0,0.0
+821.0,2.5,4.07478667174869,1.0,0.0
+822.0,2.5,4.074700418206247,1.0,0.0
+823.0,2.5,4.074613606637252,1.0,0.0
+824.0,2.5,4.074526219804822,1.0,0.0
+825.0,2.5,4.07443824124094,1.0,0.0
+826.0,2.5,4.0743496552349345,1.0,0.0
+827.0,2.5,4.07426044682273,1.0,0.0
+828.0,2.5,4.074170601776774,1.0,0.0
+829.0,2.5,4.074080106596522,1.0,0.0
+830.0,2.5,4.073988944409249,1.0,0.0
+831.0,2.5,4.07389706411082,1.0,0.0
+832.0,2.5,4.07380448348669,1.0,0.0
+833.0,2.5,4.073711189875896,1.0,0.0
+834.0,2.5,4.073617171155592,1.0,0.0
+835.0,2.5,4.073522415729633,1.0,0.0
+836.0,2.5,4.073426912517358,1.0,0.0
+837.0,2.5,4.073330650942989,1.0,0.0
+838.0,2.5,4.073233620925456,1.0,0.0
+839.0,2.5,4.073135812868662,1.0,0.0
+840.0,2.5,4.073037217652044,1.0,0.0
+841.0,2.5,4.072937826621785,1.0,0.0
+842.0,2.5,4.072837631582176,1.0,0.0
+843.0,2.5,4.072736624454799,1.0,0.0
+844.0,2.5,4.072634785196609,1.0,0.0
+845.0,2.5,4.07253211599917,1.0,0.0
+846.0,2.5,4.07242860985028,1.0,0.0
+847.0,2.5,4.072324260116496,1.0,0.0
+848.0,2.5,4.072219060535384,1.0,0.0
+849.0,2.5,4.072113005207956,1.0,0.0
+850.0,2.5,4.072006088591653,1.0,0.0
+851.0,2.5,4.07189830549335,1.0,0.0
+852.0,2.5,4.071789651062911,1.0,0.0
+853.0,2.5,4.071680120786833,1.0,0.0
+854.0,2.5,4.071569710482282,1.0,0.0
+855.0,2.5,4.071458416291358,1.0,0.0
+856.0,2.5,4.071346234675647,1.0,0.0
+857.0,2.5,4.071233157910828,1.0,0.0
+858.0,2.5,4.071119185993691,1.0,0.0
+859.0,2.5,4.0710043162925444,1.0,0.0
+860.0,2.5,4.070888546282846,1.0,0.0
+861.0,2.5,4.070771873720951,1.0,0.0
+862.0,2.5,4.0706542966396135,1.0,0.0
+863.0,2.5,4.070535813343663,1.0,0.0
+864.0,2.5,4.070416422405941,1.0,0.0
+865.0,2.5,4.070296122663345,1.0,0.0
+866.0,2.5,4.070174913213193,1.0,0.0
+867.0,2.5,4.070052793409649,1.0,0.0
+868.0,2.5,4.069929762860374,1.0,0.0
+869.0,2.5,4.069805821423346,1.0,0.0
+870.0,2.5,4.069680951292653,1.0,0.0
+871.0,2.5,4.069555163670968,1.0,0.0
+872.0,2.5,4.069428460770549,1.0,0.0
+873.0,2.5,4.069300842934896,1.0,0.0
+874.0,2.5,4.069172310729855,1.0,0.0
+875.0,2.5,4.069042864941206,1.0,0.0
+876.0,2.5,4.06891250657255,1.0,0.0
+877.0,2.5,4.068781236843257,1.0,0.0
+878.0,2.5,4.068649057186542,1.0,0.0
+879.0,2.5,4.06851596924772,1.0,0.0
+880.0,2.5,4.068381974882488,1.0,0.0
+881.0,2.5,4.068247076155449,1.0,0.0
+882.0,2.5,4.06811127533861,1.0,0.0
+883.0,2.5,4.067974574910159,1.0,0.0
+884.0,2.5,4.067836977553112,1.0,0.0
+885.0,2.5,4.067698486154311,1.0,0.0
+886.0,2.5,4.067559103803314,1.0,0.0
+887.0,2.5,4.067418833791489,1.0,0.0
+888.0,2.5,4.067277679611176,1.0,0.0
+889.0,2.5,4.067135644954893,1.0,0.0
+890.0,2.5,4.066992733714616,1.0,0.0
+891.0,2.5,4.066848892267121,1.0,0.0
+892.0,2.5,4.066704158323439,1.0,0.0
+893.0,2.5,4.066558545968444,1.0,0.0
+894.0,2.5,4.066412058590058,1.0,0.0
+895.0,2.5,4.066264699716728,1.0,0.0
+896.0,2.5,4.066116473016315,1.0,0.0
+897.0,2.5,4.065967382294969,1.0,0.0
+898.0,2.5,4.065817431496182,1.0,0.0
+899.0,2.5,4.065666624699817,1.0,0.0
+900.0,2.5,4.065514966121278,1.0,0.0
+901.0,2.5,4.0653624601105625,1.0,0.0
+902.0,2.5,4.065209111151687,1.0,0.0
+903.0,2.5,4.065054923861827,1.0,0.0
+904.0,2.5,4.064899902990779,1.0,0.0
+905.0,2.5,4.064744053420258,1.0,0.0
+906.0,2.5,4.064587380163446,1.0,0.0
+907.0,2.5,4.064429888364402,1.0,0.0
+908.0,2.5,4.06427158329768,1.0,0.0
+909.0,2.5,4.064112470367832,1.0,0.0
+910.0,2.5,4.063952555109091,1.0,0.0
+911.0,2.5,4.063791843184997,1.0,0.0
+912.0,2.5,4.063630277497095,1.0,0.0
+913.0,2.5,4.063467894940995,1.0,0.0
+914.0,2.5,4.063304716928806,1.0,0.0
+915.0,2.5,4.063140748220183,1.0,0.0
+916.0,2.5,4.062975993642285,1.0,0.0
+917.0,2.5,4.06281045808888,1.0,0.0
+918.0,2.5,4.062644146519421,1.0,0.0
+919.0,2.5,4.062477063958197,1.0,0.0
+920.0,2.5,4.062309215493494,1.0,0.0
+921.0,2.5,4.062140606276824,1.0,0.0
+922.0,2.5,4.061971241522149,1.0,0.0
+923.0,2.5,4.061801126505238,1.0,0.0
+924.0,2.5,4.0616302665629105,1.0,0.0
+925.0,2.5,4.061458667092474,1.0,0.0
+926.0,2.5,4.061286333551058,1.0,0.0
+927.0,2.5,4.061113271455032,1.0,0.0
+928.0,2.5,4.060939486379491,1.0,0.0
+929.0,2.5,4.060764983957747,1.0,0.0
+930.0,2.5,4.060589769880763,1.0,0.0
+931.0,2.5,4.060413849896752,1.0,0.0
+932.0,2.5,4.060237229810745,1.0,0.0
+933.0,2.5,4.06005987981483,1.0,0.0
+934.0,2.5,4.0598818196646285,1.0,0.0
+935.0,2.5,4.059703067216386,1.0,0.0
+936.0,2.5,4.059523627666805,1.0,0.0
+937.0,2.5,4.059343506233953,1.0,0.0
+938.0,2.5,4.059162708156519,1.0,0.0
+939.0,2.5,4.058981238693309,1.0,0.0
+940.0,2.5,4.058799103122527,1.0,0.0
+941.0,2.5,4.058616306741245,1.0,0.0
+942.0,2.5,4.058432854864801,1.0,0.0
+943.0,2.5,4.05824875282633,1.0,0.0
+944.0,2.5,4.058064005976207,1.0,0.0
+945.0,2.5,4.057878619681599,1.0,0.0
+946.0,2.5,4.057692599325923,1.0,0.0
+947.0,2.5,4.05750595030854,1.0,0.0
+948.0,2.5,4.0573186780442025,1.0,0.0
+949.0,2.5,4.057130787962739,1.0,0.0
+950.0,2.5,4.056942285508683,1.0,0.0
+951.0,2.5,4.0567531761408,1.0,0.0
+952.0,2.5,4.056563465331922,1.0,0.0
+953.0,2.5,4.056373158568492,1.0,0.0
+954.0,2.5,4.056182249396747,1.0,0.0
+955.0,2.5,4.055990746503981,1.0,0.0
+956.0,2.5,4.055798660633878,1.0,0.0
+957.0,2.5,4.055605997033133,1.0,0.0
+958.0,2.5,4.05541276094956,1.0,0.0
+959.0,2.5,4.055218957631721,1.0,0.0
+960.0,2.5,4.055024592328643,1.0,0.0
+961.0,2.5,4.054829670289562,1.0,0.0
+962.0,2.5,4.054634196763572,1.0,0.0
+963.0,2.5,4.054438176999461,1.0,0.0
+964.0,2.5,4.054241616245413,1.0,0.0
+965.0,2.5,4.054044519748825,1.0,0.0
+966.0,2.5,4.053846892756033,1.0,0.0
+967.0,2.5,4.053648740512184,1.0,0.0
+968.0,2.5,4.0534500682609895,1.0,0.0
+969.0,2.5,4.05325088124461,1.0,0.0
+970.0,2.5,4.053051184703445,1.0,0.0
+971.0,2.5,4.0528509838760245,1.0,0.0
+972.0,2.5,4.052650283998865,1.0,0.0
+973.0,2.5,4.05244909030632,1.0,0.0
+974.0,2.5,4.052247408030486,1.0,0.0
+975.0,2.5,4.052045239239031,1.0,0.0
+976.0,2.5,4.051842589327295,1.0,0.0
+977.0,2.5,4.051639465184019,1.0,0.0
+978.0,2.5,4.051435871888983,1.0,0.0
+979.0,2.5,4.051231814512316,1.0,0.0
+980.0,2.5,4.051027298114285,1.0,0.0
+981.0,2.5,4.0508223277452835,1.0,0.0
+982.0,2.5,4.050616908445679,1.0,0.0
+983.0,2.5,4.050411045245694,1.0,0.0
+984.0,2.5,4.050204743165406,1.0,0.0
+985.0,2.5,4.049998007214599,1.0,0.0
+986.0,2.5,4.0497908423927385,1.0,0.0
+987.0,2.5,4.049583253688934,1.0,0.0
+988.0,2.5,4.049375246081811,1.0,0.0
+989.0,2.5,4.049166824539588,1.0,0.0
+990.0,2.5,4.048957994019945,1.0,0.0
+990.000000001,0.0,4.066274523105717,1.0,1.0
+991.0,0.0,4.067511739204034,1.0,1.0
+992.0,0.0,4.068650009253588,1.0,1.0
+993.0,0.0,4.0696997147561635,1.0,1.0
+994.0,0.0,4.070670124553682,1.0,1.0
+995.0,0.0,4.0715693731808384,1.0,1.0
+996.0,0.0,4.072404508687583,1.0,1.0
+997.0,0.0,4.073181636025303,1.0,1.0
+998.0,0.0,4.0739062339845,1.0,1.0
+999.0,0.0,4.074584320156081,1.0,1.0
+1000.0,0.0,4.075218792981734,1.0,1.0
+1001.0,0.0,4.07581509928771,1.0,1.0
+1002.0,0.0,4.0763762026188575,1.0,1.0
+1003.0,0.0,4.0769049131918,1.0,1.0
+1004.0,0.0,4.077404780641758,1.0,1.0
+1005.0,0.0,4.077877158490983,1.0,1.0
+1006.0,0.0,4.07832509236538,1.0,1.0
+1007.0,0.0,4.0787501488805855,1.0,1.0
+1008.0,0.0,4.079154052977803,1.0,1.0
+1009.0,0.0,4.079538687437624,1.0,1.0
+1010.0,0.0,4.0799050326547475,1.0,1.0
+1011.0,0.0,4.080254786713908,1.0,1.0
+1012.0,0.0,4.080588888736091,1.0,1.0
+1013.0,0.0,4.080908472259136,1.0,1.0
+1014.0,0.0,4.081214603883834,1.0,1.0
+1015.0,0.0,4.081507905298471,1.0,1.0
+1016.0,0.0,4.0817893903723315,1.0,1.0
+1017.0,0.0,4.082059896227781,1.0,1.0
+1018.0,0.0,4.082320048210548,1.0,1.0
+1019.0,0.0,4.082570341984091,1.0,1.0
+1020.0,0.0,4.082811496044326,1.0,1.0
+1021.0,0.0,4.083044069852036,1.0,1.0
+1022.0,0.0,4.083268510883889,1.0,1.0
+1023.0,0.0,4.083485244294439,1.0,1.0
+1024.0,0.0,4.083694693278856,1.0,1.0
+1025.0,0.0,4.08389721605856,1.0,1.0
+1026.0,0.0,4.0840933422143015,1.0,1.0
+1027.0,0.0,4.08428335109877,1.0,1.0
+1028.0,0.0,4.084467487019907,1.0,1.0
+1029.0,0.0,4.084645991753886,1.0,1.0
+1030.0,0.0,4.084819072696092,1.0,1.0
+1031.0,0.0,4.084986904340376,1.0,1.0
+1032.0,0.0,4.085149911007361,1.0,1.0
+1033.0,0.0,4.085308604700753,1.0,1.0
+1034.0,0.0,4.08546285585263,1.0,1.0
+1035.0,0.0,4.0856128132306715,1.0,1.0
+1036.0,0.0,4.08575860412488,1.0,1.0
+1037.0,0.0,4.085900335197976,1.0,1.0
+1038.0,0.0,4.086038098836824,1.0,1.0
+1039.0,0.0,4.08617270770479,1.0,1.0
+1040.0,0.0,4.086303863559995,1.0,1.0
+1041.0,0.0,4.086431684092347,1.0,1.0
+1042.0,0.0,4.086556275849842,1.0,1.0
+1043.0,0.0,4.086677734646073,1.0,1.0
+1044.0,0.0,4.0867961459470274,1.0,1.0
+1045.0,0.0,4.086911791390844,1.0,1.0
+1046.0,0.0,4.08702481724515,1.0,1.0
+1047.0,0.0,4.087135220618481,1.0,1.0
+1048.0,0.0,4.0872430942025275,1.0,1.0
+1049.0,0.0,4.087348524979184,1.0,1.0
+1050.0,0.0,4.087451594413944,1.0,1.0
+1051.0,0.0,4.087552393836369,1.0,1.0
+1052.0,0.0,4.0876510648822855,1.0,1.0
+1053.0,0.0,4.087747639120805,1.0,1.0
+1054.0,0.0,4.08784218853943,1.0,1.0
+1055.0,0.0,4.087934781211356,1.0,1.0
+1056.0,0.0,4.088025481420903,1.0,1.0
+1057.0,0.0,4.088114349783614,1.0,1.0
+1058.0,0.0,4.088201455845237,1.0,1.0
+1059.0,0.0,4.088286851571946,1.0,1.0
+1060.0,0.0,4.088370586763548,1.0,1.0
+1061.0,0.0,4.088452710494326,1.0,1.0
+1062.0,0.0,4.088533268835792,1.0,1.0
+1063.0,0.0,4.088612304946186,1.0,1.0
+1064.0,0.0,4.08868988445602,1.0,1.0
+1065.0,0.0,4.088766078305341,1.0,1.0
+1066.0,0.0,4.0888408949833455,1.0,1.0
+1067.0,0.0,4.088914370653588,1.0,1.0
+1068.0,0.0,4.088986538911817,1.0,1.0
+1069.0,0.0,4.089057430858544,1.0,1.0
+1070.0,0.0,4.089127075168416,1.0,1.0
+1071.0,0.0,4.0891954981568714,1.0,1.0
+1072.0,0.0,4.089262723844032,1.0,1.0
+1073.0,0.0,4.089328774015838,1.0,1.0
+1074.0,0.0,4.089393689368266,1.0,1.0
+1075.0,0.0,4.089457657266609,1.0,1.0
+1076.0,0.0,4.0895205732893665,1.0,1.0
+1077.0,0.0,4.089582460509208,1.0,1.0
+1078.0,0.0,4.089643340419053,1.0,1.0
+1079.0,0.0,4.089703232972178,1.0,1.0
+1080.0,0.0,4.089762156620776,1.0,1.0
+1081.0,0.0,4.089820128353002,1.0,1.0
+1082.0,0.0,4.089877163728433,1.0,1.0
+1083.0,0.0,4.0899332769123,1.0,1.0
+1084.0,0.0,4.089988480708047,1.0,1.0
+1085.0,0.0,4.090042942961702,1.0,1.0
+1086.0,0.0,4.090096605343914,1.0,1.0
+1087.0,0.0,4.09014946085848,1.0,1.0
+1088.0,0.0,4.0902015264805796,1.0,1.0
+1089.0,0.0,4.090252818381426,1.0,1.0
+1090.0,0.0,4.090303351946826,1.0,1.0
+1091.0,0.0,4.090353141795051,1.0,1.0
+1092.0,0.0,4.090402201794179,1.0,1.0
+1093.0,0.0,4.090450545078762,1.0,1.0
+1094.0,0.0,4.090498184065852,1.0,1.0
+1095.0,0.0,4.09054517636494,1.0,1.0
+1096.0,0.0,4.090591544875099,1.0,1.0
+1097.0,0.0,4.090637274177523,1.0,1.0
+1098.0,0.0,4.090682378239904,1.0,1.0
+1099.0,0.0,4.090726870582236,1.0,1.0
+1100.0,0.0,4.090770764286746,1.0,1.0
+1101.0,0.0,4.090814072007476,1.0,1.0
+1102.0,0.0,4.0908568059794765,1.0,1.0
+1103.0,0.0,4.09089897802794,1.0,1.0
+1104.0,0.0,4.090940599576809,1.0,1.0
+1105.0,0.0,4.090981683409852,1.0,1.0
+1106.0,0.0,4.091022245792877,1.0,1.0
+1107.0,0.0,4.091062295272398,1.0,1.0
+1108.0,0.0,4.091101843141846,1.0,1.0
+1109.0,0.0,4.091140900448937,1.0,1.0
+1110.0,0.0,4.091179478000868,1.0,1.0
+1110.000000001,-2.5,4.108685027099113,1.0,2.0
+1111.0,-2.5,4.109249145264736,1.0,2.0
+1112.0,-2.5,4.109756288211877,1.0,2.0
+1113.0,-2.5,4.110216306657217,1.0,2.0
+1114.0,-2.5,4.11063679848971,1.0,2.0
+1115.0,-2.5,4.111024144279855,1.0,2.0
+1116.0,-2.5,4.111383688693465,1.0,2.0
+1117.0,-2.5,4.111719910353336,1.0,2.0
+1118.0,-2.5,4.112036627838165,1.0,2.0
+1119.0,-2.5,4.1123374513584645,1.0,2.0
+1120.0,-2.5,4.112624703713546,1.0,2.0
+1121.0,-2.5,4.112901264842645,1.0,2.0
+1122.0,-2.5,4.113169023059253,1.0,2.0
+1123.0,-2.5,4.113429662109631,1.0,2.0
+1124.0,-2.5,4.1136849705905485,1.0,2.0
+1125.0,-2.5,4.11393590218169,1.0,2.0
+1126.0,-2.5,4.114183898556045,1.0,2.0
+1127.0,-2.5,4.114429812580923,1.0,2.0
+1128.0,-2.5,4.114674508933649,1.0,2.0
+1129.0,-2.5,4.114918858556363,1.0,2.0
+1130.0,-2.5,4.115163355133316,1.0,2.0
+1131.0,-2.5,4.115408750813659,1.0,2.0
+1132.0,-2.5,4.115655457774607,1.0,2.0
+1133.0,-2.5,4.115903970540377,1.0,2.0
+1134.0,-2.5,4.116154731935361,1.0,2.0
+1135.0,-2.5,4.1164079747050675,1.0,2.0
+1136.0,-2.5,4.116664113153866,1.0,2.0
+1137.0,-2.5,4.116923483994771,1.0,2.0
+1138.0,-2.5,4.117186304751822,1.0,2.0
+1139.0,-2.5,4.117452733393656,1.0,2.0
+1140.0,-2.5,4.117723048647415,1.0,2.0
+1141.0,-2.5,4.117997449976209,1.0,2.0
+1142.0,-2.5,4.118276067261086,1.0,2.0
+1143.0,-2.5,4.118559027442687,1.0,2.0
+1144.0,-2.5,4.118846454892512,1.0,2.0
+1145.0,-2.5,4.119138434977853,1.0,2.0
+1146.0,-2.5,4.119435211584634,1.0,2.0
+1147.0,-2.5,4.1197368141989426,1.0,2.0
+1148.0,-2.5,4.120043272604645,1.0,2.0
+1149.0,-2.5,4.120354607129009,1.0,2.0
+1150.0,-2.5,4.120670808247033,1.0,2.0
+1151.0,-2.5,4.120991834230043,1.0,2.0
+1152.0,-2.5,4.121317949818342,1.0,2.0
+1153.0,-2.5,4.1216494070134075,1.0,2.0
+1154.0,-2.5,4.121985930927271,1.0,2.0
+1155.0,-2.5,4.122327484251333,1.0,2.0
+1156.0,-2.5,4.122674005538976,1.0,2.0
+1157.0,-2.5,4.123025407361925,1.0,2.0
+1158.0,-2.5,4.123381649938508,1.0,2.0
+1159.0,-2.5,4.1237434461927736,1.0,2.0
+1160.0,-2.5,4.124110291142608,1.0,2.0
+1161.0,-2.5,4.124482143996708,1.0,2.0
+1162.0,-2.5,4.124858951949952,1.0,2.0
+1163.0,-2.5,4.125240649374779,1.0,2.0
+1164.0,-2.5,4.125627156974626,1.0,2.0
+1165.0,-2.5,4.126018765297173,1.0,2.0
+1166.0,-2.5,4.126415420508046,1.0,2.0
+1167.0,-2.5,4.1268169804047625,1.0,2.0
+1168.0,-2.5,4.1272234104186545,1.0,2.0
+1169.0,-2.5,4.127634671758837,1.0,2.0
+1170.0,-2.5,4.128050721125763,1.0,2.0
+1171.0,-2.5,4.128471557190049,1.0,2.0
+1172.0,-2.5,4.128897234233817,1.0,2.0
+1173.0,-2.5,4.129327650792582,1.0,2.0
+1174.0,-2.5,4.1297627716613174,1.0,2.0
+1175.0,-2.5,4.130202559226611,1.0,2.0
+1176.0,-2.5,4.13064697326481,1.0,2.0
+1177.0,-2.5,4.131095970727928,1.0,2.0
+1178.0,-2.5,4.131549539618323,1.0,2.0
+1179.0,-2.5,4.132007619400688,1.0,2.0
+1180.0,-2.5,4.132470161637274,1.0,2.0
+1181.0,-2.5,4.132937116253136,1.0,2.0
+1182.0,-2.5,4.133408429926535,1.0,2.0
+1183.0,-2.5,4.133884045858476,1.0,2.0
+1184.0,-2.5,4.13436399518869,1.0,2.0
+1185.0,-2.5,4.134848256511372,1.0,2.0
+1186.0,-2.5,4.135336720628326,1.0,2.0
+1187.0,-2.5,4.135829329839066,1.0,2.0
+1188.0,-2.5,4.136326022479192,1.0,2.0
+1189.0,-2.5,4.136826732668227,1.0,2.0
+1190.0,-2.5,4.137331390055763,1.0,2.0
+1191.0,-2.5,4.137839919566874,1.0,2.0
+1192.0,-2.5,4.138352241147238,1.0,2.0
+1193.0,-2.5,4.138868269508739,1.0,2.0
+1194.0,-2.5,4.139388090405576,1.0,2.0
+1195.0,-2.5,4.139911945468805,1.0,2.0
+1196.0,-2.5,4.140439469506935,1.0,2.0
+1197.0,-2.5,4.140970596830726,1.0,2.0
+1198.0,-2.5,4.141505258693858,1.0,2.0
+1199.0,-2.5,4.142043383132191,1.0,2.0
+1200.0,-2.5,4.142584894803722,1.0,2.0
+1201.0,-2.5,4.143129714829247,1.0,2.0
+1202.0,-2.5,4.143677760634381,1.0,2.0
+1203.0,-2.5,4.1442289457928165,1.0,2.0
+1204.0,-2.5,4.14478322862258,1.0,2.0
+1205.0,-2.5,4.145341122756782,1.0,2.0
+1206.0,-2.5,4.145902133383769,1.0,2.0
+1207.0,-2.5,4.146466201686998,1.0,2.0
+1208.0,-2.5,4.147033267834858,1.0,2.0
+1209.0,-2.5,4.1476032709162425,1.0,2.0
+1210.0,-2.5,4.148176148876015,1.0,2.0
+1211.0,-2.5,4.148751838450418,1.0,2.0
+1212.0,-2.5,4.149330275102583,1.0,2.0
+1213.0,-2.5,4.149911392958335,1.0,2.0
+1214.0,-2.5,4.150495124742351,1.0,2.0
+1215.0,-2.5,4.151081702911843,1.0,2.0
+1216.0,-2.5,4.151670935118932,1.0,2.0
+1217.0,-2.5,4.152262725946282,1.0,2.0
+1218.0,-2.5,4.152857026354436,1.0,2.0
+1219.0,-2.5,4.153453787405518,1.0,2.0
+1220.0,-2.5,4.154052960236228,1.0,2.0
+1221.0,-2.5,4.154654496030229,1.0,2.0
+1222.0,-2.5,4.155258345990371,1.0,2.0
+1223.0,-2.5,4.155864461310419,1.0,2.0
+1224.0,-2.5,4.156472793146713,1.0,2.0
+1225.0,-2.5,4.157083337101548,1.0,2.0
+1226.0,-2.5,4.157696051150865,1.0,2.0
+1227.0,-2.5,4.1583108666402815,1.0,2.0
+1228.0,-2.5,4.158927739327761,1.0,2.0
+1229.0,-2.5,4.159546625154724,1.0,2.0
+1230.0,-2.5,4.160167480223082,1.0,2.0
+1231.0,-2.5,4.160790260771999,1.0,2.0
+1232.0,-2.5,4.161414923154602,1.0,2.0
+1233.0,-2.5,4.162041423814567,1.0,2.0
+1234.0,-2.5,4.16266971926274,1.0,2.0
+1235.0,-2.5,4.163299771039238,1.0,2.0
+1236.0,-2.5,4.1639315429873,1.0,2.0
+1237.0,-2.5,4.164564985346292,1.0,2.0
+1238.0,-2.5,4.165200055599982,1.0,2.0
+1239.0,-2.5,4.165836711249497,1.0,2.0
+1240.0,-2.5,4.1664749097914004,1.0,2.0
+1241.0,-2.5,4.1671146086956625,1.0,2.0
+1242.0,-2.5,4.167755765383997,1.0,2.0
+1243.0,-2.5,4.168398337208374,1.0,2.0
+1244.0,-2.5,4.1690422814296175,1.0,2.0
+1245.0,-2.5,4.169687567259625,1.0,2.0
+1246.0,-2.5,4.170334241751983,1.0,2.0
+1247.0,-2.5,4.170982193315098,1.0,2.0
+1248.0,-2.5,4.171631382319352,1.0,2.0
+1249.0,-2.5,4.172281769042215,1.0,2.0
+1250.0,-2.5,4.172933313647918,1.0,2.0
+1251.0,-2.5,4.173585976167334,1.0,2.0
+1252.0,-2.5,4.174239716478154,1.0,2.0
+1253.0,-2.5,4.1748944942855015,1.0,2.0
+1254.0,-2.5,4.175550269102773,1.0,2.0
+1255.0,-2.5,4.1762070002328775,1.0,2.0
+1256.0,-2.5,4.176864646749841,1.0,2.0
+1257.0,-2.5,4.177523167480745,1.0,2.0
+1258.0,-2.5,4.178182520988054,1.0,2.0
+1259.0,-2.5,4.178842665552368,1.0,2.0
+1260.0,-2.5,4.179503559155461,1.0,2.0
+1260.000000001,0.0,4.160964013318741,1.0,3.0
+1261.0,0.0,4.158572141824962,1.0,3.0
+1262.0,0.0,4.156376079810138,1.0,3.0
+1263.0,0.0,4.154355287883229,1.0,3.0
+1264.0,0.0,4.152491375699777,1.0,3.0
+1265.0,0.0,4.15076812516371,1.0,3.0
+1266.0,0.0,4.149171470426165,1.0,3.0
+1267.0,0.0,4.147689317719975,1.0,3.0
+1268.0,0.0,4.146309632986848,1.0,3.0
+1269.0,0.0,4.145023571363815,1.0,3.0
+1270.0,0.0,4.143820927136515,1.0,3.0
+1271.0,0.0,4.142695079880294,1.0,3.0
+1272.0,0.0,4.1416381894283445,1.0,3.0
+1273.0,0.0,4.14064487102113,1.0,3.0
+1274.0,0.0,4.13970920934347,1.0,3.0
+1275.0,0.0,4.138826626364079,1.0,3.0
+1276.0,0.0,4.137992857750286,1.0,3.0
+1277.0,0.0,4.137204112149755,1.0,3.0
+1278.0,0.0,4.136456270215449,1.0,3.0
+1279.0,0.0,4.135746551393303,1.0,3.0
+1280.0,0.0,4.135072086036729,1.0,3.0
+1281.0,0.0,4.134429879915956,1.0,3.0
+1282.0,0.0,4.133817769759332,1.0,3.0
+1283.0,0.0,4.133233704495695,1.0,3.0
+1284.0,0.0,4.132675743275834,1.0,3.0
+1285.0,0.0,4.132141856675212,1.0,3.0
+1286.0,0.0,4.13163047997326,1.0,3.0
+1287.0,0.0,4.13114039589672,1.0,3.0
+1288.0,0.0,4.130670508342971,1.0,3.0
+1289.0,0.0,4.130219777592415,1.0,3.0
+1290.0,0.0,4.129785742285175,1.0,3.0
+1291.0,0.0,4.129368320529917,1.0,3.0
+1292.0,0.0,4.1289667590876435,1.0,3.0
+1293.0,0.0,4.128580441095567,1.0,3.0
+1294.0,0.0,4.128208154421832,1.0,3.0
+1295.0,0.0,4.127848527451031,1.0,3.0
+1296.0,0.0,4.127501498535111,1.0,3.0
+1297.0,0.0,4.127166525127259,1.0,3.0
+1298.0,0.0,4.12684313956645,1.0,3.0
+1299.0,0.0,4.126530143174026,1.0,3.0
+1300.0,0.0,4.1262271792578895,1.0,3.0
+1301.0,0.0,4.125933882682511,1.0,3.0
+1302.0,0.0,4.125649818819935,1.0,3.0
+1303.0,0.0,4.125374543972036,1.0,3.0
+1304.0,0.0,4.125107415795206,1.0,3.0
+1305.0,0.0,4.124848189574386,1.0,3.0
+1306.0,0.0,4.124596511743216,1.0,3.0
+1307.0,0.0,4.124352057786894,1.0,3.0
+1308.0,0.0,4.124114469897172,1.0,3.0
+1309.0,0.0,4.123883423770482,1.0,3.0
+1310.0,0.0,4.123658683075876,1.0,3.0
+1311.0,0.0,4.123440001395834,1.0,3.0
+1312.0,0.0,4.123227154652392,1.0,3.0
+1313.0,0.0,4.123019671431074,1.0,3.0
+1314.0,0.0,4.122817455156986,1.0,3.0
+1315.0,0.0,4.122620334724273,1.0,3.0
+1316.0,0.0,4.122428142796556,1.0,3.0
+1317.0,0.0,4.12224073234334,1.0,3.0
+1318.0,0.0,4.122057976175602,1.0,3.0
+1319.0,0.0,4.121879766506314,1.0,3.0
+1320.0,0.0,4.121706014534377,1.0,3.0
+1321.0,0.0,4.121535798038875,1.0,3.0
+1322.0,0.0,4.121369506151888,1.0,3.0
+1323.0,0.0,4.121207051728784,1.0,3.0
+1324.0,0.0,4.12104834283579,1.0,3.0
+1325.0,0.0,4.120893300672793,1.0,3.0
+1326.0,0.0,4.120741859315891,1.0,3.0
+1327.0,0.0,4.120593965473212,1.0,3.0
+1328.0,0.0,4.12044955868774,1.0,3.0
+1329.0,0.0,4.12030772622053,1.0,3.0
+1330.0,0.0,4.120168950001753,1.0,3.0
+1331.0,0.0,4.120033151243904,1.0,3.0
+1332.0,0.0,4.119900257880457,1.0,3.0
+1333.0,0.0,4.119770204439625,1.0,3.0
+1334.0,0.0,4.119642931924266,1.0,3.0
+1335.0,0.0,4.119518387696884,1.0,3.0
+1336.0,0.0,4.119396494292352,1.0,3.0
+1337.0,0.0,4.119276777146785,1.0,3.0
+1338.0,0.0,4.1191594517585095,1.0,3.0
+1339.0,0.0,4.119044450606128,1.0,3.0
+1340.0,0.0,4.118931709417646,1.0,3.0
+1341.0,0.0,4.11882116710964,1.0,3.0
+1342.0,0.0,4.118712765728629,1.0,3.0
+1343.0,0.0,4.1186064503949895,1.0,3.0
+1344.0,0.0,4.118502156713998,1.0,3.0
+1345.0,0.0,4.118399739448249,1.0,3.0
+1346.0,0.0,4.118299209261662,1.0,3.0
+1347.0,0.0,4.118200513557185,1.0,3.0
+1348.0,0.0,4.1181036019272454,1.0,3.0
+1349.0,0.0,4.118008426115434,1.0,3.0
+1350.0,0.0,4.117914939979552,1.0,3.0
+1351.0,0.0,4.117823099456101,1.0,3.0
+1352.0,0.0,4.117732860639865,1.0,3.0
+1353.0,0.0,4.1176441741203815,1.0,3.0
+1354.0,0.0,4.117557007544608,1.0,3.0
+1355.0,0.0,4.117471323815646,1.0,3.0
+1356.0,0.0,4.117387087687448,1.0,3.0
+1357.0,0.0,4.11730426573703,1.0,3.0
+1358.0,0.0,4.117222826337418,1.0,3.0
+1359.0,0.0,4.117142739631756,1.0,3.0
+1360.0,0.0,4.117063958651974,1.0,3.0
+1361.0,0.0,4.116986396092423,1.0,3.0
+1362.0,0.0,4.116910074054813,1.0,3.0
+1363.0,0.0,4.116834966029668,1.0,3.0
+1364.0,0.0,4.116761047174298,1.0,3.0
+1365.0,0.0,4.116688294290901,1.0,3.0
+1366.0,0.0,4.11661668580559,1.0,3.0
+1367.0,0.0,4.116546201748191,1.0,3.0
+1368.0,0.0,4.1164768237325,1.0,3.0
+1369.0,0.0,4.116408534937501,1.0,3.0
+1370.0,0.0,4.116341320089215,1.0,3.0
+1371.0,0.0,4.1162751654430405,1.0,3.0
+1372.0,0.0,4.116210058766934,1.0,3.0
+1373.0,0.0,4.1161459643077425,1.0,3.0
+1374.0,0.0,4.11608277734336,1.0,3.0
+1375.0,0.0,4.116020544200532,1.0,3.0
+1376.0,0.0,4.115959245171489,1.0,3.0
+1377.0,0.0,4.115898860961665,1.0,3.0
+1378.0,0.0,4.11583937268339,1.0,3.0
+1379.0,0.0,4.115780761849897,1.0,3.0
+1380.0,0.0,4.115723010369455,1.0,3.0
diff --git a/examples/scripts/spm_descent.py b/examples/scripts/spm_descent.py
new file mode 100644
index 000000000..85f77f262
--- /dev/null
+++ b/examples/scripts/spm_descent.py
@@ -0,0 +1,60 @@
+import pybop
+import numpy as np
+import matplotlib.pyplot as plt
+
+# Parameter set and model definition
+parameter_set = pybop.ParameterSet("pybamm", "Chen2020")
+model = pybop.lithium_ion.SPMe(parameter_set=parameter_set)
+
+# Fitting parameters
+parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.7, 0.05),
+ bounds=[0.6, 0.9],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.58, 0.05),
+ bounds=[0.5, 0.8],
+ ),
+]
+
+# Generate data
+sigma = 0.001
+t_eval = np.arange(0, 900, 2)
+values = model.predict(t_eval=t_eval)
+corrupt_values = values["Terminal voltage [V]"].data + np.random.normal(
+ 0, sigma, len(t_eval)
+)
+
+# Dataset definition
+dataset = [
+ pybop.Dataset("Time [s]", t_eval),
+ pybop.Dataset("Current function [A]", values["Current [A]"].data),
+ pybop.Dataset("Terminal voltage [V]", corrupt_values),
+]
+
+# Generate problem, cost function, and optimisation class
+problem = pybop.Problem(model, parameters, dataset)
+cost = pybop.SumSquaredError(problem)
+optim = pybop.Optimisation(cost, optimiser=pybop.GradientDescent)
+optim.optimiser.set_learning_rate(0.025)
+optim.set_max_iterations(100)
+
+# Run optimisation
+x, final_cost = optim.run()
+print("Estimated parameters:", x)
+
+# Show the generated data
+simulated_values = problem.evaluate(x)
+
+plt.figure(dpi=100)
+plt.xlabel("Time", fontsize=12)
+plt.ylabel("Values", fontsize=12)
+plt.plot(t_eval, corrupt_values, label="Measured")
+plt.fill_between(t_eval, simulated_values - sigma, simulated_values + sigma, alpha=0.2)
+plt.plot(t_eval, simulated_values, label="Simulated")
+plt.legend(bbox_to_anchor=(0.6, 1), loc="upper left", fontsize=12)
+plt.tick_params(axis="both", labelsize=12)
+plt.show()
diff --git a/examples/scripts/spm_nlopt.py b/examples/scripts/spm_nlopt.py
new file mode 100644
index 000000000..19401ed45
--- /dev/null
+++ b/examples/scripts/spm_nlopt.py
@@ -0,0 +1,53 @@
+import pybop
+import pandas as pd
+import matplotlib.pyplot as plt
+
+# Form dataset
+Measurements = pd.read_csv("examples/scripts/Chen_example.csv", comment="#").to_numpy()
+dataset = [
+ pybop.Dataset("Time [s]", Measurements[:, 0]),
+ pybop.Dataset("Current function [A]", Measurements[:, 1]),
+ pybop.Dataset("Terminal voltage [V]", Measurements[:, 2]),
+]
+
+# Define model
+parameter_set = pybop.ParameterSet("pybamm", "Chen2020")
+model = pybop.models.lithium_ion.SPM(
+ parameter_set=parameter_set, options={"thermal": "lumped"}
+)
+
+# Fitting parameters
+parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.75, 0.05),
+ bounds=[0.6, 0.9],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.65, 0.05),
+ bounds=[0.5, 0.8],
+ ),
+]
+
+# Define the cost to optimise
+signal = "Terminal voltage [V]"
+problem = pybop.Problem(model, parameters, dataset, signal=signal, init_soc=0.98)
+cost = pybop.RootMeanSquaredError(problem)
+
+# Build the optimisation problem
+parameterisation = pybop.Optimisation(cost=cost, optimiser=pybop.NLoptOptimize)
+
+# Run the optimisation problem
+x, final_cost = parameterisation.run()
+
+# Show the generated data
+simulated_values = problem.evaluate(x)
+
+plt.figure()
+plt.xlabel("Time")
+plt.ylabel("Values")
+plt.plot(dataset[0].data, dataset[2].data, label="Measured")
+plt.plot(dataset[0].data, simulated_values, label="Simulated")
+plt.legend(bbox_to_anchor=(0.6, 1), loc="upper left", fontsize=12)
+plt.show()
diff --git a/noxfile.py b/noxfile.py
new file mode 100644
index 000000000..c88e483e4
--- /dev/null
+++ b/noxfile.py
@@ -0,0 +1,26 @@
+import nox
+
+# nox options
+nox.options.reuse_existing_virtualenvs = True
+
+
+@nox.session
+def unit(session):
+ session.run_always("pip", "install", "-e", ".")
+ session.install("pytest")
+ session.run("pytest", "--unit", "-v")
+
+
+@nox.session
+def coverage(session):
+ session.run_always("pip", "install", "-e", ".")
+ session.install("pytest-cov")
+ session.run("pytest", "--unit", "-v", "--cov", "--cov-report=xml")
+
+
+@nox.session
+def notebooks(session):
+ """Run the examples tests for Jupyter notebooks."""
+ session.run_always("pip", "install", "-e", ".")
+ session.install("pytest", "nbmake")
+ session.run("pytest", "--nbmake", "examples/", external=True)
diff --git a/pybop/__init__.py b/pybop/__init__.py
new file mode 100644
index 000000000..29dcd88b1
--- /dev/null
+++ b/pybop/__init__.py
@@ -0,0 +1,75 @@
+#
+# Root of the pybop module.
+# Provides access to all shared functionality (models, solvers, etc.).
+#
+# This file is adapted from Pints
+# (see https://github.com/pints-team/pints)
+#
+
+import sys
+from os import path
+
+#
+# Version info
+#
+from pybop.version import __version__
+
+#
+# Constants
+#
+# Float format: a float can be converted to a 17 digit decimal and back without
+# loss of information
+FLOAT_FORMAT = "{: .17e}"
+# Absolute path to the pybop repo
+script_path = path.dirname(__file__)
+
+#
+# Cost function class
+#
+from .costs.error_costs import BaseCost, RootMeanSquaredError, SumSquaredError
+
+#
+# Dataset class
+#
+from .datasets.base_dataset import Dataset
+
+#
+# Model classes
+#
+from .models.base_model import BaseModel
+from .models import lithium_ion
+
+#
+# Main optimisation class
+#
+from .optimisation import Optimisation
+
+#
+# Optimiser class
+#
+from .optimisers.base_optimiser import BaseOptimiser
+from .optimisers.nlopt_optimize import NLoptOptimize
+from .optimisers.scipy_minimize import SciPyMinimize
+from .optimisers.pints_optimisers import GradientDescent, CMAES
+
+#
+# Parameter classes
+#
+from .parameters.base_parameter import Parameter
+from .parameters.base_parameter_set import ParameterSet
+from .parameters.priors import Gaussian, Uniform, Exponential
+
+#
+# Problem class
+#
+from ._problem import Problem
+
+#
+# Plotting class
+#
+from .plotting.quick_plot import QuickPlot
+
+#
+# Remove any imported modules, so we don't expose them as part of pybop
+#
+del sys
diff --git a/pybop/_problem.py b/pybop/_problem.py
new file mode 100644
index 000000000..469b65047
--- /dev/null
+++ b/pybop/_problem.py
@@ -0,0 +1,97 @@
+import numpy as np
+
+
+class Problem:
+ """
+ Defines a PyBOP single output problem, follows the PINTS interface.
+ """
+
+ def __init__(
+ self,
+ model,
+ parameters,
+ dataset,
+ signal="Terminal voltage [V]",
+ check_model=True,
+ init_soc=None,
+ x0=None,
+ ):
+ self._model = model
+ self.parameters = parameters
+ self.signal = signal
+ self._model.signal = self.signal
+ self._dataset = {o.name: o for o in dataset}
+ self.check_model = check_model
+ self.init_soc = init_soc
+ self.x0 = x0
+ self.n_parameters = len(self.parameters)
+ self.n_outputs = len([self.signal])
+
+ # Check that the dataset contains time and current
+ for name in ["Time [s]", "Current function [A]", signal]:
+ if name not in self._dataset:
+ raise ValueError(f"expected {name} in list of dataset")
+
+ self._time_data = self._dataset["Time [s]"].data
+ self.n_time_data = len(self._time_data)
+ self._target = self._dataset[signal].data
+
+ if np.any(self._time_data < 0):
+ raise ValueError("Times can not be negative.")
+ if np.any(self._time_data[:-1] >= self._time_data[1:]):
+ raise ValueError("Times must be increasing.")
+
+ if len(self._target) != len(self._time_data):
+ raise ValueError("Time data and signal data must be the same length.")
+
+ # Set bounds
+ self.bounds = dict(
+ lower=[param.bounds[0] for param in self.parameters],
+ upper=[param.bounds[1] for param in self.parameters],
+ )
+
+ # Sample from prior for x0
+ if x0 is None:
+ self.x0 = np.zeros(self.n_parameters)
+ for i, param in enumerate(self.parameters):
+ self.x0[i] = param.rvs(1)
+ elif len(x0) != self.n_parameters:
+ raise ValueError("x0 dimensions do not match number of parameters")
+
+ # Add the initial values to the parameter definitions
+ for i, param in enumerate(self.parameters):
+ param.update(value=self.x0[i])
+
+ # Set the fitting parameters and build the model
+ self.fit_parameters = {o.name: o.value for o in parameters}
+ if self._model._built_model is None:
+ self._model.build(
+ dataset=self._dataset,
+ fit_parameters=self.fit_parameters,
+ check_model=self.check_model,
+ init_soc=self.init_soc,
+ )
+
+ def evaluate(self, parameters):
+ """
+ Evaluate the model with the given parameters and return the signal.
+ """
+
+ y = np.asarray(self._model.simulate(inputs=parameters, t_eval=self._time_data))
+
+ return y
+
+ def evaluateS1(self, parameters):
+ """
+ Evaluate the model with the given parameters and return the signal and
+ its derivatives.
+ """
+ for i, key in enumerate(self.fit_parameters):
+ self.fit_parameters[key] = parameters[i]
+
+ y, dy = self._model.simulateS1(
+ inputs=self.fit_parameters,
+ t_eval=self._time_data,
+ )
+
+ return (np.asarray(y), np.asarray(dy))
diff --git a/PyBOP/__init__.py b/pybop/costs/__init__.py
similarity index 100%
rename from PyBOP/__init__.py
rename to pybop/costs/__init__.py
diff --git a/pybop/costs/error_costs.py b/pybop/costs/error_costs.py
new file mode 100644
index 000000000..2c497d45b
--- /dev/null
+++ b/pybop/costs/error_costs.py
@@ -0,0 +1,114 @@
+import numpy as np
+
+
+class BaseCost:
+ """
+ Base class for defining cost functions.
+ This class computes a corresponding goodness-of-fit for a corresponding model prediction and dataset.
+ Lower cost values indicate a better fit.
+ """
+
+ def __init__(self, problem):
+ self.problem = problem
+ if problem is not None:
+ self._target = problem._target
+ self.x0 = problem.x0
+ self.bounds = problem.bounds
+ self.n_parameters = problem.n_parameters
+
+ def __call__(self, x, grad=None):
+ """
+ Returns the cost function value and computes the cost.
+ """
+ raise NotImplementedError
+
+
+class RootMeanSquaredError(BaseCost):
+ """
+ Defines the root mean square error cost function.
+ """
+
+ def __init__(self, problem):
+ super(RootMeanSquaredError, self).__init__(problem)
+
+ def __call__(self, x, grad=None):
+ """
+ Computes the cost.
+ """
+ try:
+ prediction = self.problem.evaluate(x)
+
+ if len(prediction) < len(self._target):
+ return np.float64(np.inf) # simulation stopped early
+ else:
+ return np.sqrt(np.mean((prediction - self._target) ** 2))
+
+ except Exception as e:
+ raise ValueError(f"Error in cost calculation: {e}")
+
+
+class SumSquaredError(BaseCost):
+ """
+ Defines the sum squared error cost function.
+
+ The initial fail gradient is set equal to one, but this can be
+ changed at any time with :meth:`set_fail_gradient()`.
+ """
+
+ def __init__(self, problem):
+ super(SumSquaredError, self).__init__(problem)
+
+ # Default fail gradient
+ self._de = 1.0
+
+ def __call__(self, x, grad=None):
+ """
+ Computes the cost.
+ """
+ try:
+ prediction = self.problem.evaluate(x)
+
+ if len(prediction) < len(self._target):
+ return np.float64(np.inf) # simulation stopped early
+ else:
+ return np.sum(
+ (np.sum(((prediction - self._target) ** 2), axis=0)),
+ axis=0,
+ )
+
+ except Exception as e:
+ raise ValueError(f"Error in cost calculation: {e}")
+
+ def evaluateS1(self, x):
+ """
+ Compute the cost and corresponding
+ gradients with respect to the parameters.
+ """
+ try:
+ y, dy = self.problem.evaluateS1(x)
+ if len(y) < len(self._target):
+ e = np.float64(np.inf)
+ de = self._de * np.ones(self.problem.n_parameters)
+ else:
+ dy = dy.reshape(
+ (
+ self.problem.n_time_data,
+ self.problem.n_outputs,
+ self.problem.n_parameters,
+ )
+ )
+ r = y - self._target
+ e = np.sum(np.sum(r**2, axis=0), axis=0)
+ de = 2 * np.sum(np.sum((r.T * dy.T), axis=2), axis=1)
+
+ return e, de
+
+ except Exception as e:
+ raise ValueError(f"Error in cost calculation: {e}")
+
+ def set_fail_gradient(self, de):
+ """
+ Sets the fail gradient for this optimiser.
+ """
+ de = float(de)
+ self._de = de
diff --git a/pybop/costs/standalone.py b/pybop/costs/standalone.py
new file mode 100644
index 000000000..197dcca5b
--- /dev/null
+++ b/pybop/costs/standalone.py
@@ -0,0 +1,18 @@
+import pybop
+import numpy as np
+
+
+class StandaloneCost(pybop.BaseCost):
+ def __init__(self, problem=None):
+ super().__init__(problem)
+
+ self.x0 = np.array([4.2])
+ self.n_parameters = len(self.x0)
+
+ self.bounds = dict(
+ lower=[-1],
+ upper=[10],
+ )
+
+ def __call__(self, x, grad=None):
+ return x[0] ** 2 + 42
diff --git a/PyBOP/cost_functions/__init__.py b/pybop/datasets/__init__.py
similarity index 100%
rename from PyBOP/cost_functions/__init__.py
rename to pybop/datasets/__init__.py
diff --git a/pybop/datasets/base_dataset.py b/pybop/datasets/base_dataset.py
new file mode 100644
index 000000000..ed194ae48
--- /dev/null
+++ b/pybop/datasets/base_dataset.py
@@ -0,0 +1,20 @@
+import pybamm
+
+
+class Dataset:
+ """
+ Class for experimental observations.
+ """
+
+ def __init__(self, name, data):
+ self.name = name
+ self.data = data
+
+ def __repr__(self):
+ return f"Dataset: {self.name} \n Data: {self.data}"
+
+ def Interpolant(self):
+ if self.variable == "time":
+ self.Interpolant = pybamm.Interpolant(self.x, self.y, pybamm.t)
+ else:
+ NotImplementedError("Only time interpolation is supported")
diff --git a/pybop/models/__init__.py b/pybop/models/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py
new file mode 100644
index 000000000..ced38437e
--- /dev/null
+++ b/pybop/models/base_model.py
@@ -0,0 +1,248 @@
+import pybamm
+import numpy as np
+
+
+class BaseModel:
+ """
+ Base class for pybop models.
+ """
+
+ def __init__(self, name="Base Model"):
+ self.name = name
+ self.pybamm_model = None
+ self.fit_parameters = None
+ self.dataset = None
+ self.signal = None
+
+ def build(
+ self,
+ dataset=None,
+ fit_parameters=None,
+ check_model=True,
+ init_soc=None,
+ ):
+ """
+ Build the PyBOP model (if not built already).
+ For PyBaMM forward models, this method follows a
+ similar process to pybamm.Simulation.build().
+ """
+ self.fit_parameters = fit_parameters
+ self.dataset = dataset
+ if self.fit_parameters is not None:
+ self.fit_keys = list(self.fit_parameters.keys())
+
+ if init_soc is not None:
+ self.set_init_soc(init_soc)
+
+ if self._built_model:
+ return
+
+ elif self.pybamm_model.is_discretised:
+ self._model_with_set_params = self.pybamm_model
+ self._built_model = self.pybamm_model
+ else:
+ self.set_params()
+ self._mesh = pybamm.Mesh(self.geometry, self.submesh_types, self.var_pts)
+ self._disc = pybamm.Discretisation(self.mesh, self.spatial_methods)
+ self._built_model = self._disc.process_model(
+ self._model_with_set_params, inplace=False, check_model=check_model
+ )
+
+ # Clear solver
+ self._solver._model_set_up = {}
+
+ def set_init_soc(self, init_soc):
+ """
+ Set the initial state of charge.
+ """
+ if self._built_initial_soc != init_soc:
+ # reset
+ self._model_with_set_params = None
+ self._built_model = None
+ self.op_conds_to_built_models = None
+ self.op_conds_to_built_solvers = None
+
+ param = self.pybamm_model.param
+ self._parameter_set = (
+ self._unprocessed_parameter_set.set_initial_stoichiometries(
+ init_soc, param=param, inplace=False
+ )
+ )
+ # Save solved initial SOC in case we need to rebuild the model
+ self._built_initial_soc = init_soc
+
+ def set_params(self):
+ """
+ Set the parameters in the model.
+ """
+ if self.model_with_set_params:
+ return
+
+ if self.fit_parameters is not None:
+ # set input parameters in parameter set from fitting parameters
+ for i in self.fit_parameters.keys():
+ self._parameter_set[i] = "[input]"
+
+ if self.dataset is not None and self.fit_parameters is not None:
+ if "Current function [A]" not in self.fit_keys:
+ self.parameter_set["Current function [A]"] = pybamm.Interpolant(
+ self.dataset["Time [s]"].data,
+ self.dataset["Current function [A]"].data,
+ pybamm.t,
+ )
+ # Set t_eval
+ self.time_data = self._parameter_set["Current function [A]"].x[0]
+
+ self._model_with_set_params = self._parameter_set.process_model(
+ self._unprocessed_model, inplace=False
+ )
+ self._parameter_set.process_geometry(self.geometry)
+ self.pybamm_model = self._model_with_set_params
+
+ def simulate(self, inputs, t_eval):
+ """
+ Run the forward model and return the result in Numpy array format
+ aligning with Pints' ForwardModel simulate method.
+ """
+
+ if self._built_model is None:
+ raise ValueError("Model must be built before calling simulate")
+ else:
+ if not isinstance(inputs, dict):
+ inputs_dict = {
+ key: inputs[i] for i, key in enumerate(self.fit_parameters)
+ }
+ return self.solver.solve(
+ self.built_model, inputs=inputs_dict, t_eval=t_eval
+ )[self.signal].data
+ else:
+ return self.solver.solve(
+ self.built_model, inputs=inputs, t_eval=t_eval
+ )[self.signal].data
+
+ def simulateS1(self, inputs, t_eval):
+ """
+ Run the forward model and return the function evaulation and it's gradient
+ aligning with Pints' ForwardModel simulateS1 method.
+ """
+
+ if self._built_model is None:
+ raise ValueError("Model must be built before calling simulate")
+ else:
+ if not isinstance(inputs, dict):
+ inputs_dict = {
+ key: inputs[i] for i, key in enumerate(self.fit_parameters)
+ }
+
+ sol = self.solver.solve(
+ self.built_model,
+ inputs=inputs_dict,
+ t_eval=t_eval,
+ calculate_sensitivities=True,
+ )
+ else:
+ sol = self.solver.solve(
+ self.built_model,
+ inputs=inputs,
+ t_eval=t_eval,
+ calculate_sensitivities=True,
+ )
+
+ return (
+ sol[self.signal].data,
+ np.asarray(
+ [
+ sol[self.signal].sensitivities[key].toarray()
+ for key in self.fit_keys
+ ]
+ ).T,
+ )
+
+ def predict(
+ self,
+ inputs=None,
+ t_eval=None,
+ parameter_set=None,
+ experiment=None,
+ init_soc=None,
+ ):
+ """
+ Create a PyBaMM simulation object, solve it, and return a solution object.
+ """
+ parameter_set = parameter_set or self._parameter_set
+ if inputs is not None:
+ parameter_set.update(inputs)
+ if self._unprocessed_model is not None:
+ if experiment is None:
+ return pybamm.Simulation(
+ self._unprocessed_model,
+ parameter_values=parameter_set,
+ ).solve(t_eval=t_eval, initial_soc=init_soc)
+ else:
+ return pybamm.Simulation(
+ self._unprocessed_model,
+ experiment=experiment,
+ parameter_values=parameter_set,
+ ).solve(initial_soc=init_soc)
+ else:
+ raise ValueError("This sim method currently only supports PyBaMM models")
+
+ @property
+ def built_model(self):
+ return self._built_model
+
+ @property
+ def parameter_set(self):
+ return self._parameter_set
+
+ @parameter_set.setter
+ def parameter_set(self, parameter_set):
+ self._parameter_set = parameter_set.copy()
+
+ @property
+ def model_with_set_params(self):
+ return self._model_with_set_params
+
+ @property
+ def geometry(self):
+ return self._geometry
+
+ @geometry.setter
+ def geometry(self, geometry):
+ self._geometry = geometry.copy()
+
+ @property
+ def submesh_types(self):
+ return self._submesh_types
+
+ @submesh_types.setter
+ def submesh_types(self, submesh_types):
+ self._submesh_types = submesh_types.copy()
+
+ @property
+ def mesh(self):
+ return self._mesh
+
+ @property
+ def var_pts(self):
+ return self._var_pts
+
+ @var_pts.setter
+ def var_pts(self, var_pts):
+ self._var_pts = var_pts.copy()
+
+ @property
+ def spatial_methods(self):
+ return self._spatial_methods
+
+ @spatial_methods.setter
+ def spatial_methods(self, spatial_methods):
+ self._spatial_methods = spatial_methods.copy()
+
+ @property
+ def solver(self):
+ return self._solver
+
+ @solver.setter
+ def solver(self, solver):
+ self._solver = solver.copy()
diff --git a/pybop/models/lithium_ion/__init__.py b/pybop/models/lithium_ion/__init__.py
new file mode 100644
index 000000000..69b51653b
--- /dev/null
+++ b/pybop/models/lithium_ion/__init__.py
@@ -0,0 +1,4 @@
+#
+# Import lithium ion based models
+#
+from .base_echem import SPM, SPMe
diff --git a/pybop/models/lithium_ion/base_echem.py b/pybop/models/lithium_ion/base_echem.py
new file mode 100644
index 000000000..d22a99e6d
--- /dev/null
+++ b/pybop/models/lithium_ion/base_echem.py
@@ -0,0 +1,88 @@
+import pybamm
+from ..base_model import BaseModel
+
+
+class SPM(BaseModel):
+ """
+ Composition of the PyBaMM Single Particle Model class.
+
+ """
+
+ def __init__(
+ self,
+ name="Single Particle Model",
+ parameter_set=None,
+ geometry=None,
+ submesh_types=None,
+ var_pts=None,
+ spatial_methods=None,
+ solver=None,
+ options=None,
+ ):
+ super().__init__()
+ self.pybamm_model = pybamm.lithium_ion.SPM(options=options)
+ self._unprocessed_model = self.pybamm_model
+ self.name = name
+
+ self.default_parameter_values = self.pybamm_model.default_parameter_values
+ self._parameter_set = (
+ parameter_set or self.pybamm_model.default_parameter_values
+ )
+ self._unprocessed_parameter_set = self._parameter_set
+
+ self.geometry = geometry or self.pybamm_model.default_geometry
+ self.submesh_types = submesh_types or self.pybamm_model.default_submesh_types
+ self.var_pts = var_pts or self.pybamm_model.default_var_pts
+ self.spatial_methods = (
+ spatial_methods or self.pybamm_model.default_spatial_methods
+ )
+ self.solver = solver or self.pybamm_model.default_solver
+
+ self._model_with_set_params = None
+ self._built_model = None
+ self._built_initial_soc = None
+ self._mesh = None
+ self._disc = None
+
+
+class SPMe(BaseModel):
+ """
+ Composition of the PyBaMM Single Particle Model with Electrolyte class.
+
+ """
+
+ def __init__(
+ self,
+ name="Single Particle Model with Electrolyte",
+ parameter_set=None,
+ geometry=None,
+ submesh_types=None,
+ var_pts=None,
+ spatial_methods=None,
+ solver=None,
+ options=None,
+ ):
+ super().__init__()
+ self.pybamm_model = pybamm.lithium_ion.SPMe(options=options)
+ self._unprocessed_model = self.pybamm_model
+ self.name = name
+
+ self.default_parameter_values = self.pybamm_model.default_parameter_values
+ self._parameter_set = (
+ parameter_set or self.pybamm_model.default_parameter_values
+ )
+ self._unprocessed_parameter_set = self._parameter_set
+
+ self.geometry = geometry or self.pybamm_model.default_geometry
+ self.submesh_types = submesh_types or self.pybamm_model.default_submesh_types
+ self.var_pts = var_pts or self.pybamm_model.default_var_pts
+ self.spatial_methods = (
+ spatial_methods or self.pybamm_model.default_spatial_methods
+ )
+ self.solver = solver or self.pybamm_model.default_solver
+
+ self._model_with_set_params = None
+ self._built_model = None
+ self._built_initial_soc = None
+ self._mesh = None
+ self._disc = None
diff --git a/pybop/optimisation.py b/pybop/optimisation.py
new file mode 100644
index 000000000..6dc947de7
--- /dev/null
+++ b/pybop/optimisation.py
@@ -0,0 +1,408 @@
+import pybop
+import pints
+import numpy as np
+
+
+class Optimisation:
+ """
+ Optimisation class for PyBOP.
+ This class provides functionality for PyBOP optimisers and Pints optimisers.
+ args:
+ cost: PyBOP cost function
+ optimiser: A PyBOP or Pints optimiser
+ sigma0: initial step size
+ verbose: print optimisation progress
+
+ """
+
+ def __init__(
+ self,
+ cost,
+ optimiser=None,
+ sigma0=None,
+ verbose=False,
+ ):
+ self.cost = cost
+ self.optimiser = optimiser
+ self.verbose = verbose
+ self.x0 = cost.x0
+ self.bounds = cost.bounds
+ self.n_parameters = cost.n_parameters
+ self.sigma0 = sigma0
+ self.log = []
+
+ # Convert x0 to pints vector
+ self._x0 = pints.vector(self.x0)
+
+ # PyBOP doesn't currently support the pints transformation class
+ self._transformation = None
+
+ # Check if minimising or maximising
+ self._minimising = not isinstance(cost, pints.LogPDF)
+ if self._minimising:
+ self._function = self.cost
+ else:
+ self._function = pints.ProbabilityBasedError(cost)
+ del cost
+
+ # Construct Optimiser
+ self.pints = True
+
+ if self.optimiser is None:
+ self.optimiser = pybop.CMAES
+ elif issubclass(self.optimiser, pints.Optimiser):
+ pass
+ else:
+ self.pints = False
+
+ if issubclass(self.optimiser, pybop.NLoptOptimize):
+ self.optimiser = self.optimiser(self.n_parameters)
+
+ elif issubclass(self.optimiser, pybop.SciPyMinimize):
+ self.optimiser = self.optimiser()
+
+ else:
+ raise ValueError("Unknown optimiser type")
+
+ if self.pints:
+ self.optimiser = self.optimiser(self.x0, self.sigma0, self.bounds)
+
+ # Check if sensitivities are required
+ self._needs_sensitivities = self.optimiser.needs_sensitivities()
+
+ # Track optimiser's f_best or f_guessed
+ self._use_f_guessed = None
+ self.set_f_guessed_tracking()
+
+ # Parallelisation
+ self._parallel = False
+ self._n_workers = 1
+ self.set_parallel()
+
+ # User callback
+ self._callback = None
+
+ # Define stopping criteria
+ # Maximum iterations
+ self._max_iterations = None
+ self.set_max_iterations()
+
+ # Maximum unchanged iterations
+ self._unchanged_threshold = 1 # smallest significant f change
+ self._unchanged_max_iterations = None
+ self.set_max_unchanged_iterations()
+
+ # Maximum evaluations
+ self._max_evaluations = None
+
+ # Threshold value
+ self._threshold = None
+
+ # Post-run statistics
+ self._evaluations = None
+ self._iterations = None
+
+ def run(self):
+ """
+ Run the optimisation algorithm.
+ Selects between PyBOP backend or Pints backend.
+ returns:
+ x: best parameters
+ final_cost: final cost
+ """
+
+ if self.pints:
+ x, final_cost = self._run_pints()
+ elif not self.pints:
+ x, final_cost = self._run_pybop()
+
+ return x, final_cost
+
+ def _run_pybop(self):
+ """
+ Run method for PyBOP based optimisers.
+ returns:
+ x: best parameters
+ final_cost: final cost
+ """
+ x, final_cost = self.optimiser.optimise(
+ cost_function=self.cost,
+ x0=self.x0,
+ bounds=self.bounds,
+ )
+ return x, final_cost
+
+ def _run_pints(self):
+ """
+ Run method for PINTS optimisers.
+ This method is heavily based on the run method in the PINTS.OptimisationController class.
+ returns:
+ x: best parameters
+ final_cost: final cost
+ """
+
+ # Check stopping criteria
+ has_stopping_criterion = False
+ has_stopping_criterion |= self._max_iterations is not None
+ has_stopping_criterion |= self._unchanged_max_iterations is not None
+ has_stopping_criterion |= self._max_evaluations is not None
+ has_stopping_criterion |= self._threshold is not None
+ if not has_stopping_criterion:
+ raise ValueError("At least one stopping criterion must be set.")
+
+ # Iterations and function evaluations
+ iteration = 0
+ evaluations = 0
+
+ # Unchanged iterations counter
+ unchanged_iterations = 0
+
+ # Choose method to evaluate
+ f = self._function
+ if self._needs_sensitivities:
+ f = f.evaluateS1
+
+ # Create evaluator object
+ if self._parallel:
+ # Get number of workers
+ n_workers = self._n_workers
+
+ # For population based optimisers, don't use more workers than
+ # particles!
+ if isinstance(self._optimiser, pints.PopulationBasedOptimiser):
+ n_workers = min(n_workers, self._optimiser.population_size())
+ evaluator = pints.ParallelEvaluator(f, n_workers=n_workers)
+ else:
+ evaluator = pints.SequentialEvaluator(f)
+
+ # Keep track of current best and best-guess scores.
+ fb = fg = np.inf
+
+ # Internally we always minimise! Keep a 2nd value to show the user.
+ fg_user = (fb, fg) if self._minimising else (-fb, -fg)
+
+ # Keep track of the last significant change
+ f_sig = np.inf
+
+ # Run the ask-and-tell loop
+ running = True
+ try:
+ while running:
+ # Ask optimiser for new points
+ xs = self.optimiser.ask()
+
+ # Evaluate points
+ fs = evaluator.evaluate(xs)
+
+ # Tell optimiser about function values
+ self.optimiser.tell(fs)
+
+ # Update the scores
+ fb = self.optimiser.f_best()
+ fg = self.optimiser.f_guessed()
+ fg_user = (fb, fg) if self._minimising else (-fb, -fg)
+
+ # Check for significant changes
+ f_new = fg if self._use_f_guessed else fb
+ if np.abs(f_new - f_sig) >= self._unchanged_threshold:
+ unchanged_iterations = 0
+ f_sig = f_new
+ else:
+ unchanged_iterations += 1
+
+ # Update counts
+ evaluations += len(fs)
+ iteration += 1
+ self.log.append(xs)
+
+ # Check stopping criteria:
+ # Maximum number of iterations
+ if (
+ self._max_iterations is not None
+ and iteration >= self._max_iterations
+ ):
+ running = False
+ halt_message = (
+ "Maximum number of iterations (" + str(iteration) + ") reached."
+ )
+
+ # Maximum number of iterations without significant change
+ halt = (
+ self._unchanged_max_iterations is not None
+ and unchanged_iterations >= self._unchanged_max_iterations
+ )
+ if running and halt:
+ running = False
+ halt_message = (
+ "No significant change for "
+ + str(unchanged_iterations)
+ + " iterations."
+ )
+
+ # Maximum number of evaluations
+ if (
+ self._max_evaluations is not None
+ and evaluations >= self._max_evaluations
+ ):
+ running = False
+ halt_message = (
+ "Maximum number of evaluations ("
+ + str(self._max_evaluations)
+ + ") reached."
+ )
+
+ # Threshold value
+ halt = self._threshold is not None and f_new < self._threshold
+ if running and halt:
+ running = False
+ halt_message = (
+ "Objective function crossed threshold: "
+ + str(self._threshold)
+ + "."
+ )
+
+ # Error in optimiser
+ error = self.optimiser.stop()
+ if error:
+ running = False
+ halt_message = str(error)
+
+ elif self._callback is not None:
+ self._callback(iteration - 1, self.optimiser)
+
+ except (Exception, SystemExit, KeyboardInterrupt):
+ # Show last result and exit
+ print("\n" + "-" * 40)
+ print("Unexpected termination.")
+ print("Current score: " + str(fg_user))
+ print("Current position:")
+
+ # Show current parameters
+ x_user = self.optimiser.x_guessed()
+ if self._transformation is not None:
+ x_user = self._transformation.to_model(x_user)
+ for p in x_user:
+ print(pints.strfloat(p))
+ print("-" * 40)
+ raise
+
+ if self.verbose:
+ print("Halt: " + halt_message)
+
+ # Save post-run statistics
+ self._evaluations = evaluations
+ self._iterations = iteration
+
+ # Get best parameters
+ if self._use_f_guessed:
+ x = self.optimiser.x_guessed()
+ f = self.optimiser.f_guessed()
+ else:
+ x = self.optimiser.x_best()
+ f = self.optimiser.f_best()
+
+ # Inverse transform search parameters
+ if self._transformation is not None:
+ x = self._transformation.to_model(x)
+
+ # Return best position and score
+ return x, f if self._minimising else -f
+
+ def f_guessed_tracking(self):
+ """
+ Returns ``True`` if f_guessed instead of f_best is being tracked,
+ ``False`` otherwise. See also :meth:`set_f_guessed_tracking`.
+
+ Credit: PINTS
+ """
+ return self._use_f_guessed
+
+ def set_f_guessed_tracking(self, use_f_guessed=False):
+ """
+ Sets the method used to track the optimiser progress to
+ :meth:`pints.Optimiser.f_guessed()` or
+ :meth:`pints.Optimiser.f_best()` (default).
+
+ The tracked ``f`` value is used to evaluate stopping criteria.
+
+ Credit: PINTS
+ """
+ self._use_f_guessed = bool(use_f_guessed)
+
+ def set_max_evaluations(self, evaluations=None):
+ """
+ Adds a stopping criterion, allowing the routine to halt after the
+ given number of ``evaluations``.
+
+ This criterion is disabled by default. To enable, pass in any positive
+ integer. To disable again, use ``set_max_evaluations(None)``.
+
+ Credit: PINTS
+ """
+ if evaluations is not None:
+ evaluations = int(evaluations)
+ if evaluations < 0:
+ raise ValueError("Maximum number of evaluations cannot be negative.")
+ self._max_evaluations = evaluations
+
+ def set_parallel(self, parallel=False):
+ """
+ Enables/disables parallel evaluation.
+
+ If ``parallel=True``, the method will run using a number of worker
+ processes equal to the detected cpu core count. The number of workers
+ can be set explicitly by setting ``parallel`` to an integer greater
+ than 0.
+ Parallelisation can be disabled by setting ``parallel`` to ``0`` or
+ ``False``.
+
+ Credit: PINTS
+ """
+ if parallel is True:
+ self._parallel = True
+ self._n_workers = pints.ParallelEvaluator.cpu_count()
+ elif parallel >= 1:
+ self._parallel = True
+ self._n_workers = int(parallel)
+ else:
+ self._parallel = False
+ self._n_workers = 1
+
+ def set_max_iterations(self, iterations=10000):
+ """
+ Adds a stopping criterion, allowing the routine to halt after the
+ given number of ``iterations``.
+
+ This criterion is enabled by default. To disable it, use
+ ``set_max_iterations(None)``.
+
+ Credit: PINTS
+ """
+ if iterations is not None:
+ iterations = int(iterations)
+ if iterations < 0:
+ raise ValueError("Maximum number of iterations cannot be negative.")
+ self._max_iterations = iterations
+
+ def set_max_unchanged_iterations(self, iterations=200, threshold=1e-11):
+ """
+ Adds a stopping criterion, allowing the routine to halt if the
+ objective function doesn't change by more than ``threshold`` for the
+ given number of ``iterations``.
+
+ This criterion is enabled by default. To disable it, use
+ ``set_max_unchanged_iterations(None)``.
+
+ Credit: PINTS
+ """
+ if iterations is not None:
+ iterations = int(iterations)
+ if iterations < 0:
+ raise ValueError("Maximum number of iterations cannot be negative.")
+
+ threshold = float(threshold)
+ if threshold < 0:
+ raise ValueError("Minimum significant change cannot be negative.")
+
+ self._unchanged_max_iterations = iterations
+ self._unchanged_threshold = threshold
diff --git a/pybop/optimisers/__init__.py b/pybop/optimisers/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/pybop/optimisers/base_optimiser.py b/pybop/optimisers/base_optimiser.py
new file mode 100644
index 000000000..1938c1db2
--- /dev/null
+++ b/pybop/optimisers/base_optimiser.py
@@ -0,0 +1,30 @@
+class BaseOptimiser:
+ """
+
+ Base class for the optimisation methods.
+
+ """
+
+ def __init__(self):
+ self.name = "Base Optimiser"
+
+ def optimise(self, cost_function, x0=None, bounds=None):
+ """
+ Optimisiation method to be overloaded by child classes.
+
+ """
+ self.cost_function = cost_function
+ self.x0 = x0
+ self.bounds = bounds
+
+ # Run optimisation
+ result = self._runoptimise(self.cost_function, x0=self.x0, bounds=self.bounds)
+
+ return result
+
+ def _runoptimise(self, cost_function, x0=None, bounds=None):
+ """
+ Run optimisation method, to be overloaded by child classes.
+
+ """
+ pass
diff --git a/pybop/optimisers/nlopt_optimize.py b/pybop/optimisers/nlopt_optimize.py
new file mode 100644
index 000000000..5c0da8f47
--- /dev/null
+++ b/pybop/optimisers/nlopt_optimize.py
@@ -0,0 +1,54 @@
+import nlopt
+from .base_optimiser import BaseOptimiser
+
+
+class NLoptOptimize(BaseOptimiser):
+ """
+ Wrapper class for the NLOpt optimiser class. Extends the BaseOptimiser class.
+ """
+
+ def __init__(self, n_param, xtol=None, method=None):
+ super().__init__()
+ self.name = "NLoptOptimize"
+ self.n_param = n_param
+
+ if method is not None:
+ self.optim = nlopt.opt(method, self.n_param)
+ else:
+ self.optim = nlopt.opt(nlopt.LN_BOBYQA, self.n_param)
+
+ if xtol is not None:
+ self.optim.set_xtol_rel(xtol)
+ else:
+ self.optim.set_xtol_rel(1e-5)
+
+ def _runoptimise(self, cost_function, x0, bounds):
+ """
+ Run the NLOpt optimisation method.
+
+ Inputs
+ ----------
+ cost_function: function for optimising
+ method: optimisation algorithm
+ x0: initialisation array
+ bounds: bounds array
+ """
+
+ # Pass settings to the optimiser
+ self.optim.set_min_objective(cost_function)
+ self.optim.set_lower_bounds(bounds["lower"])
+ self.optim.set_upper_bounds(bounds["upper"])
+
+ # Run the optimser
+ x = self.optim.optimize(x0)
+
+ # Get performance statistics
+ final_cost = self.optim.last_optimum_value()
+
+ return x, final_cost
+
+ def needs_sensitivities(self):
+ """
+ Returns True if the optimiser needs sensitivities.
+ """
+ return False
diff --git a/pybop/optimisers/pints_optimisers.py b/pybop/optimisers/pints_optimisers.py
new file mode 100644
index 000000000..6524cb607
--- /dev/null
+++ b/pybop/optimisers/pints_optimisers.py
@@ -0,0 +1,30 @@
+import pints
+
+
+class GradientDescent(pints.GradientDescent):
+ """
+ Gradient descent optimiser. Inherits from the PINTS gradient descent class.
+ """
+
+ def __init__(self, x0, sigma0=0.1, bounds=None):
+ if bounds is not None:
+ print("Boundaries ignored by GradientDescent")
+
+ boundaries = None # Bounds ignored in pints.GradDesc
+ super().__init__(x0, sigma0, boundaries)
+
+
+class CMAES(pints.CMAES):
+ """
+ Class for the PINTS optimisation. Extends the BaseOptimiser class.
+ """
+
+ def __init__(self, x0, sigma0=0.1, bounds=None):
+ if bounds is not None:
+ self.boundaries = pints.RectangularBoundaries(
+ bounds["lower"], bounds["upper"]
+ )
+ else:
+ self.boundaries = None
+
+ super().__init__(x0, sigma0, self.boundaries)
diff --git a/pybop/optimisers/scipy_minimize.py b/pybop/optimisers/scipy_minimize.py
new file mode 100644
index 000000000..083d93c53
--- /dev/null
+++ b/pybop/optimisers/scipy_minimize.py
@@ -0,0 +1,50 @@
+from scipy.optimize import minimize
+from .base_optimiser import BaseOptimiser
+
+
+class SciPyMinimize(BaseOptimiser):
+ """
+ Wrapper class for the SciPy optimisation class. Extends the BaseOptimiser class.
+ """
+
+ def __init__(self, method=None, bounds=None):
+ super().__init__()
+ self.name = "SciPyMinimize"
+ self.method = method
+ self.bounds = bounds
+
+ if self.method is None:
+ self.method = "L-BFGS-B"
+
+ def _runoptimise(self, cost_function, x0, bounds):
+ """
+ Run the SciPy optimisation method.
+
+ Inputs
+ ----------
+ cost_function: function for optimising
+ method: optimisation algorithm
+ x0: initialisation array
+ bounds: bounds array
+ """
+
+ if bounds is not None:
+ # Reformat bounds and run the optimser
+ bounds = (
+ (lower, upper) for lower, upper in zip(bounds["lower"], bounds["upper"])
+ )
+ output = minimize(cost_function, x0, method=self.method, bounds=bounds)
+ else:
+ output = minimize(cost_function, x0, method=self.method)
+
+ # Get performance statistics
+ x = output.x
+ final_cost = output.fun
+
+ return x, final_cost
+
+ def needs_sensitivities(self):
+ """
+ Returns True if the optimiser needs sensitivities.
+ """
+ return False
diff --git a/pybop/parameters/__init__.py b/pybop/parameters/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/pybop/parameters/base_parameter.py b/pybop/parameters/base_parameter.py
new file mode 100644
index 000000000..fa8754831
--- /dev/null
+++ b/pybop/parameters/base_parameter.py
@@ -0,0 +1,46 @@
+import numpy as np
+
+
+class Parameter:
+ """ ""
+ Class for creating parameters in PyBOP.
+ """
+
+ def __init__(self, name, value=None, prior=None, bounds=None):
+ self.name = name
+ self.prior = prior
+ self.value = value
+ self.bounds = bounds
+ self.lower_bound = self.bounds[0]
+ self.upper_bound = self.bounds[1]
+ self.margin = 1e-4
+
+ if self.lower_bound >= self.upper_bound:
+ raise ValueError("Lower bound must be less than upper bound")
+
+ def rvs(self, n_samples):
+ """
+ Returns a random value sample from the prior distribution.
+ """
+ samples = self.prior.rvs(n_samples)
+
+ # Constrain samples to be within bounds
+ offset = self.margin * (self.upper_bound - self.lower_bound)
+ samples = np.clip(samples, self.lower_bound + offset, self.upper_bound - offset)
+
+ return samples
+
+ def update(self, value):
+ self.value = value
+
+ def __repr__(self):
+ return f"Parameter: {self.name} \n Prior: {self.prior} \n Bounds: {self.bounds} \n Value: {self.value}"
+
+ def set_margin(self, margin):
+ """
+ Sets the margin for the parameter.
+ """
+ if not 0 < margin < 1:
+ raise ValueError("Margin must be between 0 and 1")
+
+ self.margin = margin
diff --git a/pybop/parameters/base_parameter_set.py b/pybop/parameters/base_parameter_set.py
new file mode 100644
index 000000000..dd1653d81
--- /dev/null
+++ b/pybop/parameters/base_parameter_set.py
@@ -0,0 +1,13 @@
+import pybamm
+
+
+class ParameterSet:
+ """
+ Class for creating parameter sets in PyBOP.
+ """
+
+ def __new__(cls, method, name):
+ if method.casefold() == "pybamm":
+ return pybamm.ParameterValues(name).copy()
+ else:
+ raise ValueError("Only PyBaMM parameter sets are currently implemented")
diff --git a/pybop/parameters/priors.py b/pybop/parameters/priors.py
new file mode 100644
index 000000000..f98e9b767
--- /dev/null
+++ b/pybop/parameters/priors.py
@@ -0,0 +1,80 @@
+import scipy.stats as stats
+
+
+class Gaussian:
+ """
+ Gaussian prior class.
+ """
+
+ def __init__(self, mean, sigma):
+ self.name = "Gaussian"
+ self.mean = mean
+ self.sigma = sigma
+
+ def pdf(self, x):
+ return stats.norm.pdf(x, loc=self.mean, scale=self.sigma)
+
+ def logpdf(self, x):
+ return stats.norm.logpdf(x, loc=self.mean, scale=self.sigma)
+
+ def rvs(self, size):
+ if size < 0:
+ raise ValueError("size must be positive")
+ else:
+ return stats.norm.rvs(loc=self.mean, scale=self.sigma, size=size)
+
+ def __repr__(self):
+ return f"{self.name}, mean: {self.mean}, sigma: {self.sigma}"
+
+
+class Uniform:
+ """
+ Uniform prior class.
+ """
+
+ def __init__(self, lower, upper):
+ self.name = "Uniform"
+ self.lower = lower
+ self.upper = upper
+
+ def pdf(self, x):
+ return stats.uniform.pdf(x, loc=self.lower, scale=self.upper - self.lower)
+
+ def logpdf(self, x):
+ return stats.uniform.logpdf(x, loc=self.lower, scale=self.upper - self.lower)
+
+ def rvs(self, size):
+ if size < 0:
+ raise ValueError("size must be positive")
+ else:
+ return stats.uniform.rvs(
+ loc=self.lower, scale=self.upper - self.lower, size=size
+ )
+
+ def __repr__(self):
+ return f"{self.name}, lower: {self.lower}, upper: {self.upper}"
+
+
+class Exponential:
+ """
+ Exponential prior class.
+ """
+
+ def __init__(self, scale):
+ self.name = "Exponential"
+ self.scale = scale
+
+ def pdf(self, x):
+ return stats.expon.pdf(x, scale=self.scale)
+
+ def logpdf(self, x):
+ return stats.expon.logpdf(x, scale=self.scale)
+
+ def rvs(self, size):
+ if size < 0:
+ raise ValueError("size must be positive")
+ else:
+ return stats.expon.rvs(scale=self.scale, size=size)
+
+ def __repr__(self):
+ return f"{self.name}, scale: {self.scale}"
diff --git a/pybop/plotting/__init__.py b/pybop/plotting/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/PyBOP/plotting/quick_plot.py b/pybop/plotting/quick_plot.py
similarity index 54%
rename from PyBOP/plotting/quick_plot.py
rename to pybop/plotting/quick_plot.py
index f36fe2f31..5acbb2626 100644
--- a/PyBOP/plotting/quick_plot.py
+++ b/pybop/plotting/quick_plot.py
@@ -1,28 +1,22 @@
-import os
-import numpy
-import matplotlib
-
-class QuickPlot(item):
+class QuickPlot:
"""
-
- Class to generate the quick plots associated with PRISM.
+
+ Class to generate plots with standard variables and formatting.
Plots
--------------
Observability
- if method == parameterisation
-
+ if method == parameterisation
+
Comparison of fitting data with optimised forward model
-
+
elseif method == optimisation
-
+
Pareto front
Alternative solutions
- Initial value compared to optimal
+ Initial value compared to optimal
"""
def __init__(self):
self.name = "Quick Plot"
-
-
diff --git a/pybop/version.py b/pybop/version.py
new file mode 100644
index 000000000..915a9aedb
--- /dev/null
+++ b/pybop/version.py
@@ -0,0 +1 @@
+__version__ = "23.11"
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index dae82630d..000000000
--- a/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-numpy
-pandas
-scipy
-pybamm
-matplotlib
\ No newline at end of file
diff --git a/ruff.toml b/ruff.toml
new file mode 100644
index 000000000..29a4a2442
--- /dev/null
+++ b/ruff.toml
@@ -0,0 +1,8 @@
+extend-include = ["*.ipynb"]
+extend-exclude = ["__init__.py"]
+
+[lint]
+ignore = ["E501","E741"]
+
+[lint.per-file-ignores]
+"**.ipynb" = ["E402", "E703"]
diff --git a/setup.py b/setup.py
new file mode 100644
index 000000000..4d6b63a65
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,38 @@
+from distutils.core import setup
+import os
+from setuptools import find_packages
+
+# User-friendly description from README.md
+current_directory = os.path.dirname(os.path.abspath(__file__))
+try:
+ with open(os.path.join(current_directory, "README.md"), encoding="utf-8") as f:
+ long_description = f.read()
+except Exception:
+ long_description = ""
+
+# Defines __version__
+root = os.path.abspath(os.path.dirname(__file__))
+with open(os.path.join(root, "pybop", "version.py")) as f:
+ exec(f.read())
+
+setup(
+ name="pybop",
+ packages=find_packages("."),
+ version=__version__, # noqa F821
+ license="BSD-3-Clause",
+ description="Python Battery Optimisation and Parameterisation",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url="https://github.com/pybop-team/PyBOP",
+ install_requires=[
+ "pybamm>=23.1",
+ "numpy>=1.16",
+ "scipy>=1.3",
+ "pandas>=1.0",
+ "nlopt>=2.6",
+ "pints>=0.5",
+ ],
+ # https://pypi.org/classifiers/
+ classifiers=[],
+ python_requires=">=3.8,<=3.12",
+)
diff --git a/tests/unit/test_cost.py b/tests/unit/test_cost.py
new file mode 100644
index 000000000..0c7e329f3
--- /dev/null
+++ b/tests/unit/test_cost.py
@@ -0,0 +1,87 @@
+import pytest
+import pybop
+import numpy as np
+
+
+class TestCosts:
+ """
+ Class for tests cost functions
+ """
+
+ @pytest.mark.parametrize("cut_off", [2.5, 3.777])
+ @pytest.mark.unit
+ def test_costs(self, cut_off):
+ # Construct model
+ model = pybop.lithium_ion.SPM()
+
+ parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.5, 0.02),
+ bounds=[0.375, 0.625],
+ )
+ ]
+
+ # Form dataset
+ x0 = np.array([0.52])
+ solution = self.getdata(model, x0)
+ dataset = [
+ pybop.Dataset("Time [s]", solution["Time [s]"].data),
+ pybop.Dataset("Current function [A]", solution["Current [A]"].data),
+ pybop.Dataset("Voltage [V]", solution["Terminal voltage [V]"].data),
+ ]
+
+ # Construct Problem
+ signal = "Voltage [V]"
+ model.parameter_set.update({"Lower voltage cut-off [V]": cut_off})
+ problem = pybop.Problem(model, parameters, dataset, signal=signal, x0=x0)
+
+ # Base Cost
+ base_cost = pybop.BaseCost(problem)
+ assert base_cost.problem == problem
+ with pytest.raises(NotImplementedError):
+ base_cost([0.5])
+
+ # Root Mean Squared Error
+ rmse_cost = pybop.RootMeanSquaredError(problem)
+ rmse_cost([0.5])
+
+ # Sum Squared Error
+ sums_cost = pybop.SumSquaredError(problem)
+ sums_cost([0.5])
+
+ # Test type of returned value
+ assert type(rmse_cost([0.5])) == np.float64
+ assert rmse_cost([0.5]) >= 0
+
+ assert type(sums_cost([0.5])) == np.float64
+ assert sums_cost([0.5]) >= 0
+ e, de = sums_cost.evaluateS1([0.5])
+
+ assert type(e) == np.float64
+ assert type(de) == np.ndarray
+
+ # Test option setting
+ sums_cost.set_fail_gradient(1)
+
+ # Test exception for non-numeric inputs
+ with pytest.raises(ValueError):
+ rmse_cost(["StringInputShouldNotWork"])
+ with pytest.raises(ValueError):
+ sums_cost(["StringInputShouldNotWork"])
+ with pytest.raises(ValueError):
+ sums_cost.evaluateS1(["StringInputShouldNotWork"])
+
+ # Test treatment of simulations that terminated early
+ # by variation of the cut-off voltage.
+
+ def getdata(self, model, x0):
+ model.parameter_set = model.pybamm_model.default_parameter_values
+ model.parameter_set.update(
+ {
+ "Negative electrode active material volume fraction": x0[0],
+ }
+ )
+
+ sim = model.predict(t_eval=np.linspace(0, 10, 100))
+ return sim
diff --git a/tests/unit/test_examples.py b/tests/unit/test_examples.py
new file mode 100644
index 000000000..6e8fc09e0
--- /dev/null
+++ b/tests/unit/test_examples.py
@@ -0,0 +1,19 @@
+import pybop
+import pytest
+import runpy
+import os
+
+
+class TestExamples:
+ """
+ A class to test the example scripts.
+ """
+
+ @pytest.mark.unit
+ def test_example_scripts(self):
+ path_to_example_scripts = os.path.join(
+ pybop.script_path, "..", "examples", "scripts"
+ )
+ for example in os.listdir(path_to_example_scripts):
+ if example.endswith(".py"):
+ runpy.run_path(os.path.join(path_to_example_scripts, example))
diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py
new file mode 100644
index 000000000..ce73000a6
--- /dev/null
+++ b/tests/unit/test_models.py
@@ -0,0 +1,56 @@
+import pybop
+import pytest
+import numpy as np
+
+
+class TestModels:
+ """
+ A class to test the models.
+ """
+
+ @pytest.mark.unit
+ def test_simulate_without_build_model(self):
+ # Define model
+ model = pybop.lithium_ion.SPM()
+
+ with pytest.raises(
+ ValueError, match="Model must be built before calling simulate"
+ ):
+ model.simulate(None, None)
+
+ with pytest.raises(
+ ValueError, match="Model must be built before calling simulate"
+ ):
+ model.simulateS1(None, None)
+
+ @pytest.mark.unit
+ def test_predict_without_pybamm(self):
+ # Define model
+ model = pybop.lithium_ion.SPM()
+ model._unprocessed_model = None
+
+ with pytest.raises(ValueError):
+ model.predict(None, None)
+
+ @pytest.mark.unit
+ def test_predict_with_inputs(self):
+ # Define model
+ model = pybop.lithium_ion.SPM()
+ t_eval = np.linspace(0, 10, 100)
+ inputs = {
+ "Negative electrode active material volume fraction": 0.52,
+ "Positive electrode active material volume fraction": 0.63,
+ }
+
+ res = model.predict(t_eval=t_eval, inputs=inputs)
+ assert len(res["Terminal voltage [V]"].data) == 100
+
+ @pytest.mark.unit
+ def test_build(self):
+ model = pybop.lithium_ion.SPM()
+ model.build()
+ assert model.built_model is not None
+
+ # Test that the model can be built again
+ model.build()
+ assert model.built_model is not None
diff --git a/tests/unit/test_optimisation.py b/tests/unit/test_optimisation.py
new file mode 100644
index 000000000..5bbb4998b
--- /dev/null
+++ b/tests/unit/test_optimisation.py
@@ -0,0 +1,144 @@
+import pybop
+import numpy as np
+import pytest
+from pybop.costs.standalone import StandaloneCost
+
+
+class TestOptimisation:
+ """
+ A class to test the optimisation class.
+ """
+
+ @pytest.mark.unit
+ def test_standalone(self):
+ # Build an Optimisation problem with a StandaloneCost
+ cost = StandaloneCost()
+
+ opt = pybop.Optimisation(cost=cost, optimiser=pybop.NLoptOptimize)
+
+ assert len(opt.x0) == opt.n_parameters
+
+ x, final_cost = opt.run()
+
+ np.testing.assert_allclose(x, 0, atol=1e-2)
+ np.testing.assert_allclose(final_cost, 42, atol=1e-2)
+
+ @pytest.mark.unit
+ def test_prior_sampling(self):
+ # Tests prior sampling
+ model = pybop.lithium_ion.SPM()
+
+ dataset = [
+ pybop.Dataset("Time [s]", np.linspace(0, 3600, 100)),
+ pybop.Dataset("Current function [A]", np.zeros(100)),
+ pybop.Dataset("Terminal voltage [V]", np.ones(100)),
+ ]
+
+ param = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.75, 0.2),
+ bounds=[0.73, 0.77],
+ )
+ ]
+
+ signal = "Terminal voltage [V]"
+ problem = pybop.Problem(model, param, dataset, signal=signal)
+ cost = pybop.RootMeanSquaredError(problem)
+
+ for i in range(50):
+ opt = pybop.Optimisation(cost=cost, optimiser=pybop.NLoptOptimize)
+
+ assert opt.x0 <= 0.77 and opt.x0 >= 0.73
+
+ @pytest.mark.unit
+ def test_optimiser_construction(self):
+ # Tests construction of optimisers
+
+ dataset = [
+ pybop.Dataset("Time [s]", np.linspace(0, 360, 10)),
+ pybop.Dataset("Current function [A]", np.zeros(10)),
+ pybop.Dataset("Terminal voltage [V]", np.ones(10)),
+ ]
+ parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.75, 0.2),
+ bounds=[0.73, 0.77],
+ )
+ ]
+
+ problem = pybop.Problem(
+ pybop.lithium_ion.SPM(), parameters, dataset, signal="Terminal voltage [V]"
+ )
+ cost = pybop.SumSquaredError(problem)
+
+ # Test construction of optimisers
+ # NLopt
+ opt = pybop.Optimisation(cost=cost, optimiser=pybop.NLoptOptimize)
+ assert opt.optimiser is not None
+ assert opt.optimiser.name == "NLoptOptimize"
+ assert opt.optimiser.n_param == 1
+
+ # Gradient Descent
+ opt = pybop.Optimisation(cost=cost, optimiser=pybop.GradientDescent)
+ assert opt.optimiser is not None
+
+ # None
+ opt = pybop.Optimisation(cost=cost)
+ assert opt.optimiser is not None
+ assert (
+ opt.optimiser.name()
+ == "Covariance Matrix Adaptation Evolution Strategy (CMA-ES)"
+ )
+
+ # None with no bounds
+ cost.bounds = None
+ opt = pybop.Optimisation(cost=cost)
+ assert opt.optimiser.boundaries is None
+
+ # SciPy
+ opt = pybop.Optimisation(cost=cost, optimiser=pybop.SciPyMinimize)
+ assert opt.optimiser is not None
+ assert opt.optimiser.name == "SciPyMinimize"
+
+ # Incorrect class
+ class randomclass:
+ pass
+
+ with pytest.raises(ValueError):
+ pybop.Optimisation(cost=cost, optimiser=randomclass)
+
+ @pytest.mark.unit
+ def test_halting(self):
+ # Tests halting criteria
+ model = pybop.lithium_ion.SPM()
+
+ dataset = [
+ pybop.Dataset("Time [s]", np.linspace(0, 3600, 100)),
+ pybop.Dataset("Current function [A]", np.zeros(100)),
+ pybop.Dataset("Terminal voltage [V]", np.ones(100)),
+ ]
+
+ param = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.75, 0.2),
+ bounds=[0.73, 0.77],
+ )
+ ]
+
+ problem = pybop.Problem(model, param, dataset, signal="Terminal voltage [V]")
+ cost = pybop.SumSquaredError(problem)
+
+ # Test max evalutions
+ optim = pybop.Optimisation(cost=cost, optimiser=pybop.GradientDescent)
+ optim.set_max_evaluations(10)
+ x, __ = optim.run()
+ assert optim._iterations == 10
+
+ # Test max unchanged iterations
+ optim = pybop.Optimisation(cost=cost, optimiser=pybop.GradientDescent)
+ optim.set_max_unchanged_iterations(1)
+ x, __ = optim.run()
+ assert optim._iterations == 2
diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py
new file mode 100644
index 000000000..9cc478525
--- /dev/null
+++ b/tests/unit/test_parameter_sets.py
@@ -0,0 +1,20 @@
+import pybop
+import numpy as np
+import pytest
+
+
+class TestParameterSets:
+ """
+ A class to test parameter sets.
+ """
+
+ @pytest.mark.unit
+ def test_parameter_set(self):
+ # Tests parameter set creation
+ with pytest.raises(ValueError):
+ pybop.ParameterSet("pybamms", "Chen2020")
+
+ parameter_test = pybop.ParameterSet("pybamm", "Chen2020")
+ np.testing.assert_allclose(
+ parameter_test["Negative electrode active material volume fraction"], 0.75
+ )
diff --git a/tests/unit/test_parameterisations.py b/tests/unit/test_parameterisations.py
new file mode 100644
index 000000000..142e590d0
--- /dev/null
+++ b/tests/unit/test_parameterisations.py
@@ -0,0 +1,209 @@
+import pybop
+import pybamm
+import pytest
+import numpy as np
+
+
+class TestModelParameterisation:
+ """
+ A class to test the model parameterisation methods.
+ """
+
+ @pytest.mark.parametrize("init_soc", [0.3, 0.7])
+ @pytest.mark.unit
+ def test_spm(self, init_soc):
+ # Define model
+ parameter_set = pybop.ParameterSet("pybamm", "Chen2020")
+ model = pybop.lithium_ion.SPM(parameter_set=parameter_set)
+
+ # Form dataset
+ x0 = np.array([0.52, 0.63])
+ solution = self.getdata(model, x0, init_soc)
+
+ dataset = [
+ pybop.Dataset("Time [s]", solution["Time [s]"].data),
+ pybop.Dataset("Current function [A]", solution["Current [A]"].data),
+ pybop.Dataset(
+ "Terminal voltage [V]", solution["Terminal voltage [V]"].data
+ ),
+ ]
+
+ # Fitting parameters
+ parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.5, 0.02),
+ bounds=[0.375, 0.625],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.65, 0.02),
+ bounds=[0.525, 0.75],
+ ),
+ ]
+
+ # Define the cost to optimise
+ signal = "Terminal voltage [V]"
+ problem = pybop.Problem(
+ model, parameters, dataset, signal=signal, init_soc=init_soc
+ )
+ cost = pybop.RootMeanSquaredError(problem)
+
+ # Select optimiser
+ optimiser = pybop.NLoptOptimize
+
+ # Build the optimisation problem
+ parameterisation = pybop.Optimisation(cost=cost, optimiser=optimiser)
+
+ # Run the optimisation problem
+ x, final_cost = parameterisation.run()
+
+ # Assertions
+ np.testing.assert_allclose(final_cost, 0, atol=1e-2)
+ np.testing.assert_allclose(x, x0, atol=1e-1)
+
+ @pytest.mark.parametrize("init_soc", [0.3, 0.7])
+ @pytest.mark.unit
+ def test_spme_optimisers(self, init_soc):
+ # Define model
+ parameter_set = pybop.ParameterSet("pybamm", "Chen2020")
+ model = pybop.lithium_ion.SPMe(parameter_set=parameter_set)
+
+ # Form dataset
+ x0 = np.array([0.52, 0.63])
+ solution = self.getdata(model, x0, init_soc)
+
+ dataset = [
+ pybop.Dataset("Time [s]", solution["Time [s]"].data),
+ pybop.Dataset("Current function [A]", solution["Current [A]"].data),
+ pybop.Dataset(
+ "Terminal voltage [V]", solution["Terminal voltage [V]"].data
+ ),
+ ]
+
+ # Fitting parameters
+ parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.5, 0.02),
+ bounds=[0.375, 0.625],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.65, 0.02),
+ bounds=[0.525, 0.75],
+ ),
+ ]
+
+ # Define the cost to optimise
+ signal = "Terminal voltage [V]"
+ problem = pybop.Problem(
+ model, parameters, dataset, signal=signal, init_soc=init_soc
+ )
+ cost = pybop.RootMeanSquaredError(problem)
+
+ # Select optimisers
+ optimisers = [pybop.NLoptOptimize, pybop.SciPyMinimize, pybop.CMAES]
+
+ # Test each optimiser
+ for optimiser in optimisers:
+ parameterisation = pybop.Optimisation(cost=cost, optimiser=optimiser)
+
+ if optimiser == pybop.CMAES:
+ parameterisation.set_f_guessed_tracking(True)
+ assert parameterisation._use_f_guessed is True
+ parameterisation.set_max_iterations(1)
+ x, final_cost = parameterisation.run()
+
+ parameterisation.set_f_guessed_tracking(False)
+ parameterisation.set_max_iterations(250)
+
+ x, final_cost = parameterisation.run()
+ assert parameterisation._max_iterations == 250
+
+ else:
+ x, final_cost = parameterisation.run()
+
+ # Assertions
+ np.testing.assert_allclose(final_cost, 0, atol=1e-2)
+ np.testing.assert_allclose(x, x0, atol=1e-1)
+
+ @pytest.mark.parametrize("init_soc", [0.3, 0.7])
+ @pytest.mark.unit
+ def test_model_misparameterisation(self, init_soc):
+ # Define two different models with different parameter sets
+ # The optimisation should fail as the models are not the same
+
+ parameter_set = pybop.ParameterSet("pybamm", "Chen2020")
+ model = pybop.lithium_ion.SPM(parameter_set=parameter_set)
+
+ second_parameter_set = pybop.ParameterSet("pybamm", "Ecker2015")
+ second_model = pybop.lithium_ion.SPM(parameter_set=second_parameter_set)
+
+ # Form observations
+ x0 = np.array([0.52, 0.63])
+ solution = self.getdata(second_model, x0, init_soc)
+
+ dataset = [
+ pybop.Dataset("Time [s]", solution["Time [s]"].data),
+ pybop.Dataset("Current function [A]", solution["Current [A]"].data),
+ pybop.Dataset(
+ "Terminal voltage [V]", solution["Terminal voltage [V]"].data
+ ),
+ ]
+
+ # Fitting parameters
+ parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.5, 0.02),
+ bounds=[0.375, 0.625],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.65, 0.02),
+ bounds=[0.525, 0.75],
+ ),
+ ]
+
+ # Define the cost to optimise
+ signal = "Terminal voltage [V]"
+ problem = pybop.Problem(
+ model, parameters, dataset, signal=signal, init_soc=init_soc
+ )
+ cost = pybop.RootMeanSquaredError(problem)
+
+ # Select optimiser
+ optimiser = pybop.NLoptOptimize
+
+ # Build the optimisation problem
+ parameterisation = pybop.Optimisation(cost=cost, optimiser=optimiser)
+
+ # Run the optimisation problem
+ x, final_cost = parameterisation.run()
+
+ # Assertions
+ with np.testing.assert_raises(AssertionError):
+ np.testing.assert_allclose(final_cost, 0, atol=1e-2)
+ np.testing.assert_allclose(x, x0, atol=1e-1)
+
+ def getdata(self, model, x0, init_soc):
+ model.parameter_set.update(
+ {
+ "Negative electrode active material volume fraction": x0[0],
+ "Positive electrode active material volume fraction": x0[1],
+ }
+ )
+ experiment = pybamm.Experiment(
+ [
+ (
+ "Discharge at 1C for 3 minutes (1 second period)",
+ "Rest for 2 minutes (1 second period)",
+ "Charge at 1C for 3 minutes (1 second period)",
+ "Rest for 2 minutes (1 second period)",
+ ),
+ ]
+ * 2
+ )
+ sim = model.predict(init_soc=init_soc, experiment=experiment)
+ return sim
diff --git a/tests/unit/test_priors.py b/tests/unit/test_priors.py
new file mode 100644
index 000000000..342c35c46
--- /dev/null
+++ b/tests/unit/test_priors.py
@@ -0,0 +1,59 @@
+import pybop
+import numpy as np
+import pytest
+
+
+class TestPriors:
+ """
+ A class to test the priors.
+ """
+
+ @pytest.fixture
+ def Gaussian(self):
+ return pybop.Gaussian(mean=0.5, sigma=1)
+
+ @pytest.fixture
+ def Uniform(self):
+ return pybop.Uniform(lower=0, upper=1)
+
+ @pytest.fixture
+ def Exponential(self):
+ return pybop.Exponential(scale=1)
+
+ @pytest.mark.unit
+ def test_priors(self, Gaussian, Uniform, Exponential):
+ # Test pdf
+ np.testing.assert_allclose(Gaussian.pdf(0.5), 0.3989422804014327, atol=1e-4)
+ np.testing.assert_allclose(Uniform.pdf(0.5), 1, atol=1e-4)
+ np.testing.assert_allclose(Exponential.pdf(1), 0.36787944117144233, atol=1e-4)
+
+ # Test logpdf
+ np.testing.assert_allclose(Gaussian.logpdf(0.5), -0.9189385332046727, atol=1e-4)
+ np.testing.assert_allclose(Uniform.logpdf(0.5), 0, atol=1e-4)
+ np.testing.assert_allclose(Exponential.logpdf(1), -1, atol=1e-4)
+
+ @pytest.mark.unit
+ def test_gaussian_rvs(self, Gaussian):
+ samples = Gaussian.rvs(size=500)
+ mean = np.mean(samples)
+ std = np.std(samples)
+ assert abs(mean - 0.5) < 0.2
+ assert abs(std - 1) < 0.2
+
+ @pytest.mark.unit
+ def test_uniform_rvs(self, Uniform):
+ samples = Uniform.rvs(size=500)
+ assert (samples >= 0).all() and (samples <= 1).all()
+
+ @pytest.mark.unit
+ def test_exponential_rvs(self, Exponential):
+ samples = Exponential.rvs(size=500)
+ assert (samples >= 0).all()
+ mean = np.mean(samples)
+ assert abs(mean - 1) < 0.2
+
+ @pytest.mark.unit
+ def test_repr(self, Gaussian, Uniform, Exponential):
+ assert repr(Gaussian) == "Gaussian, mean: 0.5, sigma: 1"
+ assert repr(Uniform) == "Uniform, lower: 0, upper: 1"
+ assert repr(Exponential) == "Exponential, scale: 1"
diff --git a/tests/unit/test_problem.py b/tests/unit/test_problem.py
new file mode 100644
index 000000000..aa470d9b4
--- /dev/null
+++ b/tests/unit/test_problem.py
@@ -0,0 +1,74 @@
+import pybop
+import numpy as np
+import pybamm
+import pytest
+
+
+class TestProblem:
+ """
+ A class to test the problem class.
+ """
+
+ @pytest.mark.unit
+ def test_problem(self):
+ # Define model
+ model = pybop.lithium_ion.SPM()
+ parameters = [
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.5, 0.02),
+ bounds=[0.375, 0.625],
+ ),
+ pybop.Parameter(
+ "Positive electrode active material volume fraction",
+ prior=pybop.Gaussian(0.65, 0.02),
+ bounds=[0.525, 0.75],
+ ),
+ ]
+ signal = "Voltage [V]"
+
+ # Form dataset
+ x0 = np.array([0.52, 0.63])
+ solution = self.getdata(model, x0)
+
+ dataset = [
+ pybop.Dataset("Time [s]", solution["Time [s]"].data),
+ pybop.Dataset("Current function [A]", solution["Current [A]"].data),
+ pybop.Dataset("Voltage [V]", solution["Terminal voltage [V]"].data),
+ ]
+
+ # Test incorrect number of initial parameter values
+ with pytest.raises(ValueError):
+ pybop.Problem(model, parameters, dataset, signal=signal, x0=np.array([]))
+
+ # Construct Problem
+ problem = pybop.Problem(model, parameters, dataset, signal=signal)
+
+ assert problem._model == model
+ assert problem._model._built_model is not None
+
+ # Test model.simulate
+ model.simulate(inputs=[0.5, 0.5], t_eval=np.linspace(0, 10, 100))
+
+ def getdata(self, model, x0):
+ model.parameter_set = model.pybamm_model.default_parameter_values
+
+ model.parameter_set.update(
+ {
+ "Negative electrode active material volume fraction": x0[0],
+ "Positive electrode active material volume fraction": x0[1],
+ }
+ )
+ experiment = pybamm.Experiment(
+ [
+ (
+ "Discharge at 1C for 5 minutes (1 second period)",
+ "Rest for 2 minutes (1 second period)",
+ "Charge at 1C for 5 minutes (1 second period)",
+ "Rest for 2 minutes (1 second period)",
+ ),
+ ]
+ * 2
+ )
+ sim = model.predict(experiment=experiment)
+ return sim