# bw2calc#

## Package Contents#

### Classes#

 DenseLCA A static LCI or LCIA calculation. GraphTraversal Traverse a supply chain, following paths of greatest impact. IndependentLCAMixin Mixin that allows method, etc. to be filepaths or np.ndarray instead of DataStore object names. LCA A static LCI or LCIA calculation. LeastSquaresLCA Solve overdetermined technosphere matrix with more products than activities using least-squares approximation. MatrixBuilder The class, and its subclasses, load structured arrays, manipulate them, and generate SciPy sparse matrices. MultiLCA Wrapper class for performing LCA calculations with many functional units and LCIA methods. TechnosphereBiosphereMatrixBuilder Subclass of MatrixBuilder that separates technosphere and biosphere parameters

### Functions#

 Load a calculation package created by save_calculation_package.
class bw2calc.DenseLCA(demand, method=None, weighting=None, normalization=None, database_filepath=None, log_config=None, presamples=None, seed=None, override_presamples_seed=False)[source]#

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 (matrixbuilders). The LCA class only does the LCA calculations themselves.

Create a new LCA calculation.

Parameters
• demand (*) – The demand or functional unit. Needs to be a dictionary to indicate amounts, e.g. {("my database", "my process"): 2.5}.

• method (*) – LCIA Method tuple, e.g. ("My", "great", "LCIA", "method"). Can be omitted if only interested in calculating the life cycle inventory.

Returns

A new LCA object

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.

class bw2calc.GraphTraversal[source]#

Bases: object

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.

Parameters
• demand (*) – The functional unit. Same format as in LCA class.

• method (*) – LCIA method. Same format as in LCA class.

• cutoff (*) – 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 (*) – 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

class bw2calc.IndependentLCAMixin[source]#

Bases: object

Mixin that allows method, etc. to be filepaths or np.ndarray instead of DataStore object names.

Removes dependency on bw2data.

fix_dictionaries()#

Don’t adjust dictionaries even if bw2data is present, as functional unit is an integer.

get_array_filepaths()#

class bw2calc.LCA(demand, method=None, weighting=None, normalization=None, database_filepath=None, log_config=None, presamples=None, seed=None, override_presamples_seed=False)[source]#

Bases: object

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 (matrixbuilders). The LCA class only does the LCA calculations themselves.

Create a new LCA calculation.

Parameters
• demand (*) – The demand or functional unit. Needs to be a dictionary to indicate amounts, e.g. {("my database", "my process"): 2.5}.

• method (*) – LCIA Method tuple, e.g. ("My", "great", "LCIA", "method"). Can be omitted if only interested in calculating the life cycle inventory.

Returns

A new LCA object

property score#

The LCIA score as a float.

Note that this is a property, so it is foo.lca, not foo.score()

build_demand_array(demand=None)#

Turn the demand dictionary into a NumPy array of correct size.

Parameters

demand (*) – 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 deleting self.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 and self.biosphere_dict.

get_array_filepaths()#

Use utility functions to get all array filepaths

lci(factorize=False, builder=TBMBuilder)#

Calculate a life cycle inventory.

1. Load LCI data, and construct the technosphere and biosphere matrices.

2. Build the demand array

3. Solve the linear system to get the supply array and life cycle inventory.

Parameters
• factorize (*) – 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 (*) – Default is bw2calc.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 and self.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=MatrixBuilder)#

Calculate the life cycle impact assessment.

1. Load and construct the characterization matrix

2. Multiply the characterization matrix by the life cycle inventory

Parameters

builder (*) – Default is bw2calc.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 data and create technosphere and biosphere matrices.

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 if bw2data is not importable.

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.

Parameters

vector (*) – 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.

Parameters

vector (*) – 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.

Parameters

vector (*) – 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.

Parameters

demand (*) – A demand dictionary.

Doesn’t return anything, but overwrites self.demand_array, self.supply_array, and self.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.

Parameters

demand (*) – New demand dictionary. Optional, defaults to self.demand.

Doesn’t return anything, but overwrites self.characterized_inventory. If demand is given, also overwrites self.demand_array, self.supply_array, and self.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 and self.biosphere_dict)

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.LeastSquaresLCA(demand, method=None, weighting=None, normalization=None, database_filepath=None, log_config=None, presamples=None, seed=None, override_presamples_seed=False)[source]#

Solve overdetermined technosphere matrix with more products than activities using least-squares approximation.

Create a new LCA calculation.

Parameters
• demand (*) – The demand or functional unit. Needs to be a dictionary to indicate amounts, e.g. {("my database", "my process"): 2.5}.

• method (*) – LCIA Method tuple, e.g. ("My", "great", "LCIA", "method"). Can be omitted if only interested in calculating the life cycle inventory.

Returns

A new LCA object

abstract 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 deleting self.solver when doing these types of advanced calculations.

solve_linear_system(solver=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.

class bw2calc.MatrixBuilder[source]#

Bases: object

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.

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 building-matrices.

This method does the following:

TODO: Update

1. Load and concatenate the structured arrays files in filepaths paths using the function utils.load_arrays() into a parameter array.

2. If not row_dict, use build_dictionary() to build row_dict from the parameter array column row_id_label.

3. Using the row_id_label and the row_dict, use the method add_matrix_indices() to add matrix indices to the row_index_label column.

4. If not one_d, do the same to col_dict and col_index_label, using col_id_label.

5. If not one_d, use build_matrix() to build a sparse matrix using data_label for the matrix data values, and row_index_label and col_index_label for row and column indices.

6. Else if one_d, use build_diagonal_matrix() to build a diagonal matrix using data_label for diagonal matrix data values and row_index_label as row/column indices.

7. Return the loaded parameter arrays from step 1, row and column dicts from steps 2 & 4, and matrix from step 5 or 6.

Parameters
• paths (*) – List of array filepaths to load.

• data_label (*) – Label of column in parameter arrays with matrix data values.

• row_id_label (*) – Label of column in parameter arrays with row ID values, i.e. the integer values returned from mapping.

• row_index_label (*) – Label of column in parameter arrays where matrix row indices will be stored.

• col_id_label (*) – 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 (*) – Label of column in parameter arrays where matrix column indices will be stored. Not needed for diagonal matrices.

• row_dict (*) – Mapping dictionary linking row_id_label values to row_index_label values. Will be built if not given.

• col_dict (*) – Mapping dictionary linking col_id_label values to col_index_label values. Will be built if not given.

• one_d (*) – Build diagonal matrix.

• drop_missing (*) – Remove rows from the parameter array which aren’t mapped by row_dict or col_dict. Default is True. 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.

class bw2calc.MultiLCA(cs_name, log_config=None)[source]#

Bases: object

Wrapper class for performing LCA calculations with many functional units and LCIA methods.

Needs to be passed a calculation_setup name.

This class does not subclass the LCA class, and performs all calculations upon instantiation.

Initialization creates self.results, which is a NumPy array of LCA scores, with rows of functional units and columns of LCIA methods. Ordering is the same as in the calculation_setup.

property all#

Get all possible databases by merging all functional units

class bw2calc.TechnosphereBiosphereMatrixBuilder[source]#

Bases: MatrixBuilder

Subclass of MatrixBuilder that separates technosphere and biosphere parameters

classmethod build(paths)#

Build the technosphere and biosphere sparse matrices.

classmethod build_technosphere_matrix(array, activity_dict, product_dict, new_data=None)#
classmethod fix_supply_use(array, vector)#

Make technosphere inputs negative.

Get boolean mask of biosphere flows from array (i.e. the ones to include when building the biosphere matrix).

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

Load a calculation package created by save_calculation_package.
fp is the absolute file path of a calculation package file.
Returns a dictionary suitable for passing to an LCA object, e.g. LCA(**load_calculation_package(fp)).