Skip to content

Commit 2b4f51b

Browse files
committed
2 parents df4cff2 + caa7185 commit 2b4f51b

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

.github/workflows/python-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@ jobs:
5959
pytest
6060
6161
- name: Upload coverage reports to Codecov
62-
uses: codecov/codecov-action@v4
62+
uses: codecov/codecov-action@v5

README.md

+32-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,45 @@
99

1010
`bw_interface_schemas` defines a set of [pydantic](https://docs.pydantic.dev/2.0/) classes which will be the fundamental data schema for Brightway Cloud, the next iteration of the Brightway LCA software ecosystem. These schemas provide clear and consistent graph-based interfaces between Brightway software libraries, and simplify and harmonize the way data was modeled and stored in Brightway.
1111

12-
We have chosen to model all data in a graph, as a list of nodes and edges. This includes inventory data, which models how processes consume and produce products to form supply chains. It also includes impact assessment, where elementary flows are linked to impact categories via characterization edges, and data organization. Now both projects and databases are also in the graph, and process and product nodes are linked to databases via `belongs_to` relationship edges.
12+
We have chosen to model all data in a directed graph, i.e. as nodes and (directed) edges. This includes inventory data, which models how processes consume and produce products to form supply chains, but also includes impact assessment, where elementary flows are linked to impact categories via characterization edges, and collections, where processes and products belong to databases.
1313

1414
## Example
1515

1616
Here is our standard bicycle production example in the new paradigm:
1717

1818
<img src="example.png">
1919

20-
You can see two ways of building this graph in code in `tests/conftest.py`.
20+
You can see this graph in code in `tests/conftest.py`.
21+
22+
## Motivation
23+
24+
In previous Brightway versions, the libraries were tightly coupled, and the schemas for passing data between Python libraries or with other software were never explicitly defined or custom-developed. This led to a chaos of utility conversion functions without any guarantees on broad format or on the availability of specific attributes.
25+
26+
The approach in `bw_interface_schemas` allows for a more modular approach, where Brightway IO libraries can work with multiple data stores or data generation and manipulation packages. The definition of nodes and edges is clear, and using `pydantic` gives us reasonable error messages and validation performance.
27+
28+
We have also fixed some poor design choices in older Brightway versions. For example, previously edges were defined on nodes: `node['exchanges'] = list`. In this schema, the `node` was *always* the edge `target`, even if that didn't make any sense. So emissions were inputs, goods being produced were inputs, etc. Edges also had to be quantitative, so dummy values were added to make proxies for qualitative edges.
29+
30+
Another poor design choice was storing some aspects of the graph outside of the graph. Things like project, databases, impact categories, and other LCIA objects, were stored in a different format (JSON or pickle) in a separate place (filesystem instead of relational database). We now unify these concepts and their data schemas in single graph.
31+
32+
## Design decisions
33+
34+
* All data is in a graph. That means that the only way we have to express data is nodes linked with edges. A single graph can provide all the information in a project.
35+
* Add attribute data is stored as JSON-serializable values.
36+
* Nodes have identifiers. We stores nodes as a dictionary, where the identifiers are the keys. Edge `source` and `target` attributes refer to these identifiers. Identifiers can be strings or integers, and their label in the node datasets themselves is flexible.
37+
* Nodes and edges have types, and type labels are given in a set of `Enum` classes. These types correspond with pydantic classes which include custom data attributes and validation functions.
38+
* Edges have direction, and their direction is meaningful. For example, a process producing a product would have an edge from (`source`) the process to (`target`) a product. If the product was consumed as an input of the process, the product would be the `source` and the process would be the `target`. The same logic applies to processes and elementary flows.
39+
* The technosphere part of the graph has a strict product -> process -> product pattern. Edges between processes and products must state whether or not they are functional. A functional edge is one where the modeller has indicated that the product being consumed or produced is one of the functions of the process.
40+
* Processes are located in time and space. Products can be generic (their attributes apply regardless of where or when the product is produced or consumed, such as products meeting some standard), or can have spatio-temporal specificity (the sulfur content or energetic density of natural gas varies across time and space).
41+
* Elementary flows and products can refer to the same underlying concepts, but are distinct nodes. For example, carbon dioxide has industrial uses and is also an important air resource and emission, but because it operates in different contexts in all three cases, it is modeled as different objects. Biosphere edges always link process nodes to elementary flow nodes, and elementary flow nodes cannot operate in the technosphere.
42+
* There is no rigid normalization pattern. Edges allow for some degree of normalization (edge source and targets act like foreign keys to nodes), but other attributes like units are not normalized. Our intent is to specify some of these non-normalized attributes in the [Sentier.dev](https://vocab.sentier.dev/en-US/) vocabulary, and to develop practical approaches to other tricky attributes like location.
43+
44+
## Tags, properties, or dataset attributes?
45+
46+
* Tags are for choosing from an already known set of possibilities where more than one node could share the same value.
47+
* Properties are for numeric values which describe the object's attributes or performance.
48+
* Dataset attributes (i.e. `node['foo']`) are for everything else.
49+
50+
As always, [hard cases make bad law](https://en.wikipedia.org/wiki/Hard_cases_make_bad_law), and some things could fit into multiple possible buckets. We will expand and clarify this distinction with more experience.
2151

2252
## Comparison with Brightway2
2353

tests/integration.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from bw_interface_schemas import GraphLoader
22

33

4-
def dump_graph(bike_as_graph):
4+
def test_dump_graph(bike_as_graph):
55
assert bike_as_graph.model_dump()
66

77

8-
def construct_graph(bike_as_dict):
8+
def test_construct_graph(bike_as_dict):
99
assert GraphLoader(identifier_field="name").load(bike_as_dict, use_identifiers=True)

0 commit comments

Comments
 (0)