Source code for bw2calc.single_value_diagonal_matrix

from typing import Any, Callable, Sequence, Union

import numpy as np
from bw_processing import Datapackage
from matrix_utils import MappedMatrix
from scipy import sparse

from bw2calc.errors import MultipleValues


[docs] class SingleValueDiagonalMatrix(MappedMatrix): """A scipy sparse matrix handler which takes in ``bw_processing`` data packages. Row and column ids are mapped to matrix indices, and a matrix is constructed. Use primarily in the weighting step of life cycle impact assessment. `indexer_override` allows for custom indexer behaviour. Indexers should follow a simple API: they must support `.__next__()`, and have the attribute `.index`, which returns an integer. `custom_filter` allows you to remove some data based on their indices. It is applied to all resource groups. If you need more fine-grained control, process the matrix after construction/iteration. `custom_filter` should take the indices array as an input, and return a Numpy boolean array with the same length as the indices array. Args: * packages: A list of Ddatapackage objects. * matrix: The string identifying the matrix to be built. * use_vectors: Flag to use vector data from datapackages * use_arrays: Flag to use array data from datapackages * use_distributions: Flag to use `stats_arrays` distribution data from datapackages * row_mapper: Optional instance of `ArrayMapper`. Used when matrices must align. * col_mapper: Optional instance of `ArrayMapper`. Used when matrices must align. * seed_override: Optional integer. Overrides the RNG seed given in the datapackage, if any. * indexer_override: Parameter for custom indexers. See above. * diagonal: If True, only use the `row` indices to build a diagonal matrix. * custom_filter: Callable for function to filter data based on `indices` values. See above. * empty_ok: If False, raise `AllArraysEmpty` if the matrix would be empty """ def __init__( self, *, packages: Sequence[Datapackage], matrix: str, dimension: int, use_vectors: bool = True, use_arrays: bool = True, use_distributions: bool = False, seed_override: Union[int, None] = None, indexer_override: Any = None, custom_filter: Union[Callable, None] = None, **kwargs, ):
[docs] self.dimension = dimension
# We let it build an incorrect matrix, mappers, etc. just to ignore them # It would be riskier to copy/paste out parts of the `__init__`, and # remember to be consistent in the future. The resource cost # of this approach is very low. super().__init__( packages=packages, matrix=matrix, use_vectors=use_vectors, use_arrays=use_arrays, use_distributions=use_distributions, seed_override=seed_override, indexer_override=indexer_override, diagonal=True, custom_filter=custom_filter, ) if self.raw_data.shape != (1,): raise MultipleValues( ( "Multiple ({}) numerical values found, but only one single numerical value is " + "allowed. Data packages:\n\t{}" ).format(len(self.raw_data), "\n\t".join([str(x) for x in self.packages])) )
[docs] self.matrix = sparse.coo_matrix( ( np.ones(self.dimension), (np.arange(self.dimension), np.arange(self.dimension)), ), (self.dimension, self.dimension), dtype=np.float64, ).tocsr()
self.rebuild_matrix()
[docs] def rebuild_matrix(self): self.raw_data = np.hstack([group.calculate()[2] for group in self.groups]) self.matrix.data *= 0 self.matrix.data += float(self.raw_data[0])