Skip to main content

Greenhouse GFM

The Greenhouse Gap Filling Module calculates greenhouse gas emissions from heated greenhouse cultivation of vegetables. Greenhouse production can increase climate impact by up to 10x compared to field-grown equivalents, making this module critical for accurate environmental assessments of fresh produce.

Quick Reference

PropertyDescription
Runs onModeledActivityNode with FoodProductFlowNode parent containing matched vegetable terms
DependenciesOriginGapFillingWorker, AttachFoodTagsGapFillingWorker, ConservationGapFillingWorker
Key InputProduction date, origin country, matched vegetable type
OutputHeating emissions, infrastructure emissions, electricity emissions
TriggerProduct matched to one of 7 greenhouse vegetables

When It Runs

The module triggers when:

  1. A product is matched to a covered vegetable term
  2. The product has a valid origin country with Meteonorm climate data
  3. The product does NOT have an exclusion tag (frozen, canned, dried)
  4. Heating is required (based on climate calculations)

Key Output

The module adds three types of emissions to the calculation graph:

  • Heating: Based on country climate, vegetable requirements, and production date
  • Infrastructure: Glass and plastic greenhouse materials
  • Electricity: Vegetable-specific energy consumption

Scientific Methodology

The greenhouse model calculates emissions using the formula:

Total Emissions = Heating + Infrastructure + Electricity

Each component is calculated per kilogram of vegetable produced.

Heating Demand Model

The heating demand model is based on Stössel et al. (2012) and uses a heat balance approach:

Q_heating = (Q_trans + Q_air) * (T_in - T_out) - Q_solar * G

Where:

  • Q_trans: Heat transmission through greenhouse envelope
  • Q_air: Heat loss through air exchange
  • T_in: Required inside temperature for the vegetable (Kelvin)
  • T_out: Monthly average outside temperature (from Meteonorm)
  • Q_solar: Solar heat gain factor
  • G: Monthly average solar radiation (from Meteonorm)

Heat Transmission Factor (Q_trans)

U_VALUE = 3.4  # W/m2/K - thermal insulation value
CLADDING_AREA = 54_978.2 # m2 - greenhouse envelope area

Q_TRANS_FACTOR = U_VALUE * CLADDING_AREA # = 186,925.88 W/K

The U-value of 3.4 W/m2/K represents a weighted average for conventional greenhouses according to Scharfy et al. (2017).

Air Exchange Factor (Q_air)

AIR_EXCHANGE_NUMBER = 0.24  # air changes per hour
BUILDING_VOLUME = 259_506.0 # m3
SPEC_VOLUMETRIC_ENERGY_CONSTANT_FOR_AIR = 0.32 # Wh/m3/K

Q_AIR_FACTOR = AIR_EXCHANGE_NUMBER * BUILDING_VOLUME * SPEC_VOLUMETRIC_ENERGY_CONSTANT_FOR_AIR
# = 19,924.46 W/K

Solar Heat Gain Factor (Q_solar)

Q_SOLAR_FACTOR = 0.609 * 46_800.0 * 0.99 * 0.9 * 0.7
# = 17,849.82 W/(W/m2)

Components:

  • 0.609: Solar transmittance of greenhouse cover
  • 46,800 m2: Ground area exposed to sun
  • 0.99: Fraction of solar radiation reaching plants
  • 0.9: Utilization factor
  • 0.7: Conversion efficiency

Heating Emissions Calculation

Heating [kg CO2eq/kg] = Heating demand [MJ/kg] * Heating mixture [kg CO2eq/MJ]

The heating mixture depends on the country and represents the average mix of natural gas, heating oil, and renewables used in greenhouse heating.

Infrastructure Calculation

Infrastructure emissions account for the greenhouse building materials over their 30-year lifespan:

FRACTION_OF_GLASS_IN_BUILDING_MATERIAL = 0.604  # 60.4%
FRACTION_OF_PLASTIC_IN_BUILDING_MATERIAL = 0.396 # 39.6%
AREA_OF_THE_WINDOWS_EXPOSED_TO_THE_SUN = 46_800 # m2

The infrastructure mix (60.4% glass, 39.6% plastic tunnel) is based on Swiss greenhouse statistics from Scharfy et al. (2017).

Calculation:

# m2*year of greenhouse needed per kg of vegetable
building_material_per_kg = greenhouse_area / total_yield_per_year * production_amount

# Split between glass and plastic
glass_material = building_material_per_kg * 0.604
plastic_material = building_material_per_kg * 0.396

Electricity Calculation

Electricity consumption is vegetable-specific and multiplied by the country's electricity mix:

Electricity [kg CO2eq/kg] = Energy input [kWh/kg] * Electricity mix [kg CO2eq/kWh]

The electricity mix uses Ecoinvent's "market for electricity, low voltage" for each country.


Implementation Details

Covered Products

The module runs when a product is matched to one of these FoodEx2 terms:

FoodEx2 CodeVegetableModel TypeDescription
B1458eggplanteggplantEggplant
A00JDeggplanteggplantAubergines
A00JMcucumbercucumberCucumbers
A00JRcucumbercucumberCourgettes (zucchini)
A00KYlettucelettuceHead lettuce
A00MJlettucelettuceSpinach
B4946lettucelettuceBatavia lettuce
A00KXlettucelettuceLettuces generic
A1563lettucelettuceIceberg lettuce
A0DLBlettucelettuceLettuces and similar
A1612lettucelettuceOakleaf lettuce
A00LBlettucelettuceLollo rosso
A00JAbell pepperbell pepperSweet peppers
A00QVradishradishRadishes
A00LMradishradishRoman rocket and similar
B2474radishradishRocket
A0DMXtomatotomatoTomatoes
A00HYvine tomatovine tomatoCherry tomatoes

Vegetable Parameters

Each vegetable type has specific cultivation parameters:

VegetableGrowing DaysInside Temp (K)Yield (kg/m2/month)Electricity (kWh/kg)
eggplant50291.15 (18C)3.150.5492
cucumber32291.15 (18C)4.360.1982
lettuce60281.15 (8C)1.740.4636
bell pepper41293.15 (20C)1.970.5746
radish51279.15 (6C)1.360.33798
tomato127291.15 (18C)4.660.2207
vine tomato127291.15 (18C)4.720.2099

Data sources: ProfiCost-Tool (Chollet et al., 2012), Swiss Association of Vegetable Producers technical handbook.

Covered Countries

The module has Meteonorm climate data for 28 European countries:

CodeCountryCodeCountry
ATAustriaITItaly
BEBelgiumLTLithuania
BGBulgariaLULuxembourg
CHSwitzerlandLVLatvia
CZCzech RepublicNLNetherlands
DEGermanyPLPoland
DKDenmarkPTPortugal
EEEstoniaRORomania
ESSpainSESweden
FIFinlandSISlovenia
FRFranceSKSlovakia
GBGreat BritainTRTurkey
GRGreeceHRCroatia
HUHungaryIEIreland

Missing EU countries: Cyprus, Malta

Exclusion Rules

The greenhouse model does NOT run if the product has any of these conservation tags:

Term XIDDescription
J0001Generic Conserved
J0136Frozen
J0111Canned
J0116Dried

These products are excluded because conserved products don't require greenhouse production at the time of consumption - they were likely produced during the regular growing season.

Note: J0003 (Not Conserved) and J0131 (Cooled) do NOT exclude products from the greenhouse model.

Production Date Handling

The production date determines which months' climate data is used for heating calculations:

  1. If activity_date is specified on the product or any parent node, it's used
  2. The harvest date is calculated as production_date - 3 days
  3. Growing days are backtracked from the harvest date based on the vegetable type
  4. Monthly heating requirements are calculated for each month in the growing period

Example: Tomatoes with production date March 15:

  • Harvest date: March 12
  • Growing period: 127 days (October 6 to March 12)
  • Months with growing days: October (partial), November, December, January, February, March (partial)

Full Code Reference

Heating Calculation

The compute_required_heating method calculates heating demand in MJ per kg of vegetable:

def compute_required_heating(
self,
flow_country_code: str,
flow_processing_date: datetime,
vegetable_name: str,
) -> float:
"""Compute the necessary amount of heating."""
days_between_harvest_and_production_date = 3

harvest_date = flow_processing_date - timedelta(days=days_between_harvest_and_production_date)

# Get growing days per month based on harvest date and vegetable growth duration
monthly_growing_days = np.array(days_in_each_month(NUMBER_OF_GROWING_DAYS[vegetable_name], harvest_date))

# Load country-specific climate data
monthly_avg_outside_temp = np.array(
self.gfm_factory.aggregated_meteonorm_data[flow_country_code]["average_temperature"]
)
monthly_avg_solar_radiation = np.array(
self.gfm_factory.aggregated_meteonorm_data[flow_country_code]["average_solar_radiation"]
)

# Calculate heat balance
monthly_temp_difference = REQUIRED_INSIDE_TEMPERATURE[vegetable_name] - monthly_avg_outside_temp
monthly_required_heating_power_watts = (
Q_TRANS_FACTOR + Q_AIR_FACTOR
) * monthly_temp_difference - Q_SOLAR_FACTOR * monthly_avg_solar_radiation

# No negative heating (no cooling modeled)
monthly_required_heating_power_watts = np.array(
[val if val >= 0.0 else 0.0 for val in monthly_required_heating_power_watts]
)

# Convert power to energy
monthly_required_heating_energy_wh = monthly_required_heating_power_watts * monthly_growing_days * 24
monthly_required_heating_energy_kwh = monthly_required_heating_energy_wh / 1000

# Calculate yield during growing period
average_yield_kg_per_day = (
AVG_YIELD_PER_M2_PER_MONTH[vegetable_name] * AREA_OF_THE_WINDOWS_EXPOSED_TO_THE_SUN * 12 / 365
)
yield_in_growing_days_kg = average_yield_kg_per_day * sum(monthly_growing_days)

# Convert to MJ per kg
mj_in_kwh = 3.6
monthly_required_heating_energy_mj = monthly_required_heating_energy_kwh * mj_in_kwh

required_heating_energy_mj_for_kg_of_vegetable = (
np.sum(monthly_required_heating_energy_mj) / yield_in_growing_days_kg
)

return required_heating_energy_mj_for_kg_of_vegetable

Infrastructure Accounting

async def account_for_infrastructure(
self, calc_graph: CalcGraph, greenhouse_activity: FoodProcessingActivityNode, vegetable_name: str
) -> None:
"""Account for infrastructure of greenhouse."""
size_of_greenhouse_in_m2 = AREA_OF_THE_WINDOWS_EXPOSED_TO_THE_SUN
average_yield_in_kg_per_m2_and_month = AVG_YIELD_PER_M2_PER_MONTH[vegetable_name]
total_yield_per_year = average_yield_in_kg_per_m2_and_month * 12 * size_of_greenhouse_in_m2

# Calculate m2*year of building material per kg of crop
area_and_time_of_greenhouse_building_material = (
size_of_greenhouse_in_m2 / total_yield_per_year * self.node.production_amount.value
)

# Split between glass (60.4%) and plastic (39.6%)
glass_building_material = (
area_and_time_of_greenhouse_building_material * FRACTION_OF_GLASS_IN_BUILDING_MATERIAL
)
plastic_building_material = (
area_and_time_of_greenhouse_building_material * FRACTION_OF_PLASTIC_IN_BUILDING_MATERIAL
)

# Add glass and plastic flow nodes to the graph
# Connected to Ecoinvent processes for greenhouse infrastructure

Electricity Accounting

async def account_for_electrical_energy(
self,
calc_graph: CalcGraph,
greenhouse_activity: FoodProcessingActivityNode,
country_code: str,
vegetable_name: str,
) -> None:
"""Account for electrical energy consumption of greenhouse."""
energy_needed_per_kg = REQUIRED_ELECTRICITY_KWH_PER_KG[vegetable_name]

# Create electricity consumption flow
electricity_consumption_flow = FlowNode(
uid=UuidStr(uuid4()),
amount=QuantityProp(
value=energy_needed_per_kg * self.node.production_amount.value,
unit_term_uid=self.gfm_factory.kWh_term.uid,
),
)

# Connect to country-specific electricity market from cache
electrical_energy_node = self.gfm_factory.electricity_markets_cache.get(country_code)

Data Sources

Meteonorm Climate Data

Climate data is sourced from Meteonorm software (2016 data):

  • Temperature: Monthly average outside temperature in Kelvin
  • Solar radiation: Monthly average global solar irradiation in W/m2

The data is stored in the GFM cache and loaded at service startup:

  • meteonorm_average_temperature_{country_code}: Array of 12 monthly values
  • meteonorm_average_solar_radiation_{country_code}: Array of 12 monthly values

Heating Mixes

Country-specific heating mixes for greenhouse heating:

CountryBrightway XIDComposition
CH (Switzerland)EDB_4220cbaabca343c09b19415d5ab4079f_copy141.3% natural gas, 35.2% heating oil, 23.5% renewables
DE (Germany)EDB_4220cbaabca343c09b19415d5ab4079f_copy228% coal, 21% natural gas, 15% fuel oil, 20% renewables, 16% other
NL (Netherlands)EDB_4220cbaabca343c09b19415d5ab4079f86.2% natural gas, 0.1% heating oil, 13.7% renewables
EU otherEDB_4220cbaabca343c09b19415d5ab4079f_copy354% natural gas, 46% heating oil

Infrastructure Materials

Ecoinvent processes for greenhouse building materials:

MaterialEcoinvent IDUnit
Glass greenhouseecoinvent 3.6 cutoff_0ce659c3cfd443a38761058ee62e3f10m2*year
Plastic tunnelecoinvent 3.6 cutoff_fddfe51c6959f41ac044089c3a892af7m2*year

Calculation Example

Scenario: 1 kg of tomatoes, produced in Sweden on March 15

Step 1: Determine Growing Period

  • Production date: March 15
  • Harvest date: March 12 (3 days before production)
  • Growing duration: 127 days
  • Start date: November 5 (previous year)

Step 2: Calculate Monthly Growing Days

MonthDays
November25
December31
January31
February28
March12
Total127

Step 3: Calculate Heating Demand

Using Swedish climate data and tomato requirements (18C inside temperature):

  • Monthly temperature differences calculated
  • Solar radiation offset applied
  • Negative values clamped to zero

Result: ~32.3 MJ/kg heating demand

Step 4: Calculate Infrastructure

Total yield/year = 4.66 kg/m2/month * 12 * 46,800 m2 = 2,616,576 kg/year
Building material per kg = 46,800 / 2,616,576 = 0.0179 m2*year/kg

Glass: 0.0179 * 0.604 = 0.0108 m2*year
Plastic: 0.0179 * 0.396 = 0.0071 m2*year

Step 5: Calculate Electricity

Electricity = 0.2207 kWh/kg * Swedish electricity mix emissions

Final Output

The module adds three flow nodes to the calculation graph:

  1. Heating flow (32.3 MJ) connected to Swedish heating mix process
  2. Glass infrastructure flow (0.0108 m2*year) connected to Ecoinvent glass process
  3. Plastic infrastructure flow (0.0071 m2*year) connected to Ecoinvent plastic process
  4. Electricity flow (0.2207 kWh) connected to Swedish electricity market

Known Limitations

Geographic Coverage

  • Only 28 European countries have Meteonorm data
  • No coverage for US, Canada, or other major producing regions
  • No sub-country regional differentiation (important for large countries)

Crop Coverage

  • Only 7 vegetable types are modeled (tomato, cucumber, lettuce, bell pepper, eggplant, radish, vine tomato)
  • Herbs, chilis, strawberries, and other greenhouse crops are not covered
  • Some crops like lamb's lettuce have data available but aren't implemented

Model Assumptions

  • No heating required = no greenhouse assumed (may underestimate emissions for unheated greenhouses)
  • Same infrastructure mix used for all countries (based on Swiss data)
  • Organic production not differentiated (minimal impact difference found)
  • No country-specific greenhouse growing seasons enforced

Data Age

  • Meteonorm climate data is from 2016
  • Heating mixes may not reflect current energy transitions

References

  1. Stössel, F., Juraske, R., Pfister, S., & Hellweg, S. (2012). Life cycle inventory and carbon and water footprint of fruits and vegetables: application to a Swiss retailer. The International Journal of Life Cycle Assessment, 17(9), 1191-1202.

  2. Eymann, L., et al. (2014). Gewächshausmodell v1.0. ZHAW Report for Eaternity.

  3. Scharfy, D., et al. (2017). OFP Report - New Data ZHAW v1.3. Organic Food Print project report.

  4. Chollet, D., et al. (2012). ProfiCost-Tool. Swiss Association of Vegetable Producers.

  5. Meteonorm Software. https://meteonorm.com/