oie-mines-paristech / lca_algebraic

Layer over brightway2 for algebraic definition of parametric models and super fast computation of LCA
BSD 2-Clause "Simplified" License
35 stars 18 forks source link

Support coproducts in graphtraversal #9

Closed ntropy-esa closed 3 years ago

ntropy-esa commented 3 years ago

Brightway2 activities can have exchanges of type "production" to refer to the products they produce. It's often associated with tag for "reference product" e.g. in the activity browser.

When an activity has several exchanges of type "production" it means that the activity is producing several products, the reference ones, and others defined in another activity.

bw2 LCA calculations supports this, and performs substitutions on the co-products, as long as the database / technosphere matrix is well-defined (i.e. square)

For lca_algebraic to support this, in the graph traversal, we need to check if the exchange is of type production and not referring to the current activity.

Use case:

YieldBiochar = newFloatParam('y_bc',
                            default=0.25, min=0.18, max=0.30,
                            description='Biochar yield, in kg dry per kg dry biomass')

eibiomass = getActByCode('ecoinvent 3.5', '9b997b399076f62b40b72a85648f8fbe')

activity1 = newActivity(USER_DB, 
    "heat production", 
    "megajoule", 
    exchanges= { },
    code='soup-heat') 
activity1.addExchanges({activity1 :  1})

activity2 = newActivity(USER_DB, 
    "biochar production",
    "kilogram", 
    exchanges= {},
    code='mop-biochar' )

activity2.addExchanges({activity2 : {'amount':1}}) # type = production for that exchange, because input is self
activity2.addExchanges({activity1 : {'amount': 234.94 * exp(-6.56*YieldBiochar) , 'type':'production'}}) # coproduct

activity3 = newActivity(USER_DB, 
    "biomass production", 
    "kilogram", 
    exchanges= { },
    code='soup-biomass' )
activity3.addExchanges({activity3: {'amount':1}})
activity3.addExchanges({eibiomass:1})

activity1.addExchanges({activity3 : {'amount':1/20}})
activity2.addExchanges({activity3 : {'amount':1/YieldBiochar}})

printAct(activity1) 
printAct(activity2)
printAct(activity3)

impacts = [m for m in bw.methods if 'ILCD 1.0.8 2016' in str(m) and 'no LT' in str(m)]

with bw2 function

multiLCA(
    activity2, 
    [impacts[1]],                    
    # Parameters of the model
    y_bc=0.15
)

with lca_algebraic function

multiLCAAlgebric(
    activity2, 
    [impacts[1]], 
    # Parameters of the model
    y_bc=0.15
)

Now yield the same results.

raphaeljolivet commented 3 years ago

Thanks for this !

I think I will add some tests in the code for basic non-regression checks. Currently I have one script only checking that the example Notebook runs well.

I will integrate this use case as one of the tests. I will merge it once I do this.