Skip to content

Commit

Permalink
Move API docs to new doc/api.rst; adjust for code re-org
Browse files Browse the repository at this point in the history
  • Loading branch information
khaeru committed Jan 10, 2021
1 parent 3d00cfc commit d9539f9
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 272 deletions.
263 changes: 263 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
API
***

.. currentmodule:: genno

Top-level methods and classes:

.. autosummary::

configure
Computer
Key
Quantity

Others:

.. contents::
:local:
:depth: 3

.. autofunction:: configure

.. autoclass:: genno.Computer
:members:
:exclude-members: graph, add, add_load_file, apply

A Computer is used to postprocess data from from one or more
:class:`ixmp.Scenario` objects. The :meth:`get` method can be used to:

- Retrieve individual **quantities**. A quantity has zero or more
dimensions and optional units. Quantities include the ‘parameters’,
‘variables’, ‘equations’, and ‘scalars’ available in an
:class:`ixmp.Scenario`.

- Generate an entire **report** composed of multiple quantities. A report
may:

- Read in non-model or exogenous data,
- Trigger output to files(s) or a database, or
- Execute user-defined methods.

Every report and quantity (including the results of intermediate steps) is
identified by a :class:`.Key`; all the keys in a Computer can be listed with
:meth:`keys`.

Computer uses a :doc:`graph <graphs>` data structure to keep track of
**computations**, the atomic steps in postprocessing: for example, a single
calculation that multiplies two quantities to create a third. The graph
allows :meth:`get` to perform *only* the requested computations. Advanced
users may manipulate the graph directly; but common reporting tasks can be
handled by using Computer methods:

.. autosummary::
add
add_file
add_product
add_queue
add_single
aggregate
apply
check_keys
configure
describe
disaggregate
full_key
get
keys
visualize
write

.. autoattribute:: graph

.. automethod:: add

:meth:`add` may be called with:

- :class:`list` : `data` is a list of computations like ``[(list(args1), dict(kwargs1)), (list(args2), dict(kwargs2)), ...]`` that are added one-by-one.
- the name of a function in :mod:`.computations` (e.g. 'select'): A computation is added with key ``args[0]``, applying the named function to ``args[1:]`` and `kwargs`.
- :class:`str`, the name of a :class:`Computer` method (e.g. 'apply'): the corresponding method (e.g. :meth:`apply`) is called with the `args` and `kwargs`.
- Any other :class:`str` or :class:`.Key`: the arguments are passed to :meth:`add_single`.

:meth:`add` may also be used to:

- Provide an alias from one *key* to another:

>>> from genno import Computer
>>> rep = Computer() # Create a new Computer object
>>> rep.add('aliased name', 'original name')

- Define an arbitrarily complex computation in a Python function that
operates directly on the :class:`ixmp.Scenario`:

>>> def my_report(scenario):
>>> # many lines of code
>>> return 'foo'
>>> rep.add('my report', (my_report, 'scenario'))
>>> rep.finalize(scenario)
>>> rep.get('my report')
foo

.. note::
Use care when adding literal ``str()`` values as a *computation*
argument for :meth:`add`; these may conflict with keys that
identify the results of other computations.

.. automethod:: apply

The `generator` may have a type annotation for Computer on its first positional argument.
In this case, a reference to the Computer is supplied, and `generator` may use the Computer methods to add computations:

.. code-block:: python
def gen0(r: ixmp.Computer, **kwargs):
r.load_file('file0.txt', **kwargs)
r.load_file('file1.txt', **kwargs)
# Use the generator to add several computations
rep.apply(my_gen, units='kg')
Or, `generator` may ``yield`` a sequence (0 or more) of (`key`, `computation`), which are added to the :attr:`graph`:

.. code-block:: python
def gen1(**kwargs):
op = partial(computations.load_file, **kwargs)
yield from (f'file:{i}', op, 'file{i}.txt') for i in range(2)
rep.apply(my_gen, units='kg')
.. autoclass:: genno.Key
:members:

Quantities in a :class:`Scenario` can be indexed by one or more dimensions.
A Key refers to a quantity using three components:

1. a string :attr:`name`,
2. zero or more ordered :attr:`dims`, and
3. an optional :attr:`tag`.

For example, an ixmp parameter with three dimensions can be initialized
with:

>>> scenario.init_par('foo', ['a', 'b', 'c'], ['apple', 'bird', 'car'])

Key allows a specific, explicit reference to various forms of “foo”:

- in its full resolution, i.e. indexed by a, b, and c:

>>> k1 = Key('foo', ['a', 'b', 'c'])
>>> k1 == 'foo:a-b-c'
True

Notice that a Key has the same hash, and compares equal (`==`) to its ``str()``.

- in a partial sum over one dimension, e.g. summed along c with dimensions
a and b:

>>> k2 = k1.drop('c')
>>> k2 == 'foo:a-b'
True

- in a partial sum over multiple dimensions, etc.:

>>> k1.drop('a', 'c') == k2.drop('a') == 'foo:b'
True

.. note::
Some remarks:

- ``repr(key)`` prints the Key in angle brackets ('<>') to signify it is a Key object.

>>> repr(k1)
<foo:a-b-c>

- Keys are *immutable*: the properties :attr:`name`, :attr:`dims`, and :attr:`tag` are read-only, and the methods :meth:`append`, :meth:`drop`, and :meth:`add_tag` return *new* Key objects.

- Keys may be generated concisely by defining a convenience method:

>>> def foo(dims):
>>> return Key('foo', dims.split())
>>> foo('a b c')
foo:a-b-c

.. autodata:: genno.Quantity(data, *args, **kwargs)
:annotation:

The :data:`.Quantity` constructor converts its arguments to an internal, :class:`xarray.DataArray`-like data format:

.. code-block:: python
# Existing data
data = pd.Series(...)
# Convert to a Quantity for use in reporting calculations
qty = Quantity(data, name="Quantity name", units="kg")
rep.add("new_qty", qty)
Common :mod:`genno` usage, e.g. in :mod:`message_ix`, creates large, sparse data frames (billions of possible elements, but <1% populated); :class:`~xarray.DataArray`'s default, 'dense' storage format would be too large for available memory.

- Currently, Quantity is :class:`.AttrSeries`, a wrapped :class:`pandas.Series` that behaves like a :class:`~xarray.DataArray`.
- In the future, :mod:`genno` will use :class:`.SparseDataArray`, and eventually :class:`~xarray.DataArray` backed by sparse data, directly.

The goal is that reporting code, including built-in and user computations, can treat quantity arguments as if they were :class:`~xarray.DataArray`.


Computations
============

.. automodule:: genno.computations
:members:

Unless otherwise specified, these methods accept and return
:class:`Quantity <genno.utils.Quantity>` objects for data
arguments/return values.

Calculations:

.. autosummary::
add
aggregate
apply_units
disaggregate_shares
product
ratio
select
sum

Input and output:

.. autosummary::
load_file
write_report

Data manipulation:

.. autosummary::
concat


Internal format for quantities
==============================

.. currentmodule:: genno.core.quantity

.. automodule:: genno.core.quantity
:members: assert_quantity

.. currentmodule:: genno.core.attrseries

.. automodule:: genno.core.attrseries
:members:

.. currentmodule:: genno.core.sparsedataarray

.. automodule:: genno.core.sparsedataarray
:members: SparseDataArray, SparseAccessor


Utilities
=========

.. automodule:: genno.util
:members:

0 comments on commit d9539f9

Please sign in to comment.