brightway

Monte Carlo simulation in BW25


Beginner-type question here.

I have a function to run a Monte Carlo LCA that I used to use in BW2, but apparently, the old Monte Carlo LCA class is Deprecated from what I understood, and I use the normal LCA class.

I am using the latest version of brightway25.

def get_multiImpactMonteCarloLCA(iterations=20):
    myMethods = methods
    list_of_activities = activities
    myDict = {}
    for act in list_of_activities:
        print("running Monte Carlo LCA for: ", act)
        temp_act_dict = {str(act): []}
        myDict.update(temp_act_dict)
        MC_lca = bc.LCA({act: 1})
        MC_lca.lci()
        C_matrices = {}
        for method in myMethods:
            MC_lca.switch_method(method)
            C_matrices[method] = MC_lca.characterization_matrix
        results = np.empty((len(myMethods), iterations))
        for iteration in range(iterations):
            next(MC_lca)
            for method_index, method in enumerate(myMethods):
                results[method_index, iteration] = (
                    C_matrices[method]*MC_lca.inventory).sum()
        myDict[str(act)].append(results)
        return myDict
    print("Monte Carlo LCA calculation finished")

Running it gives me the results like a static LCA, and nothing changes between iterations. A) What am I missing here? B) is there a better way to structure this? Because it's kind of slow in how I'm doing it now.


Solution

  • To get better performance, try to:

    Also, you need to pass use_distributions=True to actually use the probability distributions during LCA calculations.

    We can then rewrite your function:

    import bw2data as bd
    import bw2calc as bc
    
    
    def MultiLCA(
        demands: list[dict[bd.Node, float]], methods: list[tuple], iterations: int = 20
    ) -> dict[int : dict[tuple, list[float]]]:
        # Create all possible demands
        all_demands = {k: 1 for demand in demands for k in demand}
    
        # Create a single LCA object and use uncertainty distributions
        lca = bc.LCA(demand=all_demands, method=methods[0], use_distributions=True)
        lca.lci()
    
        # Create a list of characterization matrices
        C_matrices = {}
    
        for method in methods:
            lca.switch_method(method)
            C_matrices[method] = lca.characterization_matrix.copy()
    
        # Create container for results
        results = {
            index: {method: [] for method in methods} for index, _ in enumerate(demands)
        }
    
        # Do one monte carlo iteration for all functional units and impact categories
        for _ in range(iterations):
            # Resample all matrices
            next(lca)
            for index, demand in enumerate(demands):
                # Convert to integer ids instead of `bd.Node` objects
                lca.lci({key.id: value for key, value in demand.items()})
                for method in methods:
                    results[index][method].append(
                        (C_matrices[method] * lca.inventory).sum()
                    )
    
        return results
    

    And use it like:

    import random
    
    demands = [
        {bd.Database("ecoinvent-3.7.1-apos").random(): random.random()} 
        for _ in range(5)
    ]
    methods = [bd.methods.random() for _ in range(5)]
    results = MultiLCA(demands=demands, methods=methods, iterations=5)
    

    This function isn't perfect - the indexing into demands isn't great, and the results should probably be converted to numpy arrays, but it is a start.