Activities and Exchanges

This notebook shows how to use the Activity and Exchange classes.

In [1]:
from brightway2 import *

Let's create a new project just for this notebook

In [2]:
projects.set_current("cats and dogs")

Let's start with a new database:

In [3]:
db = Database("a&e")

and insert some basic data:

In [4]:
db.write({
    ("a&e", "cat"): {
        'name': 'cat',
        'unit': 'kilogram',
        'color': 'black',  # Custom field - you can add whatever fields you need
        'exchanges': [{
            'input': ('a&e', 'cat food'),
            'amount': 10,
            'type': 'technosphere'
        }, {
            'input': ('a&e', 'kitty litter'),
            'amount': 10,
            'type': 'technosphere'            
        }, {
            'input': ('a&e', 'smell'),
            'amount': 1,
            'type': 'biosphere'            
        }]
    },
    ("a&e", "kitty litter"): {'name': 'yuck'},
    ("a&e", "cat food"): {'name': 'yum'},
    ("a&e", "smell"): {'name': 'stinky', 'type': 'biosphere'},
})
Writing activities to SQLite3 database:
0%  100%
[####] | ETA[sec]: 0.000 
Total time elapsed: 0.026 sec
Title: Writing activities to SQLite3 database:
  Started: 07/15/2016 11:50:08
  Finished: 07/15/2016 11:50:08
  Total time elapsed: 0.026 sec
  CPU %: 113.900000
  Memory %: 0.349951

We can get an activity with .get():

In [5]:
act = db.get("cat")
act
Out[5]:
'cat' (kilogram, None, None)

The cat process has no categories or location so far. Let's change that:

In [6]:
act['location'] = 'inside'
act['categories'] = ['felis', 'catus']
act
Out[6]:
'cat' (kilogram, inside, ['felis', 'catus'])

When we are ready, we can save our changes:

In [7]:
act.save()

We can iterate over the available data fields:

In [8]:
for key in act:
    print(key, ':', act[key])
location : inside
unit : kilogram
database : a&e
name : cat
categories : ['felis', 'catus']
color : black
code : cat

Note that the fields database and code are added automatically for us.

There are only a few methods for an activity. We can see the activity key (combination of database and code):

In [9]:
act.key
Out[9]:
('a&e', 'cat')

We can iterate over all exchanges:

In [10]:
for exc in act.exchanges():
    print(exc)
Exchange: 10 None 'yum' (None, None, None) to 'cat' (kilogram, inside, ['felis', 'catus'])>
Exchange: 10 None 'yuck' (None, None, None) to 'cat' (kilogram, inside, ['felis', 'catus'])>
Exchange: 1 None 'stinky' (None, None, None) to 'cat' (kilogram, inside, ['felis', 'catus'])>

Or just the technosphere/biosphere/production exchanges:

In [11]:
print("technosphere:")
for exc in act.technosphere():
    print(exc)
print("biosphere:")
for exc in act.biosphere():
    print(exc)
print("production:")
for exc in act.production():
    print(exc)
technosphere:
Exchange: 10 None 'yum' (None, None, None) to 'cat' (kilogram, inside, ['felis', 'catus'])>
Exchange: 10 None 'yuck' (None, None, None) to 'cat' (kilogram, inside, ['felis', 'catus'])>
biosphere:
Exchange: 1 None 'stinky' (None, None, None) to 'cat' (kilogram, inside, ['felis', 'catus'])>
production:

You can also count exchanges (or any of the specific types of exchanges):

In [12]:
len(act.exchanges())
Out[12]:
3

There weren't any production exchanges. Brightway2 will add a default production exchanges with amount of 1 when building the technosphere matrix if no production exchange is given.

We can also look at upstream exchanges - those that consume this activity's reference product. We don't have any yet, so let's create a new activity:

In [13]:
na = db.new_activity("dog")
na.save()
---------------------------------------------------------------------------
ValidityError                             Traceback (most recent call last)
<ipython-input-13-1ce2ba0be795> in <module>()
      1 na = db.new_activity("dog")
----> 2 na.save()

/Users/cmutel/local35/bw3/lib/python3.5/site-packages/bw2data/project.py in writable_project(wrapped, instance, args, kwargs)
    383     if projects.read_only:
    384         raise ReadOnlyProject(READ_ONLY_PROJECT)
--> 385     return wrapped(*args, **kwargs)

/Users/cmutel/local35/bw3/lib/python3.5/site-packages/bw2data/backends/peewee/proxies.py in save(self)
    104             raise ValidityError("This activity can't be saved for the "
    105                 "following reasons\n\t* " + \
--> 106                 "\n\t* ".join(self.valid(why=True)[1])
    107             )
    108 

ValidityError: This activity can't be saved for the following reasons
	* Missing field ``name``

Oops, activities must have names. Let's fix that:

In [14]:
na['name'] = 'fido'
na.save()

We will also get a nice error message for invalid new exchanges:

In [15]:
na.new_exchange().save()
---------------------------------------------------------------------------
ValidityError                             Traceback (most recent call last)
<ipython-input-15-514e23f89f03> in <module>()
----> 1 na.new_exchange().save()

/Users/cmutel/local35/bw3/lib/python3.5/site-packages/bw2data/project.py in writable_project(wrapped, instance, args, kwargs)
    383     if projects.read_only:
    384         raise ReadOnlyProject(READ_ONLY_PROJECT)
--> 385     return wrapped(*args, **kwargs)

/Users/cmutel/local35/bw3/lib/python3.5/site-packages/bw2data/backends/peewee/proxies.py in save(self)
    268             raise ValidityError("This exchange can't be saved for the "
    269                 "following reasons\n\t* " + \
--> 270                 "\n\t* ".join(self.valid(why=True)[1])
    271             )
    272 

ValidityError: This exchange can't be saved for the following reasons
	* Missing field ``input``
	* Invalid or missing field ``amount``
	* Missing field ``type``

Let's add a link to our cat process. Don't worry, the dog won't really eat the cat!

In [16]:
new_exc = na.new_exchange(input=act, amount=1, type='technosphere')
new_exc.save()

We can now see that 'fido' links to 'cat':

In [17]:
for exc in na.technosphere():
    print(exc)
for exc in act.upstream():
    print(exc)
Exchange: 1 kilogram 'cat' (kilogram, inside, ['felis', 'catus']) to 'fido' (None, GLO, None)>
Exchange: 1 kilogram 'cat' (kilogram, inside, ['felis', 'catus']) to 'fido' (None, GLO, None)>

exc.input and exc.output will return activities:

In [18]:
new_exc.input, new_exc.output
Out[18]:
('cat' (kilogram, inside, ['felis', 'catus']), 'fido' (None, GLO, None))

Exchanges have a few more methods:

In [19]:
new_exc.unit, new_exc.amount, new_exc.uncertainty_type
Out[19]:
('kilogram', 1, stats_arrays.distributions.undefined.UndefinedUncertainty)

Let's add some uncertainty to this exchange (see http://stats-arrays.readthedocs.org/en/latest/):

In [20]:
from stats_arrays import NormalUncertainty

new_exc['uncertainty type'] = NormalUncertainty.id
new_exc['loc'], new_exc['scale'] = 1, 0.25
new_exc.save()

We can now get an uncertainty dictionary for use in stats_arrays functions:

In [21]:
new_exc.uncertainty
Out[21]:
{'loc': 1, 'scale': 0.25, 'uncertainty type': 3}

And can get a random sample:

In [22]:
new_exc.random_sample(n=10)
Out[22]:
array([ 0.99004329,  1.07175437,  0.47354696,  1.32863177,  1.38786416,
        1.40075775,  1.12460893,  1.08966507,  1.31904524,  1.27995624])

We can copy activities. This will copy the activities exchanges:

In [23]:
kudu = act.copy(name="kudu", code='antelope')
kudu
Out[23]:
'kudu' (kilogram, inside, ['felis', 'catus'])
In [24]:
for exc in kudu.exchanges():
    print(exc)
Exchange: 10 None 'yum' (None, None, None) to 'kudu' (kilogram, inside, ['felis', 'catus'])>
Exchange: 10 None 'yuck' (None, None, None) to 'kudu' (kilogram, inside, ['felis', 'catus'])>
Exchange: 1 None 'stinky' (None, None, None) to 'kudu' (kilogram, inside, ['felis', 'catus'])>

Upstream exchanges are (of course) not copied:

In [25]:
for exc in kudu.upstream():
    print(exc)

You can delete the some or all of an activities exchanges:

In [26]:
print("Before:",len(kudu.exchanges()))
kudu.biosphere().delete()
print("After:", len(kudu.exchanges()))
Before: 3
After: 2

You can also delete activities:

In [27]:
kudu.delete()

Our new activity is no longer in the database:

In [28]:
kudu in db
Out[28]:
False