13. Life cycle assessment#

For a sustainable bioeconomy, it is critical to assess the environmental impact of a production process. This chapter goes over BioSTEAM’s life cycle assessment (LCA) capabilities through a cradle-to-biorefinery-gate LCA of a sugarcane biorefinery that produces electricity and ethanol. We focus on the global warning potential (GWP) because it is central to policy implementation.

13.1. Quantifying GWP of a surgarcane biorefinery#

A biorefinery system defines the life cycle inventory. Apart from the model itself, only the characterization factors for inputs and outputs are needed to perform LCA. These can be retrieved from standard public models like the Greenhouse Gases, Regulated Emissions, and Energy Use in Transportation (Argonne GREET Model). Here we load a sugarcane to ethanol biorefinery, define characterization factors from GREET, and perform LCA using energy based, revenue base, and displacement allocation methods (i.e. system expansion).

Define the impact indicator and the characterization factors:

[1]:
### Load system
import biosteam as bst
from warnings import filterwarnings; filterwarnings('ignore')
from biorefineries import sugarcane as sc
sc.load(pellet_bagasse=False) # Do not dry and pellet bagasse feed to the boiler
system = sc.sugarcane_sys

### Set characterization factors on a per kg basis, as available in GREET 2020

# Key for GWP characterization factor; we make it informative
# but any value can work, even just a number.
# Note that the impact assessment methodology used in GREET is the
# Tool for the Reduction and Assessment of Chemical and other
# Environmental Impacts (TRACI)
GWP = 'GWP 100yr'
bst.settings.define_impact_indicator(key=GWP, units='kg*CO2e')

# Sugarcane for ethanol production, adjusted for moisture content (0.75 originally, 0.70 in the model).
sc.sugarcane.set_CF(GWP, 0.02931 * 0.30 / 0.25, basis='kg', units='kg*CO2e')

# Production of phosphoric acid from P2O5
sc.H3PO4.set_CF(GWP, 1.) # Basis defaults to kg; units default to defined units

# NG-Fired Simple-Cycle Gas Turbine CHP Plant, no transmission included
bst.settings.set_electricity_CF(GWP, 0.36, basis='kWhr', units='kg*CO2e')

# Lime production from lime stone, adjusted for dilution
lime_dilution = 1 - sc.lime.get_mass_composition('Water')
sc.lime.set_CF(GWP, 1.28 * lime_dilution)

# Gasoline blendstock from Crude Oil for US Refineries
sc.denaturant.set_CF(GWP, 0.84)

# Assume all other feeds are negligible.

Compute the GWP per kg of ethanol using energy, revenue, and displacement allocation:

[2]:
# Displacement allocation [kg-CO2e / kg-ethanol]
GWP_sugarcane_ethanol_displacement = system.get_net_impact(key=GWP) / system.get_mass_flow(sc.ethanol)

# Energy allocation by gasoline gallon equivalent (GGE)
GWP_per_GGE = system.get_property_allocated_impact(
    key=GWP, name='energy', basis='GGE', # Energy basis defaults to 'kJ'
    ignored={sc.yeast, sc.filter_cake}
) # kg-CO2e / GGE

GWP_sugarcane_ethanol_energy = (
    GWP_per_GGE * sc.ethanol.get_property('LHV', 'GGE/hr') / sc.ethanol.F_mass
) # kg-CO2e / kg sugarcane ethanol

# Economic/revenue allocation
GWP_per_USD = system.get_property_allocated_impact(
    key=GWP, name='revenue', basis='USD', # Revenue basis defaults to USD
) # kg-CO2e / USD

GWP_sugarcane_ethanol_revenue = (
    GWP_per_USD * sc.ethanol.price
) # kg-CO2e / kg-ethanol

print(
    "Cradle to biorefinery gate GWP of sugarcane ethanol:\n "
    f"Displacement allocation: {GWP_sugarcane_ethanol_displacement:.2f} [kg CO2e / kg]\n "
    f"Energy allocation: {GWP_sugarcane_ethanol_energy:.2f} [kg CO2e / kg]\n "
    f"Economic allocation: {GWP_sugarcane_ethanol_revenue:.2f} [kg CO2e / kg]"
)
Cradle to biorefinery gate GWP of sugarcane ethanol:
 Displacement allocation: -0.44 [kg CO2e / kg]
 Energy allocation: 0.39 [kg CO2e / kg]
 Economic allocation: 0.43 [kg CO2e / kg]

Let’s double check our results by performing the computation manually:

[3]:
# Displacement allocation
GWP_total_displacement = (
    system.get_total_feeds_impact(GWP)
    + system.get_net_electricity_impact(GWP)
) # kg-CO2e / yr
annual_ethanol_flow_rate = system.get_mass_flow(sc.ethanol)
GWP_sugarcane_ethanol_displacement = GWP_total_displacement / annual_ethanol_flow_rate

# Energy allocation by gasoline gallon equivalent (GGE)
total_impact_per_kg_ethanol = system.get_total_feeds_impact(GWP) / annual_ethanol_flow_rate
sec_per_hr = 60 * 60
kJ_per_GGE = 120276
kW_to_GGE = sec_per_hr / kJ_per_GGE
net_electricity_production = (
    system.get_electricity_production()
    - system.get_electricity_consumption()
)
GGE_electricity = kW_to_GGE * net_electricity_production
GGE_ethanol = sc.ethanol.get_property('LHV', 'GGE/hr') * system.operating_hours # GGE / yr
ethanol_energy_allocation = GGE_ethanol / (GGE_electricity + GGE_ethanol)
GWP_sugarcane_ethanol_energy = ethanol_energy_allocation * total_impact_per_kg_ethanol

# Revenue allocation
revenue_electricity = net_electricity_production * bst.settings.electricity_price
revenue_ethanol = annual_ethanol_flow_rate * sc.ethanol.price
ethanol_revenue_allocation = revenue_ethanol / (revenue_ethanol + revenue_electricity)
GWP_sugarcane_ethanol_revenue = ethanol_revenue_allocation * total_impact_per_kg_ethanol

print(
    "Cradle to biorefinery gate GWP of sugarcane ethanol:\n "
    f"Displacement allocation: {GWP_sugarcane_ethanol_displacement:.2f} [kg CO2e / kg]\n "
    f"Energy allocation: {GWP_sugarcane_ethanol_energy:.2f} [kg CO2e / kg]\n "
    f"Economic allocation: {GWP_sugarcane_ethanol_revenue:.2f} [kg CO2e / kg]"
)
Cradle to biorefinery gate GWP of sugarcane ethanol:
 Displacement allocation: -0.44 [kg CO2e / kg]
 Energy allocation: 0.39 [kg CO2e / kg]
 Economic allocation: 0.43 [kg CO2e / kg]

The displacement and energy allocation for vinasse was assumed to be negligible. Note that biogenic emissions do not contribute any GWP while that non-biogenic emissions associated to the bioreinfery do. In this example, all emissions are biogenic. The GWP computed here using energy allocation is very close to the value available in the Ecoinvent life cycle inventory (2020 database) for a modern autonomous sugarcane ethanol plant in Brazil (value not shown here to avoid proprietary issues).

13.2. Life cycle inventory and impact breakdown#

A breakdown of the inventory and impacts comes in handy for inpecting values and verifying results. The biosteam.report module includes a few helpful functions for this:

[4]:
from biosteam import report
report.lca_inventory_table(
    systems=[system],
    key=GWP,
    items=[sc.ethanol], # For including products without characterization factors
)
[4]:
Inventory [kg/yr]
Inputs H3PO4 3.43e+05
Denaturant 2.41e+06
Lime 6.86e+05
Sugarcane 1.6e+09
Outputs Ethanol 1.12e+08
Electricity [kWhr/yr] 3e+08
[5]:
report.lca_displacement_allocation_table(
    systems=[system],
    key=GWP,
    items=[sc.ethanol], # For dividing yearly impact by ethanol production
)
[5]:
Characterization factor [kg*CO2e/kg] GWP 100yr [kg*CO2e/kg*ethanol]
Inputs H3PO4 1 0.00306
Denaturant 0.84 0.0181
Lime 0.0589 0.000361
Sugarcane 0.0352 0.503
Total inputs 0.524
Outputs displaced Electricity 0.36 kg*CO2e/kWhr 0.966
Total outputs displaced 0.966
Total -0.442
[6]:
report.lca_property_allocation_factor_table(
    systems=[system],
    property='energy',
)
[6]:
Energy allocation factors
Electricity 0.243
Ethanol 0.679
Fiber fines 0.000433
Filter cake 0.0134
Yeast 0.0643
[7]:
report.lca_property_allocation_factor_table(
    systems=[system],
    property='revenue',
)
[7]:
Revenue allocation factors
Electricity 0.181
Ethanol 0.819
[8]:
report.lca_displacement_allocation_factor_table(
    systems=[system],
    items=[sc.ethanol],
    key=GWP,
)
[8]:
Displacement allocation factors
Electricity 1.84
Ethanol -0.843

13.3. Excluding co-heat and power generation in system boundary#

While cooling water and steam utilities were produced on-site at the biorefinery, it is also common to assume utilities are provided outside the system boundaries. In BioSTEAM, characterization factors of heat utilities can be defined on an energy or mass basis. As an example, the system boundaries are redefined to exclude the co-heat and power system and solve for the GWP displacement of bagasse when used for on-site generation of steam and electricity:

[9]:
### Create the system without co-heat and power and simulate
BT = bst.main_flowsheet(bst.BoilerTurbogenerator)
BT.ins.empty()
system_no_CHP = bst.System.from_units(
    'system_no_CHP',
    units=[i for i in system.units if i is not BT],
    operating_hours=system.operating_hours,
)
system_no_CHP.simulate()

### Redefine characterization factors

# NG-Fired Simple-Cycle Gas Turbine CHP Plant, transmission included!
bst.settings.set_electricity_CF(GWP, 0.38) # Basis defaults to kWhr; units default to defined units

# Steam Production via Small Boiler from North American Natural Gas
bst.settings.set_utility_agent_CF('low_pressure_steam', GWP, 88.44, basis='MMBtu', units='kg*CO2e')

# Displacement allocation
GWP_total_new = (
    system_no_CHP.get_total_feeds_impact(GWP)
    + system_no_CHP.get_net_electricity_impact(GWP)
    + system_no_CHP.get_net_heat_utility_impact('low_pressure_steam', GWP)
) # kg CO2 eq. / yr
annual_bagasse_flow_rate = system_no_CHP.get_mass_flow(sc.bagasse)
GWP_total_displacement = (
    system.get_total_feeds_impact(GWP)
    + system.get_net_electricity_impact(GWP)
) # kg CO2 eq. / yr
GWP_bagasse_displacement = (GWP_total_new - GWP_total_displacement) / annual_bagasse_flow_rate # kg CO2 eq. / kg bagasse
print(f"GWP displacement of burning bagasse for on-site steam and power: {GWP_bagasse_displacement:.2f} [kg CO2e / kg]\n ")
GWP displacement of burning bagasse for on-site steam and power: 0.45 [kg CO2e / kg]