Skip to content

Commit

Permalink
add text to explain tests
Browse files Browse the repository at this point in the history
* include version, release and author info from uncertainty_wrapper/__init__.py in sphinx conf.py
* change copyright to SunPower
* enable Next/Previous, remove relations
* update Getting Started with plots of Jacobian errors for IV curve, new sections for complex example and python c/c++ extension
* fix some broken links
* show release and version info on docs splash page
* make it easier to required packages for all tests using __all__
* make plot of relative differences between AlgoPy and jacobian estimate
* move optional requires into new section
* update link to Pint to latest, not v0.6
  • Loading branch information
mikofski committed Apr 18, 2016
1 parent 090d188 commit 8c8a246
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 26 deletions.
10 changes: 9 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ Requirements
------------

* `NumPy <http://www.numpy.org/>`_

Optional Requirements
~~~~~~~~~~~~~~~~~~~~~

* `Nose <https://nose.readthedocs.org/en/latest/index.html>`_ for testing.
* `Sphinx <http://www.sphinx-doc.org/en/stable/>`_ to build documentation.
* `NREL SOLPOS <http://rredc.nrel.gov/solar/codesandalgorithms/solpos/>`_ for testing
* `AlgoPy <https://pythonhosted.org/algopy/>`_ for testing


History
Expand All @@ -31,6 +37,8 @@ Releases are named after
* Fixes #1 works with Pint's @ureg.wraps()
* Use indices for positional arguments. Don't use inspect.argspec since not
guaranteed to be the same for wrapped or decorated functions
* Test Jacobian estimate for IV with `AlgoPy <https://pythonhosted.org/algopy/>`_
* Show Jacobian errors plot in getting started docs.


`v0.3 <https://github.com/SunPower/UncertaintyWrapper/releases/tag/v0.3>`_ `Proterozoic Eon <https://en.wikipedia.org/wiki/Proterozoic>`_
Expand All @@ -41,7 +49,7 @@ Releases are named after
together so that in the original function they can stay unpacked.
* return values are grouped correctly so that they can remain unpacked in
original function. These allow Uncertainty Wrapper to be used with
`Pint's wrapper <http://pint.readthedocs.org/en/0.6/wrapping.html>`_
`Pint's wrapper <http://pint.readthedocs.org/en/latest/wrapping.html>`_
* covariance now specified as dimensionaless fraction of square of arguments
* more complex tests: IV curve and solar position (requires
`NREL's solpos <http://rredc.nrel.gov/solar/codesandalgorithms/solpos/>`_)
Expand Down
13 changes: 12 additions & 1 deletion uncertainty_wrapper/docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,30 @@ all independent arguments are already grouped together.
Tests
-----

.. automodule:: uncertainty_wrapper.tests
.. automodule:: uncertainty_wrapper.tests.test_uncertainty_wrapper

Test Uncertainty Wrapper
~~~~~~~~~~~~~~~~~~~~~~~~

.. autofunction:: test_unc_wrapper

Test simple exponential function with known derivative. Assert derivative is
correct and that uncertainty is propagated correctly.

Test IV curve
~~~~~~~~~~~~~

.. autofunction:: test_IV

Test complex function with several operations, including :math:`exp`, :math:`log`
and powers, with several input arguments and with several return values. Check
Jacobian calculated with central finite difference approximation with automatic
differentiation using AlgoPy.

Test Solar Position
~~~~~~~~~~~~~~~~~~~

.. autofunction:: test_solpos

Test function from a Python C/C++ extension. Check calcuated Jacobian with John
D'Errico's ``numdifftools`` Python package (MATLAB ``derivest``).
12 changes: 7 additions & 5 deletions uncertainty_wrapper/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))

from uncertainty_wrapper import __VERSION__, __RELEASE__, __AUTHOR__

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
Expand Down Expand Up @@ -52,17 +54,17 @@

# General information about the project.
project = u'Uncertainty Wrapper'
copyright = u'2016, Mark Mikofski'
author = u'Mark Mikofski'
copyright = u'2016, SunPower'
author = __AUTHOR__

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.1'
version = __VERSION__
# The full version, including alpha/beta/rc tags.
release = u'0.1'
release = __RELEASE__

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down Expand Up @@ -122,6 +124,7 @@
'logo': 'sp_2014_logo_black_orange_rgb.png',
'github_user': 'SunPower',
'github_repo': 'UncertaintyWrapper',
'show_related': True
}

# Add any paths that contain custom themes here, relative to this directory.
Expand Down Expand Up @@ -168,7 +171,6 @@
'navigation.html',
'relations.html',
'searchbox.html',
'donate.html',
]
}

Expand Down
44 changes: 34 additions & 10 deletions uncertainty_wrapper/docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Getting Started
===============
You can wrap any Python callable using :func:`~uncertainty_wrapper.unc_wrapper`
or :func:`~uncertainty_wrapper.unc_wrapper_args`, that does the following:
You can wrap any Python callable using :func:`~uncertainty_wrapper.core.unc_wrapper`
or :func:`~uncertainty_wrapper.core.unc_wrapper_args`, that does the following:

* looks for ``__covariance__`` as a keyword argument
* calculates the Jacobian and covariance matrices
Expand All @@ -12,10 +12,10 @@ or :func:`~uncertainty_wrapper.unc_wrapper_args`, that does the following:
However you may need to manipulate the input arguments to match the expected
:ref:`API`.

Examples
--------
Simple Example
--------------

The following example is from
This simple example using two input arguments and two return values is from
`Uncertainty Benchmarks <https://github.com/mikofski/uncertainty_benchmarks>`_::

from uncertainty_wrapper import unc_wrapper
Expand Down Expand Up @@ -79,12 +79,36 @@ The following example is from
# [[ 14.86241279 14.86241279]
# [ -3.6044591 11.2579537 ]]

Complex Example
---------------

A more complex example is from the :mod:`~uncertainty_wrapper.tests` module
called :func:`~uncertainty_wrapper.tests.test_IV`.
It includes combinations of several exponential and power operations. Here the
uncertainty in the calculation is shown using matplotlib to plot the errorbars.
A more complex example from the :mod:`~uncertainty_wrapper.tests.test_uncertainty_wrapper`
module called :func:`~uncertainty_wrapper.tests.test_uncertainty_wrapper.test_IV`,
includes combinations of several exponential and power operations. It contains
9 input arguments, there 126 observations of each corresponding to different
voltages and there are 3 return values. The calculated uncertainty using a 1%
standard deviation (square root of variance) for all 9 inputs is shown below.

.. image:: _static/IV_and_PV_plots_with_uncertainty.png


The test compares the derivatives calculated using central finite difference
approximation with an analytical calculation from 0.3[V] to 0.6[V]. Below 0.3[V]
the approximations deviate from the analytical for
:math:`\frac{\partial I_{sc}}{\partial I_{sat_{1,0}}}`,
:math:`\frac{\partial I_{sc}}{\partial I_{sat_2}}` and
:math:`\frac{\partial I_{sc}}{\partial E_g}` while all other independent
variables are consistently below 10e-7. The analytical derivatives are propagated
using `AlgoPy <https://pythonhosted.org/algopy/>`_, an automatic differentiation
package, which requires rewriting all NumPy operations like :math:`exp` using
AlgoPy. This makes it impractical for use in most models, but still useful for
testing.

.. image:: _static/IV-PV-jac-errors.png

Python Extension Example
------------------------

Often Python packages contain extensions in C/C++ which can't be tested using
automatic differentiation. The Numdidfftools is an alternative package that can
calculate derivatives more accurately than the central finite difference
approximation.
2 changes: 2 additions & 0 deletions uncertainty_wrapper/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
Welcome to Uncertainty Wrapper's documentation!
===============================================

Version: |version| (|release|)

Contents:

.. toctree::
Expand Down
3 changes: 3 additions & 0 deletions uncertainty_wrapper/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
import pint
from matplotlib import pyplot as plt


UREG = pint.UnitRegistry()
PST = pytz.timezone('US/Pacific')
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
__all__ = ['ok_', 'np', 'unc_wrapper', 'unc_wrapper_args', 'KB', 'QE',
'datetime', 'timedelta', 'solposAM', 'plt', 'UREG', 'PST', 'LOGGER']
52 changes: 43 additions & 9 deletions uncertainty_wrapper/tests/test_uncertainty_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
:func:`~uncertainty_wrapper.unc_wrapper_args`
"""

from uncertainty_wrapper.tests import (
unc_wrapper, unc_wrapper_args, np, ok_, datetime, timedelta, solposAM, plt,
UREG, LOGGER, PST, KB, QE
)
from uncertainty_wrapper.tests import *
from uncertainty_wrapper.tests.test_algopy import IV_algopy_jac


Expand Down Expand Up @@ -118,7 +115,7 @@ def test_IV():
rms = np.sqrt(np.sum(reldiff ** 2.0) / 9.0/ 3.0)
LOGGER.debug('rms at Vd = %g[V]: %r', VD[n], rms)
ok_(np.allclose(pv_jac_n, pv_jac_algopy_n, rtol=1e-3, atol=1e-3))
return pv, pv_cov, pv_jac
return pv, pv_cov, pv_jac, pv_jac_algopy


def plot_pv(pv, pv_cov):
Expand All @@ -131,18 +128,52 @@ def plot_pv(pv, pv_cov):
p_stdev = np.sqrt(pv_cov.diagonal()[2::3])
fig, ax1 = plt.subplots()
ax1.errorbar(v_pv, i_pv, i_stdev, v_stdev)
ax1.grid()
ax1.set_xlabel('voltage [V]')
ax1.set_ylabel('current [A]', color='b')
ax1.set_ylim([0, 6.0])
ax2 = ax1.twinx()
ax2.errorbar(v_pv, p_pv, p_stdev, v_stdev, fmt='r')
ax2.grid()
ax2.set_ylabel('power [W]', color='r')
ax2.set_ylim([0, 3.0])
ax1.grid()
ax1.set_title('IV and PV curves')
return fig


def plot_pv_jac(pv_jac, pv_jac_algopy, Vd=VD):
"""
Log plot of relative difference between AlgoPy and central finite difference
approximations
:param pv_jac: central finite approximations
:param pv_jac_algopy: automatic differentiation
:param Vd: voltages
:return: fig
"""
fn = ['Cell Current, Ic [A]', 'Cell Voltage, Vc [V]', 'Cell Power, Pc [W]']
fig, ax = plt.subplots(3, 1, **{'figsize': (8.0, 18.0)})
colorcycle = [
'firebrick', 'goldenrod', 'sage', 'lime', 'seagreen', 'turquoise',
'royalblue', 'indigo', 'fuchsia'
]
for m in xrange(3):
for n in xrange(9):
pv_jac_n = pv_jac[m::3, n::9].diagonal()
pv_jac_algopy_n = pv_jac_algopy[m, :, n * 126:(n + 1) * 126].diagonal()
reldiff = np.abs(pv_jac_n / pv_jac_algopy_n - 1.0)
ax[m].semilogy(Vd, reldiff, colorcycle[n])
ax[m].grid()
ax[m].legend(
['Ee', 'Tc', 'Rs', 'Rsh', 'Isat1_0', 'Isat2', 'Isc0', 'alpha_Isc',
'Eg'], fancybox=True, framealpha=0.5
)
ax[m].set_xlabel('Diode Voltage, Vd [V]')
ax[m].set_ylabel('Relative Difference')
ax[m].set_title(fn[m])
plt.tight_layout()
return fig

@UREG.wraps(('deg', 'deg', 'dimensionless', 'dimensionless'),
('deg', 'deg', 'millibar', 'degC', None, 'second'))
@unc_wrapper_args(0, 1, 2, 3, 5)
Expand Down Expand Up @@ -191,7 +222,10 @@ def test_solpos():

if __name__ == '__main__':
test_unc_wrapper()
pv, pv_cov, pv_jac = test_IV()
pv, pv_cov, pv_jac, pv_jac_algopy = test_IV()
test_solpos()
fig = plot_pv(pv, pv_cov)
fig.show()
fig1 = plot_pv(pv, pv_cov)
fig1.show()
fig2 = plot_pv_jac(pv_jac, pv_jac_algopy)
fig2.savefig('IV-PV-jac-errors.png')
fig2.show()

0 comments on commit 8c8a246

Please sign in to comment.