Brightway2-calc#
Matrix builders#
One of the most basic and most important components of bw2calc
is the ability to build a sparse matrix from a processed parameter array.
Matrix Builder#
- class bw2calc.MatrixBuilder#
The class, and its subclasses, load structured arrays, manipulate them, and generate SciPy sparse matrices.
Matrix builders use an array of row indices, an array of column indices, and an array of values to create a coordinate (coo) matrix, which is then converted to a compressed sparse row (csr) matrix.
See the following for more information on structured arrays:
These classes are not instantiated, and have only classmethods. They are not really true classes, but more organizational. In other words, you should use:
MatrixBuilder.build(args)
and not:
mb = MatrixBuilder() mb.build(args)
- classmethod build(paths, data_label, row_id_label, row_index_label, col_id_label=None, col_index_label=None, row_dict=None, col_dict=None, one_d=False, drop_missing=True)#
Build a sparse matrix from NumPy structured array(s).
See more detailed documentation at Turning processed data arrays in matrices.
This method does the following:
TODO: Update
Load and concatenate the structured arrays files in filepaths
paths
using the functionutils.load_arrays()
into a parameter array.If not
row_dict
, usebuild_dictionary()
to buildrow_dict
from the parameter array columnrow_id_label
.Using the
row_id_label
and therow_dict
, use the methodadd_matrix_indices()
to add matrix indices to therow_index_label
column.If not
one_d
, do the same tocol_dict
andcol_index_label
, usingcol_id_label
.If not
one_d
, usebuild_matrix()
to build a sparse matrix usingdata_label
for the matrix data values, androw_index_label
andcol_index_label
for row and column indices.Else if
one_d
, usebuild_diagonal_matrix()
to build a diagonal matrix usingdata_label
for diagonal matrix data values androw_index_label
as row/column indices.Return the loaded parameter arrays from step 1, row and column dicts from steps 2 & 4, and matrix from step 5 or 6.
- Args:
paths (list): List of array filepaths to load.
data_label (str): Label of column in parameter arrays with matrix data values.
row_id_label (str): Label of column in parameter arrays with row ID values, i.e. the integer values returned from
mapping
.row_index_label (str): Label of column in parameter arrays where matrix row indices will be stored.
col_id_label (str, optional): Label of column in parameter arrays with column ID values, i.e. the integer values returned from
mapping
. Not needed for diagonal matrices.col_index_label (str, optional): Label of column in parameter arrays where matrix column indices will be stored. Not needed for diagonal matrices.
row_dict (dict, optional): Mapping dictionary linking
row_id_label
values torow_index_label
values. Will be built if not given.col_dict (dict, optional): Mapping dictionary linking
col_id_label
values tocol_index_label
values. Will be built if not given.one_d (bool): Build diagonal matrix.
drop_missing (bool): Remove rows from the parameter array which aren’t mapped by
row_dict
orcol_dict
. Default isTrue
. Advanced use only.
- Returns:
A numpy parameter array, the row mapping dictionary, the column mapping dictionary, and a COO sparse matrix.
- classmethod build_diagonal_matrix(array, row_dict, index_label, data_label=None, new_data=None)#
Build diagonal sparse matrix.
- classmethod build_matrix(array, row_dict, col_dict, row_index_label, col_index_label, data_label=None, new_data=None)#
Build sparse matrix.
Technosphere Biosphere Matrix Builder#
- class bw2calc.TechnosphereBiosphereMatrixBuilder#
Subclass of
MatrixBuilder
that separates technosphere and biosphere parameters- classmethod build(paths)#
Build the technosphere and biosphere sparse matrices.
- classmethod fix_supply_use(array, vector)#
Make technosphere inputs negative.
- classmethod get_biosphere_inputs_mask(array)#
Get boolean mask of biosphere flows from
array
(i.e. the ones to include when building the biosphere matrix).
- classmethod get_technosphere_inputs_mask(array)#
Get boolean mask of technosphere inputs from
array
(i.e. the ones to include when building the technosphere matrix).
- classmethod select_biosphere_array(array)#
Create a new array with biosphere matrix exchanges
- classmethod select_technosphere_array(array)#
Create a new array with technosphere matrix exchanges
Indexing#
- bw2calc.indexing.index_with_arrays(array_from, array_to, mapping)#
Map
array_from
keys toarray_to
values using the dictionarymapping
.Turns the keys and values of mapping into index arrays.
This is needed to take the
flow
,input
, andoutput
columns, which can be arbitrarily large integers, and transform them to matrix indices, which start from zero.Here is an example:
import numpy as np a_f = np.array((1, 2, 3, 4)) a_t = np.zeros(4) mapping = {1: 5, 2: 6, 3: 7, 4: 8} index_with_arrays(a_f, a_t, mapping) # => a_t is now [5, 6, 7, 8]
- Args:
array_from (array): 1-dimensional integer numpy array.
array_to (array): 1-dimensional integer numpy array.
mapping (dict): Dictionary that links
mapping
indices torow
orcol
indices, e.g.{34: 3}
.
Operates in place. Doesn’t return anything.
- bw2calc.indexing.index_with_searchsorted(array_from, array_to)#
Build a dictionary from the sorted, unique elements of an array, and map this dictionary from
array_from
toarray_to
.Adapted from http://stackoverflow.com/questions/3403973/fast-replacement-of-values-in-a-numpy-array.
Here is an example:
import numpy as np array = np.array((4, 8, 6, 2, 4)) output = np.zeros(5) index_with_searchsorted(array, output) # => returns {2: 0, 4: 1, 6: 2, 8: 3} # and `output` is [1, 3, 2, 0, 1]
array_from
andarray_to
are arrays of integers.Returns a dictionary that maps the sorted, unique elements of
array_from
to integers starting with zero.
Static life cycle assessment#
- class bw2calc.LCA(demand, method=None, weighting=None, normalization=None, database_filepath=None, log_config=None, presamples=None, seed=None, override_presamples_seed=False)#
A static LCI or LCIA calculation.
Following the general philosophy of Brightway2, and good software practices, there is a clear separation of concerns between retrieving and formatting data and doing an LCA. Building the necessary matrices is done with MatrixBuilder objects (Matrix builders). The LCA class only does the LCA calculations themselves.
- build_demand_array(demand=None)#
Turn the demand dictionary into a NumPy array of correct size.
- Args:
demand (dict, optional): Demand dictionary. Optional, defaults to
self.demand
.
- Returns:
A 1-dimensional NumPy array
- decompose_technosphere()#
Factorize the technosphere matrix into lower and upper triangular matrices, \(A=LU\). Does not solve the linear system \(Ax=B\).
Doesn’t return anything, but creates
self.solver
.Warning
Incorrect results could occur if a technosphere matrix was factorized, and then a new technosphere matrix was constructed, as
self.solver
would still be the factorized older technosphere matrix. You are responsible for deletingself.solver
when doing these types of advanced calculations.
- fix_dictionaries()#
Fix technosphere and biosphere dictionaries from this:
{mapping integer id: matrix row/column index}
To this:
{(database, key): matrix row/column index}
This isn’t needed for the LCA calculation itself, but is helpful when interpreting results.
Doesn’t require any arguments or return anything, but changes
self.activity_dict
,self.product_dict
andself.biosphere_dict
.
- get_array_filepaths()#
Use utility functions to get all array filepaths
- lci(factorize=False, builder=<class 'bw2calc.matrices.TechnosphereBiosphereMatrixBuilder'>)#
Calculate a life cycle inventory.
Load LCI data, and construct the technosphere and biosphere matrices.
Build the demand array
Solve the linear system to get the supply array and life cycle inventory.
- Args:
factorize (bool, optional): Factorize the technosphere matrix. Makes additional calculations with the same technosphere matrix much faster. Default is
False
; not useful is only doing one LCI calculation.builder (
MatrixBuilder
object, optional): Default isbw2calc.matrices.TechnosphereBiosphereMatrixBuilder
, which is fine for most cases. Custom matrix builders can be used to manipulate data in creative ways before building the matrices.
Warning
Custom matrix builders should inherit from
TechnosphereBiosphereMatrixBuilder
, because technosphere inputs need to have their signs flipped to be negative, as we do \(A^{-1}f\) directly instead of \((I - A^{-1})f\).Doesn’t return anything, but creates
self.supply_array
andself.inventory
.
- lci_calculation()#
The actual LCI calculation.
Separated from
lci
to be reusable in cases where the matrices are already built, e.g.redo_lci
and Monte Carlo classes.
- lcia(builder=<class 'bw2calc.matrices.MatrixBuilder'>)#
Calculate the life cycle impact assessment.
Load and construct the characterization matrix
Multiply the characterization matrix by the life cycle inventory
- Args:
builder (
MatrixBuilder
object, optional): Default isbw2calc.matrices.MatrixBuilder
, which is fine for most cases. Custom matrix builders can be used to manipulate data in creative ways before building the characterization matrix.
Doesn’t return anything, but creates
self.characterized_inventory
.
- lcia_calculation()#
The actual LCIA calculation.
Separated from
lcia
to be reusable in cases where the matrices are already built, e.g.redo_lcia
and Monte Carlo classes.
- load_lci_data(fix_dictionaries=True, builder=<class 'bw2calc.matrices.TechnosphereBiosphereMatrixBuilder'>)#
Load data and create technosphere and biosphere matrices.
- load_lcia_data(builder=<class 'bw2calc.matrices.MatrixBuilder'>)#
Load data and create characterization matrix.
This method will filter out regionalized characterization factors. This filtering needs access to
bw2data
- therefore, regionalized methods will cause incorrect results ifbw2data
is not importable.
- load_normalization_data(builder=<class 'bw2calc.matrices.MatrixBuilder'>)#
Load normalization data.
- load_weighting_data()#
Load weighting data, a 1-element array.
- normalization_calculation()#
The actual normalization calculation.
Creates
self.normalized_inventory
.
- normalize()#
Multiply characterized inventory by flow-specific normalization factors.
- rebuild_biosphere_matrix(vector)#
Build a new biosphere matrix using the same row and column indices, but different values. Useful for Monte Carlo iteration or sensitivity analysis.
- Args:
vector (array): 1-dimensional NumPy array with length (# of biosphere parameters), in same order as
self.bio_params
.
Doesn’t return anything, but overwrites
self.biosphere_matrix
.
- rebuild_characterization_matrix(vector)#
Build a new characterization matrix using the same row and column indices, but different values. Useful for Monte Carlo iteration or sensitivity analysis.
- Args:
vector (array): 1-dimensional NumPy array with length (# of characterization parameters), in same order as
self.cf_params
.
Doesn’t return anything, but overwrites
self.characterization_matrix
.
- rebuild_technosphere_matrix(vector)#
Build a new technosphere matrix using the same row and column indices, but different values. Useful for Monte Carlo iteration or sensitivity analysis.
- Args:
vector (array): 1-dimensional NumPy array with length (# of technosphere parameters), in same order as
self.tech_params
.
Doesn’t return anything, but overwrites
self.technosphere_matrix
.
- redo_lci(demand=None)#
Redo LCI with same databases but different demand.
- Args:
demand (dict): A demand dictionary.
Doesn’t return anything, but overwrites
self.demand_array
,self.supply_array
, andself.inventory
.Warning
If you want to redo the LCIA as well, use
redo_lcia(demand)
directly.
- redo_lcia(demand=None)#
Redo LCIA, optionally with new demand.
- Args:
demand (dict, optional): New demand dictionary. Optional, defaults to
self.demand
.
Doesn’t return anything, but overwrites
self.characterized_inventory
. Ifdemand
is given, also overwritesself.demand_array
,self.supply_array
, andself.inventory
.
- reverse_dict()#
Construct reverse dicts from technosphere and biosphere row and col indices to activity_dict/product_dict/biosphere_dict keys.
- Returns:
(reversed
self.activity_dict
,self.product_dict
andself.biosphere_dict
)
- property score#
The LCIA score as a
float
.Note that this is a property, so it is
foo.lca
, notfoo.score()
- solve_linear_system()#
Master solution function for linear system \(Ax=B\).
To most numerical analysts, matrix inversion is a sin.
—Nicolas Higham, Accuracy and Stability of Numerical Algorithms, Society for Industrial and Applied Mathematics, Philadelphia, PA, USA, 2002, p. 260.
We use UMFpack, which is a very fast solver for sparse matrices.
If the technosphere matrix has already been factorized, then the decomposed technosphere (
self.solver
) is reused. Otherwise the calculation is redone completely.
- switch_method(method)#
Switch to LCIA method method
- switch_normalization(normalization)#
Switch to LCIA normalization normalization
- switch_weighting(weighting)#
Switch to LCIA weighting weighting
- to_dataframe(cutoff=200)#
Return all nonzero elements of characterized inventory as Pandas dataframe
- top_activities(**kwargs)#
Call
bw2analyzer.ContributionAnalyses.annotated_top_processes
- top_emissions(**kwargs)#
Call
bw2analyzer.ContributionAnalyses.annotated_top_emissions
- weight()#
Multiply characterized inventory by weighting value.
Can be done with or without normalization.
- weighting_calculation()#
The actual weighting calculation.
Multiples weighting value by normalized inventory, if available, otherwise by characterized inventory.
Creates
self.weighted_inventory
.
- class bw2calc.least_squares.LeastSquaresLCA(demand, method=None, weighting=None, normalization=None, database_filepath=None, log_config=None, presamples=None, seed=None, override_presamples_seed=False)#
Solve overdetermined technosphere matrix with more products than activities using least-squares approximation.
See also:
- decompose_technosphere()#
Factorize the technosphere matrix into lower and upper triangular matrices, \(A=LU\). Does not solve the linear system \(Ax=B\).
Doesn’t return anything, but creates
self.solver
.Warning
Incorrect results could occur if a technosphere matrix was factorized, and then a new technosphere matrix was constructed, as
self.solver
would still be the factorized older technosphere matrix. You are responsible for deletingself.solver
when doing these types of advanced calculations.
- solve_linear_system(solver=<function lsmr>)#
Master solution function for linear system \(Ax=B\).
To most numerical analysts, matrix inversion is a sin.
—Nicolas Higham, Accuracy and Stability of Numerical Algorithms, Society for Industrial and Applied Mathematics, Philadelphia, PA, USA, 2002, p. 260.
We use UMFpack, which is a very fast solver for sparse matrices.
If the technosphere matrix has already been factorized, then the decomposed technosphere (
self.solver
) is reused. Otherwise the calculation is redone completely.
Graph Traversal#
- class bw2calc.GraphTraversal#
Traverse a supply chain, following paths of greatest impact.
This implementation uses a queue of datasets to assess. As the supply chain is traversed, datasets inputs are added to a list sorted by LCA score. Each activity in the sorted list is assessed, and added to the supply chain graph, as long as its impact is above a certain threshold, and the maximum number of calculations has not been exceeded.
Because the next dataset assessed is chosen by its impact, not its position in the graph, this is neither a breadth-first nor a depth-first search, but rather “importance-first”.
This class is written in a functional style - no variables are stored in self, only methods.
Should be used by calling the
calculate
method.Warning
Graph traversal with multioutput processes only works when other inputs are substituted (see Multioutput processes in LCA for a description of multiputput process math in LCA).
- build_lca(demand, method)#
Build LCA object from demand and method.
- calculate(demand, method, cutoff=0.005, max_calc=100000.0, skip_coproducts=False)#
Traverse the supply chain graph.
- Args:
demand (dict): The functional unit. Same format as in LCA class.
method (tuple): LCIA method. Same format as in LCA class.
cutoff (float, default=0.005): Cutoff criteria to stop LCA calculations. Relative score of total, i.e. 0.005 will cutoff if a dataset has a score less than 0.5 percent of the total.
max_calc (int, default=10000): Maximum number of LCA calculations to perform.
- Returns:
Dictionary of nodes, edges, LCA object, and number of LCA calculations.
- cumulative_score(index, supply, characterized_biosphere, lca)#
Compute cumulative LCA score for a given activity
- initialize_heap(demand, lca, supply, characterized_biosphere)#
Create a priority queue or
heap
to store inventory datasets, sorted by LCA score.Populates the heap with each activity in
demand
. Initial nodes are the functional unit, i.e. the complete demand, and each activity in the functional unit. Initial edges are inputs from each activity into the functional unit.The functional unit is an abstract dataset (as it doesn’t exist in the matrix), and is assigned the index
-1
.
- traverse(heap, nodes, edges, counter, max_calc, cutoff, total_score, supply, characterized_biosphere, lca, skip_coproducts)#
Build a directed graph by traversing the supply chain.
Node ids are actually technosphere row/col indices, which makes lookup easier.
- Returns:
(nodes, edges, number of calculations)
- unit_score(index, supply, characterized_biosphere)#
Compute the LCA impact caused by the direct emissions and resource consumption of a given activity
Stochastic Life Cycle Assessment#
Monte Carlo LCA#
- class bw2calc.MonteCarloLCA(demand, method=None, iter_solver=<function cgs>, seed=None, *args, **kwargs)#
Monte Carlo uncertainty analysis with separate random number generators (RNGs) for each set of parameters.
Vector Monte Carlo LCA#
- class bw2calc.ParameterVectorLCA(demand, method=None, iter_solver=<function cgs>, seed=None, *args, **kwargs)#
A Monte Carlo class where all uncertain parameters are stored in a single large array.
Useful for sensitivity analysis and easy manipulation.
- rebuild_all(vector=None)#
Rebuild the LCI/LCIA matrices from a new Monte Carlo sample or provided vector.
Parallel Monte Carlo LCA#
- class bw2calc.ParallelMonteCarlo(demand, method, iterations=1000, chunk_size=None, cpus=None, log_config=None)#
Split a Monte Carlo calculation into parallel jobs
Utilities#
- bw2calc.utils.load_arrays(objs)#
Load the numpy arrays from list of objects
objs
.- Currently accepts
str
filepaths,BytesIO
, numpy.ndarray
arrays. Creates copies of objects
- Currently accepts