Teaching model · Spain 2050 · provisional edition · v0.36.0

The Net Zero Game

Build a national 2050 pathway. Transport, building heating and industry are driven by the detailed game engine; agriculture, energy and waste complete the national inventory through transparent first-order modules. Play it with a dozen coarse controls in the simple view, or with all of them in the detailed view — the model, the reference scenario and the score are the same in both.
An open-source teaching model by Robin Girard, MINES Paris — PSL · about & other versions

Map of the model

2050 scenario dashboard

National view aligned with the Inventario Nacional de GEI (edición 2026) and the ELP 2050 sector pathway.

Reference scenario

Emissions

Six emitting sectors, plus natural and technological carbon sinks.

Resource and system constraints

Three limited renewable molecule and biomass pools, plus the winter electricity peak.

Modal shares always add up to 100%. Use the − / + buttons or sliders to change the pathway.

How far, and by what

Four questions about mobility: how much of it there is, what the cars run on, what pulls the freight, and how much of it flies. Each one moves several detailed settings at once — the annex lists exactly which, and by how much.

Current fuel-car travel: destination in 2050

Allocation of passenger-kilometres currently supplied by fuel cars.

Passenger mobility

Current fuel-truck freight: destination in 2050

“Residual thermal” follows the classification convention used in the workbook.

Freight and fuels

The stock says how much heat the country needs; these say what covers it. Gas has no slider — it absorbs whatever the targets leave uncovered.

How much heat, and where it comes from

Ask for less heat, lose less of it, then change what produces it. Watch the winter peak on the dashboard as you electrify: it is the constraint that bites first.

Targets

Two settings, three numbers. You set how much of the heat runs on electricity and how much wood is burned; gas takes whatever is left, so it is read out below rather than set. The three always close on the heat the stock needs, which is why only two of them can be free.

How the electric heat is produced

Rebalanced to 100% of the electric heat above. The differences are not cosmetic: on the coldest evening an air-air or air-water pump falls to a COP of 2, a network heat pump to 1.5, a resistance stays at 1, and a hybrid moves 70% of its load onto gas.

Heat networks

Declared in TWh. With the network heat pumps set above, these say how much of a network is decarbonised; gas absorbs the rest along with everything else.

Building-stock performance

What the country builds

Not carried in this edition. The floor area a country starts each year, the cement and the structural steel it carries, and the timber frame that displaces part of them are the reference edition's. This package declares no construction intensities, so its cement volume rests on the intensity slider alone, and the four controls this paragraph introduces are not drawn.

What this does not do yet: the new floor area consumes cement and heats nothing. The heated stock is still frozen at its base-year surface, which is why the heating bill above does not move when you build more. That is the next stage, and it is named in the annex.

Everything that is not space heating

Hot water, cooking, air conditioning and the specific electrical uses — lighting, appliances, screens, and the servers behind them. Roughly as much energy again as heating, and until v0.8.0 none of it was in the account. Appliance efficiency and equipment growth pull against each other on the same usage, which is why both are here.

Air conditioning makes a summer peak, and the only peak this model constrains is a winter one — the number is carried, the asymmetry is not scored. Fuel switching in hot water and cooking is not a lever yet: their carrier mix is carried forward as observed.

What the heat balance and the stock do

Algebraic port of the five value chains represented in Excel: steel, ammonia, olefins, food and cement.

How much material, and made how

The three ways an industrial sector decarbonises: make less of the material, change the process that makes it, or use less energy for the same output. They are separate here because they cost different things and are argued about separately.

Steel and ammonia

How the hydrogen is made

Every tonne of hydrogen in the model — steel, ammonia, freight, chemistry, refining — comes from this mix. Until v0.12.0 all of it was electrolytic by assumption, which was a strong claim wearing no clothes: 87 TWh of electricity, and no way to ask what a reformer would cost instead.

Reforming trades electricity for methane, and in this edition 2050 methane is biomethane — an assumption inherited from the French file rather than measured here, and a stronger one in Spain, whose gas system is large and fed by imported LNG. So the colour of the hydrogen follows the colour of the gas, and it competes for the same pool the buildings and the power stations want. With capture on biogenic methane the route goes carbon-negative, which is real physics and the most contested line in the model. Read the Controversy tab, and the gas emission factor's own note, before leaning on either.

Plastics and industrial heat

The rest of industry

The manufacturing branches the game does not model as value chains, grouped into five: metals and machinery, minerals, the rest of chemistry, paper, and a diverse remainder. Together about 123 TWh of final energy, 40 of it electricity — 0.7 times the French block. Output and processes would move separately; here only the process axis is offered, and the note below says why.

The output axis is not shown in this edition. The Spanish block has an observed corner from JRC-IDEES and no national output index to 2050, so the output lever would move nothing at all and is hidden; the annex names it and says so. What is left is the process axis, and its meaning is narrower than its label: it is how much of the French per-branch process change is applied to Spanish branch energy. The reference scenario sits at today's output and 100% process change.

Cement

One account, read four ways. Every hectare sits in exactly one of seven classes and the total never moves; the forest's carbon sink is an identity in cubic metres rather than a number somebody chose; what the country eats sizes its herd, and the herd and the fields are the agriculture sector's emissions; and the biogas, liquid fuel and wood the scoreboard scores are what this same land can supply. Nothing on this tab is a trajectory drawn between two points.

The land, the plate and what grows on the rest

Four questions about the same territory: what is eaten off it, what is planted on it, what is spread on it, and how much of it grows energy. Each one moves several detailed settings at once — the annex lists exactly which, and by how much — and they pull against each other on purpose, because they share one account, whose size the land table below states.

The land account

Seven classes, one fixed total: every hectare one of these levers takes out of a class arrives in another. Nothing absorbs a residual, because there is none — and what a hectare is worth depends entirely on which class it left.

Where the hectares are, and where they go

The same territory twice: as the land survey measured it, and as these levers leave it at the horizon. The two bars are the same length because the account closes — a partition, not a budget — so every gain you can see is a loss somewhere else in the same bar.

Not carried in this edition. The artificialisation flow, the land account it moves hectares inside, and the legal path this edition would compare it with are the reference edition's. This package keeps a natural-sink slider and a published agriculture pathway instead, and the tab this paragraph belongs to is not drawn.

The forest and what is cut from it

The sink is growth, less mortality, less what is harvested, times a carbon coefficient per cubic metre. Cutting more wood therefore costs the sink what it gains the boiler — and the climate the forest lives through moves the answer further than any of these levers do.

The six pools of the sink

Positive absorbs, in both columns. The inventory writes a sink negative and this module writes it positive; the sign is applied once, where the national account needs it, so a pool shown here as a source really is one. Two of the six are sources today, and the artificial pool is a source because building on a hectare releases what was in it.

What the country eats, and what it sells

Demand sets production, production sets the herd. Trade sits in the middle: cut the milk and the dairy herd shrinks, but a large share of the beef is a by-product of that herd, so the suckler herd grows to meet a beef demand that has not moved. How large a share is a national number, and the annex gives this edition's.

The fields, the nitrogen and the farm's fuel

Mineral nitrogen is the longest lever here: it sets the nitrous oxide the soils give off, the carbon dioxide of urea and liming, and the ammonia the industry chain has to make — which is where the hydrogen goes.

The farm account — emissions, herd, plates and nitrogen

The agriculture sector is no longer a position on a published trajectory: it is this account, and it is built forwards. The inventory publishes three blocks and this module splits the livestock one into enteric and manure methane on its own authority, which is worth knowing before quoting the split.

What the land can supply

Manure that goes to a digester emits less than manure that sits in a store, and it produces methane while it is there. These levers, the manure one above and the harvest one further up decide all three biomass resources at once — and the scoreboard's biogas, biofuel and wood bands are now those resources rather than a rule. Cover crops share their hectare with the spring crop that follows; the fuel crops do not, and come out of the same arable land the food chain wants.

Biomass, supply against demand

Three pools, each built feedstock by feedstock and each drawn against what the rest of the scenario asks of it, on one scale. The supply bar is what this land makes; the demand bar is what the transport, building, industry and power levers have ordered. The scoreboard's three biomass bands are these same numbers, so a card and a chart cannot disagree.

How much CO₂ a kilowatt-hour carries in 2050. These are scenario assumptions, not measurements, and in a decarbonised pathway they decide almost everything that is left. They were editable in the source workbook and are editable here.

2050 emission factors

Observed 2020 values for Spain, for comparison: electricity 157.5, methane 227, liquid fuel 264, wood 27 gCO₂/kWh. Coal is fixed at 340 gCO₂/kWh because it is a property of the fuel, not a choice. Hydrogen and e-fuel carry no factor of their own — they are converted back into the electricity used to make them. The Spanish grid factor is twice France's and is a combustion figure, computed from the Spanish inventory over Spanish generation; the wood factor is a French value carried, because no Spanish one was found.

Try this in class. Set methane back to 227 and liquid fuel to 264 and watch what happens: the scenario relies on every molecule being biogenic. The whole difference between a decarbonised transport sector and today's is carried by two numbers nobody in the game ever chose to produce.

What makes the electricity, and what the gas plants burn when the wind drops. Everything else in this model asks the power system for kilowatt-hours; this is the only tab that answers with what. The hydrogen share below is also the single largest methane lever in the game — every point of it takes gas out of a resource the buildings, the trucks and the factories are all competing for.

The electricity mix

One of six Spanish 2050 electricity mixes, ordered by how much dispatchable gas they still run — from the ELP's 100%-renewable outcome to the PNIEC's 2030 mix. Four of the six come from the ENTSO-E and ENTSOG TYNDP 2024 scenarios for the Spanish bidding zone. None of them has nuclear after 2035: the ordered closure plan retires all seven reactors between 2027 and 2035, so the axis this slider moves is firm capacity, not the nuclear share. It selects a set of shares, not a quantity: the mix is scaled to whatever electricity the rest of the model turns out to need, so this answers with what and never how much. Capacity follows from energy through a load factor, and what has to be built each year from capacity through a lifetime.

TechnologyShareTWh/yGWGW built/ybn€/y

This does not check that the mix works. There is no hourly balance, no adequacy calculation and no storage: a 100%-renewable share structure is applied exactly as a nuclear-heavy one is, and the winter peak the building module computes is a demand-side number that nothing here has to meet. The cost is plant only — no fuel, no carbon, no network, no storage.

What the pathway weighs. A satellite account: it reads the scenario, nothing reads it back — the steel a wind farm needs is not charged to the steel industry the model already has, and none of it emits. Wiring it back would double-count against an industry whose output is set by its own levers.

Battery chemistry

The sharpest trade-off in the account, and there is no chemistry that is cheap in every metal at once.

Annual material demand of the transition, 2050

MaterialGenerationVehiclesBatteriesBuildingsTotal

Annualised cost in real euros, from the point of view of whoever pays: the industrial producer, the building owner, the household. Read the deltas rather than the levels — the levels carry all the parameter uncertainty, the deltas are what the game is about. Several of the unit costs behind them are French figures carried across and labelled as such in the sources annex; the Spanish industrial electricity price is Eurostat's.

Financing

Two separate rates, because an industrial investor and a household do not face the same cost of capital. This single choice moves retrofit economics by about a factor of two, which is why it is a lever and not a hidden constant.

Prices and provisional assumptions

The last two are flagged provisional: no primary source has been secured for them yet.

Industry — cost per tonne of product

Product and routeOutput (kt/y)Capital + fixedEnergy and feedstockCarbonTotal €/t

Carbon capture — what the two capture levers draw and cost

A capture plant takes every molecule up the stack, so it is powered and paid for on the fossil and the biogenic tonnes alike, while only the fossil ones lower the total. The last column divides the whole bill by the fossil tonnes alone: it is what a tonne off the national total costs through each lever.

WhereFossil captured (Mt/y)Biogenic captured (Mt/y)Electricity (TWh/y)Cost (M€/y)€ per fossil tonne

Aviation — what a ticket costs when the kerosene is synthetic

Flight categories and traffic are Eurostat's, for 2019 — the last pre-Covid year — in the three route groups the European aviation statistics use: domestic, intra-EEA-and-UK, and the rest of the world. The energy is the one the emissions account already charges, so the ticket and the carbon describe the same flight. These are costs, not fares: no margin, no tax, no yield management. The domestic group mixes peninsular routes with the Balearics and the Canaries, which have no rail alternative at all.

FlightDistanceCost todayof which fuelCost in 2050of which fuelChangekgCO₂ todaykgCO₂ 2050

Every flight gets the same relative increase, and that is a limit of the model, not a result. Everything that is not fuel is derived from today's ticket through a single fuel share of operating cost, so the non-fuel cost is proportional to distance. In reality a short flight carries far more per-flight cost — airport charges, crew, turnaround — so short-haul is much less exposed to the fuel price than long-haul, and its ticket here is understated. Correcting this needs a per-flight versus per-kilometre cost split that no source in hand provides.

Buildings — annualised cost of retrofit, equipment and energy

ComponentInvestment (bn€)Annualised (bn€/y)€/m²/y
The two segments are split by their energy mix, not by floor area. The residential stock takes 87% of the wood but only 54% of the gas, so a floor-area split would have misstated both — which is why the two €/m² figures now differ. The retrofit and equipment annuities are still split by area, because the model has no separate stock for them. That is the remaining approximation, and the reason to split the building module properly rather than its cost.

Households — annualised car mobility cost

Component€/household/yBasis
Purchase, insurance and maintenance are technology-neutral by decision. The electric-versus-thermal purchase premium and maintenance saving are not yet sourced, so they are excluded: only the size of the car fleet moves this block. A scenario that electrifies without changing mobility demand will therefore show its saving on energy only, and understate or overstate the true household cost.
What this cost layer does not include

Freight, aviation and public-transport costs; the counterfactual boiler avoided when a heat pump is installed; grid reinforcement; CO₂ transport and storage; the cost of the CO₂ feedstock for synthetic olefins; industrial equipment for food-industry heat; and any subsidy, tax or transfer. Nothing here says who actually pays.

Prices mix reference years — 2017 for the household mobility budget, 2025 for household energy, 2050 for industrial commodities — with no deflator applied. Treat cross-sector comparisons of levels with caution.

The published inventory and the published objective, side by side with the sectors the model does not compute. The reconciliation that connects them to the model is under the results, on the right, because it belongs next to the number it explains.

The published inventory and the ELP 2050 objective

Official sector1990Model coverage
Latest observed year: 2024, from the 2026 edition of the Spanish inventory. No official 2025 proxy had been published when this edition was built, so the 2025 column repeats 2024 rather than inventing a trend.

What happens to what the model does not compute

0% keeps the consolidated 2024 value; 100% reaches the ELP 2050 sector level. These are inputs, not results: at 100% agriculture, waste and energy production sit exactly on the ELP value, so three of the six national rows are a recopy of the objective they are being compared with. Read them as an assumption about the rest of the economy, not as an answer. Spanish waste is the one to watch: it emits more today than in 1990, because Spain landfills where France incinerates, so this pathway asks for a bigger change than its French counterpart on a smaller number.

The industry lever is a coverage gap, not a pathway. The model computes five value chains — steel, ammonia, olefins, cement and food-industry heat — plus the seventeen remaining manufacturing branches, rebuilt for Spain from the JRC's energy balance. What is still outside it is construction, refining, mining and the fluorinated gases, which the Spanish inventory books to industry. The size of that hole is computed from the official total rather than assumed, and this lever decides only how fast it shrinks.
Official Spanish sources and scope caveats

The consolidated 2024 values come from the Inventario Nacional de Gases de Efecto Invernadero, edición 2026 (MITECO, Sistema Español de Inventario), on the national territory including the Balearics, the Canaries, Ceuta and Melilla. They were read through the Eurostat mirror of the same submission, whose totals reproduce it.

The 2030 column is the PNIEC 2023-2030, Tabla 2.3, mapped from its thirteen rows onto the game's six sectors; the mapping closes exactly on the Plan's own 195.189 MtCO₂e. The 2050 column is the ELP 2050, whose six horizon bars sum to its stated maximum of 29 MtCO₂e.

Spain declares no technological sink, and that is a finding rather than a gap. The ELP closes on natural absorption alone — 37 MtCO₂e against 29 emitted, so the strategy is net −8 MtCO₂e. The French edition of this game opens on 30 MtCO₂e a year of capture, against the 43 its published account implies as a closure residual; Spain needs none. What Spain's pathway does instead is weaken its own sink, from −51.9 MtCO₂e observed in 2024 to −43.6 in 2030 and −37 in 2050.

Two perimeter caveats. Fugitive emissions (CRF 1B) and other combustion (1A5) are booked to energy production here; left out, the six sectors would fall 4.1 MtCO₂e short of the published total. And the ELP's own base column is a TIMES-Sinergia model output anchored near 2018, not an inventory year, so the 2050 figures sit on the strategy's perimeter placed on the game's sectors.

A model that shows its sources still hides which of them are argued over. This names them. Everything here is visible elsewhere in the annex — a reader should not have to reverse-engineer which numbers are settled and which are live.

This is open source, and the point of it is that you can check it. If a number looks wrong to you, that is a contribution, not a complaint.

Where it came from

It started as a home-made Excel workbook — the kind every teacher builds and nobody else can read. Rebuilding it with the help of AI made it something else: every formula is declared in a YAML file, not buried in a cell, and every assumption carries its value, its bounds, its provenance and its sources. The engine that runs in your browser, the annex you are reading and a Python checker are all compiled from those same two files, and a test fails the build if the two engines ever disagree. A value shown and a value used cannot differ.

That is the whole argument for the rewrite. Not that it is more accurate than the spreadsheet — in places it is the same numbers — but that you can audit it.

Who made this, and where it lives

Built by Robin Girard, MINES Paris — PSL. The project page, with every published version kept at its own permanent link, is at robingirard.eu/TheNetZeroGame.html — a scenario shared with a class still opens against the model it was built on.

It is open source. Everything, including the model, its sources and this page:

Tell us what is wrong

In English, Spanish or French, whichever you prefer. Bugs, remarks, a figure you disagree with, or a Spanish source we should have used and did not — this edition has a list of those, and it is in the sources annex.

What happens to it. Every disagreement about a number gets one of three answers, and we will tell you which: the assumption changes, or we explain why it does not, or — when the honest answer is that reasonable people differ — it goes into the Controversy tab so the disagreement is visible to everyone rather than settled quietly.

Before you start

Strategy prompts — not solutions

Four ways in, none of them an answer. A winning combination does exist — every band can be met at once — but there is more than one, and the interesting part is which trade-offs you accept to get there: emissions against electricity, molecules against demand, this decade's peak against the next one's materials.

Start with demand

Ask which services must grow, which can stabilise, and where efficiency or sufficiency can reduce energy before changing technologies.

Electrify selectively

Prioritise direct electricity where it is efficient, while watching the building-heating peak and electricity used indirectly for H₂ and e-fuels.

Reserve scarce molecules

Biogas, biofuels and wood are limited pools. Consider which uses have few credible alternatives and which can switch to direct electricity.

Build a balanced portfolio

Combine modal shift, renovation, process change, material efficiency and carbon capture rather than relying on one lever.

How complete is the calculation engine?

This is a provisional Spanish edition. The model structure and the equations are country-agnostic and unchanged. The Spanish data is complete enough to run and is sourced wherever a source could be reached — the building stock, the rest of industry, transport activity, the electricity mixes and the inventory bridge are all Spanish measurements. Fourteen entries are not: they carry a French value or a French ratio, each labelled in the sources annex with a why that begins "PLACEHOLDER". Read a Spanish result as an order of magnitude with a known list of borrowed assumptions, not as a Spanish study.
ModuleCoverageWhat is recalculatedMain limitation
TransportDetailed algebraic portNeeds, modal shifts, unit energy, fuel split, H₂/e-fuel electricity and emissionsActivity from the JRC's 2019 Spanish balance; the two reallocation tables are French conventions
Building heatingStock, allocated by target24 Spanish segments built from the 2021 census and the JRC's measured useful heat; targets allocate it across five electric technologies, biomass and a gas residualOne-shot 2019→2050. District heating is exactly zero in Spain, so the two network levers act on nothing
Building, other usagesObserved levels, moved by leversHot water, cooking, cooling and specific electricity, by carrierThe services half disagrees with its French counterpart by a factor of five on cooling — see the Controversy tab
IndustryDetailed algebraic portFive value chains plus seventeen branches, rebuilt for Spain from the JRC energy balanceThe observed corner is Spanish; every assumption about how it decarbonises is a French ratio
HydrogenProduction mixElectrolysis, steam reforming and autothermal reforming with capture, serving every consumerNo capture-train capital cost, no CO₂ transport or storage cost
Electricity supplyMix follows demandOne of six Spanish mixes sets shares; capacity, annual build, fuel and plant cost followNo hourly balance, no storage, no adequacy check — which is exactly the question Spain has instead of a nuclear question
MaterialsSatellite accountSteel, concrete and critical metals for the generation build, vehicles and batteriesVehicle production is France's, carried. Spain builds more vehicles than France, so this understates it
National inventory bridgeScope 1, shared with the inventorySix sectors, both carbon sinks, gross and net totalsInternational aviation and shipping are the one remaining difference, and they are large in Spain
Agriculture and wasteFirst-order trajectoriesLinear interpolation from observed 2024 to the ELP 2050 levelThe ELP does not separate the two; they are split in the PNIEC's own 2030 ratio
Energy productionComputed from the mixThe fuel the chosen electricity mix burns, at the model's own emission factorsPower generation only — refining and fugitive emissions are outside the model and inside the Spanish inventory's energy sector
Carbon sinksSet directlyNatural and technological absorptions, each on its own sliderSpain's technological sink is zero because its strategy names none — the single largest assumption in the French edition simply is not here
Model-risk statement: this version is suitable for teaching and scenario comparison, and not for forecasting. The three limitations that would matter most if anyone tried: there is no adequacy check on the electricity supply, so no scenario here is shown to be buildable hour by hour; the peak indicator is a winter one in a country heading for a summer peak; and the building transition is a single jump with no rate. Each is stated where it applies rather than only here.

Transport levers

Modal destination shares redistribute the 2020 service demand of a source mode among 2050 modes. Existing activity in other modes remains in the calculation.

Passenger or freight demand reduction is applied to all passenger-kilometres or tonne-kilometres before modal allocation.

Biofuel share splits liquid fuel between biofuel and e-fuel. E-fuel production uses electricity with a 40% conversion efficiency.

Building-heating levers

The stock — 3 655 Mm² across 24 segments, 8 heating systems × 3 building types — says how much heat the country needs and anchors the winter peak. What covers that heat is set by target, and gas has no slider: it absorbs whatever the targets leave uncovered. That is what makes the account close by construction, and what makes the cost of not choosing visible.

Biomass is a target in TWh of wood burned, not a share, so it can be read straight against the biomass limit on the dashboard instead of being reconstructed from two shares. Electrification is a share of the heat need — of heat, not of energy; how that heat is produced is the next question down, and it is where the peak is won or lost.

The five electric technologies are not interchangeable. Over a year an air-water pump returns 3 kWh of heat per kWh of electricity, an air-air or network pump 2.5, a resistance 1. On the coldest evening both air pumps fall to 2, a network pump to 1.5, a resistance stays at 1, and a hybrid moves 70% of its load onto gas while running 95% electric over the year. Electric resistance is a slider rather than a stock that can only shrink, because a scenario may genuinely install more of it: it is cheap to fit and the worst thing that can happen to the peak.

Heat networks are declared in TWh of wood and of recovered heat. With the network heat pumps set above, those say how much of a network is decarbonised; gas absorbs the rest along with everything else. Recovered heat has no emission factor and adds nothing to the peak, which makes it the cheapest thing a network can run on — and the model does not check it against the waste-heat gisement the industry module computes, so raising it far is optimistic in a way nothing here will stop you being.

Retrofit improvement is an average demand reduction across the whole stock, not the percentage of buildings renovated. It acts on the heat need before any system sees it, so it benefits every vector alike and is the only lever that lowers the peak without changing a single technology.

If the targets over-subscribe — more heat allocated than the stock needs — gas floors at zero and the surplus is reported beside the sliders rather than absorbed. A scenario that has quietly allocated more heat than exists is one whose numbers should not be trusted.

What this replaced, twice. Until v0.5.0 building heating was an aggregate fitted at a single point: three linear regressions, one COP of 3, one peak COP of 2. Its three carriers each implied a different total heat demand — 332 TWh via electricity, 366 via wood, 229 via gas — so the shares were not a partition and substitution did not conserve heat: on a path to 95% electric, 41 TWh appeared from nowhere. The 60% cap on electric heating existed to hide that. v0.5.0 replaced it with a transition of surfaces, which conserved heat properly but could only ever shrink electric resistance and split the biomass a scenario used between "leaving" and "arriving" shares nobody could add up. v0.7.0 keeps the stock for the heat need and the peak anchor, and sets the allocation by target.

What it still does not carry: domestic hot water, cooking, cooling and the specific electrical uses — this is space heating only, roughly half of what a building consumes. The allocation is national, so it cannot say that a heat network needs density and a detached house will not get one; the residential/tertiary split of each vector follows the heat need rather than a separate stock.

The winter electricity peak constraint

The peak indicator is the additional winter power demand created by electric space heating. It is the constraint that makes electrification a trade-off rather than a free win: a scenario can be excellent on emissions and still be unbuildable because it asks the power system for too much capacity on the coldest evenings.

It is built from the stock: every segment's heat need, at its system's peak efficiency rather than its seasonal one, counting only the share of that system actually running on electricity on the coldest evening. Those three things differ by technology in ways a single COP cannot express. Air-air and air-water heat pumps fall from 2.5 and 3.0 seasonal to 2.0 apiece at peak; district-heating electricity falls from 2.5 to 1.5; electric resistance is 1 in both, which is why retiring it is the strongest single lever here. A hybrid heat pump runs 95% on electricity over the year but 70% on gas at peak, so it is by some distance the cheapest way to electrify heat without buying winter capacity — and the gas shows up in the emissions.

The 2020 figure of 40 GW is an anchor, not an output: the same expression is evaluated for the 2020 and the 2050 stock and their ratio scales it, so freezing the stock returns the anchor. Thresholds are 35 GW (target) and 45 GW (limit).

The reference scenario is over the limit, at 51 GW, and that is the finding rather than a slip. The workbook's own peak formula divided by the peak efficiency twice, and anchored its 40 GW against the 2020 useful heat instead of the 2020 peak load — two different quantities, so running its own 2020 stock through it returned 36.8 GW rather than 40. Its answer, 39.45 GW, is the number the old aggregate module was fitted to reproduce, and the 35/45 band was set against it. Corrected, the transition the workbook describes does not hold the winter peak flat: it multiplies it by about 1.27. The band was deliberately left where it was, because a scenario that meets its carbon targets and still cannot be built is the thing this indicator exists to show. The levers out of the red are real ones — retrofit, hybrid heat pumps, district heating, and not replacing electric convectors with more electric convectors.

Scope limitation: only building heating is counted, as in the workbook. Electricity used by transport, industry, hydrogen and e-fuels changes the annual energy but is not added to this peak, even though electrolysers and industrial loads do interact with system adequacy in reality.

Building usages other than heating

Space heating is about half of what a Spanish building consumes. This is the other half — hot water, cooking, air conditioning, and the specific electrical uses: lighting, appliances, screens and the servers behind them.

The residential data is Eurostat's disaggregated household table for 2023, whose four carriers sum to the published household total to the last digit. The tertiary data is the JRC's, for 2021, because Eurostat publishes end-use detail for households and not for services.

Spanish hot water is a gas and butane business. Only 12.3% of the energy is electric, against France's 68% of the service — natural gas 57 PJ, oil products (mostly bottled LPG) 40 PJ. Spain has more solar thermal on its roofs than any other large European country and still heats most of its water with a flame. Cooking is the other way round: 53% electric by energy, ahead of France.

The tertiary half does not agree with its French counterpart, and the disagreement is worth knowing. Run the same extraction on France and the JRC's services cooling is 4.2 TWh where the French source gives 21.7 — a factor of five on the same country in the same year. Spain's figure here is 8.13 TWh. If the French source's method is right, Spanish services cooling is three or four times larger than this table says, and the air-conditioning lever is growing a number that starts far too small. In the country where cooling matters most, that is the open question of this whole edition.

It is a weaker model than the heating one, deliberately. There is no stock and no technology choice: each usage is its observed energy carried to 2050 and moved by efficiency, growth, or both.

Three gaps, named. Fuel switching in hot water and cooking is not a lever. Air conditioning makes a summer peak and the only peak this model constrains is a winter one. And the "other uses" row is zero, because the JRC decomposes Spanish services energy into exactly five end uses with no residual — the French edition carries 10.7 TWh there, so the Spanish tertiary account is that much thinner for reasons of nomenclature rather than of consumption.

The accounting scope — read this before comparing anything

This model is a scope-1 account. Emissions are booked where the combustion happens. A power station's emissions belong to the power station; they are not spread back over everyone who used a kilowatt-hour. Electricity therefore carries nothing where it is consumed — a building that electrifies its heating shows zero emissions for that electricity, and the emissions appear in Electricity generation instead, computed from the fuel the chosen mix actually burns.

The consequence to hold onto: electrification moves emissions rather than removing them. Where they land depends on the electricity mix, which is a separate choice on the Supply tab. That matters more in Spain than in France: the Spanish grid emitted 157.5 gCO₂/kWh in 2020 against France's 79, so electrifying a Spanish sector moves twice as much carbon into the energy branch.

This is the convention the Inventario Nacional uses, which is why the national reconciliation is a short page: the only difference left between the two accounts is international aviation and shipping, which the inventory reports as a memo item outside the national total. For Spain that memo item is 140 TWh of fuel, more than Spanish road freight burns, and a large part of it belongs to ships that change containers at Algeciras and never enter the country.

What the grid factor is and is not. The model derives the 2050 factor from the mix rather than declaring it, and every Spanish mix on offer is at least 89% renewable, so it is very small. The 2020 anchor, 157.5 gCO₂/kWh, is a combustion figure — no construction, no fuel chain, no decommissioning — computed from the Spanish inventory's electricity and heat generation over Spanish gross generation. It is not comparable with a life-cycle figure, and no life-cycle factor for Spain was found; expect one to land 25 to 45 gCO₂/kWh higher. Comparing the two is the most common way to make this model say something it does not say.

The electricity mix

The supply follows the demand rather than standing beside it: whatever electricity the rest of the model turns out to need is served by the share structure of one of six published Spanish mixes. Two are national — the ELP 2050's 100%-renewable outcome and the PNIEC's 2030 mix — and four are the ENTSO-E and ENTSOG TYNDP 2024 scenarios for the Spanish bidding zone ES00, climate year 2009. Choosing one answers with what, never how much.

There is no nuclear axis. The ordered closure plan retires all seven Spanish reactors between 2027 and 2035; the TYNDP's own capacity table gives Spain zero nuclear from 2040 in every scenario. Only the 2030 mix still has any. The slider is therefore ordered by firm thermal generation — from none at all to the 10% the 2030 plan runs — which is the Spanish question: adequacy, storage and interconnection rather than nuclear share. Three of the six are not 2050 mixes: two are 2040 and one is 2030, because National Trends+ has no 2050 run.

Capacity follows from energy through a load factor. The Spanish load factors are the resource, and they are not France's: solar 20.7% against 14%, onshore wind 23.9%, offshore 46.4%, and hydro only 22.6% against France's 29.5% — Spanish hydrology is drier and far more variable, and the drought years are much worse than the mean. The combined cycle runs 757 hours a year: the 26.6 GW fleet is there for adequacy, not for energy.

Three splits the sources do not make are made here. Solar is split ground/rooftop on the TYNDP's own Spanish rooftop share; concentrated solar power, 3 to 4% of supply, is folded into ground-mounted photovoltaic because the model has no row for it, so the material account is wrong on that slice; and all Spanish offshore wind is treated as floating, which is what the bathymetry and the national roadmap say it will be.

This does not check that the mix works. There is no hourly balance, no adequacy calculation and no storage — and that is a sharper omission in Spain than in France, because with no nuclear question the Spanish argument is the adequacy one. The PNIEC plans 22.5 GW of storage by 2030 and none of it is in this model. The cost shown is plant only.

How the hydrogen is made

One mix serves every hydrogen consumer in the model. Three routes: electrolysis, which buys hydrogen with electricity at the 60% conversion the rest of the model uses; steam methane reforming, which buys it with methane; and autothermal reforming with capture, which does the same and puts 94% of the carbon underground.

That 60% is not a neutral choice for Spain. The POMMES dataset the cost layer otherwise follows uses 74%. Spain's whole industrial strategy in the ELP rests on cheap renewable hydrogen, and an inherited 60% makes hydrogen here roughly 40% more expensive than a POMMES-native calculation gives. It is the single assumption to which the H₂-DRI steel and electrolytic ammonia figures are most sensitive, and it decides the answer rather than informing it.

The capture credit is charged against the physical carbon, not against the emission factor. Those are different numbers and both are needed: efGas at 25 gCO₂/kWh answers "what does burning this count as?", while carbon_in_methane at 202 gCO₂/kWh answers "how much carbon is there to capture?". A capture plant removes molecules, not conventions.

Hence the negative number, and hence the warning. Reforming biomethane with capture takes carbon out of the air and puts it underground, so the route reads negative at full deployment. That is the physics of BECCS. It is also the point at which this model will most easily mislead: it says nothing about whether the biomethane exists, what land it came from, or whether the storage holds. Spain produced 4.4 TWh of biogas in 2024 against a gas demand an order of magnitude larger, so the "all 2050 methane is biomethane" assumption behind efGas is a stronger claim here than in France. The Controversy tab says so too.

What is missing. No separate capital cost for the capture train. No transport or storage cost for the CO₂. And the methane a reformer needs is charged to the biogas pool, which at full reforming is well past anything Spain could supply.

Materials of the transition

A decarbonisation pathway is usually argued in TWh and MtCO₂. This says what the same pathway weighs: the steel, concrete and critical metals it asks for each year in 2050.

It is a satellite account, and deliberately a one-way one. It reads the scenario; nothing reads it back. The steel a wind farm needs is not charged to the steel industry the model already has, the concrete is not charged to cement, and none of it emits. Wiring it back would double-count against an industry whose output is set by its own levers.

The vehicle production in this edition is France's, carried, and it is the weakest thing on this page. Spain is the European Union's second vehicle producer, after Germany and ahead of France, and it builds far more vehicles than it registers — so the material account of a Spanish transition is an export industry's account rather than a domestic fleet's, and carrying France's production understates it rather than being neutral. ANFAC publishes the Spanish figures; they were not obtained.

The chemistry lever is the sharpest trade-off here. LFP carries almost no cobalt — 7 grams per MWh against 27 kilogrammes — and a quarter of the nickel, but 4.4 times the lithium. There is no chemistry that is cheap in every metal at once.

Two comparisons worth reading. The transition's steel against the steel this scenario's own industry produces — and Spain's steel is two thirds scrap-based already, which changes what "more steel" costs. And its concrete against clinker: a ratio above one would not be an error, since concrete is mostly aggregate.

What is missing, and it is named rather than filled. Heat pumps are absent: no source in hand gives their material content per unit. Flat glass, plastics and rubber are carried by the source for vehicles but not totalled here. Nothing is recycled: this is primary demand.

Industry levers

Steel production change is the relative change in 2050 steel output compared with the country’s 2020 route volumes. The coefficient is used as 1 + g: +30% means a multiplier of 1.30, while −20% means 0.80.

H-DRI steel share splits primary steel between the BF-BOF and hydrogen direct-reduction routes. Recycled EAF steel is scaled by the same production-change coefficient.

Green ammonia is entered in kt/y. The workbook reference also contains 200 kt/y of grey ammonia; its treatment is documented as an accounting limitation.

CO₂ + H₂ olefins combines a new production-route share with plastic-demand reduction and an optional biogenic-CO₂ credit.

Clinker ratio and capture separately affect cement production-process emissions — the decarbonation of the limestone, about 0.53 tCO₂ per tonne of clinker. The kiln burns 1.064 MWh a tonne on top of it, and waste-derived fuel sets how much of that heat is waste, about half of it biomass. Capture takes the whole fossil stack, calcination and fuel; the biogenic CO₂ of the waste goes up the same stack and is not credited.

The land account, the forest and the carbon sink

Not carried in this edition. The seven-class land account, the forest identity in cubic metres and the six sink pools are the reference edition's, built on its own land survey and its own forest inventory. This package declares land_module_active: 0, so its natural carbon sink is the slider it always was, its land levers are hidden and provably inert, and the Land & food tab is not drawn. Porting the module means answering two national tables and about forty national constants from this country's own statistics; app/model/README.md says which, and make porting-checklist lists them one by one.

The farm — diet, herd, nitrogen and ammonia

Not carried in this edition. The diet, herd, nitrogen and ammonia chain is the reference edition's, calibrated on its own inventory and its own farm survey. This package declares land_module_active: 0: agriculture is still a position on a published pathway between the observed year and the horizon, the eleven food levers are hidden and provably inert, and the absolute ammonia lever it replaced is still the one this page uses. The two tables and the national constants it needs carry the reference edition's shapes as labelled placeholders so that this build closes, and nothing reads them.

What the land can supply — biogas, liquid fuel and wood

Not carried in this edition. The three biomass bands on this page are the threshold table's own teaching figures, not a supply computed from this country's land: no herd sizes the manure, no forest sizes the harvest, and no arable area sizes the cover crops. This package declares land_module_active: 0 and the five bioenergy levers are hidden and provably inert. A card here therefore says “target ≤” where the reference edition says “within what the land supplies”, and the difference is the point rather than a rendering detail.

National reconciliation — method

The game and the national inventory do not measure the same thing. Reconciling them by a ratio transfers relative change but hides the differences and any sub-sector the game does not model. Each difference is its own line.

Both accounts are scope 1. The game books emissions where the combustion happens, which is what the Inventario Nacional does: power-station emissions sit in the energy branch, at stack level, and not in the sector that used the kilowatt-hour. The line that used to undo a life-cycle electricity factor is therefore zero, and is kept only so the change is visible rather than silent.

International bunkers. International aviation and maritime shipping are in the game and are a memo item outside the national inventory total. The deduction is computed from the model's own international rows, so it follows the scenario instead of being asserted. Spain's are unusually large — 56 TWh of kerosene and 84 of marine fuel in 2019 — because Spain is one of the world's largest inbound tourism markets and Algeciras, Valencia and Barcelona are transhipment ports.

The coverage gap. The game models five industrial value chains plus the seventeen remaining manufacturing branches. Everything else the inventory calls industry — construction, refining, mining, fluorinated gases, metal-process emissions — is a named line whose size is the difference between the official industry total and what the model represents: 53.3 against 45.5 MtCO₂e, so +7.8. See the constant industry_covered_2020 in the generated annex for the derivation.

First-order sectors. Agriculture, waste and energy production interpolate linearly between observed 2024 and the ELP 2050 sector level. At 100% they sit exactly on the ELP value, so those three rows are an input, not a result.

Carbon sinks. Natural and technological sinks are separate, and Spain's technological sink is zero: the ELP closes on 37 MtCO₂e of natural absorption against 29 MtCO₂e of residual emissions, a net −8. There is no Spanish counterpart to the closure residual the French edition carries. What Spain's pathway does instead is expect its natural sink to weaken, from −51.9 MtCO₂e in 2024 to −37 in 2050.

Emission factors — today and in 2050

These were editable assumptions in the source workbook and are restored here as levers, because they are scenario choices rather than measurements, and because in a decarbonised pathway they decide almost everything that is left.

Carrier2020, observed2050, assumedWhat the 2050 value assumes
Electricity79 gCO₂/kWhderived No longer a slider. Under a scope-1 account the grid factor is a result of the generation mix, so the model computes it — about 1.7 gCO₂/kWh at the reference. That is a combustion figure and is not comparable with the 79 beside it, which is life-cycle: comparing the two is the most common way to make this model say something it does not say.
Methane227 gCO₂/kWh25 gCO₂/kWh That all 2050 methane is biomethane. Raising the slider back towards 227 shows what a failure of that assumption costs.
Liquid fuel264 gCO₂/kWh25 gCO₂/kWh That no fossil liquid fuel is left: every litre is biofuel or e-fuel.
Wood27 gCO₂/kWh0 gCO₂/kWh The biogenic-carbon convention. Note the workbook is not internally consistent here — it uses 27 for 2020 and 0 for 2050 for the same fuel.
Coal340 gCO₂/kWh, both years Coking coal at the IPCC default, 94.6 kgCO₂/GJ. Not a lever: it is a measured property of the fuel, not a scenario choice.
HydrogenDerived, not declared Hydrogen carries no factor of its own. It is converted back into the electricity used to make it, at 60% efficiency, and that electricity carries the electricity factor. The same holds for e-fuel at 40%.
Three corrections were made to the workbook's own accounting. Coal was charged at the hydrogen factor, 66.7 gCO₂/kWh, while the workbook's factor table declared it at zero and its 1.76 tCO₂ per tonne of steel already contained that same carbon — the coal was counted twice, and is now counted once, as energy. Gas used by steel and by grey ammonia was counted in the biogas resource but charged no emissions at all; all gas is now charged. And two legacy transport aggregations created about 32 TWh of electricity that no vehicle consumed; they are gone. Together these move the reference scenario from 47.2 to 40.6 MtCO₂. The Excel edition still contains all three.

Aviation — method, sources and what it leaves out

The ticket is built from the bottom: the energy the model already charges the flight, multiplied by a synthetic-fuel price, plus everything else derived from today's economics. Aviation matters more in the Spanish edition than in the French one, and the reason is on this page.

Distance comes from Eurostat's 2019 aviation statistics for flights departing Spain: passenger-kilometres divided by passengers, route group by route group. It is an average, so "intra-EEA and the United Kingdom" blends a Palma hop with a Helsinki sector. The departing basis matters: it is the convention the international-bunker memo item uses, and it is not the convention the French edition's own source uses, so the two countries' flight tables are not directly comparable in activity — only in energy.

Spain's tourism is in one number. 77.6 million departing passengers on intra-EEA-and-UK routes in 2019, against France's 38.9. Those flights are outside the Spanish inventory as a memo item and squarely inside this model's footprint.

Energy is the model's own aviation consumption, not a separate figure. Domestic aviation is the exception and it is worth knowing why: Spain's energy balance books 2 378 ktoe of domestic aviation for 2019, which would be 7.1 MtCO₂, while the Spanish inventory reports 3.14 MtCO₂ for the same thing. France's two agree to 4%, so this is a Spanish reporting artefact. The row is inside the inventory perimeter, so the inventory wins: using the balance instead would have put 15.6 TWh of phantom domestic flying into the Spanish account.

Domestic aviation is not what it is in France. 33.8 Gpkm on a mean stage of 796 km, because the Balearics, the Canaries, Ceuta and Melilla have no rail alternative at all. A slider that shifts domestic flights to rail cannot mean here what it means between Paris and Lyon.

Fuel price. The published estimates for sustainable aviation fuel disagree by a factor of six, and the review behind the two sliders spans EASA, the European Commission's ReFuelEU impact assessment, ISAE-Supaero, ATAG's Waypoint 2050, the IEA, Solakivi et al. (2022), Brynolf et al. (2020) and Massol et al. (2025). Bio-jet from waste oils is the cheapest route at 600–1 900 €/t; power-to-liquid the dearest at 1 800–10 000. The defaults sit mid-range and the ranges are the honest answer, which is why they are sliders.

Efficiency. The default gain is zero. The published trajectories converge on about 1%/year — ICAO, the IEA and the World Economic Forum's Clean Skies for Tomorrow all sit near it. Moving the slider to 1 compounds to a 27% saving over thirty-one years, which is less than most people expect and is the point of exposing it.

What this omits

Non-CO₂ effects — contrails and nitrogen oxides — which several studies put at the same order of magnitude again as the combustion CO₂; the upstream chain of the fuel; any change in airline cost structure between now and 2050; airport and air-traffic-control costs; and the question of whether the aviation demand itself should be a lever rather than a projection.

The rest of industry — Spanish structure, French assumptions

The seventeen branches the game does not model as value chains. For Spain the observed corner is rebuilt from the JRC's Spanish energy balance; everything about how it decarbonises is a French ratio, and that has to be said in the panel and not only in the sources.

What is Spanish

E00, the observed situation, is the JRC's 2021 Spanish energy balance by manufacturing branch and by carrier, with the five branches the game models explicitly removed so nothing is counted twice: iron and steel, cement, basic chemicals and food. Total 123 TWh of final energy against France's 174.

The Spanish branch structure is genuinely different. Minerals is Spain's largest rest-of-industry group at 35.8 TWh — the ceramics of Castellón, glass, lime and plaster — where France's largest is metals and machinery. Spanish minerals burn 18.0 TWh of gas and 7.7 of oil against France's 13.7 and 3.5, so the group is both bigger and dirtier, and the process lever has more to work on here.

What is French

E01, the horizon processes, is the French per-branch, per-carrier substitution ratio applied to the Spanish E00. E10 equals E00, because there is no Spanish industrial output index to 2050 — so the output lever does nothing in this edition and should be read as disabled rather than as saying Spanish industry does not grow. E11 follows.

The branch mapping was checked by running the same extraction on France and comparing with the French model: metals and machinery 0.85, minerals 1.03, other chemicals 0.79, paper 0.80, other industries 0.94. Two of five inside 15%. The differences are perimeter and they are identifiable — mining, quarrying and construction are excluded here because the French table comes from a manufacturing survey; the chemicals group is over-trimmed because removing basic chemicals removes chlorine and soda too; and paper biomass is counted differently because of black liquor.

The two process rows are the least trustworthy

They are national-inventory arithmetic: minerals is CRF 2A minus 2A1 (cement, already carried by the cement chain), 2.87 MtCO₂ in 2021; other chemicals is 2B minus ammonia minus petrochemicals, 1.14. The same construction on France over-states the French figures by 1.6 and 3.5, which means the French perimeter is narrower than "the inventory minus the modelled chains" and could not be reconstructed. The Spanish numbers are measurements on a stated perimeter; the French ones are not comparable with them.

Waste heat — a resource that decarbonisation consumes, and that Spain cannot carry

Industrial processes reject heat. Some of it can be recovered and used instead of burning more fuel. The usual way to model this is a fixed reserve in TWh, and that is wrong in a way that matters here.

Why the gisement shrinks

Waste heat is a by-product of combustion and of process inefficiency. An electric furnace or a heat pump rejects far less of it, and at lower temperature. So the more a scenario electrifies industrial heat, the smaller the waste-heat resource it has left to recover. Recovering waste heat and electrifying heat compete for the same physics, and a model that treats the gisement as a constant lets a player count the same energy twice.

The intensities are ADEME's, measured on French industry, and they are carried. The study expresses the gisement against the fuel each sector burns rather than as a bare total — 6.3% of fuel on average, from 1.2% in metals to 31% in paper, where drying dominates — so the model can attach them to the fuel, post by post, and let the gisement follow whatever the scenario actually burns. A Spanish cement kiln rejects heat in about the same proportion as a French one, which is why carrying a ratio is defensible where carrying a stock would not be. The named replacement is the sEEnergies family of European excess-heat datasets, which covers Spain and has not been explored.

The Spanish constraint the French study cannot express

Spain has no heat networks. The energy balance reports no derived heat in Spanish dwellings or services in any year, so the recovered heat this account finds has nowhere to go outside the factory that made it. Above 100 °C it can displace process heat on the spot; below, it needs a heat pump to upgrade it or a network to carry it somewhere useful, and Spain has neither costed nor built. Roughly half the gisement is below 100 °C, so a recovery rate above 50% implicitly assumes infrastructure that does not exist.

Conventions

Recovered heat displaces gas, the marginal fuel, and cannot displace more than the post burns. The second-order feedback — less gas means a slightly smaller gisement in turn — is neglected. Transport and buildings carry no gisement because the study is industrial. Nor is the capital cost of recovery represented anywhere in the cost layer.

Energy efficiency — a ceiling, not a wish

Motors, drives, compressed air, insulation, heat integration: the cross-cutting savings that need no change of process. The danger with a lever like this is that it lets a player invent efficiency, so it is bounded by what a published study actually found — and here the study is French, which is the caveat this panel exists to carry.

The ceiling, and whose it is

These ceilings are RTE's, after CEREN, measured on French industry. They are ratios rather than stocks — a percentage of the fuel or the electricity a process consumes — so they travel better than most things in this model: the physics of a compressor, a motor or a heat exchanger is not national. What is French is the starting point, the efficiency already captured, and Spanish industry's specific consumption is not French industry's. No Spanish equivalent was found; IDAE's sectoral studies or the audits collected under Real Decreto 56/2016 would replace them.

The study identifies a potential of 21.1% on industrial electricity and 19.8% on fuels, of which about 58% pays back in under three years. The electricity ceiling is branch-specific and applied as such:

PostElectricity ceilingof which under 3 years
Steel11.4%68%
Metals and machinery15.5%73%
Paper and board19.3%47%
Other industries23.6%66%
Minerals, cement24.1%40%
Food industry25.0%60%
Chemistry, ammonia, olefins31.1%38%

The lever says how much of that identified potential is captured, not how much exists. At 100% every branch reaches its own ceiling and no further; at about 58% the scenario is taking roughly the part that pays back in under three years, which is the honest "no-regrets" anchor to argue from in class.

Efficiency also destroys waste heat

Fuel that is never burned rejects no heat. So the efficiency effort shrinks the waste-heat gisement exactly as electrification does. Efficiency, electrification and waste-heat recovery all draw on the same combustion, and the model makes them compete rather than letting a scenario bank all three.

What is not represented

Only direct electricity carries the electricity ceiling. There is no branch breakdown on the fuel side, so one ceiling applies across industry. Transport and buildings are untouched, their own levers already carrying demand and equipment efficiency. And nothing here costs the investment that buys the efficiency.

Every input, with its provenance

This annex is generated from the model specification itself — model/technology.yaml, model/countries/ES/ES.yaml and model/equations.yaml — so what is documented here and what the engine executes are the same thing. The model has 121 levers, 233 constants, 25 data tables and 591 equations.

Published external statistic or study, cited · Workbook inherited from the teaching workbook, not independently re-sourced · Calibrated fitted so the module reproduces a reference baseline · Provisional plausible and widely quoted, but no primary publication secured · Game rule chosen by the teaching team to make the game work · Derived computed from other declared values, not an input in its own right

Levers — what the player can move

LeverDefaultRangeProvenanceWhy, and where it comes from
Fuel car
carFuel
10%0 … 100Game rule

Share of 2020 private-car demand still served by a liquid-fuelled car in 2050. The four car shares are rebalanced to 100% as the player moves them.

Biogas car
carGas
10%0 … 100Provisional

PLACEHOLDER — French value carried, not Spanish data: 10% is the French teaching workbook's horizon share for gas-fuelled cars. Spain's compressed-natural-gas fleet is proportionally larger than France's, so if anything the Spanish figure is higher. It cannot be moved from here alone: the four car shares must sum to 100% at their defaults and only this one is national, so changing it needs carFuel, carElectric and carRail made national too. What would close it: the DGT vehicle register by fuel and a PNIEC/ELP fleet trajectory.

  • countries/FR/FR.yaml, carGas — carried unchanged — Not a Spanish source. See NOTES.md under Placeholders.
Electric car
carElectric
70%0 … 100Game rule—
Shift to short-distance rail
carRail
10%0 … 100Game rule

Car demand transferred to short-distance rail, at the occupancy and unit consumption of the rail row rather than the car row.

Passenger mobility reduction
passengerReduction
0%0 … 45Game rule—
Domestic aviation → rail
domesticAviationRail
50%0 … 100Game rule—
Hydrogen truck
truckH2
20%0 … 100Game rule—
Residual thermal
truckThermal
10%0 … 100Game rule—
Electric truck
truckElectric
40%0 … 100Game rule—
Shift to rail freight
truckRail
30%0 … 100Game rule—
Freight-demand reduction
freightReduction
0%0 … 45Game rule—
Air freight → maritime
freightAviationSea
20%0 … 100Game rule—
Biofuel share
biofuelShare
40%0 … 100Game rule

In 2050 the model leaves no fossil liquid fuel at all: every litre is either biofuel or e-fuel made from electricity. This is a scenario assumption, and it is why liquid fuel carries a low emission factor.

Heat covered by electricity
bldgElectricShare
49%0 … 100Game rule

The headline decarbonisation choice for buildings, and the one that drives the winter peak. It is a share of heat need, not of energy: how that heat is produced is the next question down.

Biomass for heating
bldgBiomassTwh
17 TWh/y0 … 60Published

Wood burned for space heating, not heat delivered. Spanish households burned 61 507.9 TJ = 17.09 TWh of primary solid biofuels and renewable waste on space heating in 2023. The rest of Eurostat's "renewables and biofuels" aggregate is 8 748.1 TJ (2.43 TWh) of ambient heat harvested by heat pumps, which the model counts as heat-pump electricity and must not count twice, and 1 403.3 TJ (0.39 TWh) of solar thermal, which is not wood. The default is today's level, which is the neutral reading. The upper bound stays below Spain's whole national consumption of primary solid biofuels, 65.4 TWh in 2024. France's lever sits at 46 TWh — 2.7 times Spain's, on 1.6 times the dwellings. Wood heating is a rural French institution and much less of a Spanish one.

Air-air heat pump
bldgElecAirAir
47%0 … 100Game rule

Seasonal COP 2.5, falling to 2.0 at peak.

Air-water heat pump
bldgElecAirWater
31%0 … 100Game rule

Seasonal COP 3.0, falling to 2.0 at peak.

Electric resistance
bldgElecResistance
15%0 … 100Game rule

A slider rather than a stock that can only shrink, because a scenario may genuinely install more electric convectors — they are cheap to fit and terrible for the peak. Efficiency 1 in both seasons, so this is the one electric option that buys no COP at all.

Hybrid heat pump
bldgElecHybrid
4%0 … 100Game rule—
Heat pump on a network
bldgElecDistrictHP
3%0 … 100Game rule—
Wood in heat networks
districtWoodTwh
0 TWh/y0 … 10Published

Spain has no district heating to speak of, and that is measured rather than assumed. Three independent sources agree: Eurostat's household balance reports no derived heat in Spanish dwellings; JRC-IDEES reports zero dwellings and zero energy on "Distributed heat" for space heating in every year 2000-2021; and its services workbook reports zero building cells on distributed heat as well. The six district_* rows of building_segment are therefore exact zeros. The default is zero and the ceiling is deliberately low. A slider that let a Spanish player decarbonise heat through networks that do not exist would be a fiction, not a simplification; 10 TWh is roughly what the few hundred small biomass networks ADHAC counts could grow into, and it is offered as a build-from-nothing option rather than as a conversion of an existing fleet — which is the opposite of the French argument.

Recovered and waste heat
districtWasteTwh
0 TWh/y0 … 10Published

Recovered industrial and waste heat delivered through networks. Zero for the same reason as the wood row: there is no Spanish network fleet to deliver it into. Spanish industry does reject recoverable heat — the post table's waste-heat shares say how much — but with no network the model has nowhere to put it, and the honest ceiling is small.

Average retrofit improvement
bldgRetrofit
30%0 … 65Game rule

One slider conflates retrofit depth and retrofit rate, which have very different costs. Separating them is a documented next step.

Temperature-related sufficiency
bldgSobriety
5%0 … 25Game rule—
New housing built
newHousing
Hidden
0 Mm²/y0 … 36Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

Hidden and inert: this edition carries no cement intensity per square metre, so no floor area can reach its cement. Zero rather than the observed rate, because a number that moves nothing would invite a reader to quote it.

New non-residential built
newNonResidential
Hidden
0 Mm²/y0 … 36Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

Hidden and inert, for the same reason as newHousing.

Built in timber
timberShare
Hidden
0%0 … 80Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

Hidden and inert: with no floor area reaching cement, a timber share has nothing to displace.

Roads, networks and civil works
civilWorksVolume
Hidden
100%50 … 130Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

Hidden and inert: this edition's cement is all in the residual row, which no lever drives, so there is no civil-works tonnage for this index to multiply.

H-DRI steel share
steelDRI
50%0 … 100Game rule—
Steel production change
steelGrowth
30%-40 … 50Game rule—
Ammonia production
ammoniaProduction
175 kt/y0 … 600Provisional

DERIVED WITH A FRENCH INTENSITY, not a Spanish statistic. No Spanish ammonia production figure was reached. What was reached is the national inventory's process line for ammonia: CRF 2B1 is 0.2908 MtCO₂ for Spain in 2021 against 1.5167 for France. France's ammoniaProduction is 900 kt/y, so the same CO₂ per tonne gives Spain 900 × 0.2908 / 1.5167 = 173 kt/y, rounded to 175. Two reasons to distrust it and one to keep it. CRF 2B1 is reported net of the CO₂ that goes into urea, and the two countries do not make the same amount of urea, so the intensity is not identical. And Fertiberia's declared nameplate capacity — 400 kt/y at Palos de la Frontera and 200 kt/y at Puertollano — is over three times this figure, which is why the slider's maximum is 600 rather than something near the default. The reason to keep it is that the alternative is zero, and Spain plainly does make ammonia.

CO₂ + H₂ olefin route
olefinRoute
50%0 … 100Game rule—
Biogenic CO₂ share
biogenicCO2
10%0 … 50Game rule

Only the biogenic fraction of the CO₂ fed to the synthetic-olefin route counts as a removal, which is why this lever alone can turn the olefin process term negative.

Plastic-demand reduction
plasticReduction
30%0 … 70Game rule

How much less plastic the country asks for, against the base year — a demand reduction and not a recycling rate. It scales the olefin tonnage the crackers make and, since 0.28.0, the plastic the country's incinerators burn — which is where most of its effect now lies, and why it finally lowers emissions rather than raising them. It is the one lever in this chain that answers "how much of this do we need" rather than "how do we make it". The two French reference scenarios cannot anchor it. ADEME's Transition(s) 2050 publishes material-demand trajectories for steel, aluminium, cement and glass and none for plastics; its plastics content is an 80% recycling rate, and négaWatt does the same. Both express plastics as a rate of recycling, which since 0.33.0 is read on plasticRecycling, not here. What can is SYSTEMIQ's ReShaping Plastics, the one published pathway that separates the wedges. European plastic demand grows in its baseline, 37 to 48 Mt by 2050; its Circularity scenario takes 25% off that baseline by reducing demand and 4% more by substituting materials. Against 2050 that is 29%; against today it is under 10%, because a quarter of a growing baseline is a tenth of the present. This slider is written against the base year, so the two readings are the two ends of what one study supports — and the reference, 30%, sits at the far edge of the more generous one. The sectors move in opposite directions underneath: packaging can lose 38% (an eighth eliminated, a further three tenths reused), vehicles 22%, while construction plastic grows by half in every scenario published. A single national share hides that, and a player moving this slider is assuming the packaging wedge does all the work.

  • SYSTEMIQ (2022), ReShaping Plastics: Pathways to a Circular, Climate Neutral Plastics System in Europe, for Plastics Europe — EU27+UK, baseline 37→48 Mt by 2050; Circularity scenario 25% reduce + 4% substitute
  • ADEME, Transition(s) 2050 — material-demand trajectories for steel, aluminium, cement and glass; plastics carried as a recycling rate
  • See docs/waste/olefins_and_plastic_demand.md for the legal instruments (PPWR, SUP, loi AGEC, décret 3R) and why they do not bound this slider
Plastic kept out of the incinerators by recycling
plasticRecycling
0%0 … 75Game rule

The share of the plastic that reaches the incinerators in the base year which is sorted out and recycled instead. It is how the French reference scenarios express plastics: ADEME's Transition(s) 2050 and négaWatt both carry an 80% recycling rate, against 20% for all French plastic waste in 2022. If what is not recycled is burned, going from 20% to 80% leaves a quarter of today's burned plastic, which is 75 on this slider; the default, 0, is today's rate. Applied after plasticReduction: plastic not consumed is not there to recycle. Each tonne recycled costs 0.5 MWh of electricity, the middle of the 0.3–0.7 the JRC gives for mechanical recycling, booked on the waste-to-energy post because the model has no post for sorting and recycling. Three things it does not do. The recycled polymer does not displace any virgin olefin: the territorial inventory credits nothing unless French crackers actually make less, and the JRC discounts most recycled polymers to 0.6 of a virgin tonne. Sorting losses are not modelled — a recycling line rejects part of what it receives, and that refuse is burned or landfilled. And the plastic still in the residual bin is the hardest to recover: films, soiled and multilayer packaging, and the plastic in textiles and nappies.

  • SDES (September 2025), Bilan 2022 de la production de déchets en France, p. 4 — plastics recycling rate 20%
  • ADEME, Transition(s) 2050 — plastics carried as an 80% recycling rate
  • JRC (2023), Environmental and economic assessment of plastic waste recycling, EUR 31423, p. 54 — mechanical recycling 0.3–0.7 MWh of electricity a tonne; pp. 29–30, substitution factors (PP 0.6, HIPS 0.65, food-grade PET 1)
  • See docs/waste/plastics_and_incineration.md, §2.2
Capture on incinerators
wteCapture
0%0 … 90Game rule

The share of an incinerator's stack CO₂ that is captured and stored. A capture plant does not sort the molecules, so it takes the fossil and the biogenic CO₂ together — and about 60% of what leaves a French incinerator is biogenic. Capturing on an incinerator is therefore mostly bioenergy with carbon capture, which is the point worth teaching. Only the fossil part lowers the national total here. The biogenic part is shown and not counted: a captured biogenic tonne is a removal, and removals are what techSink already stands for — counting them here as well would book the same tonne twice. The hydrogen route does count its biogenic capture as negative, and the controversy table says why that is contested. 90% is the top because it is what the plants being built claim: 85% in the techno-economic literature, 87% at Oslo's Klemetsrud, 90% announced at Le Mans. Since 0.32.0 the capture is powered and paid for: 0.315 MWh of electricity a tonne captured, fossil or biogenic, which the mix has to produce, and 100 € a tonne for the plant plus 50 for transport and storage, in the cost tab. The biogenic tonnes are paid for and not counted, which is why a fossil tonne avoided here costs two and a half times a tonne captured.

Heat pumps for steam
foodHPSteam
60%0 … 100Game rule—
Heat pumps for direct heat
foodHPDirect
25%0 … 100Game rule—
Food-industry efficiency
foodEfficiency
20%0 … 50Game rule—
Less cement per unit of works
cementReduction
10%0 … 60Game rule

Renamed in v0.20, because it finally has a driver. Until then it was "cement-demand reduction" with no why, no help and nothing behind it: a scenario could take 60% off the country's cement without saying which building it had not built, and the annex could not say what the slider meant. How much is built is now the construction module's business. What is left here is the intensity of the works: leaner mixes, thinner slabs and post-tensioned structures, a design that uses the concrete it pours. It is not clinkerRate, which replaces clinker inside the cement with slag or fly ash; this one asks for less cement in the first place. The two multiply, and a scenario that pushes both is asking for a lot from the same building twice over. The range is a rule. The published levers for the sector are the clinker ratio and capture, and nobody has assessed how far structural design alone can go — so 60% is a bound on an argument rather than on an assessment.

Clinker ratio
clinkerRate
81%50 … 85Published

Spain's observed clinker-to-cement ratio is 81.4%, against France's 63.9%, and that one number changes the Spanish cement game. The model computes clinker as cement_base_production × clinkerRate, so a file that inherited France's default of 60% would understate Spanish clinker — and with it Spanish cement process emissions — by a quarter. At 81 the model makes 14 564 kt of clinker from 17 980 kt of cement, against the 14 634 kt Spain actually made in 2024: 0.5% out, which is the rounding of an integer-percentage slider. The default is today's value, the neutral reading. France's 60 is already a decarbonisation assumption rather than an observation, so the two defaults are not comparable. The floor of 50% is about what a heavily blended cement reaches with slag and calcined clay; the ceiling of 85% is a little above today, because a Spanish scenario that raises the ratio is one in which clinker exports grow, and Spain is a net exporter. Its high ratio is a structural fact, not an inefficiency: clinker exported is clinker not blended down at home.

CO₂ capture
carbonCapture
20%0 … 95Game rule

The share of a cement kiln's fossil stack that is captured: the decarbonation of the limestone and, since 0.29.0, the fossil part of the kiln fuel, because a capture plant on a cement stack does not sort the molecules. The biogenic CO₂ of the waste the kiln burns goes up the same stack and would be captured too; it is not credited, for the reason wteCapture gives. Until 0.27.0 the term this lever multiplied carried the kiln fuel under the name of calcination, and the same fuel was also charged through the energy account — emitted twice, captured once. In 0.27.0 it captured the calcination alone and was a floor; now it is the whole fossil stack. Since 0.32.0 it is powered and paid for: 0.54 MWh of electricity a tonne of clinker at 95%, which the mix has to produce, the capture plant's capital in the cost of clinker, and 50 € a tonne for transport and storage on everything it stores, biogenic included.

Waste-derived fuel in cement kilns
kilnAltFuel
85%0 … 95Published

The share of a kiln's heat that comes from waste rather than from petroleum coke and coal. French kilns were at 38% in 2015, 44% in 2021 and 52% in 2023, burning over a million tonnes of waste a year; the sector's roadmap takes it to 80% in 2030 and 85% in 2050, the default. About half of that waste is biomass, so the lever cuts the kiln's fossil CO₂ roughly half as fast as it moves: at 0% the whole heat is fossil, at 85% still 56% of it is. It does not take waste from the incinerators, and since 0.33.0 that is a finding rather than a gap. The refuse-derived fuel French kilns burn is made from the refuse of sorting lines — commercial waste, separate collection, bulky waste — and French policy keeps residual household waste out of it. Its alternative is landfill, not the incinerators, which are full and turned away half a million tonnes in 2022. The two would compete for the same tonne only once landfill is close to zero.

Output of the rest of industry
otherIndustryVolume
Hidden
0%0 … 100Published

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

How much the branches the game does not model produce, between today's output and the source workbook's 2050 scenario. That scenario is a reindustrialisation: measured branch by branch it multiplies textile output by 8.5, electronics by 3.1, mineral extraction by 2.5, while mineral chemistry falls to 0.52 and naval and aerospace to 0.56. Growth of that size is not decarbonisation, and separating it from the process lever is the whole point — otherwise a player could appear to clean up industry while assuming an eightfold textile sector.

Less output from the rest of industry
otherIndustrySobriety
0%0 … 40Provisional

Less of everything the rest of industry makes, branch by branch in the same proportion — metals, minerals, chemistry, paper and the rest — with its fuel, its electricity and its process emissions going down together. Added in 0.30 after students found that the rest of industry could only grow: otherIndustryVolume runs from today's output towards a reindustrialisation, and nothing ran the other way, although these branches carry two thirds of the methane a scenario cannot otherwise get rid of. The top of the range is the one French pathway that contracts industry: ADEME's Génération frugale cuts industrial production by 38% by 2050, because people buy fewer, longer-lived goods. Provisional, because that figure is read from summaries of the study rather than from its industry chapter. And one thing this lever cannot tell apart: a scenario in which France buys less, and one in which France makes less and imports the rest. The territorial account cannot tell them apart either; the first is sufficiency, the second is leakage.

  • ADEME (2021), Transition(s) 2050, scenario S1 Génération frugale — industrial production −38% by 2050, as reported in summaries of the study
Processes of the rest of industry
otherIndustryProcess
100%0 … 100Published

How much energy each unit of output takes, between today's processes and the 2050 ones. This is where electrification lives: at constant output it takes the electricity of these branches from 68 to 138 TWh while cutting coal and fuel oil to zero. The default is 100% and the volume default is 0%, so the reference scenario reads "the rest of industry modernises at today's output" — the neutral reading, with growth added explicitly.

  • Offre_et_demande.xlsx, branch sheets E18–E38 — unit consumption in MWh per tonne, 2019 and 2050
Waste-heat recovery
wasteHeatRecovery
0%0 … 100Published

Heat rejected by industrial processes and recovered instead of vented. ADEME puts the recoverable gisement at 15.6 TWh on the 2019 industry, of which 7.7 TWh above 100 °C, and — this is what makes it a real constraint — expresses it against the fuel each sector burns. So the gisement is not a fixed reserve: it shrinks as processes electrify, because there is no combustion left to reject heat from. Recovering waste heat and electrifying heat compete for the same physics, and the model makes them compete.

Energy-efficiency effort
industryEfficiency
0% of the identified potential0 … 100Published

Cross-cutting energy efficiency — motors, drives, compressed air, insulation, heat integration. RTE, after CEREN, identifies a potential of 21.1% on industrial electricity and 19.8% on fuels, of which about 58% pays back in under three years. The ceiling is branch-specific and applied as such: 11.4% for steel, 15.5% for metals and machinery, 19.3% for paper, 24.1% for minerals, 25.0% for the food industry, 31.1% for chemistry. This lever says how much of that identified potential is actually captured, not how much exists — so it cannot invent efficiency beyond what the study found, which is the point of a ceiling.

Methane (biogas), 2050
efGas
25 gCO₂/kWh0 … 250Provisional

PLACEHOLDER — French value carried, with a Spanish argument for it rather than a Spanish measurement. 25 gCO₂/kWh encodes "the 2050 gas system is biomethane". The Spanish basis for that is the ELP 2050's own headline — 97% of final energy from renewables in 2050 — and the Hoja de Ruta del Biogás, which sets a national biogas objective this pass did not fetch. What would replace it: that roadmap's 2030 objective extended to 2050 against the Spanish gas demand this model computes, which would say what share of the methane can actually be biogenic. The assumption is stronger in Spain than in France, and it should be argued in the interface rather than inherited: Spain's gas system is large relative to everything else, it is fed by LNG from Algeria, the United States and Nigeria, and Spanish biogas production today is 4.36 TWh against a gas demand an order of magnitude larger.

Liquid fuel (bio and e-fuel), 2050
efLiquid
25 gCO₂/kWh0 … 300Provisional

PLACEHOLDER — French value carried, not Spanish data: 25 gCO₂/kWh for 2050 liquid fuel, on the same reasoning as the methane row. Spain has no published 2050 liquid-fuel emission factor. What would close it: the Spanish share of advanced biofuels and e-fuels in the PNIEC's transport chapter, or the ELP's own liquid-fuel assumption, neither of which states a factor. Spain's liquid demand at the horizon is dominated by aviation and maritime bunkers — 140 TWh of them in 2019, more than road freight — so this factor is worth more here than in France, and it is the least Spanish number in the file.

Wood, 2050
efWood
27 gCO₂/kWh0 … 60Provisional

PLACEHOLDER — French value carried, not Spanish data: 27 gCO₂/kWh is the fossil energy of the French wood chain, from felling to delivery. What would close it: a Spanish life-cycle factor from IDAE or AVEBIOM, or a Spanish entry in an LCA database. Neither was fetched. It should not be assumed equal. Spanish firewood travels further on average than French, Spain imports a larger share of its pellets, and the quantity it multiplies is smaller — 17 TWh against France's 46 — so an error of the same relative size moves a third as much here.

Aviation efficiency gain
aviationEfficiency
0%/y0 … 2Published

Kerosene per passenger-kilometre, improving each year through aircraft renewal, seat density and load factor. Published trajectories converge tightly on 1%/year: ICAO 1.0, ADEME 1.0, T&E 0.9, the UK Committee on Climate Change 0.9, the World Economic Forum's Clean Skies for Tomorrow 1.0, against 2.5 in the more optimistic ICSA figure. The default is 0 because the source workbook uses today's consumption for 2050 — moving the slider to 1 shows what a quarter-century of fleet renewal is worth, and it is worth less than most people expect.

Air-traffic growth
aviationDemandGrowth
0%/y-1.5 … 3.5Published

Passenger-kilometres, compounded over thirty years. The source workbook carries 2020 demand straight through to 2050, which is a growth assumption of zero and a very strong one — no published trajectory says that. For flights departing France the DGAC roadmap gives 1.62%/year falling to 1.19, or 1.8 without a price effect and 0.8 with one; ADEME spans −1.3 to +3.0 depending on scenario and price effect; Eurocontrol gives 3.3 then 1.7. World figures are higher still: ICAO 1.1 to 3.4, Airbus 2.6, Boeing 5.6 falling to 2.5. At 1.5%/year over thirty years traffic grows by 56%, which is worth more than every efficiency gain in the sector combined.

Bio-jet fuel
safBioPrice
2 000 €/t600 … 4 000Published

Sustainable aviation fuel from biomass. The published estimates disagree by a factor of six, and which route is assumed matters as much as who estimated it: HEFA from waste oils 600–1 900 €/t, biomass-to-liquid 1 400–2 900, alcohol-to-jet 750–3 900. The default sits mid-range across the three. The width of that range is the honest answer, which is why this is a slider and the range is printed beside it.

E-jet fuel (power-to-liquid)
safEfuelPrice
5 000 €/t1 500 … 10 000Published

Synthetic kerosene from electrolytic hydrogen and captured CO₂. Estimates range from 1 820 €/t (European Commission) to 10 000 (DGAC), with the review's central band at 3 700–6 200. Direct air capture costs more than biogenic CO₂: EASA gives 7 300–8 700 €/t for atmospheric CO₂ against 6 600–7 975 for biogenic.

Fuel share of airline operating cost
fuelShareOperating
30%15 … 40Published

Everything that is not fuel — aircraft, crew, airport charges, maintenance, overheads — is assumed unchanged in 2050 and is derived from today's ticket through this share. It is the weakest link in the ticket calculation: a 2050 airline may well have a different cost structure, and nothing here models that.

Agriculture pathway position
agriPathway
100%0 … 100Game rule

Position on the Spanish agriculture pathway, from the 2024 inventory (42.24 MtCO₂e) to the ELP 2050 level (14.03). The default sits on the strategy, as in France, so the reference scenario is the country's own plan rather than a judgement about it. The ELP does not separate agriculture from waste; the two are split in the PNIEC's own 2030 ratio. See ES.official.yaml, which shows the arithmetic.

Waste pathway position
wastePathway
100%0 … 100Game rule

Position on the Spanish waste pathway, from 17.29 MtCO₂e in 2024 to 5.58 in 2050. Spanish waste emissions are above their 1990 level (13.27) and still rising, where French waste emissions have fallen: Spain landfills far more of its municipal waste than France incinerates, so this pathway asks for a bigger change than its French counterpart even though it starts from a smaller absolute number.

Natural carbon sink
naturalSink
37 MtCO₂e/y absorbed15 … 60Published

A signed magnitude of absorption: 37 MtCO₂e absorbed in 2050 is the ELP's own figure, stated in the same sentence as the 29 MtCO₂e of residual emissions. Positive absorbs. Spain's official pathway weakens its sink, and the slider should make that visible: the observed 2024 LULUCF balance is −51.9 MtCO₂e, the PNIEC's 2030 objective is −43.6, and the ELP's 2050 figure is −37. The default therefore sits below today's observation, which is the opposite of the French arrangement, and a player who wants a stronger sink has to argue for it. The range spans a badly degraded Mediterranean forest (15) to a sink stronger than any year on record (60).

Technological carbon sink
techSink
0 MtCO₂e/y absorbed0 … 30Published

Zero, and that is the single most interesting difference between the Spanish and the French games. Spain's published 2050 account closes on natural sinks alone — 37 MtCO₂e absorbed against 29 emitted, so the ELP is net −8 MtCO₂e — and the strategy names no technological removals at all. France's published account implies 43 MtCO₂e a year of capture as a closure residual, and its own controversy table calls the line the largest assumption in the model; the French game opens at 30 and marks the slider red past 20. Spain does not need the line at all. The slider still goes to 30, because a Spanish player should be able to add capture and see what it costs; it starts at zero because nothing Spanish plans it.

Flagged above 20 MtCO₂e/y absorbed. Twenty megatonnes a year, for Spain alone, is around half of everything the planet currently captures and stores, across every facility in operation — and the ELP 2050 asks for none of it, closing its account on natural sinks alone. Nothing in this model builds the plant, supplies the electricity the capture consumes, or pays for either.

Land taken for building
artificialisationRate
Hidden
12 kha/y0 … 52Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: the rate at which land is built on, in thousand hectares a year. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
New forest planted
afforestationRate
Hidden
15 kha/y0 … 90Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: the rate at which new forest is planted, in thousand hectares a year. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Grassland to crops
grasslandConversion
Hidden
0 kha/y-50 … 100Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: the net rate at which permanent grassland is ploughed into arable land. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Store carbon in the soil
soilCarbonPractices
Hidden
30%0 … 100Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: the share of the identified agricultural soil-carbon potential taken. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Wood harvested
forestHarvest
Hidden
60 Mm³/y40 … 75Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: the volume of wood removed a year, informal firewood included. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Wood into long-lived products
harvestToProducts
Hidden
30%15 … 35Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: the share of the harvest that becomes sawn timber and panels. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Drained peatland rewetted
peatRewetting
Hidden
0%0 … 100Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the share of the drained organic soil put back under water. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Climate effect on the forest
forestClimate
Hidden
21 … 3Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not Spanish data: which of three published climate cases the forest lives through. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Red meat eaten
dietRedMeat
Hidden
40 kgec/cap/y15 … 60Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: red meat eaten per person, in carcass-weight equivalent. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Poultry eaten
dietPoultry
Hidden
28 kgec/cap/y10 … 35Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: poultry eaten per person, in carcass-weight equivalent. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Dairy eaten
dietDairy
Hidden
90%50 … 110Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: dairy eaten per person, as an index on the base year. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Cut edible food waste
foodWaste
Hidden
0%0 … 50Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: how much of today's edible food waste is cut. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Livestock exports
livestockExport
Hidden
100%0 … 150Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: animal produce exported, as an index on base-year volumes. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Crop exports
cropExport
Hidden
100%0 … 150Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: arable crops exported, as an index on the base-year volume. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Mineral nitrogen
nIntensity
Hidden
70%40 … 110Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: mineral nitrogen delivered to the fields, as a share of the base year. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Legumes in the rotation
legumeArea
Hidden
2.7 Mha1 … 3Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: legumes in the rotation, in million hectares. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Organic farming
organicShare
Hidden
25%0 … 50Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the organic share of the arable area. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Cattle on low-methane rations
entericMitigation
Hidden
82%0 … 100Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the share of cattle on a low-methane ration. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Manure to digesters
manureMethanised
Hidden
0%0 … 80Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the share of manure sent to a digester rather than to a store. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Get fossil fuel off the farm
agriFuelSwitch
Hidden
100%0 … 100Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the fossil fuel taken off the farm. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Nitrogen made at home
ammoniaDomesticShare
Hidden
34%0 … 100Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the share of mineral nitrogen made inside the country. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Winter energy cover crops
civeArea
Hidden
2.5 Mha0 … 3Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the area of winter cover crop grown for a digester, in million hectares. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Crop residues taken off the field
residueMobilisation
Hidden
16%0 … 30Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the share of crop residues carried off the field for energy. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Land growing fuel
energyCropArea
Hidden
0.62 Mha0 … 1.7Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the arable area growing a first-generation biofuel crop, in million hectares. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Land growing methane
energyMaizeArea
Hidden
0 Mha0 … 0Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the arable area growing a main crop for a digester, in million hectares. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Imported biofuel allowed
bioImports
Hidden
20 TWh/y0 … 40Provisional

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

PLACEHOLDER — French bounds carried, not national data: the liquid biofuel the scenario allows itself to import, in TWh a year. Inert in this edition, and drawn nowhere, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Hot-water efficiency
usageDhwEfficiency
0%0 … 40Game rule—
Cooking efficiency
usageCookingEfficiency
0%0 … 40Game rule—
Hot water on electricity
usageDhwElectric
25%0 … 100Derived

The observed electric share of Spanish domestic hot water: 15 545.5 TJ of electricity out of 126 795.0 TJ for water heating in 2023, i.e. 12.3% of the energy — but the model's lever is the share of the service, and an electric water heater converts at about twice the efficiency of a gas one on the model's own convention. Correcting for that gives about 25% of the hot water actually delivered. France's figure is 68%. Spanish hot water is a gas and butane business: natural gas 56 578 TJ, oil products (mostly LPG) 39 958, renewables and solar thermal 14 713. Spain has more solar thermal on its roofs than any other large European country and it still heats most of its water with a flame.

Cooking on electricity
usageCookingElectric
70%0 … 100Derived

The observed electric share of Spanish cooking: 25 038.4 TJ of electricity out of 47 321.3 TJ in 2023, i.e. 52.9% of the energy, and about 70% of the service once the efficiency of an induction hob is set against a gas ring on the model's own convention. France's figure is 61%. Spanish kitchens electrified earlier and further than French ones, and the remaining 9 204 TJ of oil products is bottled butane — a fuel France has almost eliminated from its kitchens and Spain has not.

Air-conditioning growth
usageCoolingGrowth
0%0 … 300Game rule

12.0 TWh — 3.87 residential and 8.13 tertiary — against France's 24, which is the single most counter-intuitive number in the Spanish package: Spain is hotter than France and cools with half the energy, because the French figure carries a much larger tertiary stock and because Spanish residential air conditioning is heavily seasonal and often room-level. The asymmetry France declares is worse here than anywhere: cooling makes a summer peak, Spanish summer peaks are the ones that bind the Spanish system, and the only peak constraint in this model is a winter one. A Spanish edition that took the peak score seriously would have to add one.

Appliance efficiency
usageSpecificEfficiency
0%0 … 50Game rule

Lighting, appliances, screens and servers. It is the lever that has historically delivered — French specific consumption has been roughly flat for a decade while the equipment count rose — and here it is set against the growth lever below, which is the whole point of having both.

Digital and equipment growth
usageSpecificGrowth
0%-20 … 150Game rule

The counterweight to appliance efficiency. Data centres and AI are the part of this that is growing fastest and the part the model is least able to source, so it is left as an explicit assumption rather than given a trajectory it cannot defend.

Gas plants run on hydrogen
gasPlantHydrogen
0%0 … 100Game rule

RTE keeps a few GW of combustion capacity in every 2050 scenario, for the windless fortnight that no amount of storage covers. What it burns is a choice: methane, which draws on the same biomethane everything else wants, or hydrogen, which draws on electricity instead and emits nothing at the stack. Hydrogen is much the dearer of the two, and the model charges it: the electrolytic price the industry module already computes, against a methane price. What it does not do is add the electrolysis back into the electricity the mix has to serve — that would be a fixed point the compiler cannot express, since demand sets the mix and the mix would set demand. The extra electricity is reported instead of hidden.

Electrolysis
h2Electrolysis
100%0 … 100Game rule

The model assumed this for every tonne of hydrogen until v0.12.0, which was a strong assumption wearing no clothes: 87 TWh of electricity for hydrogen, and no way to ask what a reformer would cost instead.

Steam methane reforming
h2Smr
0%0 … 100Game rule

A reformer burns and reforms methane. In this model 2050 methane is biomethane, so the colour of the hydrogen depends on the colour of the gas — and it draws on the same biomethane pool as everything else, which is the trade-off worth seeing.

Autothermal reforming with capture
h2AtrCcs
0%0 … 100Game rule

ATR concentrates the CO2 in one stream, which is why it captures at 94% where a reformer with post-combustion capture struggles past 60%. On biomethane this goes negative, and that is not a trick of the accounting: the carbon came out of the air last season and is being put underground. It is also the single most contested line in the model — see the controversy tab — because it makes a scenario's arithmetic depend on a biomass supply chain the model does not represent.

Electricity mix scenario
rteScenario
31 … 6Published

Six Spanish mixes, ordered by increasing firm thermal generation — which is the Spanish axis, because the French one does not exist here. There is no nuclear question in Spain: the ordered closure plan retires all seven reactors between 2027 and 2035, and every mix from position 1 to position 5 has zero nuclear. What the slider moves instead is how much dispatchable gas a 2050 Spanish system still runs, from none at all to the 10% the 2030 plan has. Position 3, Distributed Energy 2050, is the default: a published 2050 mix from a pan-European study, with a residual firm fleet so the gasPlantHydrogen lever has something to act on. Position 1 is the national strategy's own outcome and has no firm capacity at all, which is more optimistic than RTE's 100%-renewable M0 and is worth saying. Three of the six are not 2050 mixes. Positions 4 and 5 are 2040 and position 6 is 2030. National Trends+ has no 2050 run — it is the NECP-based scenario and the plans stop earlier — so a 2040 row is the only honest way to offer it. Any label that calls the whole table "2050" is wrong about half of it.

LFP share of batteries
batteryLfpShare
0%0 … 100Game rule

The chemistry choice, and the sharpest trade-off in the account. LFP carries almost no cobalt (7 grams per MWh against 27 kg) and a quarter of the nickel, but 4.4 times the lithium — 490 kg per MWh against 111. There is no chemistry that is cheap in every metal at once, which is the point of putting it on a slider. Zero by default because the source scenario's 2050 reference is NMC 811.

Industry discount rate
discountIndustry
8%2 … 15Published
Residential discount rate
discountResidential
4%0 … 10Game rule

A household and an industrial investor do not face the same cost of capital. Moving this rate from 4% to 8% raises the building indicator by about a third with no physical change at all, which is why it is a lever and not a hidden constant.

Carbon price
carbonPrice
150 €/tCO₂0 … 300Published
Industrial electricity price
elecPriceIndustry
100 €/MWh20 … 200Published

101.6 €/MWh, the Spanish price for an industrial consumer taking 20 000-69 999 MWh a year, excluding recoverable taxes, first half of 2025; the smaller 2 000-19 999 MWh band pays 111.5. France on the same call pays 92.8 and 116.4, so Spanish and French industry pay within about 10% of each other on the large band — which is itself worth showing, because the Spanish argument for electrifying industry is usually made on cheap solar rather than on cheap tariffs. The two numbers are not the same quantity. France's 70 €/MWh is a POMMES 2050 model output, and this is a 2025 observation used as a 2050 assumption. What would close it: a Spanish 2050 industrial electricity price from the ELP's or the PNIEC's own modelling.

Deep-retrofit cost
retrofitCost
550 €/m²200 … 900Provisional

PLACEHOLDER — French value carried, not Spanish data: 550 €/m² is an ADEME order of magnitude with no primary publication behind it even in France. Spanish renovation labour and materials are cheaper than French ones, so this number is very likely too high for Spain — the opposite direction from Germany, which is worth saying because the three editions carry the same figure. What would close it: IDAE's aid schedules, which publish reference costs per square metre by measure for the renovation programmes.

  • countries/FR/FR.yaml, retrofitCost — carried unchanged — Not a Spanish source. See NOTES.md under Placeholders.
Liquid fuel at the pump
liquidFuelPrice
200 €/MWh80 … 400Provisional

PLACEHOLDER — French value carried, not Spanish data: 200 €/MWh is an unsourced French 2050 pump price for biofuel and e-fuel, taxes included, and the model's own annex calls it the weakest number in the cost layer. Spanish fuel duty is markedly lower than French, so a Spanish pump price built the same way would be lower. What would close it: the CNMC or MITECO fuel price series and a Spanish 2050 renewable-fuel case.

  • countries/FR/FR.yaml, liquidFuelPrice — carried unchanged — Not a Spanish source. See NOTES.md under Placeholders.
Travel less
simpleTravelLess
Coarse control
0%0 … 100Game rule

The passenger sufficiency control. At 100% it removes 45% of passenger travel and takes air traffic from the workbook's implicit 0%/y to -1.5%/y — the two demand assumptions the transport module is most sensitive to, moved together because a scenario that flies as much as today while driving 45% less is not a coherent story about sufficiency.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Passenger mobility reduction passengerReduction: 0% → 45%
  • Air-traffic growth aviationDemandGrowth: 0%/y → -1.5%/y
Electric cars instead of fuel cars
simpleCarElectric
Coarse control
0%0 … 100Game rule

Moves the 20% of 2020 car demand still served by a liquid- or gas-fuelled car in the reference onto the electric fleet. The rail transfer is left where it is: electrifying the fleet and shifting trips off it are two different decisions, and folding them together would hide which one paid.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Fuel car carFuel: 10% → 0%
  • Biogas car carGas: 10% → 0%
  • Electric car carElectric: 70% → 90%
Get the diesel out of freight
simpleTruckClean
Coarse control
0%0 … 100Game rule

The reference already leaves only 10% of road freight thermal, so this is a small lever by construction, and that is the lesson: on the workbook's own trajectory the remaining road-freight emissions are not where the tonnes are. Hydrogen trucks are left alone, because arbitrating between hydrogen and battery is a detailed-view argument, not a coarse one.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Residual thermal truckThermal: 10% → 0%
  • Electric truck truckElectric: 40% → 45%
  • Shift to rail freight truckRail: 30% → 35%
Off the plane — rail and sea instead
simpleFlyLess
Coarse control
0%0 … 100Game rule

Modal shift away from aviation, which is where the transport module's residual emissions concentrate once the fleet is electric. Distinct from "travel less": this one moves the same journeys onto another mode rather than removing them.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Domestic aviation → rail domesticAviationRail: 50% → 100%
  • Air freight → maritime freightAviationSea: 20% → 100%
Heat less
simpleHeatLess
Coarse control
5%5 … 25Game rule

The building sufficiency control, in the unit of the lever it drives because it drives only that one. It starts at the reference 5% rather than at zero: the simple view offers effort beyond the reference scenario, never less than it.

Moving this control from 5% to 25% moves, in step and in proportion:

  • Temperature-related sufficiency bldgSobriety: 5% → 25%
Renovate the building stock
simpleRenovate
Coarse control
30%30 … 65Game rule

As with sufficiency, this is the stock-performance lever shown in its own unit and bounded below by the reference scenario. 65% across the whole stock is the upper end the workbook contemplates, not a technical limit.

Moving this control from 30% to 65% moves, in step and in proportion:

  • Average retrofit improvement bldgRetrofit: 30% → 65%
Build less, and in timber
simpleBuildLess
Coarse control, hidden
0%0 … 100Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

The materials side of the building question, and the one control in the simple view whose whole interest is how far it cannot reach. At 100% the country builds 8 Mm² of housing and 8 of everything else a year instead of 20.4 and 19.9 — the order of magnitude the official housing-need study reaches for the 2040s — and frames 60% of it in timber instead of 12%. Together those take roughly a quarter off national cement demand. They take far less off steel, because new buildings are about a ninth of it; and they cannot touch the third of cement that is roads, buried networks and bridges, nor the third that nobody has attributed. Two ideas in one control is a deliberate departure. Building less and building in timber are different decisions, and the detailed view keeps them apart; here they are bundled because they are the same material choice seen from a distance, and because a simple view that separated them would have spent two of its dozen controls on one question.

Moving this control from 0% to 100% moves, in step and in proportion:

  • New housing built newHousing: 0 Mm²/y → 8 Mm²/y
  • New non-residential built newNonResidential: 0 Mm²/y → 8 Mm²/y
  • Built in timber timberShare: 0% → 60%
Heat pumps instead of boilers
simpleHeatPumps
Coarse control
0%0 … 100Game rule

Electrification of heating, with the two consequences that make it a real choice rather than a free win. The wood boilers go with the gas ones, because 95% electric plus 46 TWh of wood would allocate more heat than the stock needs; the resistance heaters go into air-water heat pumps, because electrifying on resistance is what makes the winter peak unmanageable. The peak still rises sharply, and that is the point of the control. Pushing sufficiency and renovation at the same time shrinks the heat need under a fixed 95% share, so the building readout may report over-allocated heat; the model reports it rather than absorbing it.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Heat covered by electricity bldgElectricShare: 49% → 95%
  • Biomass for heating bldgBiomassTwh: 17 TWh/y → 0 TWh/y
  • Electric resistance bldgElecResistance: 15% → 0%
  • Air-water heat pump bldgElecAirWater: 31% → 46%
Electrify hot water and cooking
simpleElectrifyUsages
Coarse control
0%0 … 100Game rule

Hot water and cooking are about as much energy again as space heating, and neither is fully electric today. Their observed electric shares are the starting points, 100% the end.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Hot water on electricity usageDhwElectric: 25% → 100%
  • Cooking on electricity usageCookingElectric: 70% → 100%
Consume less material
simpleConsumeLess
Coarse control
0%0 … 100Game rule

The industrial sufficiency control. Freight demand is driven here rather than in transport on purpose: freight is what material consumption looks like on a road, and a scenario that halves plastic and cement demand while moving the same tonne-kilometres is not consistent. Steel goes from +30% to -40% against 2020, which is the widest swing any single number in the game commands. The output of the rest of industry is not driven, because its scale starts at today's output and has nowhere lower to go.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Plastic-demand reduction plasticReduction: 30% → 70%
  • Less cement per unit of works cementReduction: 10% → 60%
  • Steel production change steelGrowth: 30% → -40%
  • Freight-demand reduction freightReduction: 0% → 45%
Change the industrial processes
simpleCleanProcesses
Coarse control
0%0 … 100Game rule

Every route change the five value chains offer, moved together: H-DRI steel, the CO2 + H2 olefin route and the biogenic carbon it uses, heat pumps for food-industry steam and direct heat, the lowest clinker ratio in range, and capture on what is left. The processes of the rest of industry are not driven, because the reference already sits at 100% of them.

Moving this control from 0% to 100% moves, in step and in proportion:

  • H-DRI steel share steelDRI: 50% → 100%
  • CO₂ + H₂ olefin route olefinRoute: 50% → 100%
  • Biogenic CO₂ share biogenicCO2: 10% → 50%
  • Heat pumps for steam foodHPSteam: 60% → 100%
  • Heat pumps for direct heat foodHPDirect: 25% → 100%
  • Clinker ratio clinkerRate: 81% → 50%
  • CO₂ capture carbonCapture: 20% → 95%
Use less energy for the same output
simpleIndustryEfficiency
Coarse control
0%0 … 100Game rule

Efficiency rather than sufficiency or fuel switching: the same product, less energy. At 100% it claims the whole potential RTE identifies and recovers all of the recoverable waste heat, neither of which is costless or instantaneous — the cost panel and the annex say what that means.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Energy-efficiency effort industryEfficiency: 0% of the identified potential → 100% of the identified potential
  • Waste-heat recovery wasteHeatRecovery: 0% → 100%
  • Food-industry efficiency foodEfficiency: 20% → 50%
Eat less meat
simpleEatLess
Coarse control, hidden
0%0 … 100Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

The demand end of the food chain, moved as one plate. At 100% red meat falls from 40 to 20 kgec/cap/y — below INRAE's −40% and above ADEME's S1 divide-by-three — poultry from 28 to 18, dairy to 70% of the base year and the edible waste by the SNBC 3's own half. Exports are deliberately left alone: what a country sells is a separate argument from what it eats, and folding them together would let a diet lever cut a herd that is producing for somebody else's plate. The lesson is in the coupling rather than in the total. Two fifths of French beef is a by-product of the dairy herd, so cutting the milk makes the suckler herd grow to meet a beef demand that has not moved; only moving both together shrinks the cattle. A player who moves this control and watches the grassland released is watching the land account answer a food question, which is what the module is for.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Red meat eaten dietRedMeat: 40 kgec/cap/y → 20 kgec/cap/y
  • Poultry eaten dietPoultry: 28 kgec/cap/y → 18 kgec/cap/y
  • Dairy eaten dietDairy: 90% → 70%
  • Cut edible food waste foodWaste: 0% → 50%
Plant and protect the forest
simplePlantForest
Coarse control, hidden
0%0 … 100Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

The sink side of the land account. At 100% the forest expands at the 90 kha/y IGN's inventory measures rather than the 15 the SNBC 3 plans, the harvest falls from 60 to 45 Mm³/y, the long-lived share of what is still cut rises from 30 to 35%, and artificialisation stops entirely — the Climat et Résilience law's 2050 destination, on this account's own measure. It is the control that most obviously costs something, and that is the point: the forest takes k out of the living stock for every cubic metre cut, 1.5 tCO₂ in France, so every cubic metre not cut deepens the sink and leaves the boiler. Pushed to the top this control takes about a fifth off the wood the scoreboard scores — 127 TWh to 102 — and a scenario that has also electrified its heating will not notice while one that leaned on wood will. The climate case the forest lives through is not driven: it is a scenario choice rather than an effort, it moves the answer further than any of these four, and it stays a fine lever the simple view draws on its own.

Moving this control from 0% to 100% moves, in step and in proportion:

  • New forest planted afforestationRate: 15 kha/y → 90 kha/y
  • Wood harvested forestHarvest: 60 Mm³/y → 45 Mm³/y
  • Wood into long-lived products harvestToProducts: 30% → 35%
  • Land taken for building artificialisationRate: 12 kha/y → 0 kha/y
  • Drained peatland rewetted peatRewetting: 0% → 100%
Fertilise less
simpleFertiliseLess
Coarse control, hidden
0%0 … 100Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

The field end of the farm. At 100% the mineral dose on the conventional hectares falls to 50% of the base year and half the arable land goes organic, which between them deliver 26% of the 2024 nitrogen — well below the SNBC 3's own −54% and short of TYFA's zero — the legumes reach the 3.0 Mha the rotation studies stop at, and the whole 17.3 MtCO₂/y of soil-carbon practice INRAE itemises is taken. Four consequences are worth watching rather than assuming. The organic half yields two thirds of what it replaces, and since 0.24.0 the conventional half, at half the 2024 dose, keeps 0.79 of its yield — it is below the plateau — so this control costs arable land: the fields the same plates, herd and exports need grow by more than a third, and the crop block reports the shortfall, 4.2 Mha at 100%, against the land account rather than closing it — fertilising less is not free of land, and the page says by how much. Mineral nitrogen is also an industrial decision here: the same tonnage sets the ammonia the chain has to make, so fertilising less is a hydrogen saving as well as a nitrous-oxide one. More legumes raise the nitrogen balance while lowering the emissions — a legume hectare fixes more nitrogen than the mineral fertiliser its credit replaces, and only the difference between the two emission factors makes the net move downwards, so the balance is not a proxy for the tonnes. And the soil-carbon target is a thirty-year rate on a stock that saturates: the practice has to be kept up after 2050 for the carbon to stay where this account puts it.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Mineral nitrogen nIntensity: 70% → 50%
  • Legumes in the rotation legumeArea: 2.7 Mha → 3 Mha
  • Store carbon in the soil soilCarbonPractices: 30% → 100%
  • Organic farming organicShare: 25% → 50%
Grow energy on the fields
simpleGrowEnergy
Coarse control, hidden
0%0 … 100Game rule

Not shown in this edition. This country's package hides the control; the model reads the lever at the default in the next column.

The supply side of the biomass the rest of the game spends. At 100% the winter cover crops reach 3.0 Mha, the straw taken off the field reaches 30% — Agro-Transfert's ceiling for less than 2.5% of soil carbon lost — and the land growing fuel reaches 1.70 Mha, nearly three times today's and the IGEDD mission's own upper case. Between them they take the methane supply from 70 to about 86 TWh and the domestic liquid supply from 24 to 52. Two things this control does not do. It does not send manure to a digester: manureMethanised sits at 0 in the reference because the abatement it books rests on an enteric/manure split no French inventory publishes, and burying that argument inside an effort scale would be the wrong place for it. And the fuel crops it plants add no mineral nitrogen, because the dose is an intensity on an arable area held at the base year's: a fuel hectare displaces a food hectare that was already fertilised. The crop block counts the displaced food — the fuel hectare is arable land the plates, the herd and the exports can no longer use, and the headroom says by how much — but the fuel hectare itself adds no nitrogen and no nitrous oxide. That is the module's largest structural simplification and it sits directly under this control.

Moving this control from 0% to 100% moves, in step and in proportion:

  • Winter energy cover crops civeArea: 2.5 Mha → 3 Mha
  • Crop residues taken off the field residueMobilisation: 16% → 30%
  • Land growing fuel energyCropArea: 0.62 Mha → 1.7 Mha

Constants — fixed inputs

ConstantValueUnitProvenanceWhy, and where it comes from
efficiency_electricity_to_h20.6MWh H₂ per MWh electricityWorkbook

The workbook converts electricity to hydrogen at 60%. POMMES-INDUSTRY uses 45 MWh of electricity per tonne of hydrogen, which is 74%. The model keeps the workbook value so the cost layer and the electricity indicator describe the same hydrogen; hydrogen is therefore about 40% more expensive here than a POMMES-native calculation gives.

  • Teaching workbook, "General hypotheses" sheet E11
efficiency_electricity_to_efuel0.4MWh fuel per MWh electricityPublished

Electricity in, liquid e-fuel out, across the whole chain: electrolysis, CO2 supply, synthesis and upgrading. Concawe's techno-economic assessment gives 38% when the carbon comes from direct air capture and 44% when it comes from a concentrated industrial source, and 0.4 sits between the two. It is a whole-barrel figure, not a kerosene-only one: Fischer-Tropsch sends roughly a fifth of its liquids to gasoline and diesel, so the electricity behind one tonne of jet fuel alone is higher — about 38 MWh, or 3.2 kWh per kWh burnt. Use this parameter for total liquid demand, which is what the equations do, and do not quote it as an aviation figure.

ef_electricity_2020157.5gCO₂/kWhDerived

The CO₂ emitted to make a kilowatt-hour on the Spanish grid in 2020, combustion basis: 40 926 kt of CO₂ from electricity and heat generation over 259 882 GWh of gross generation. France's 79 gCO₂/kWh is a different quantity in a different year, and finding out which was the most useful thing this port did to this entry. It is ADEME Base Carbone's "Électricité, mix moyen, France", 0.0791 kgCO₂e/kWh, sourced from the IEA's CO₂ emissions from fuel combustion — highlights 2013. So it is not a life-cycle factor — the IEA series is combustion in power stations, with no construction, no fuel supply chain and no nuclear front end — and it is not 2020: the edition is 2013 on 2011 data. France's actual 2020 factor on the same combustion basis is 64.5 gCO₂/kWh. The like-for-like Spanish entry in that same ADEME table is 0.238 kgCO₂e/kWh, three times France's. This entry uses 157.5, Spain's actual 2020 figure, because the constant is named for 2020 and a 2011 vintage would be a French error copied rather than a Spanish measurement. The right fix is to recompute France on the same basis in the same pass; until that is done, comparing the two overstates the French advantage by about a fifth. Two perimeter statements. The numerator is all fuel burned in electricity and heat generation, including industrial CHP; Spain has almost no district heat, so for Spain that is effectively electricity, while for France it adds 4.5 g. And the denominator is gross generation, not consumption, so applying the factor to consumed electricity ignores roughly 9% of Spanish network losses — the French constant has exactly the same convention. No life-cycle factor for Spain was found; expect one to land 25 to 45 g above this.

dhw_efficiency_fuel0.85fraction of the energy delivered as hot waterProvisional

A gas or oil water heater, standing losses included.

  • ADEME orders of magnitude for domestic hot water production
dhw_efficiency_electric2MWh of hot water per MWh of electricityProvisional

Above one because it is not all resistance: a 2050 electric water heater stock is a mix of resistance tanks and heat-pump water heaters, the latter at a COP near 3. Two is the blend assumed here and it is an assumption, not a measurement — the honest range runs from 1.0 if nothing changes to near 3 if the stock is heat pumps. It sets how much electricity electrifying hot water actually costs, so it is worth arguing about.

  • ADEME, chauffe-eau thermodynamique — COP de 2,5 à 3,5 selon l'installation
cooking_efficiency_fuel0.4fraction of the energy reaching the panProvisional
  • Standard hob efficiencies; a gas burner loses most of its heat around the pan
cooking_efficiency_electric0.84fraction of the energy reaching the panProvisional

Induction. The gap with gas is the widest of any usage in the model.

  • Standard induction hob efficiency
carbon_in_methane202gCO₂ per kWh of methanePublished

The carbon actually in the molecule, released whether it is burned or reformed. Distinct from efGas, which is 25 gCO₂/kWh in 2050 because the model's methane is biomethane and the convention books its carbon against the digester feedstock rather than the flame. Both numbers are needed and they answer different questions. efGas answers "what does burning this count as?"; this one answers "how much carbon is there to capture?" A capture plant removes molecules, not conventions.

ef_gas_2020227gCO₂/kWhWorkbook
  • Teaching workbook, "Synthesis" sheet S42
ef_liquid_2020264gCO₂/kWhWorkbook
  • Teaching workbook, "Synthesis" sheet S44
ef_wood_202027gCO₂/kWhProvisional

PLACEHOLDER — French value carried, not Spanish data. 27 gCO₂/kWh is the fossil energy of the French wood chain, from felling and drying to delivery, and it is national because that chain is. What would close it: a Spanish life-cycle factor from IDAE or AVEBIOM, or a Spanish entry in an LCA database; neither was reachable. Do not assume the two are equal. Spanish firewood travels further on average, Spain imports a larger share of its pellets, and this factor multiplies 17 TWh here against France's 46, so the same relative error moves a third as much.

  • app/model/countries/FR/FR.yaml, ef_wood_2020 — the value this carries, and the only reason it is here — Carried, not measured. Declared provisional for exactly that reason.
ef_coal340gCO₂/kWhPublished

Coking coal, 94.6 kgCO₂ per GJ, converted at 3.6 GJ/MWh. The workbook declares coal at 0 gCO₂/kWh in its factor table and then charges it at the hydrogen factor, 66.7 gCO₂/kWh, which is neither. This model uses the published factor and removes the double count that resulted — see steel_bf_process_residual.

steel_bf_base_production3 653kt/yPublished

Blast-furnace/BOF route volume. Spain made 11.9 Mt of crude steel in 2024, 30.7% by the oxygen route and 69.3% electric — almost the mirror image of France (62.7 / 37.3). 11 900 × 0.307 = 3 653 kt. That single line changes the Spanish industry game. Two thirds of Spanish steel is already scrap-based, so the H-DRI lever has a third of the tonnage to work on that it has in France, and the scrap supply constraint the model does not represent becomes the binding one. Cross-check from a second source: JRC-IDEES gives Spanish integrated steelworks 3 901 kt and electric arc 10 284 kt in 2021 — a 27 / 73 split on 14 185 kt, against worldsteel's 31 / 69 on 11 900 kt for 2024. The shares agree; the totals differ by year.

steel_eaf_base_production8 247kt/yPublished

11 900 × 0.693 = 8 247 kt. The two route volumes sum to 11 900 kt.

steel_bf_direct_intensity1.76tCO₂ per tonne of steelPublished

The total direct intensity of the integrated route — every source on site, not a process term. It was inherited from the teaching workbook as "the blast furnace's process figure", and under that name it had been counted on top of the coal it mostly is. Re-sourced in 0.27.0, it holds: the IPCC Tier 1 defaults summed over the chain give 1.87 tCO₂/t (1.46 for the converter, which already includes the blast furnace, plus 0.56 per tonne of coke and 0.20 per tonne of sinter); the EU ETS benchmarks, set on the best tenth of European plants, chain to about 1.4; and ArcelorMittal Dunkerque, at 6.8 Mt of steel and about 12 MtCO₂ a year, is at 1.76. The model charges the route's coal its own published factor, so this figure is never booked as such: steel_bf_process_residual keeps the remainder. The limitation: 1.76 and the 0.62 t of coal charged beside it describe a furnace about 20% better than the world average — worldsteel's route average is 780 kg of coal, which at this model's factor alone would release 2.08 t. The two are consistent with each other and should be changed together or not at all.

steel_eaf_process_per_tonne0.08tCO₂ per tonne of steelPublished

What an electric furnace emits on site besides its electricity: the graphite electrodes it burns and the carbon charged to foam the slag and carburise the melt. The IPCC's Tier 1 default, and the floor of the published range — the EU ETS benchmark for carbon steel is 0.215, because it also covers the gas burners and the ladle furnace. It applies to both electric routes, from scrap and from hydrogen-reduced iron, since both end in the same furnace. Until 0.27.0 the model gave these two rows no direct term at all, so the only steel that emitted on site was the blast furnace's.

olefin_base_production2 132kt/yProvisional

DERIVED WITH A FRENCH RATIO, not a Spanish statistic. No Spanish ethylene-and-propylene production figure was reached: Eurostat PRODCOM's ds-056120 is not served by the JSON API and would need the bulk facility. What was reached is JRC-IDEES's basic-chemicals output index, in kilotonnes of ethylene equivalent: Spain 5 099.4 kt in 2021 against France 8 744.2. On France that index is 1.90 times the French olefin_base_production of 3 656 kt, because it covers the whole basic-chemicals branch — chlorine, soda, industrial gases — and not just the crackers. Applying the same ratio to Spain gives 3 656 × 5 099.4 / 8 744.2 = 2 132 kt. It was 2 686 while the French anchor still carried the C4 cut, which 0.23.0 removed. Spain has steam crackers at Tarragona (Repsol and Dow) and Puertollano. What would close it properly: PRODCOM codes 20141130 and 20141150 through the bulk facility, Petrochemicals Europe's country table, or FEIQUE's annual report.

olefin_carbon_per_tonne3.138tCO₂ per tonne of olefinDerived

The carbon a tonne of olefin can physically hold, which is the ceiling on any claim that the product stores CO₂. Ethylene and propylene are both 85.63% carbon by mass, so a tonne holds 0.8563 × 44.009 / 12.011 = 3.138 tonnes of CO₂ equivalent. Nothing about the route changes it: it is the polymer's own composition. It replaces a coefficient of 4.3 that was 37% above this ceiling. The old figure came from the teaching workbook's "Industry" sheet K48 with no derivation, and it reproduces exactly as the CO₂ fed to the front of the route rather than the carbon locked in the product: 2.988 tonnes of methanol per tonne of olefin (methanol_per_olefin, published) times the 1.3735 tCO₂ per tonne of methanol that stoichiometry demands is 4.105, and 3.138 / 4.105 = 0.765 is an ordinary light-olefin selectivity for a methanol-to-olefins step. The 0.97 tCO₂ of difference leaves as C₄⁺, coke and purge gas; it is consumed by the plant, not stored by the polymer, and crediting it was double-counting the losses as a removal.

  • IPCC 2006 Guidelines, Vol. 3, Ch. 1 §1.3.1 — feedstock carbon is stored, and released when the product is oxidised
  • Atomic masses: C 12.011, O 15.999, H 1.008 (IUPAC 2021)
cement_base_production17 980kt/yPublished

Spanish cement production in 2024, 17.98 Mt, from Robbie Andrew's Global CO₂ emissions from cement production dataset — the source OTHER_COUNTRIES.md names for this entry. It confirms the first pass's reconstruction from Oficemen trade press (18.33 Mt) to within 2%. The constant is cement and the model converts it to clinker itself, through clinkerRate: Spain's ratio is 0.814 against France's 0.639, because Spain exports clinker and France blends more substitute into its cement. A file inheriting France's 60% default would understate Spanish cement process emissions by a quarter. The defect this paragraph used to name is fixed in the shared file: until 0.27.0 cement_process_per_tonne was 0.7925 tCO₂ per tonne of clinker, half again the calcination alone because it silently carried French kiln fuel, and it over-stated Spanish kiln emissions. It is now 0.527, the French inventory's calcination, which is within the IPCC's 0.47–0.53 for any ordinary clinker; Spain's own figure would move it by a few per cent, not by half.

cement_process_per_tonne0.527tCO₂ per tonne of clinkerPublished

The decarbonation of the limestone, and nothing else: 6 193 ktCO₂ of calcination in the French inventory for 11 759 kt of clinker in 2020. The neighbouring years give 0.524 (2019) and 0.531 (2021), and it is what stoichiometry predicts: the IPCC's 0.51 × 1.02 for kiln dust = 0.52 for a 65%-lime clinker, 0.53 at 67%. No change of kiln fuel can remove it — only capture, or less clinker. It was 0.7925, and that was a total wearing the wrong name. The old value was 10.2 MtCO₂ over 12.87 Mt of clinker. 10.2 Mt is not the calcination line for any year France has published — that line ran 6.19 to 6.81 over 2015–2021 — but it is inside the range of the whole cement industry's CO₂, calcination and kiln fuel. And 12.87 Mt was not an observation: it is 16 500 × 0.78, this model's own cement anchor times the top of its own clinkerRate slider. The kiln fuel is charged separately through the energy account, so it was emitted twice — and carbonCapture, which multiplies this term, was capturing fuel CO₂ under a name that said it could not. The limitation. 0.527 is a French fleet average for one year, and it moves with the lime content of the clinker and with how much of the lime comes from slag or ash instead of carbonate: the IPCC's range is 0.47 to 0.53. It is also domestic clinker; about a quarter of the clinker behind French cement is calcined abroad, outside this perimeter.

kiln_heat_per_tonne1.064MWh per tonne of clinkerPublished

What a French kiln burns to make a tonne of clinker: 3 830 MJ in 2021, down from 3 942 in 2015. It closes against the roadmap's own statement that the sector burned 13 TWh of heat in 2021 for 12 222 kt of clinker — three published quantities, one identity, no residual. The sector aims at 3 600 MJ in 2030 and 3 500 in 2050, which is the 9% the industrial efficiency lever can take off. It replaced 0.700 in 0.29.0, the teaching workbook's figure, a third short.

kiln_waste_biomass_share0.52fraction of the waste-derived heatPublished

The biomass share of the waste a French kiln burns: 52% in 2021, from 49% in 2015 — animal meal, wood waste, sludge — where the rest is tyres, solvents, oils and plastic-rich refuse-derived fuel. The biomass half is charged to the wood carrier; the fossil half goes with the coke and the coal, whose emission factor it shares within a few per cent. The sector aims at 60% by 2050; this keeps the observed share, because a higher one needs a biomass supply the model would have to find somewhere.

wte_fossil_co2_base1.483MtCO₂/yPublished

1.5 MtCO₂ of fossil carbon in 2019 from the incineration of municipal waste, all of which has recovered energy since 2004 and is booked in energy, 1A1a. 2.2 Mt of waste were burned, a tenth of Spain's municipal waste, where nearly half still goes to landfill. Industrial waste burned with energy recovery adds 0.08 Mt and is left out, as the French figure leaves it out. The plastic share of it is not published, and the French 95% is carried across.

wte_plastic_fossil_share0.95fractionDerived

How much of an incinerator's fossil CO₂ is plastic: 95%. French residual household waste is 14.7% plastic by mass, 2 410 kt a year (ADEME, MODECOM 2017). At the IPCC's defaults — plastics are 75% carbon and all of it fossil — that is 6.63 MtCO₂. Everything else in the bin that carries fossil carbon adds 0.35: textiles 0.15 (20% of their carbon is fossil), nappies and other hygiene products 0.12, shoes and leather 0.06, soiled paper 0.02. 6.63 / 6.98 = 0.95. It is what makes plasticReduction reach the incinerator, and it is why the other 5% does not move with it. The limitation: the composition is household waste, and the fleet also burns commercial waste, which is if anything more plastic; the composites and small appliances — plastic as well — are left out rather than guessed, which errs low.

wte_biogenic_share0.552fraction of the stack CO₂Derived

Biogenic over total in the inventory's information item on waste incineration with energy recovery, 2019: 1.924 Mt biogenic against 1.563 fossil. It was 50.3% in 2024.

  • Spain, CRT submission to the EU, edition 2026, Table 1.A(a)s4, information item on waste incineration with energy recovery — 1.924 Mt biogenic, 1.563 Mt fossil CO₂ (2019)
plastic_fossil_co2_per_tonne2.75tCO₂ per tonne of plasticPublished

The fossil CO₂ a tonne of plastic releases when it burns: 75% carbon, all of it fossil, times 44/12. It converts the plastic part of the incinerators' CO₂ back into tonnes, which is what a recycling line receives and draws its electricity on.

plastic_recycling_electricity0.5MWh per tonne of plastic recycledPublished

Sorting, washing, extruding: the JRC gives 0.3 to 0.7 MWh of electricity a tonne for mechanical recycling and next to no heat. The middle is taken. Chemical recycling by pyrolysis would need more, and no inventory of it is public.

  • JRC (2023), Environmental and economic assessment of plastic waste recycling, EUR 31423, PDF p. 54
food_steam_demand16.352TWh/yProvisional

Steam raised by the Spanish food, drink and tobacco industry: 16.35 TWh of final energy in 2019, from JRC-IDEES's process decomposition of the branch. France's figure is 21.876 TWh, so Spain's food industry uses three quarters of the steam France's does while being larger by turnover — the branch is Spain's biggest manufacturing sector and it is less steam-intensive, because more of it is fresh produce, olive-oil pressing and wine, and less of it is dairy and sugar. Provisional because the mapping over-states France by 31%. The same three IDEES blocks give 28.62 TWh for France in 2019 against the French model's 21.876. The French value comes from the teaching workbook and its perimeter is not documented, so it cannot be said which is right; what can be said is that the Spanish number is IDEES's own complete steam total. Taking steam processing alone gives 15.06 TWh for Spain and 26.35 for France, the same 20% gap, so the choice of block does not explain it.

food_direct_heat_demand5.472TWh/yPublished

Direct heat — ovens, specific process heat, thermal drying, and the low-enthalpy heat that warms the plant itself — in the Spanish food, drink and tobacco industry: 5.47 TWh of final energy in 2019. This mapping is trustworthy: run on France it gives 10.174 TWh against the French model's 10.693, a ratio of 0.951, and on France's 2021 column it gives 10.699 — the French constant to three digits. That is the closest agreement anywhere in this package between an IDEES reconstruction and a teaching-workbook value, and it is why this entry is published where the steam one beside it is not.

food_heat_pump_cop3MWh heat per MWh electricityWorkbook—
food_hydrogen0.071TWh/yProvisional

DERIVED WITH A FRENCH RATIO. The Eurostat energy balance has no hydrogen row for the food industry in any country and JRC-IDEES inherits that, so the source that closed the two entries above cannot close this one. France's 0.138 TWh comes from a national survey. Scaled by the size of the two branches — Spain 31.892 TWh of final energy in 2021 against France's 61.659 — it gives 0.071 TWh. It is 0.2% of the Spanish food industry's energy, so nothing turns on it; it is carried rather than zeroed because zero would say the industry uses no merchant hydrogen, which is not known either. Gasnam or AeH2 would say what it actually is.

building_need_calibration1fractionDerived

One, exactly, and that is the finding rather than a placeholder. The constant is observed heat over the stock table's own Σ(surface × surfacic need). France's 0.65284 is not a physical coefficient: it is the gap between a normative surfacic need and what French dwellings actually consume, the effect the buildings literature calls prebound. The French table carries normative needs, so it needs the correction. The Spanish building_segment is built the other way round: its surfacic needs are JRC-IDEES's measured useful thermal energy service for space heating, divided by the census floor area of the segment that consumed it and normalised to the 2000-2020 mean heating degree-days. A measured need needs no prebound correction, so the calibration is 1 by construction, and the number to check is not this coefficient but the table's total. What the table lands on: 86.75 TWh of space-heating need in a normal year, 62.69 residential and 24.06 tertiary, against France's 359.34. Spain's stock is 43% of France's floor area in these tables and needs 24% of its heat — 1 757 heating degree-days against 2 339, plus a fifth of the dwellings with no heating installation at all. A country that inherits France's 0.65284 silently cuts its heating demand by a third. That is the argument for making this a derived equation, and Spain is the case that proves it.

building_peak_202011.9GWProvisional

PLACEHOLDER — the French anchor rescaled, not a Spanish measurement. No Spanish TSO publishes the electric-space-heating share of the winter peak. Red Eléctrica publishes the whole-system peninsular peak — 40.5 GW instantaneous on 11 January 2024 at 20-21h — and no decomposition by end use. What is done here is what OTHER_COUNTRIES.md recommends when no TSO publishes the split: keep the ratio, rescale the anchor. The model's own building_peak_load_2020 — the stock's electric heating demand at its own peak efficiencies — is 52.17 TWh-equivalent for the French stock and 15.48 for the Spanish, a ratio of 0.2967. France's 40 GW anchor times that ratio is 11.9 GW. The gigawatts-per-TWh-equivalent conversion is therefore identical in the two countries, which is the honest reading: the Spanish figure says how the Spanish stock compares with the French one, not what a Spanish meter would show. And Spain's peak may not be a winter peak at all. The 2024 peninsular maximum was in winter, but the summer maximum is close behind, cooling already takes 3.87 TWh of residential and 8.13 TWh of services electricity, and the model has no summer constraint. A Spanish player can pass this indicator while building a system that fails in August.

official_transport_202490.374MtCO₂e/yPublished

CRF 1A3, fuel combustion in transport, 2024. Spanish transport emissions are 54% above their 1990 level (58.65 MtCO₂e), where French ones are level with theirs. Transport is a third of Spain's whole inventory and it is the sector that has not turned.

official_building_202423.5041MtCO₂e/yPublished

CRF 1A4a + 1A4b, commercial-institutional and residential combustion, 2024. Spanish buildings emit 23.5 MtCO₂e against France's 56.1 — 42% of the French level for 70% of the population. That is climate and gas penetration, not virtue, and it changes which levers matter: the Spanish building game is worth less than a quarter of what the French one is.

official_industry_202453.3201MtCO₂e/yPublished

CRF 1A2 (32.99109) plus CRF 2, industrial processes and product use (20.32898), 2024.

official_industry_20507.2615MtCO₂e/yPublished

The ELP 2050's industry bar, 7 MtCO₂e from 72 in its base year, plus its share of the strategy's undifferentiated "otros" row. Spain is one of the few EU countries that publishes a 2050 figure sector by sector.

official_agriculture_202442.2386MtCO₂e/yPublished

CRF 1A4c (8.98985) plus CRF 3, agriculture (33.24879), 2024.

official_agriculture_205014.026MtCO₂e/yPublished

The ELP does not separate agriculture from waste: their 19 MtCO₂e in 2050 is split in the PNIEC's own 2030 ratio, 28 439 : 11 322, and agriculture takes the residual after the "otros" allocation.

official_waste_202417.2883MtCO₂e/yPublished

CRF 5, waste, 2024 — above the 1990 level of 13.27 and above France's 15.30 in absolute terms, on 70% of the population. Spain landfills far more of its municipal waste than France does.

official_waste_20505.58396MtCO₂e/yPublished

The waste share of the ELP's combined agriculture-and-waste bar, in the PNIEC's 2030 ratio.

official_energy_202440.9822MtCO₂e/yPublished

CRF 1A1 (36.88418) plus 1B, fugitive emissions from fuels (3.75967), plus 1A5, other combustion not elsewhere specified (0.33833), 2024. 1B and 1A5 are booked to energy here and that is a stated choice: the proposed mapping left both unassigned, and the six sectors would then fall 4.10 MtCO₂e short of the published gross total. Fugitive emissions are the energy supply industry's own losses, which is where Citepa's SECTEN puts them in the French file too.

official_energy_20500.128525MtCO₂e/yPublished

The ELP's electricity bar is zero in 2050 — the sector is 100% renewable — so what is left is the energy share of the "otros" row.

official_natural_sink_2024-51.9209MtCO₂e/yPublished

CRF 4, land use, land-use change and forestry, 2024. Negative is a sink.

official_natural_sink_2050-37MtCO₂e/yPublished

The ELP's own 2050 absorption, stated in the same sentence as the 29 MtCO₂e of residual emissions. Spain's official pathway weakens its sink: −51.9 observed in 2024, −43.6 as the 2030 objective, −37 in 2050.

official_technological_sink_20500MtCO₂e/yPublished

Zero, and it is a finding rather than a gap. Spain's published 2050 account closes on natural sinks alone: 37 MtCO₂e absorbed against 29 emitted, so the ELP is net −8 MtCO₂e. The strategy names no technological removals. France's file carries −43 MtCO₂e as a transparent closure residual and its own controversy table calls it the largest assumption in the model; Spain does not need it, and saying so is a good way to show a student what that French number is doing.

snbc_gross_205029MtCO₂e/yPublished

The national 2050 gross target: a maximum of 29 MtCO₂e, −90% on 1990. The constant id is French-branded and is kept because equations.yaml reads it by name; read it as "the national strategy's gross total at the horizon".

industry_covered_202043.81MtCO₂e/yDerived

What the model represents of the Spanish industry sector, on the inventory's basis — combustion at the stack plus process emissions, with electricity and hydrogen excluded because the inventory books those to the energy sector. 24.32 MtCO₂e from the five value chains (cement 11.77, steel 7.60, food heat 4.95, ammonia and olefins negligible on their 2020 routes) and 19.49 from the other branches (15.49 from 0.64 TWh of coal, 11.52 of oil and 53.87 of gas, plus 4.00 of process emissions). Moved in 0.27.0, by the shared file and not by Spanish data. It was 45.52. Cement fell by 3.87, because the shared calcination factor dropped from 0.7925 to 0.527 when it stopped carrying French kiln fuel; steel rose by 0.82, because the two process terms the model books — the blast furnace's remainder and, new, the electric furnace's electrodes — were added to a sum that had left them out. The chain part is recomputed by hand with industry_covered's own arithmetic: the JRC-IDEES workbooks the rest of the function reads are not kept in the repository, and the rest does not depend on anything that changed. And moved again in 0.29.0, when the kiln's fuel left the shared chain row for the fleet's measured heat per tonne: cement 10.42 → 11.77. The waste share that splits it is France's 2020 one, 43%, because Spain's own has not been sourced. Against the inventory's own industry line of 53.32 MtCO₂e, the model covers 43.81 and the difference of +9.5 is construction, refining, mining, F-gases and metal-process emissions, none of which the model has. France's difference is now about zero, −0.1, but for reasons of its own — its industry_other comes from a survey that includes things the Spanish extraction excludes — so the two diagnostics are still not comparable.

  • extract/industry.py, function `industry_covered` — the arithmetic, reproducible — Spanish volumes and Spanish energy; the per-tonne intensities and the 2020 emission factors are the shared technology file's.
fuel_efficiency_ceiling0.19792fraction of fuel savedProvisional

PLACEHOLDER — French ratio carried, applied to Spanish structure, and carried deliberately. RTE, after CEREN, puts the fuel-side energy-efficiency potential of French industry at 19.8%. It is a percentage of fuel burned, not a stock, so it travels better than most things in this file: the physics of motors, compressed air, heat integration and insulation is not national, and the branch mix that would make it national is handled separately in the post table. What is French about it is the starting point — the efficiency already captured. Spanish industry's specific consumption is not French industry's, so the remaining potential is not identical either. The Spanish replacement is IDAE's sectoral efficiency studies or the audits collected under Real Decreto 56/2016; neither was fetched.

lhv_kerosene11.9MWh per tonnePublished

42.8 MJ/kg, the standard lower heating value of jet A-1.

  • Standard lower heating value of aviation kerosene
jet_fuel_price_2023816€/tPublished

The anchor for today's ticket. Everything that is not fuel is derived from it through the fuel share of operating cost, so an error here moves the whole non-fuel block.

co2_per_tonne_kerosene3.16tCO₂ per tonne of fuelPublished

Combustion only — neither the upstream chain nor non-CO₂ effects.

  • ICAO; corroborated by the US Energy Information Administration
aviation_demand_horizon_years31yearsDerived

2019 to 2050. Unlike France, Spain has one aviation base year, not two: both the service demand and the consumption per passenger-kilometre come from the same JRC-IDEES 2019 column, so the demand and efficiency horizons are the same 31 years. France separates them — 30 and 26 — because its demand comes from a 2020 workbook and its efficiency from a 2024 statistic.

aviation_horizon_years31yearsDerived

2019 to 2050, the same horizon as the demand row and for the same reason.

observed_kerosene_per_pkm_202427.74g of kerosene per passenger-kilometreProvisional

All the jet fuel Spain burns — 2 378 ktoe of domestic aviation plus 4 891 of international bunkers, 7.10 Mt of kerosene in 2019 — divided by all the passenger-kilometres flown from Spanish airports, 256 049 Mpkm. Deliberately uncorrected, as the French entry is: it carries the freight in the holds and the real load factors, which is why it is above the per-passenger-kilometre figure the model's own aviation rows imply. The _2024 in the name is wrong for Spain and the value is 2019. JRC-IDEES stops at 2021, and 2020-2021 are Covid years in which the ratio jumps to 33 g/pkm because the fuel falls more slowly than the traffic. Provisional because the same calculation on France gives 35.34 g/pkm for 2019 against the French constant's 29.28 for 2024, a ratio of 1.207. Part of that is five years of fleet renewal and part is that DGAC's passenger-kilometre perimeter is not Eurostat's departing-flight basis.

lhv_coal7.5MWh per tonnePublished

Lower heating values, used to turn POMMES prices per tonne into prices per MWh.

  • Standard lower heating values for hard coal, natural gas and hydrogen
lhv_methane13.9MWh per tonnePublished
  • Standard lower heating value of methane
lhv_hydrogen33.33MWh per tonnePublished
  • Standard lower heating value of hydrogen
price_methane_per_tonne561€/tPublished
price_coal_per_tonne99€/tPublished
price_iron_ore100€/tPublished
price_scrap180€/tPublished
price_limestone20€/tPublished
price_household_electricity242.2€/MWh incl. taxPublished

Household band DC (2 500-4 999 kWh/year), all taxes and levies included, mean of the two 2024 semesters: 0.2436 and 0.2408 €/kWh. France's figure is 260 €/MWh.

price_household_gas88€/MWh GCV incl. taxPublished

Household band D2 (20-199 GJ/year), all taxes and levies included, mean of the two 2024 semesters: 0.0858 and 0.0901 €/kWh. France's figure is 134 €/MWh — Spanish households pay two thirds of the French gas price, which is one reason gas holds so much of the Spanish heat and hot-water market, and why electrification is a harder sell here on cost alone.

price_wood77.5€/MWhProvisional

PLACEHOLDER — French value carried, not Spanish data. 77.5 €/MWh is the Propellet index for French bulk pellets. AVEBIOM publishes the Índice de precios del pellet doméstico for Spain, which is the exact analogue; it was not reachable. Expect the Spanish figure to be lower: Spanish pellet prices have run below French ones for a decade, and the wood volume this multiplies is a third of France's, so it is a small number twice over.

iron_ore_per_steel_bf1.8t per t of steelPublished
iron_ore_per_steel_dri1.6t per t of steelPublished
scrap_per_steel_eaf1t per t of steelPublished
cement_per_concrete300kg of cement per m³ of concreteProvisional

Structural concrete dosages run roughly 250 to 400 kg a cubic metre, and 300 is the middle of the structural range. It is not the 266 kg a cubic metre that the cement-and-concrete literature uses for "béton équivalent": that figure is a whole-economy bookkeeping factor that already absorbs mortars, renders, screeds and bagged cement, and applying it to building cement alone overstates the concrete by about seven tenths. Used only to express the construction module's cement as a concrete tonnage in the materials account; no emission depends on it.

  • Usual structural concrete dosage range; cross-checked against The Shift Project's 266 kg/m³ béton-équivalent factor, which is a different perimeter
concrete_density2 380kg/m³Published

Ordinary reinforced structural concrete. Presentation only, like the dosage above.

  • Standard value for ordinary reinforced concrete, used in the comparative life-cycle assessment this module's timber coefficients come from
limestone_per_clinker1.6t per t of clinkerPublished
kiln_heat_per_clinker0.888889MWh per t of clinkerPublished
coal_per_kiln_heat0.11919t of coal per MWh of kiln heatPublished

The cement kiln fuel appears in the cost model but NOT in the physical model, which gives cement only its grinding electricity. Cement combustion CO₂ is therefore missing from the emissions account — a known defect of the workbook, recorded here rather than silently patched.

cement_capture_extra_electricity0.54MWh per t of clinkerPublished

What an amine capture plant on a cement stack draws, per tonne of clinker, when it captures 95% of the stack: the heat that regenerates the solvent, raised electrically, plus the compression and the fans. Per tonne captured it is 0.54 / (0.95 × 0.86) = 0.66 MWh, which is where the published figures put it: an advanced solvent needs 2.3 to 3.3 GJ of heat a tonne at the reboiler, and compression to 150 bar another 132 kWh. A cement works has no steam to spare, unlike an incinerator, so the heat has to be raised, and since 0.32.0 the model raises it with electricity the power system has to supply. The capture plant treats the whole stack, the biogenic CO₂ of the kiln's waste included, so this is charged per tonne of clinker rather than per fossil tonne.

cement_capture_reference_rate0.95fraction of the stackPublished

The capture rate at which cement_capture_extra_electricity was measured. The lever's share of the stack is divided by it, so the plant draws its published figure exactly at 95% and proportionally less below.

  • Raillard-Cazanove (2024), PhD thesis, Table 2.11 p. 43, after Quevedo Parra & Romano (2023)
kiln_biomass_co20.36tCO₂ per MWh of biomass burnedPublished

The biogenic CO₂ the biomass half of a kiln's waste releases — animal meal, wood waste, sludge — at the IPCC's default for "other primary solid biomass", 100 t a terajoule. It is never counted in the emissions; it is the tonnage a capture plant takes with the fossil, and so what the transport and storage of cement capture are charged on.

wte_capture_electricity0.315MWh per tonne of CO₂ capturedPublished

What capture costs an incinerator in electricity, per tonne captured, fossil and biogenic alike. The plant has its own steam: the IEAGHG's two reference plants, 20 MWe each, extract 40 to 45% of the turbine's steam at 6 bar to regenerate the solvent at 3 GJ a tonne, which costs them 6.0 and 6.8 MWe, and compression and liquefaction take 2.8 and 3.2 MWe more. Over 27.9 and 31.8 t captured an hour, both come to 0.315 MWh a tonne, and both halve the plant's net output. The electricity an incinerator no longer exports is electricity the mix has to produce, so the model books it as a demand. Where the plant feeds a heat network a heat pump can win back part of it; the IEAGHG's third case does, and this does not.

wte_capture_cost100€ per tonne of CO₂ capturedProvisional

The capture plant on an incinerator — its capital and the running costs that are not energy — per tonne captured. The energy is charged apart, at the industrial electricity price, and so are transport and storage. Provisional, and the evidence is thin at both ends. The one techno-economic study of a retrofit gives a cost of capture of 90 to 156 € a tonne for plants of 3 to 12 kt a year, a tenth of a French incinerator. The one plant being built, Oslo's Klemetsrud, budgets 8.4 billion kroner at P50 for 350 kt a year, about 720 M€: at this model's 8% over 25 years that is close to 200 € a tonne in capital alone, for a first of its kind with its own harbour terminal. The cement plant in this model costs under 50 € a tonne on the same basis, from a gas twice as concentrated. 100 sits between them.

co2_transport_storage_cost50€ per tonne of CO₂ storedPublished

Shipping or piping a captured tonne to a storage site and injecting it. 50 € is the figure France Stratégie retains for French industry. Models that assume a shared network at scale go lower — 17 to 21 € in the IND-OPT study — and the one French cluster costed so far, Dunkirk, comes out at 120 to 160 €, because the CO₂ leaves by ship for a reservoir in the North Sea. Charged on every tonne stored, biogenic ones included, since a ship does not sort them either.

  • France Stratégie (May 2023), Les coûts d'abattement — partie 5, Industrie, ch. 4 §3, pp. 38–40 — transport and storage at 50 €/t stored
  • Raillard-Cazanove, Knibiehly & Girard (2025), J. Cleaner Production 508, 145511 — transport and storage 21.2 €/t (2030), 17.2 (2050)
  • ADEME (2024), ZIBAC Dunkerque — 120–160 €/t
smr_methane_per_tonne_h23.33t of methane per t of hydrogenPublished
smr_electricity_per_tonne_h20.58MWh per t of hydrogenPublished
smr_emission_per_tonne_h29.23tCO₂ per t of hydrogenPublished
methanol_per_olefin2.98837t of methanol per t of olefinPublished
floor_area_total4 625.4Mm²Derived

Spain's whole residential plus services floor area, kept — as in France — as a cross-check rather than as an input: building_surface_coverage reports the model's heated stock (3 926.5 Mm²) against it, 84.9%. France's ratio is 87%. Residential is all 26.62 million conventional dwellings, occupied and not, at the census mean useful floor area of their building type: 9.245 M houses at 117.44 m² plus 17.047 M flats at 76.79 m² = 2 394.6 Mm². The model's own stock covers only the 19.09 M occupied ones, which is why the coverage is below one — 8.09 M Spanish dwellings are empty or second homes, a fifth more than in France in relative terms. The services half, 2 230.8 Mm², is the weakest number in the building block. JRC-IDEES puts Spanish services floor space at 140.0 m² per service-sector employee against 43.6 for France and 102.6 for Germany, in the same dataset. If it is too high, this constant and the six tertiary rows of building_segment move together and the heat need does not.

deep_retrofit_saving0.6fraction of demand removedProvisional

Demand reduction achieved by one deep renovation, used to convert the average stock improvement into an equivalent number of deep renovations.

  • ADEME orders of magnitude for a BBC-rénovation-level retrofit
retrofit_life30yearsProvisional
  • Conventional lifetime for building-envelope work
heat_pump_life17yearsProvisional
  • Conventional lifetime for a residential heat pump
heat_pump_cost_per_m280€/m² incl. taxProvisional

PLACEHOLDER — French value carried, not Spanish data: 80 €/m² installed for an air-to-water heat pump, stated in France as the middle of a 60-100 range. Spanish installation labour is cheaper and Spanish dwellings are slightly smaller, so the per-square-metre figure is probably lower and the per-dwelling one closer. IDAE's Plan de Recuperación aid schedules publish reference costs per installed kilowatt for aerotermia, which would close it.

renovation_vat1.1multiplierProvisional

Spain's reduced VAT rate on qualifying renovation and repair work in dwellings is 10%, against a standard rate of 21% and against France's 5.5%. A renovation therefore carries almost twice the tax margin it does in France, which moves the building cost indicator by about 4%.

  • Ley 37/1992 del Impuesto sobre el Valor Añadido, art. 91.Uno.2.10º — tipo reducido para ejecuciones de obra de renovación y reparación en edificios destinados a viviendas — NOT VERIFIED AGAINST THE BOE IN THIS PASS. The rate and the article are widely quoted and the value is declared provisional for exactly that reason. The consolidated text would also state the conditions — the work must not be construction or extension, and materials must not exceed 40% of the base — under which the 21% rate applies instead.
households18.873millionPublished

18.873 million Spanish households in 2019, the package's base year. France has 31.377 million on 1.43 times the population, so a Spanish household is larger: 2.49 people against 2.18. Every per-household cost the model prints is therefore spread over fewer, bigger households here.

car_ownership_reference2 161€/household/yProvisional

DERIVED WITH A FRENCH RATIO. INE's Encuesta de Presupuestos Familiares was not fetched, so the French INSEE budget — 2 541 €/household/year for buying, insuring and maintaining a car — is scaled by the ratio of the two countries' household consumption expenditure: 33 728 €2015 per Spanish household against 39 660 per French one, a ratio of 0.850. 2 541 × 0.850 = 2 161. This assumes a Spanish household spends the same share of its budget on a car as a French one. It plainly does not — Spanish car ownership per household is lower and the fleet is older — so this is an order of magnitude, not a statistic. COICOP group 07 of the EPF would close it.

car_transport_reference3 234€/household/yProvisional

DERIVED WITH A FRENCH RATIO, exactly as the row above: France's 3 803 €/household/year of total transport spending scaled by 0.850. Same caveat, same source, same fix.

km_per_car_per_year11 194kmPublished

Spanish car traffic divided by the Spanish car fleet: 274 900 million vehicle-kilometres over 24 558 126 cars in 2019. The same calculation on the French sheets gives 11 080 km against the French constant's 11 600, a ratio of 0.955, so the mapping is trustworthy. A Spanish car does 3.5% fewer kilometres a year than a French one and carries 1.24 people rather than 1.87, so the passenger-kilometres per car are a third lower.

reference_car_fleet2.28399e+07carsDerived

The car fleet the Spanish reference scenario computes: 22.84 million cars, against 24.56 million actually on the road in 2019, because the reference scenario already applies the model's own modal shifts. It is the denominator of the fleet ratio the household-cost panel uses, so at the reference the ratio is exactly one and the household car budget is the declared one. It is a pinned model output, not a statistic: run python3 app/tools/pin_reference.py --country ES, read costs.transport.fleet out of reference.json, and put it here. A value that moves because a Spanish datum was corrected is a legitimate change and shows up in that file's diff.

  • app/model/countries/ES/reference.json, costs.transport.fleet — the model's own output at the Spanish reference scenario — 22 839 935.29 cars. Cross-check: JRC-IDEES gives 24 558 126 Spanish cars in 2019.
afforestation_lag10yearsGame rule

New forest does not store carbon the year it is planted. Hectares planted less than ten years before the horizon are left out of the afforestation term altogether, which is a crude step where the truth is a curve; the alternative — a growth function nobody in the sources publishes — would be a curve we invented.

afforestation_storage_rate3tCO₂/ha/yPublished

New forest is booked at the expansion rate rather than at the average per-hectare rate of the standing forest, because a young stand does not store like a mature one. The same source gives 5.0 for a renewal plan on existing forest and 0.2 to 2.4 for the rest of the forest depending on management and climate; 3.0 is the expansion line.

soil_carbon_grass_to_crop3.6667tCO₂/ha/yPublished

1.0 tC/ha/y lost for twenty years when permanent grassland is ploughed, converted here at 44/12. The interval on it is ±40%, and the stock difference between the two uses (84.6 against 51.6 tC/ha over 0–30 cm) would imply 1.65 tC/ha/y if all of it were lost before a new equilibrium — it is not, and the modal value is what the inventory uses. These coefficients are measured on one country's soils and a port should check them against its own; they are shared because soil chemistry does not stop at a border, not because they are beyond argument.

soil_carbon_crop_to_grass1.8333tCO₂/ha/yPublished

0.5 tC/ha/y regained for twenty years when arable land goes back to grass, converted at 44/12. Half the loss rate, and deliberately so: the same source's finding is that "loss is twice as fast as gain", which is what makes re-grassing a slower repair than ploughing was a break.

soil_carbon_conversion_years20yearsPublished

How long a hectare goes on emitting, or storing, after it changes use. Twenty years is the tail the inventory applies, so at a horizon 26 years away only the last twenty years of conversions are still in the flux.

land_module_active0Game rule

This edition does not carry the land module. The natural sink is the naturalSink slider, exactly as it was before the module existed, the seven land levers are hidden and inert, and the Land & food tab is not drawn. Everything the module needs is declared below as a placeholder; switching this constant to 1 without replacing all of it would put French land in Spain.

land_horizon_years26yearsDerived

2024 to 2050 — the horizon of this edition, counted from the year after the land survey the account would be written on. Derived rather than a placeholder: it follows this edition's own horizon and nothing else.

forest_production5.4m³/ha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: gross biological production per hectare. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_mortality1m³/ha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: mortality per hectare. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_production_area16.6MhaProvisional

PLACEHOLDER — French value carried, not Spanish data: forest area available for wood production. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_standing_volume2 827Mm³Provisional

PLACEHOLDER — French value carried, not Spanish data: standing live volume. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_harvest_base53.1Mm³/yProvisional

PLACEHOLDER — French value carried, not Spanish data: base-year removals of live trees. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_carbon_k1.5tCO₂/m³Provisional

PLACEHOLDER — French value carried, not Spanish data: what a cubic metre leaving the living stock takes with it. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_carbon_ratio_base2tCO₂/m³Provisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's sink over its balance at the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_dead_wood_coefficient0.6024tCO₂ per m³ of annual mortalityProvisional

PLACEHOLDER — French value carried, not Spanish data: the dead-wood pool per cubic metre of mortality. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_dead_wood_half_life10yearsProvisional

PLACEHOLDER — French value carried, not Spanish data: the half-life of carbon in dead wood. Inert, because land_module_active is 0, which also holds the dead wood at its base year.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_litter_soil_sink4.62MtCO₂/yProvisional

PLACEHOLDER — French value carried, not Spanish data: litter and forest soil on land-use change. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_overseas_sink10MtCO₂/yProvisional

PLACEHOLDER — French value carried, not Spanish data: forest outside the land account's territory. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_harvest_sawlogs18.3Mm³/yProvisional

PLACEHOLDER — French value carried, not Spanish data: sawlogs in the base-year harvest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_harvest_industrial10Mm³/yProvisional

PLACEHOLDER — French value carried, not Spanish data: industrial wood in the base-year harvest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_harvest_energy_commercial9.7Mm³/yProvisional

PLACEHOLDER — French value carried, not Spanish data: energy wood sold, in the base-year harvest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_informal_firewood15.1Mm³/yProvisional

PLACEHOLDER — French value carried, not Spanish data: firewood cut and never sold. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_harvest_unutilised0Mm³/yProvisional

PLACEHOLDER — French value carried, not national data: wood felled and left in the forest, in million cubic metres a year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
forest_harvest_volume_factor1m³ of standing stock per m³ of the harvest statisticProvisional

PLACEHOLDER — French value carried, not national data: standing-stock volume per cubic metre of the harvest statistic. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
hwp_coefficient0.562tCO₂/m³Provisional

PLACEHOLDER — French value carried, not Spanish data: the wood-products pool per cubic metre a year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
hwp_long_lived_share_base0.225fractionProvisional

PLACEHOLDER — French value carried, not Spanish data: the base-year long-lived share of the harvest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
timber_cement_saving67kg cement per m² of floor framed in timberProvisional

Measured on one building and cross-checked against element coefficients, because no whole-building intensity by structural system is published anywhere. The anchor is an eight-storey, 142-dwelling mass-timber residential building whose bill of materials was compared with a functionally equivalent concrete one: 519 to 553 kg/m² of concrete avoided over 13 766 m² of gross floor area, which at 280–320 kg of cement a cubic metre and a density of 2 380 kg/m³ is 61 to 74 kg of cement, and 67 is the middle. A timber building is not a building without concrete, and that is the point of a saving rather than a substitution. The same measured building still carried 288 kg/m² of concrete in its foundations, its ground floor and its toppings, and used more lean concrete than its concrete twin. Against the 137 kg/m² this model books for new French housing, 67 is close to half — which is the right order: négaWatt reaches −46% of concrete at 80 to 95% timber, and half of 90% is 45. The competing way to model this is a displacement factor in tonnes of carbon avoided per tonne of carbon in the wood, and it is deliberately not used here. That literature has moved from 2.1 (Sathre and O'Connor 2010, 21 studies) to 1.2 (Leskinen 2018, 51 studies) to 0.55 at market level (Hurmekoski 2021, 44 studies, range 0.27–1.16), with a French critique arguing the benefit has been overstated several fold. A kilogramme of cement not made is a physical quantity this model already prices and emits; a displacement factor is an argument about counterfactuals. The model takes the physical route and leaves the argument to the annex.

  • FPInnovations / Gouvernement du Québec, comparative LCA of an 8-storey mass-timber residential building (Arbora, Montréal) — bill of materials
  • Hurmekoski et al. 2021, «Substitution impacts of wood use at the market level», Environmental Research Letters — market-level displacement factor 0.55 (0.27–1.16)
  • FCBA/BIPE 2019 for CODIFAB, FBF and ADEME — element-level equivalences: 1 kg of wood replaces 5.24 kg of concrete and 0.18 kg of rebar in a load-bearing CLT façade
timber_steel_saving17kg steel per m² of floor framed in timberProvisional

From the same measured building, and deliberately the net figure: the timber structure removes about 21 kg/m² of reinforcement, and adds back steel balconies, galvanised studs and brick support, so the whole-building balance is roughly −17 kg/m². Against the 21 kg/m² this model books for new French housing that is most of it — which is exactly why the national effect is small: new buildings are about a tenth of French steel, so even a wholesale switch to timber moves the steel bar by a few percent. ADEME's own biosourced scenario finds −2% then −5% on steel against −2% then −8% on cement, and this model reproduces that asymmetry rather than asserting it.

  • FPInnovations / Gouvernement du Québec, comparative LCA of an 8-storey mass-timber residential building — whole-building steel balance
  • ADEME 2019, «Prospective de consommation de matériaux pour la construction des bâtiments», scénario «développement des biosourcés»
timber_wood_intensity0.189m³ of wood product per m² of floor framed in timberProvisional

Two independent anchors agree, which is the only reason this number is here at all. The measured mass-timber building carries 2 597 m³ of cross-laminated timber, glulam beams and glulam columns over 13 766 m² — 0.189 m³/m². The French biosourced-building label's top level asks for 45 kgC/m² for housing, which at the carbon content and density of softwood is 0.200 m³/m². Light timber frame sits well below both, so 0.189 is a mass-timber figure and overstates what an ossature-bois house uses; the model says so rather than splitting a coefficient it cannot source.

  • FPInnovations / Gouvernement du Québec, Arbora mass-timber building — 2 047 m³ CLT + 378.2 m³ beams + 171.6 m³ columns over 13 766 m²
  • Arrêté du 2 juillet 2024, label «bâtiment biosourcé» — 45 kgC/m² for level 3 in housing
sawnwood_roundwood_factor2m³ of roundwood per m³ of sawn productProvisional

A sawmill turns roughly half of a sawlog into sawn timber; the rest is slabwood, sawdust and bark, and most of it is sold as chips, pellets or panel furnish rather than lost. The factor is what lets construction timber demand be compared with the long-lived harvest the forest account already computes, and 2.0 is the round number the trade uses. It is provisional because a national yield is not published on the same perimeter as this model's harvest.

  • Agreste, «Récolte de bois et production de sciages en 2024» — 18.3 Mm³ of sawlogs against 8.16 Mm³ of sawnwood produced
timber_share_base0fractionGame rule

Zero, matching the hidden timberShare lever, so the timber term is identically zero everywhere in this edition.

hwp_base_sink-0.4MtCO₂/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the base-year wood-products balance. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
hwp_carbon_per_m30.8373tCO₂/m³Provisional

PLACEHOLDER — French value carried, not national data: carbon carried into the wood-products pool per cubic metre of long-lived harvest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
hwp_half_life28.87yearsProvisional

PLACEHOLDER — French value carried, not national data: the half-life of the long-lived wood-products pool. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
hwp_stock_nir_2021359.4MtCO₂Provisional

PLACEHOLDER — French value carried, not national data: the wood-products stock the national inventory report implies. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
grassland_sink_coefficient0.6237tCO₂/ha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: absorption per hectare of permanent grassland. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
cropland_source_coefficient0.6777tCO₂/ha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: emission per hectare of arable land. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
artificialisation_carbon_content96.2tCO₂ per ha/y of flowProvisional

PLACEHOLDER — French value carried, not Spanish data: emission per unit of annual artificialisation. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
wetland_other_source1.2MtCO₂/yProvisional

PLACEHOLDER — French value carried, not Spanish data: wetlands, other land and dams. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
peat_rewetted_emission5tCO₂e/ha/yProvisional

PLACEHOLDER — French value carried, not national data: what a rewetted hectare of organic soil still emits, in tCO₂e a year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
peat_rewetting_base0fraction of the drained organic soilProvisional

PLACEHOLDER — French value carried, not national data: the share of the drained organic soil already rewetted in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
peat_agri_n2o_ef0tCO₂e/ha/yProvisional

PLACEHOLDER — French value carried, not national data: the N₂O of a drained hectare of agricultural organic soil, in tCO₂e a year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
soil_practice_potential_arable14.777MtCO₂/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the soil-carbon potential on arable land. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
soil_practice_potential_grassland2.53MtCO₂/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the soil-carbon potential on grassland. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
artificialisation_to_arable_share0.75fractionProvisional

PLACEHOLDER — French value carried, not Spanish data: the share of artificialised land taken from arable land. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
artificialisation_to_grassland_share0fractionProvisional

PLACEHOLDER — French value carried, not national data: the share of artificialised land taken from permanent grassland. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
artificialisation_to_forest_share0fractionProvisional

PLACEHOLDER — French value carried, not national data: the share of artificialised land taken from forest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
artificialisation_rate_base52kha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the observed artificialisation rate. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
afforestation_rate_base0kha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: deliberate afforestation in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
grassland_conversion_base0kha/yProvisional

PLACEHOLDER — French value carried, not Spanish data: net grassland conversion in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
soil_practice_base0fractionProvisional

PLACEHOLDER — French value carried, not Spanish data: the share of the soil-carbon potential already taken. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
secten_sink_forest_2024-64.5MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's observed forest line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
secten_sink_hwp_20240.4MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's observed wood-products line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
secten_sink_grassland_2024-5.7MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's observed grassland line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
secten_sink_cropland_202411.7MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's observed cropland line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
secten_sink_artificial_20245MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's observed artificial-areas line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
secten_sink_wetland_20241.2MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not Spanish data: the inventory's observed wetlands line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
diet_dairy_index_base1index, base year = 1Game rule

One, by definition: dietDairy is an index on the base year, so the base year sits at 100%. It is declared rather than written into the formula so that the switched-off branch of the module names what it reads.

food_waste_cut_base0fraction of edible waste removedGame rule

Zero: the base year has cut none of its own waste, because the waste share is measured on it.

livestock_export_base1index, base year = 1Game rule

One: the export volumes the table declares are the base year, so the index that scales them is one there.

crop_export_base1index, base year = 1Game rule

One, like livestock_export_base: the export hectares the crop block declares are the base year's, and the index that scales them is one there.

n_intensity_base1index, base year = 1Game rule

One: mineral_n_base is the base-year delivery, and nIntensity is a percentage of it.

enteric_mitigation_base0fraction of cattleGame rule

Zero, and this is a statement about the calibration rather than about farming practice: the per-head emission factors are fitted to the observed inventory year, so whatever low-methane feeding that year already contained is inside the factors. The lever measures the change from there, and the change at the base year is nothing.

manure_methanised_base0fraction of manureGame rule

Zero, for the same reason as enteric_mitigation_base: the digesters the base year already runs are inside the observed emission factors, and the lever books the change from there. It is not a claim that no manure is methanised today.

agri_fuel_switch_base0fraction of farm fuelGame rule

Zero: the base year burns all of the fossil fuel the inventory measures on its farms.

ef_liquid_fossil_observed264gCO₂/kWhWorkbook

The observed emission factor of fossil liquid fuel, the value efLiquid slides away from and the one the base-year farm burned. It is used in one place only — to say how much energy the base year's farm fuel represents — and no emission is charged at it.

ln_two0.693147Published

The natural logarithm of two, which turns a half-life into a first-order decay rate: k = ln 2 / half-life. Declared once rather than written into a formula, like the nitrogen fraction of ammonia, because a number that appears in an equation should be a number a reader can find.

nh3_nitrogen_fraction0.822t N per t NH₃Published

14 ÷ 17: the nitrogen in a tonne of ammonia, from the atomic masses. It is the one number in this module that is chemistry rather than statistics, and it is what turns a nitrogen demand into an ammonia tonnage for the industry chain.

  • IUPAC atomic weights: N 14.007, H 1.008 — 14.007 / 17.031 = 0.8225
population_base68.55million peopleProvisional

PLACEHOLDER — French value carried, not national data: population in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
population_horizon69.21million peopleProvisional

PLACEHOLDER — French value carried, not national data: population at the horizon. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
diet_red_meat_base53.5kgec/cap/yProvisional

PLACEHOLDER — French value carried, not national data: observed red meat eaten per person. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
diet_poultry_base30.8kgec/cap/yProvisional

PLACEHOLDER — French value carried, not national data: observed poultry eaten per person. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
food_waste_base0.07fraction of the food supplyProvisional

PLACEHOLDER — French value carried, not national data: the edible share of the food supply that is thrown away. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
dairy_beef_coupling_share0.4fraction of beef productionProvisional

PLACEHOLDER — French value carried, not national data: the share of beef that is a by-product of the dairy herd. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
enteric_lipid_effect0.14fraction of enteric methane removedProvisional

PLACEHOLDER — French value carried, not national data: the enteric methane a low-methane ration removes. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
methanisation_abatement0.6fraction of manure methane removedProvisional

PLACEHOLDER — French value carried, not national data: the manure methane a digester avoids. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
refrigerants_fixed0.02MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not national data: refrigerant leakage on farms. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
mineral_n_base1 817kt N/yProvisional

PLACEHOLDER — French value carried, not national data: mineral nitrogen delivered in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
manure_n_spread_base735kt N/yProvisional

PLACEHOLDER — French value carried, not national data: nitrogen in the manure collected and spread. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
manure_n_grazing_base727kt N/yProvisional

PLACEHOLDER — French value carried, not national data: nitrogen deposited at pasture. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
fixation_n_base364.6kt N/yProvisional

PLACEHOLDER — French value carried, not national data: nitrogen fixed biologically by legumes. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
fixation_gain0.6fraction of base-year fixationProvisional

PLACEHOLDER — French value carried, not national data: the fixation added over the legume credit's span. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
legume_area_base1MhaProvisional

PLACEHOLDER — French value carried, not national data: legume area in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
legume_n_credit128kt N/yProvisional

PLACEHOLDER — French value carried, not national data: the mineral nitrogen a larger legume area replaces. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
legume_credit_span1.7MhaProvisional

PLACEHOLDER — French value carried, not national data: the increase in legume area that credit was booked over. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
organic_share_base0.056fraction of the arable areaProvisional

PLACEHOLDER — French value carried, not national data: the organic share of the arable area in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
organic_yield_ratio0.65fraction of the conventional yieldProvisional

PLACEHOLDER — French value carried, not national data: the organic yield as a fraction of the conventional one. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
n_yield_plateau0.9index, base-year dose = 1Provisional

PLACEHOLDER — French value carried, not national data: the dose, as a fraction of the base year's, down to which a conventional hectare keeps its yield. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
crop_nue_base0.67fraction of the nitrogen inputProvisional

PLACEHOLDER — French value carried, not national data: the nitrogen use efficiency of cropland, which sets how fast the yield falls below the plateau. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
crop_food_waste_share0.222fraction of the supplyProvisional

PLACEHOLDER — French value carried, not national data: the edible share of the plant-food supply wasted downstream of the farm. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
arable_share_food0.2696fraction of the non-energy arable areaProvisional

PLACEHOLDER — French value carried, not national data: the share of the non-energy arable area growing plant food. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
arable_share_feed0.4049fraction of the non-energy arable areaProvisional

PLACEHOLDER — French value carried, not national data: the share growing feed. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
arable_share_export0.2306fraction of the non-energy arable areaProvisional

PLACEHOLDER — French value carried, not national data: the share growing export crops. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
arable_share_other0.0949fraction of the non-energy arable areaProvisional

PLACEHOLDER — French value carried, not national data: fallow, seed and the rest. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
feed_forage_share0.576fraction of the feed areaProvisional

PLACEHOLDER — French value carried, not national data: the forage part of the feed area. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
energy_maize_area_base0MhaProvisional

PLACEHOLDER — French value carried, not national data: the arable area growing a main crop for a digester in the base year, in million hectares. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
energy_maize_dm_yield0t DM/haProvisional

PLACEHOLDER — French value carried, not national data: dry matter a hectare of that main crop yields, in tonnes. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
energy_maize_digestate_ef0tCO₂e/ha/yProvisional

PLACEHOLDER — French value carried, not national data: the digester and digestate emissions per hectare of that main crop, in tCO₂e a year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
compound_feed_share_poultry0.426fraction of compound feedProvisional

PLACEHOLDER — French value carried, not national data: poultry's share of compound feed. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
compound_feed_share_cattle0.272fraction of compound feedProvisional

PLACEHOLDER — French value carried, not national data: cattle's share of compound feed. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
compound_feed_share_pig0.225fraction of compound feedProvisional

PLACEHOLDER — French value carried, not national data: pigs' share of compound feed. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ef_mineral_n2o4.21024tCO₂e per t NProvisional

PLACEHOLDER — French value carried, not national data: the N₂O per tonne of mineral nitrogen. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ef_mineral_co21.2328tCO₂e per t NProvisional

PLACEHOLDER — French value carried, not national data: the urea and liming CO₂ per tonne of mineral nitrogen. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
crop_carbon_fixed0MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not national data: agricultural CO₂ the nitrogen dose does not drive — liming and the other carbon-containing fertilisers. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ef_organic_n2o2.01361tCO₂e per t NProvisional

PLACEHOLDER — French value carried, not national data: the N₂O per tonne of nitrogen in spread manure. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ef_grazing_n2o1.9945tCO₂e per t NProvisional

PLACEHOLDER — French value carried, not national data: the N₂O per tonne of nitrogen deposited at pasture. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ef_other_crop_n2o2.26424tCO₂e per t N of total inputProvisional

PLACEHOLDER — French value carried, not national data: the remaining crop N₂O per tonne of nitrogen input. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
residue_burning_fixed0.02MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not national data: field burning of crop residues. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
farm_fuel_202410.73MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not national data: the combustion emissions of farm and forestry engines. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
grassland_rough1.38846MhaProvisional

PLACEHOLDER — French value carried, not national data: the rough grazing the farm survey and the land survey disagree about. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ammonia_non_fertiliser148.6kt NH₃/yProvisional

PLACEHOLDER — French value carried, not national data: the ammonia the chemical industry makes for something else. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
ammonia_domestic_share_base0.34fractionProvisional

PLACEHOLDER — French value carried, not national data: the base-year share of nitrogen made inside the country. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
citepa_livestock_202445.7MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not national data: the inventory's observed livestock line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
citepa_crops_202421.1MtCO₂e/yProvisional

PLACEHOLDER — French value carried, not national data: the inventory's observed crops-and-soils line. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
biomass_biogas_yield2MWh PCI per t DMPublished

Methane yield of the wet feedstocks a digester takes — manure, crop residues and grass alike, which is how the source publishes it, as one number rather than three. Cover crops get their own, higher figure (cive_biogas_yield), because a whole green plant digests better than straw or a slurry does. It is shared rather than national because it is a property of the substrate, not of the country: the same tonne of dry manure yields the same methane in Germany. What is national is how many tonnes there are, which is manure_dm_per_cattle_head and its neighbours.

cive_biogas_yield2.8MWh PCI per t DMPublished

A winter intermediate crop harvested whole gives 250–320 Nm³ of methane a tonne of dry matter, and a normal cubic metre of methane is 9.97 kWh PCI, so the range is 2.5–3.2 MWh/t DM. 2.8 is its middle, and it is the figure that makes the mission's own arithmetic work: 6 t DM/ha × 2.8 is 17 TWh per million hectares, which is what the report quotes.

residue_liquid_yield2MWh per t DMPublished

A tonne of dry residue turned into a second-generation liquid fuel by the thermochemical route yields the same 2.0 MWh as the same tonne turned into biogas, which is exactly why the two compete: choosing one forecloses the other at no gain in energy. Declared separately from the biogas figure so that a source which does separate them can move one without the other. The equality is not a coincidence of rounding — Fischer-Tropsch converts at up to 50% and a digester's methane at a similar order — but it is a coarse number, and the route's real efficiency depends on the plant.

wood_energy_per_m32.14MWh per m³Published

Two administrations publish two numbers and the game has to pick one. The energy directorate's biomass balance uses 2.14 MWh per cubic metre of roundwood; the environment inspectorate's annex uses 2.4. 2.14 is taken because it is the figure the balance that also supplies non_forest_wood and waste_wood is written on, and mixing two conventions inside one total would be worse than choosing the lower of them. The difference is 12%, or about fourteen terawatt-hours on the base year — larger than any single lever in this block moves. It is shared rather than national because it is a conversion, not a measurement of a country: what varies across borders is the species mix behind it, and a country that knows its own should say so in the why of the entries that use it.

manure_dm_per_cattle_head0.6t DM per head per yearProvisional

PLACEHOLDER — French value carried, not national data: collectable manure dry matter per head of cattle, in tonnes a year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
manure_dm_per_pig_head0.08t DM per head per yearProvisional

PLACEHOLDER — French value carried, not national data: the same per pig. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
manure_methanised_20240.1fraction of collectable manureProvisional

PLACEHOLDER — French value carried, not national data: the share of collectable manure that reached a digester in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
cive_dm_yield6t DM per hectareProvisional

PLACEHOLDER — French value carried, not national data: dry matter a hectare of winter cover crop yields, in tonnes. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
cive_area_base0.15MhaProvisional

PLACEHOLDER — French value carried, not national data: the cover-crop area in the base year, in million hectares. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
cive_land_ceiling4MhaProvisional

PLACEHOLDER — French value carried, not national data: the spring-crop area that could carry a cover crop at all. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
residue_dm_yield3.3015t DM per hectareProvisional

PLACEHOLDER — French value carried, not national data: crop residues an arable hectare produces, in tonnes of dry matter. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
residue_mobilisation_base0.01fraction of the residue poolProvisional

PLACEHOLDER — French value carried, not national data: the share of them already carried off the field in the base year. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
residue_to_biogas_share0.5fraction of mobilised residuesProvisional

PLACEHOLDER — French value carried, not national data: how the mobilised residues split between a digester and a 2G liquid plant. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
biogas_other18.9947TWh/yProvisional

PLACEHOLDER — French value carried, not national data: the biogas feedstock the module does not build — biowaste, sludge, landfill gas. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
wood_byproduct_share0.581fraction of the material harvestProvisional

PLACEHOLDER — French value carried, not national data: the share of the material harvest that comes back as sawmill and pulp-mill fuel. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
non_forest_wood22.8TWh/yProvisional

PLACEHOLDER — French value carried, not national data: wood energy from hedges, orchards and trees outside woodland, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
waste_wood9TWh/yProvisional

PLACEHOLDER — French value carried, not national data: end-of-life wood burned for energy, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
biofuel_1g_yield18.899MWh per hectareProvisional

PLACEHOLDER — French value carried, not national data: fuel a hectare of first-generation energy crop yields, in MWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
energy_crop_area_base0.618MhaProvisional

PLACEHOLDER — French value carried, not national data: the first-generation energy-crop area in the base year, in million hectares. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
waste_fats_supply3TWh/yProvisional

PLACEHOLDER — French value carried, not national data: used cooking oil and animal fats made into liquid fuel, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
bio_imports_base26.4TWh/yProvisional

PLACEHOLDER — French value carried, not national data: liquid biofuel and feedstock imported in the base year, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
sdes_wood_2024120.05TWh/yProvisional

PLACEHOLDER — French value carried, not national data: observed primary consumption of wood energy in the base year, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
sdes_biogas_202424.25TWh/yProvisional

PLACEHOLDER — French value carried, not national data: observed primary consumption of biogas in the base year, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
sdes_biofuel_202441.7TWh/yProvisional

PLACEHOLDER — French value carried, not national data: observed primary consumption of liquid biofuel in the base year, in TWh. Inert, because land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The bioenergy module is switched off in this edition (`land_module_active` = 0), so nothing reads it.

Data tables

The categories the model iterates over. Every row is addressed by its identifier, which is what the formulas in the next section refer to.

Passenger transport categories Published

Built from JRC-IDEES-2021 for 2019, the last pre-Covid year: Spanish aviation lost 62% of its passenger-kilometres in 2020 and car traffic 20%, and a 2050 stock model anchored on a lockdown would be wrong in a way no lever could undo. IDEES publishes passenger-kilometres, vehicle-kilometres and energy for every mode and, for cars and buses, for every engine type, so the three columns are ratios of published quantities rather than assumptions: occupancy is pkm/vkm and unit consumption is energy/vkm. demand × unit_consumption / occupancy therefore reproduces IDEES's own energy exactly. Three Spanish differences worth reading before playing. Spanish car occupancy is 1.24 against France's 1.87 — the biggest single difference in this table, and it means a Spanish car-sharing lever has far more room than a French one. Spanish cars are 74% diesel by passenger-kilometre and Spanish petrol cars are much thirstier than French ones (88.5 kWh/100 vkm against 68.3), which is a fleet-age effect. And Spain has a large compressed-natural-gas bus fleet: 5.3 Gpkm of 33.2. Domestic aviation is anchored on the inventory, not on the energy balance, and the difference is a factor of 2.3. Spain's balance books 2 378 ktoe of domestic aviation in 2019, which at 3.15 tCO₂ per tonne would be 7.1 MtCO₂; the Spanish inventory reports 3.144 for CRF 1A3a. The same comparison on France agrees to 4%, so this is a Spanish reporting artefact and not a method difference. The row is inside the inventory perimeter, so the inventory wins: 11.76 TWh, giving 4 856 kWh per 100 vehicle-km. Using the balance would have put 15.6 TWh of phantom domestic aviation into the Spanish account. Spanish domestic aviation is structurally unlike French: 33.8 Gpkm on a mean stage of 796 km, because the Balearics, the Canaries, Ceuta and Melilla — the Territorios No Peninsulares — have no rail alternative at all. The domesticAviationRail lever cannot mean here what it means in France. The two international rows are split intra-EEA-and-UK from the rest of the world because they have different stage lengths, occupancies and unit consumptions. Together they are 55.7 TWh of kerosene, which equals Spain's published international aviation bunkers exactly — the check that the allocation is right. 77.6 million departing passengers on intra-EEA routes against France's 38.9: this is the inbound-tourism flow, outside the national inventory as a bunker memo item and inside the game's footprint. Two rows carry a convention rather than a measurement. car_fuel folds petrol, diesel, LPG and plug-in hybrid together, because the model has no hybrid row and IDEES books most of a plug-in hybrid's energy as petrol; LPG travels with the liquids, as Eurostat classifies it. train_short carries the electricity vector for the whole of metro, tram and conventional rail, of which about a third is diesel in Spain — the Iberian-gauge network is far less electrified than the French one — which understates its emissions and overstates its electricity. Mapping check against France: cars and vans together 1.10, rail 1.04, high-speed occupancy 0.98, car unit consumption 1.07 — all inside 15%. Two-wheelers 1.45 and buses 1.26 are outside, and the discrepancy is in the French table rather than in this extraction.

Rowvectorunit_consumptionoccupancydemand_2020in_inventoryaviation
Fuel car
car_fuel
liquid77.991.2442341.3910
Natural gas car
car_gas
gas66.991.20520.26910
Electric car
car_electric
electricity17.741.19850.34610
Fuel two-wheeler
two_wheeler_fuel
liquid43.371.169316.7710
Fuel bus and coach
bus_fuel
liquid635.224.2727.4410
Natural gas bus
bus_gas
gas759.5224.3695.3110
Electric bus
bus_electric
electricity323.9624.390.510
Hydrogen bus
bus_h2
hydrogen20024.369010
Metro, tram and conventional rail
train_short
electricity947.194.70820.97810
High-speed rail
train_long
electricity2 266.3241.14316.07310
Domestic aviation
aviation_domestic
liquid4 856.3139.59133.80111
Aviation, intra-EEA and UK
aviation_international
liquid4 283.89157.416140.69201
Aviation, rest of the world
aviation_intercontinental
liquid4 679.97219.64381.55601

Passenger demand reallocation Provisional

PLACEHOLDER — the French reallocation conventions carried onto the Spanish row set, not a Spanish scenario. Each row moves a share of one base-year category's demand to a horizon category; six of them are overridden by levers and the rest are fixed conventions. What is French is those conventions: 20/50/30 of fuel buses to gas, electric and hydrogen, and all two-wheelers to electric. What would close it is the PNIEC's own 2030 fleet targets extended to 2050, or a Spanish fleet-renewal study. Two rows are Spanish rather than carried, because the Spanish table has categories France's does not. intercontinental_keep holds the rest-of-the-world aviation row, which France does not separate. And aviation_to_rail is the one whose meaning genuinely differs: Spain's domestic aviation is largely island traffic with no rail alternative, so a Spanish domesticAviationRail at 100% would move flights to a train that cannot be built. The lever's bounds should be reconsidered for Spain, and that is a change to technology.yaml, not to this table. Rows the equations name by hand — car_to_fuel, car_to_gas, car_to_electric, car_to_rail, aviation_keep, aviation_to_rail — are all present, as the loader requires.

  • app/model/countries/FR/FR.yaml, table passenger_shift — the conventions this carries — Carried, not measured. Shares rather than stocks, so they are structurally portable; the entry is provisional because portable is not the same as Spanish.
Rowsourcetargetshare
car_to_fuel
car_to_fuel
car_fuelcar_fuel0
car_to_gas
car_to_gas
car_fuelcar_gas0
car_to_electric
car_to_electric
car_fuelcar_electric0
car_to_rail
car_to_rail
car_fueltrain_short0
gas_car_keep
gas_car_keep
car_gascar_gas1
electric_car_keep
electric_car_keep
car_electriccar_electric1
two_wheeler_to_electric
two_wheeler_to_electric
two_wheeler_fueltwo_wheeler_fuel1
bus_to_fuel
bus_to_fuel
bus_fuelbus_fuel0
bus_to_gas
bus_to_gas
bus_fuelbus_gas0.2
bus_to_electric
bus_to_electric
bus_fuelbus_electric0.5
bus_to_h2
bus_to_h2
bus_fuelbus_h20.3
gas_bus_keep
gas_bus_keep
bus_gasbus_gas1
electric_bus_keep
electric_bus_keep
bus_electricbus_electric1
h2_bus_keep
h2_bus_keep
bus_h2bus_h21
train_short_keep
train_short_keep
train_shorttrain_short1
train_long_keep
train_long_keep
train_longtrain_long1
aviation_keep
aviation_keep
aviation_domesticaviation_domestic1
aviation_to_rail
aviation_to_rail
aviation_domestictrain_long0
international_keep
international_keep
aviation_internationalaviation_international1
intercontinental_keep
intercontinental_keep
aviation_intercontinentalaviation_intercontinental1

Freight transport categories Published

Built from JRC-IDEES-2021 for 2019, with tonne-kilometres, vehicle-kilometres and energy from the same source so unit consumption is a ratio and not an assumption. Spain's freight system is far more road-bound than France's: rail carries 4.8% of Spanish inland tonne-kilometres against France's 10.4%. The truckRail lever therefore starts from half the base, and because Spain's network is largely Iberian gauge and its freight corridors are still being converted, the same slider position is a much bigger physical undertaking here. The maritime row is the one that will surprise a French reader. Spain's international maritime bunkers move 1 235 Gtkm, twice France's 588 and nearly six times Spain's own road freight, at 83.6 TWh of fuel oil — more than Spanish road freight burns. Algeciras, Valencia and Barcelona are transhipment ports: much of that tonnage never enters or leaves Spain, it changes ship. It sits outside the national inventory and inside the game's footprint. Whether a teaching model should charge Spain for the world's container traffic is a real question and the interface should ask it rather than answer it silently. Two conventions differ from France's on purpose. Light commercial vehicles are freight here and passengers in France, where they carry an occupancy of 1.8 as though they were cars; IDEES books them as freight with a load of 0.35 t, which is what they physically are. And air freight carries the liquid vector, not the gas one: the French setting is a workbook convention that puts about 23 TWh of air-freight fuel into the game's "biogas" resource, and it is a defect that is deliberately not copied. The truck_h2 and truck_electric rows carry no Spanish measurement — there were none of either in Spain in 2019 — and their unit consumptions are the shared file's technology figures. Mapping check on France: road freight 0.96 and rail-freight unit consumption 1.13 are inside 15%; rail freight 0.67, maritime 0.84, air freight 0.58 and truck unit consumption 0.63 are outside. The last matters most: the French 50 kWh/100 tkm is a lightly loaded truck, IDEES's 31 to 38 is the fleet average including full loads, and the value here is the Spanish fleet average.

Rowvectorunit_consumptiondemand_2020in_inventory
Hydrogen truck
truck_h2
hydrogen1501
Fuel truck
truck_fuel
liquid38.417212.7071
Electric truck
truck_electric
electricity1501
Light commercial vehicle
van_fuel
liquid271.2079.8271
Rail freight
rail_freight
electricity7.8110.711
Domestic coastal shipping
coastal_shipping
liquid120.19310.0421
International maritime bunkers
maritime
liquid6.7651 235.180
International air freight
air_freight
liquid59.842.4840

Freight demand reallocation Provisional

PLACEHOLDER — the French reallocation conventions carried onto the Spanish row set. Every base-year category keeps its demand unless a lever moves it, which is the French arrangement; what is Spanish is the row set, which has two categories France's does not — van_fuel for light commercial vehicles and coastal_shipping for the island traffic — and both need a keep-row here or their demand would vanish at the horizon. The four truck_to_* rows and the two air_* rows are the ones equations.yaml names, and they are all present. What would close this table properly: the PNIEC's freight-modal-shift objectives, or the Ministerio de Transportes' Estrategia Indicativa del Ferrocarril, which sets a rail-freight share target this pass did not fetch.

  • app/model/countries/FR/FR.yaml, table freight_shift — the conventions this carries — Carried, not measured.
Rowsourcetargetshare
truck_to_h2
truck_to_h2
truck_fueltruck_h20
truck_to_thermal
truck_to_thermal
truck_fueltruck_fuel0
truck_to_electric
truck_to_electric
truck_fueltruck_electric0
truck_to_rail
truck_to_rail
truck_fuelrail_freight0
h2_truck_keep
h2_truck_keep
truck_h2truck_h21
electric_keep
electric_keep
truck_electrictruck_electric1
van_keep
van_keep
van_fuelvan_fuel1
rail_keep
rail_keep
rail_freightrail_freight1
coastal_keep
coastal_keep
coastal_shippingcoastal_shipping1
maritime_keep
maritime_keep
maritimemaritime1
air_to_sea
air_to_sea
air_freightmaritime0
air_keep
air_keep
air_freightair_freight1

Building heating systems Workbook

The eight systems the stock is made of. is_destination says whether new surface can arrive: fuel boilers and electric resistance can only shrink, because nobody installs either in 2050, so the six remaining systems are what the stage-2 mix distributes over. heat_pump is used by the cost layer to price the equipment actually installed.

  • Teaching workbook, "Building parc 2020" and "Building heating" sheets
Rowis_destinationheat_pump
Biomass
biomass
10
Fuel boiler
fuel
00
Gas boiler
gas
10
Electric resistance
resistance
00
District heating
district
10
Air-air heat pump
air_air
11
Air-water heat pump
air_water
11
Hybrid heat pump
hybrid
11

Building stock segments Provisional

Twenty-four rows, eight heating systems × three building types, built from three sources each used for the one thing it measures. Floor area is the 2021 census (Eurostat's tabulation of INE's own): dwellings by type of building crossed with useful-floor-space band, summed at band midpoints with the open top band at 190 m². That gives 117.44 m² for a one- or two-dwelling building and 76.79 for a flat, and 89.0 m² overall — which is INE's own published mean, so the reconstruction closes on its source. The heating-system split is JRC-IDEES-2021. The surfacic need is IDEES's measured useful thermal energy service for space heating — heat delivered into the room, not fuel bought — divided by that segment's floor area and normalised to a normal winter by dividing by the year's relative heating degree-days (0.9466 in 2021, so these needs are 5.6% above what was actually consumed). Because the need is measured rather than normative, building_need_calibration is 1. Three assumptions, all stated, none of them moving a total. (1) Heating system is independent of building type: each system's dwellings are split house/flat in the census proportions, 29.6 / 70.4. No Spanish source crosses the two, and no equation reads the house/flat distinction — only building_type != "tertiary" is ever tested — so it affects presentation, not results. (2) A house needs 1.084 times as much heat per m² as a flat, a compactness effect measured on the French table, which is the only place both exist crossed. S × u is invariant to it. (3) All of IDEES's "advanced electric heating" is counted as air-to-air, because Spain's residential heat-pump stock is overwhelmingly reversible split air-conditioning: IDEES counts 6.87 million Spanish dwellings with air conditioning against 1.00 million with advanced electric heating. Only ground-source (234 dwellings) reaches the air-to-water rows, which is why they are nearly empty. Spain's aerotermia is real and this table does not see it; since air-to-water converts at 3.0 against air-to-air's 2.5, that understates the existing stock's efficiency by up to 20% on about 3.4 TWh of need. A fifth of Spanish dwellings have no heating installation at all. INE's census says 19.4%. IDEES has no such class — it allocates every dwelling to the carrier it uses for space heating, including portable appliances — so an unheated-by-INE dwelling appears here inside whatever system it occasionally uses, carrying a low need. A separate row was not added, and the reason is structural: building_vector joins on system, so a row whose system is not one of the eight would be dropped from the peak calculation and its heat would vanish. The 19.4% is instead visible in the surfacic needs, which average 36.6 kWh/m²/y against roughly 92 in the French table — a factor 2.5 that is part climate and part unheated space, and that a Spanish teacher should be ready to explain. Coal and LPG. IDEES's residential "Solids" class is folded into the fuel row, because coal's emission factor (0.34 kgCO₂/kWh) is within 5% of fuel oil's (0.324) and the model has no residential coal system; folding it into biomass would have zeroed its emissions. LPG, which Spain uses far more than France does, is also in fuel: Eurostat classifies it under oil products, which is where building_usage already puts it. District heating is exactly zero in both halves, because IDEES reports no distributed heat in either. Six of the twenty-four rows are structural zeros, as are the three hybrid rows. The weakest number here is the tertiary floor area, and it is weak enough to be worth a warning. IDEES's Spanish services stock is 2 230.8 Mm², or 140.0 m² per service-sector employee, against 43.6 for France and 102.6 for Germany in the same dataset. The symptom is visible in these rows: the tertiary segments come out at 10.6-11.7 kWh/m²/y of space-heating need, which is not credible for a heated building and is the signature of an overstated floor area rather than of an efficient stock. The heat is unaffected — S × u reproduces IDEES's measured 24.06 TWh whatever the area — but every euro per square metre the cost panel prints for the tertiary sector is understated in the same proportion, plausibly by a factor of two to three. The Catastro's built-area statistics or ERESEE 2020 would settle it; neither was reachable.

Rowsystembuilding_typesurface_2020surfacic_needdwellings
Biomass, apartment
biomass_apartment
biomassapartment235 899 37436.28993 072 137
Fuel boiler, apartment
fuel_apartment
fuelapartment242 215 05635.67983 154 387
Gas boiler, apartment
gas_apartment
gasapartment356 005 15336.59574 636 284
Electric resistance, apartment
resistance_apartment
resistanceapartment143 732 34132.66841 871 838
District heating, apartment
district_apartment
districtapartment000
Air-air heat pump, apartment
air_air_apartment
air_airapartment53 786 65737.2488700 468
Air-water heat pump, apartment
air_water_apartment
air_waterapartment12 64636.2698165
Hybrid heat pump, apartment
hybrid_apartment
hybridapartment000
Biomass, house
biomass_house
biomasshouse151 832 39539.3261 292 856
Fuel boiler, house
fuel_house
fuelhouse155 897 37038.66481 327 469
Gas boiler, house
gas_house
gashouse229 136 32139.65731 951 101
Electric resistance, house
resistance_house
resistancehouse92 510 73935.4015787 731
District heating, house
district_house
districthouse000
Air-air heat pump, house
air_air_house
air_airhouse34 618 81540.365294 780
Air-water heat pump, house
air_water_house
air_waterhouse8 13939.304169
Hybrid heat pump, house
hybrid_house
hybridhouse000
Biomass, tertiary
biomass_tertiary
biomasstertiary76 838 68910.56060
Fuel boiler, tertiary
fuel_tertiary
fueltertiary536 575 29810.55640
Gas boiler, tertiary
gas_tertiary
gastertiary598 482 20211.03940
Electric resistance, tertiary
resistance_tertiary
resistancetertiary53 955 16811.71990
District heating, tertiary
district_tertiary
districttertiary000
Air-air heat pump, tertiary
air_air_tertiary
air_airtertiary964 852 25910.72530
Air-water heat pump, tertiary
air_water_tertiary
air_watertertiary93 39210.29090
Hybrid heat pump, tertiary
hybrid_tertiary
hybridtertiary000

Heating system efficiencies and vector mix Provisional

Only two of this table's seven columns are national — unit_2020 and unit_2050, the repartition keys that say what a network or a hybrid heat pump actually burns. The five efficiency columns are carried from the shared French file, because they are equipment physics rather than national stock, and the entry is declared provisional for that reason rather than for the Spanish half. The Spanish answer to the district-heating question is that there is none, and it is measured. Eurostat's household balance reports no derived heat in Spanish dwellings; JRC-IDEES reports zero dwellings and zero energy on "Distributed heat" for space heating in every year 2000-2021; and its services workbook reports zero building cells on distributed heat as well. So every district_* row carries unit_2020: 0 and unit_2050: 0, and the corresponding building_segment rows carry zero surface: the six rows multiply nothing. The consequence for the game is worth stating rather than hiding: the two district levers should be disabled for Spain. A slider that lets a Spanish player decarbonise heat through networks that do not exist is a fiction, not a simplification. ADHAC's Censo de redes de calor y frío would say what exists below the balance's resolution — a few hundred small biomass networks in Soria, Navarra and the Basque Country — and any Spanish district-heating story is a growth-from-nothing story, which is the opposite of the French argument the interface makes.

Rowsystemvectorseasonal_efficiencypeak_efficiencypeak_shareunit_2020unit_2050
Biomass, wood
biomass_wood
biomasswood0.850.85111
Fuel boiler, fuel oil and LPG
fuel_liquid
fuelliquid0.90.9111
Gas boiler, gas
gas_gas
gasgas0.950.95111
District heating, gas
district_gas
districtgas0.850.85100
District heating, fuel oil
district_liquid
districtliquid0.850.85100
District heating, wood
district_wood
districtwood0.850.85100
District heating, coal
district_coal
districtcoal0.850.85100
District heating, other
district_other
districtother0.850.85100
District heating, heat pump
district_electricity
districtelectricity2.51.5100
Electric resistance, electricity
resistance_electricity
resistanceelectricity11111
Air-air heat pump, electricity
air_air_electricity
air_airelectricity2.52111
Air-water heat pump, electricity
air_water_electricity
air_waterelectricity32111
Hybrid heat pump, electricity
hybrid_electricity
hybridelectricity330.30.950.95
Hybrid heat pump, gas
hybrid_gas
hybridgas0.950.950.70.050.05

Where the cement and the steel go Game rule

Not ported. No end-use map of Spain's cement has been assembled for this edition, so the whole base-year tonnage sits in the residual row and the two new-build rows carry zero intensity. The module's arithmetic then returns 17980 kt unchanged, which is exactly what the cement chain read before the module existed — and a test asserts that every one of the four construction levers moves no output at all here. What a port needs is in the French file: an end-use split between new build, civil engineering and the rest; a cement and a steel intensity per square metre; and the floor area built each year. The French version of this table also shows that the two published maps of a country's cement are unlikely to reconcile, and where to keep the difference.

Rowcement_intensitysteel_intensitycement_2024steel_2024floor_2024driver
New housing
housing_new
00000none
New non-residential
other_new
00000none
Roads, networks and civil works
civil_works
00000none
All of it, unattributed
unattributed
0017 98000none

Industrial production routes Workbook

Unit consumption in MWh per tonne of product and process emissions in tCO₂ per tonne. These are shared by the physical model and the cost model, so the two can never drift apart. Grey ammonia's 0.914 MWh/t of gas is an order of magnitude below the roughly 9 MWh/t of a real reforming plant; it is kept for continuity with the workbook energy balance but the figure needs review, and the cost module prices that route from POMMES instead. The cement row carried electricity and a process term but no kiln fuel at all until 0.9.0: a clinker kiln burns 0.70 MWh a tonne and the model had it burning nothing, which left about 9 TWh of industrial fuel — and the combustion emissions that go with it — outside the account. The three fuel intensities are the source workbook's own, from its plaster/lime/cement branch sheet. The kiln row carries its electricity and nothing else since 0.29.0. Its fuel was 0.700 MWh a tonne of clinker in gas and "liquid", which a French kiln does not burn; it is now computed from kiln_heat_per_tonne and kilnAltFuel — petroleum coke, coal and the fossil half of the waste on the coal carrier, the biomass half on the wood carrier — because how much of it is waste is a choice the player makes, and a static row cannot carry a choice.

Rowsubpostelectricitygascoalliquidhydrogen
Steel — BF-BOF
steel_bf
steel0.1940.625.0474200
Steel — H₂-DR-EAF
steel_dri
steel1.2310.55001.683
Steel — EAF from scrap
steel_eaf
steel0.9180000
Ammonia
ammonia
ammonia0.7780005.94
Olefins — CO₂ + H₂
olefins
olefins5.95120001.32
Cement clinker
cement
cement0.15230000

Industrial plant, capital and fixed cost Published

CAPEX in euros per tonne of annual capacity, lifetime in years, fixed O&M in euros per tonne of capacity per year. The annualised cost is CAPEX × CRF(discount rate, lifetime) + fixed O&M, at full utilisation.

Rowcapexlifefixed
Blast furnace + BOF
steel_bf
4422553
H₂ direct reduction + EAF
steel_dri
4142553
Electric arc furnace
steel_eaf
1842553
Haber-Bosch ammonia
haber_bosch
1 0002050
Water electrolyser
electrolyser
1 12511.4216.87
Steam methane reformer
smr
3 24325546
Cement kiln
cement_kiln
186259.31
Cement kiln with capture
cement_kiln_ccs
4562522.81
Methanol synthesis
methanol
3002015
Methanol to olefins
methanol_to_olefins
1 0002063.7

Flight categories Published

Rebuilt rather than translated. The French table is the DGAC's eight route categories, three of them involving Outre-mer, and there is no Spanish analogue. What Spain has is Eurostat's aviation statistics, which JRC-IDEES republishes with passengers, passenger-kilometres and vehicle-kilometres for three route groups — domestic, intra-EEA-and-UK, and the rest of the world. Those three are the Spanish categories, and an average stage length follows from dividing one column by another. pax_2023 and pkt_2023 keep the French column names, which are the table's schema; the values are 2019, the last pre-Covid year. The basis is departing flights. Eurostat counts a passenger once, at the airport they leave from. The DGAC statistic behind the French table counts traffic at French airports in both directions, which is why the French international row is 364 Gpkm against IDEES's 184 for the same country and year — a ratio of 0.51, almost exactly one half. The energy of the two constructions agrees to 5%, because the French table compensates with a unit consumption per passenger-kilometre that is half the physical one. A reader comparing the two flight tables is comparing activity on two conventions and energy on one; the departing basis used here is the one that matches the international-bunker convention the inventory uses. Spain's tourism shows up in one number: 77.6 million departing passengers on intra-EEA-and-UK routes, against France's 38.9.

Rowpax_2023pkt_2023game_row
Domestic — peninsula and islands
domestic
42.4933.8aviation_domestic
Intra-EEA and United Kingdom
intra_eea
77.65140.69aviation_international
Rest of the world
rest_of_world
15.1681.56aviation_intercontinental

The rest of industry — energy and process emissions Provisional

The observed corner is Spanish; the 2050 corners are French ratios on Spanish structure, and the interface has to say so. e00, the observed situation, is Spanish: JRC-IDEES-2021's Spanish energy balance for 2021, by manufacturing branch and by carrier, with the five branches the game models as explicit value chains removed so nothing is counted twice — iron and steel, cement, basic chemicals (which contains ammonia and olefins), and food, drink and tobacco. Total 123.2 TWh of final energy against France's 173.9. e10, the 2050 output at 2019 processes, equals e00: there is no Spanish industrial output index to 2050. The direct consequence is that otherIndustryVolume does nothing in Spain and should be hidden or relabelled rather than shown as a working slider. e01 is the French per-branch, per-carrier substitution ratio applied to the Spanish e00. Where the French e00 for a carrier is zero and its e01 is not — the biomass and hydrogen that arrive rather than shrink — the French e01 is taken as a share of the French group total and applied to the Spanish group total. e11 = e01 × (e10/e00) = e01. The branch mapping was checked on France and it does not reproduce the French table. Group by group: metals and machinery 0.85, minerals 1.03, other chemicals 0.79, paper 0.80, other industries 0.94. Two of five inside 15%. The differences are perimeter and they are identifiable: mining, quarrying and construction are excluded here because the French table comes from EACEI, a manufacturing survey (including them would add 21.6 TWh in Spain and 22.5 in France, and would make the French total match to 0.4% by coincidence); other chemicals is over-trimmed, because removing the whole basic-chemicals branch removes chlorine, soda and industrial gases too; and paper biomass is 7.2 TWh in the Eurostat balance for France against 14.2 in the French table, because black liquor is counted differently. The two process rows are national-inventory arithmetic and are the least trustworthy rows here. minerals__process is Spain's CRF 2A minus 2A1 (cement, which the cement chain already carries): 11.3382 − 8.4716 = 2.8666 MtCO₂ in 2021. chemicals_other__process is CRF 2B minus 2B1 (ammonia) minus 2B8 (petrochemical and carbon black): 3.3516 − 0.2908 − 1.9243 = 1.1365. The same construction on France gives 3.25 against the French table's 1.9912 (1.63) and 1.92 against 0.5559 (3.46). A 3.5-fold disagreement means the French perimeter is narrower than "the inventory minus the modelled chains" and could not be reconstructed. The Spanish figures are measurements on a stated perimeter; the French ones are not comparable with them. Spain's branch structure really is different, and it shows: minerals is Spain's largest rest-of-industry group at 35.8 TWh — ceramics in Castellón, glass, lime, plaster — where France's largest is metals and machinery. Spanish minerals burn 18.0 TWh of gas and 7.7 of oil against France's 13.7 and 3.5, so the group is both bigger and dirtier, and otherIndustryProcess has more to work on here.

Rowgroupcarriere00e10e01e11
Metals and machinery — coal
metals_machinery__coal
metals_machinerycoal0.01520.015200
Metals and machinery — oil
metals_machinery__oil
metals_machineryoil1.89211.892100
Metals and machinery — gas
metals_machinery__gas
metals_machinerygas12.245712.245711.176411.1764
Metals and machinery — biomass
metals_machinery__biomass
metals_machinerybiomass0.39880.39880.71130.7113
Metals and machinery — electricity
metals_machinery__electricity
metals_machineryelectricity16.05316.05336.925436.9254
Metals and machinery — hydrogen
metals_machinery__hydrogen
metals_machineryhydrogen0.01410.01410.01560.0156
Metals and machinery — steam
metals_machinery__steam
metals_machinerysteam0000
Minerals and building materials — coal
minerals__coal
mineralscoal0.08370.083700
Minerals and building materials — oil
minerals__oil
mineralsoil7.65557.655500
Minerals and building materials — gas
minerals__gas
mineralsgas17.989217.98929.91299.9129
Minerals and building materials — biomass
minerals__biomass
mineralsbiomass3.88943.889400
Minerals and building materials — electricity
minerals__electricity
mineralselectricity6.21546.215412.04512.045
Minerals and building materials — hydrogen
minerals__hydrogen
mineralshydrogen000.07350.0735
Minerals and building materials — steam
minerals__steam
mineralssteam0000
Minerals and building materials — process
minerals__process
mineralsprocess2.86662.86662.79722.7972
Chemicals, other — coal
chemicals_other__coal
chemicals_othercoal0.54180.541800
Chemicals, other — oil
chemicals_other__oil
chemicals_otheroil0.33280.332800
Chemicals, other — gas
chemicals_other__gas
chemicals_othergas12.913812.91383.08833.0883
Chemicals, other — biomass
chemicals_other__biomass
chemicals_otherbiomass0.3190.3190.23320.2332
Chemicals, other — electricity
chemicals_other__electricity
chemicals_otherelectricity3.93283.93289.00759.0075
Chemicals, other — hydrogen
chemicals_other__hydrogen
chemicals_otherhydrogen0.73510.73511.46521.4652
Chemicals, other — steam
chemicals_other__steam
chemicals_othersteam0000
Chemicals, other — process
chemicals_other__process
chemicals_otherprocess1.13651.136500
Paper and board — coal
paper__coal
papercoal0000
Paper and board — oil
paper__oil
paperoil0.75120.751200
Paper and board — gas
paper__gas
papergas7.33827.33825.70435.7043
Paper and board — biomass
paper__biomass
paperbiomass6.08396.08395.91955.9195
Paper and board — electricity
paper__electricity
paperelectricity6.0736.07310.441910.4419
Paper and board — steam
paper__steam
papersteam0000
Other industries — coal
other_industries__coal
other_industriescoal0000
Other industries — oil
other_industries__oil
other_industriesoil0.89150.891500
Other industries — gas
other_industries__gas
other_industriesgas3.37973.37970.73260.7326
Other industries — biomass
other_industries__biomass
other_industriesbiomass5.89585.89581.25821.2582
Other industries — electricity
other_industries__electricity
other_industrieselectricity7.5577.55710.201210.2012
Other industries — steam
other_industries__steam
other_industriessteam0000

Building energy by usage, observed Provisional

Final energy by usage and by carrier. The residential half is Eurostat 2023 and the tertiary half is JRC-IDEES 2021, because Eurostat publishes end-use detail for households and not for services. Every figure is a published quantity divided by 3 600 or multiplied by 0.01163; the residential carriers sum to the published household total to the last digit, which is the check that the table is complete on its own perimeter. The tertiary rows are provisional, and the reason is a mapping check that failed. Run on France, the same four IDEES rows give specific electricity 67.9 TWh against the French CEREN table's 70.3 — a ratio of 0.97 — and then diverge completely: hot-water electricity 1.93, catering electricity 2.74, catering liquid 38, and services cooling 0.19 (IDEES 4.2 TWh where CEREN gives 21.7). Those are not Spain-versus-France differences: they are two European series disagreeing about the same country in the same year, so one of them is wrong about French services. The cooling one matters most here — cooling is the Spanish usage that grows, and if CEREN's method is right the Spanish cooling row is understated by a factor of three or four and usageCoolingGrowth is growing a number that starts far too small. Two conventions. The wood column is Eurostat's whole "renewables and biofuels" aggregate, which also contains solar thermal and the ambient heat harvested by heat pumps; the French table excludes harvested heat explicitly, so this column over-states solid biomass. And heat is district heat, zero everywhere in Spain. other_tertiary is zero in every carrier, and that is a perimeter statement rather than a measurement. JRC-IDEES decomposes Spanish services energy into exactly five end uses — space heating, cooling, hot water, catering and specific electricity — with no residual: the five sum to the branch total. France's equivalent row carries 10.7 TWh because CEREN's tertiary series has an "autres usages" category IDEES does not. So the zero here is "this source has no such category", not "Spain uses no energy this way", and it means the Spanish tertiary account is 10 TWh thinner than the French one for reasons of nomenclature.

Rowusagesegmentelectricitygasliquidwoodheat
Hot water, residential
dhw_residential
dhwresidential4.3215.7211.14.090
Cooking, residential
cooking_residential
cookingresidential6.962.32.561.330
Air conditioning, residential
cooling_residential
coolingresidential3.870000
Specific electricity, residential
specific_residential
specificresidential52.130000
Hot water, tertiary
dhw_tertiary
dhwtertiary3.744.294.370.560
Catering, tertiary
cooking_tertiary
cookingtertiary6.3511.341.2400
Air conditioning, tertiary
cooling_tertiary
coolingtertiary8.130.12000
Specific electricity, tertiary
specific_tertiary
specifictertiary47.050000
Other uses, tertiary
other_tertiary
othertertiary00000

Spanish electricity mixes Published

Six mixes reduced to shares of supply, so each can be applied to whatever electricity the rest of the model needs rather than carrying its own demand. Two come from Spanish national documents and four from the ENTSO-E / ENTSOG TYNDP 2024 market-modelling outputs for the Spanish bidding zone ES00, climate year 2009. The lever picks a row by position, so the order is the argument. They are ordered by increasing firm thermal generation, which is the Spanish axis, because the French one does not exist here. There is no nuclear question in Spain: the ordered closure plan retires all seven reactors between 2027 and 2035, the TYNDP's own ex-ante nuclear table gives ES00 zero from 2040 in all three scenarios, and only the 2030 row at position 6 still has any. What the slider moves instead is how much dispatchable gas a Spanish system still runs — from none at all to the 10% the 2030 plan has — which is the adequacy question, and the model has no hourly balance with which to answer it. Three of the six are not 2050 mixes. Positions 4 and 5 are 2040 and position 6 is 2030. National Trends+ has no 2050 run — it is the NECP-based scenario and the plans stop earlier — so a 2040 row is the only honest way to offer it. Conventions applied to all six, each a decision rather than a result. Pumped storage, batteries, electrolyser load and demand-side response are excluded from the denominator: they are re-generation or demand, not supply, which is also how the PNIEC computes its own "porcentaje directo". Photovoltaic is split between ground and roof on the TYNDP's own Spanish rooftop share (21.34% at 2040, 28.24% at 2050) and, for the two national rows, on the PNIEC's 19 GW self-consumption target (24.909%). Concentrated solar power is folded into pv_ground because the model has no CSP row — 17 to 20 TWh in the TYNDP rows, 3 to 4% of supply, whose steel and concrete are nothing like a PV farm's, so the material account is wrong on that slice. And all Spanish offshore wind is floating: the shelf drops away fast on both coasts and MITECO's Hoja de Ruta plans floating capacity only.

Rowscenario_indexnuclearpv_groundpv_roofwind_onshorewind_offshore_fixedwind_offshore_floatinghydrobioenergygas_turbinecombined_cycle
ELP 2050 — 100% renewable
elp_2050
100.3595390.1069630.403941000.08974720.039809900
TYNDP 2024 Global Ambition, 2050
tyndp_ga_2050
200.2740930.09157380.51973100.04408060.05108430.016121300.003316
TYNDP 2024 Distributed Energy, 2050
tyndp_de_2050
300.2635960.08822920.54136200.03697570.04783380.015147600.0068553
TYNDP 2024 Distributed Energy, 2040
tyndp_de_2040
400.3045470.07182130.50803200.03903890.05131520.015985500.0092598
TYNDP 2024 National Trends+, 2040
tyndp_nt_2040
500.3771690.09189910.39150200.02300190.04515130.014718200.0565594
PNIEC 2023-2030 — the 2030 mix
pniec_2030
60.08852450.291460.08670960.327454000.07275350.032269200.100829

Generation technologies, material intensity Provisional

Only the load_factor column is Spanish. It is the resource, not the technology: a Spanish panel earns half again what a French one does, a Spanish onshore turbine slightly more, and Spanish hydro considerably less. Every other column — material intensity per MW, CAPEX, OPEX, lifetime, thermal efficiency, fuel carrier, hydrogen capability — is carried unchanged from the shared French file, and the entry is declared provisional for that reason rather than for the load factors. Where each load factor comes from is in its own paragraph, because they come from two different places and mixing them silently would be the easy mistake. Solar, onshore wind, hydro, bioenergy, the combined cycle and nuclear are generation over capacity in the PNIEC's own tables, so numerator and denominator are the same scenario and are consistent with the 2030 mix. Offshore wind and the gas turbine come from the TYNDP 2024 ES00 runs, because the PNIEC has nothing to say about either. Three numbers a Spanish player should be made to look at. Hydro at 0.226 against France's 0.295: Spanish hydrology is drier and far more variable, and the drought years are much worse than the mean. Offshore wind at 0.464, the highest load factor in the table and roughly twice the onshore figure, which is why every TYNDP run keeps building it despite the cost. And the combined cycle at 0.086: Spain keeps its whole 26.6 GW gas fleet to 2030 and runs it 757 hours a year — the capacity is there for adequacy, not for energy, which is the point the cost panel should make.

Rowrenewableload_factorthermal_efficiencyfuel_carrierhydrogen_capablelifetimecapex_per_kwopex_per_kw_yearsteelconcretealuminiumcopperlithiumcobaltnickelrare_earth
Nuclear
nuclear
00.9002370none06011 900100675330.351.61.5e-073.8e-0502.3e-05
Solar PV, ground
pv_ground
10.2069890none0257471128.470635.137317.43.19.37e-070.0003202.2235e-05
Solar PV, rooftop
pv_roof
10.2069890none0257471116.176528.8627123.18.7e-070.00031396201.9765e-05
Wind, onshore
wind_onshore
10.2393370none0251 300402004500.692.67.1e-063.4e-0504.2e-05
Wind, offshore fixed
wind_offshore_fixed
10.4643260none0202 6008025091018.58.1e-063.65e-0500.106674
Wind, offshore floating
wind_offshore_floating
10.4643260none0202 600804801 7001.158.558.55e-064.8e-0500.106676
Hydro
hydro
10.2262810none0701 0001598210.520.181.9e-070.0001409e-05
Bioenergy
bioenergy
10.658630.25gas0253 000120573.50.0590.127.2e-075.4e-0505.4e-06
Gas turbine
gas_turbine
00.020120none025800486.3410.750.791.5e-087.2e-0606.4e-06
Combined cycle
combined_cycle
00.0864480.6gas1301 1004829361.11.23.6e-080.001802e-05

Vehicle production and material intensity Provisional

PLACEHOLDER — French production carried, not Spanish data, and this is the block where carrying is least defensible. Only production_2050 and electric_share are national; the kilogrammes of steel and aluminium per vehicle and the battery sizes are technology and are the shared file's. Spain is the European Union's second vehicle producer, after Germany and ahead of France, and it produces far more vehicles than it registers. The material account of the Spanish transition is therefore an export industry's account rather than a domestic fleet's — which makes this block more interesting here than in France, not less, and makes carrying France's numbers a real understatement rather than a neutral placeholder. That ranking was not re-verified in this pass and no Spanish figure was obtained. What would close it: ANFAC's Informe Anual, which gives Spanish production by segment. Even with it the 2050 column would be an assumption, because no Spanish 2050 production scenario exists — so the honest end state for this table is "sourced today, declared for 2050", which is what France's is too.

Rowproduction_2050battery_kwhelectric_sharesteelaluminium
Car
car
2 500 004450.99951 111130
Utility vehicle
van
500 004800.99599052
Bus and coach
bus
15 7834000.94316 7851 670
Truck
truck
55 0051 0000.98 738351
Motorcycle
motorcycle
220 00714122226
Moped
moped
110 0028122226
Bicycle
bicycle
15 701 8790.5168

Battery material intensity by chemistry Workbook

Tonnes per MWh of battery. The two the model blends are the two credible 2050 options; the source also documents NMC 333, NCA and LTO.

  • Offre_et_demande.xlsx, "Matériaux transports" sheet rows 19-28
Rowsteelaluminiumcopperlithiumcobaltnickel
NMC 811
nmc_811
1.911.80.1110.0270.75
LFP
lfp
21.31.60.496.8e-060.03

Hydrogen production routes Published

Per MWh of hydrogen produced. methane is the feedstock and fuel together, which is how a reformer is measured; carbon_captured is the share of the carbon in that methane that ends up underground rather than in the air. Electrolysis has no methane, and its electricity column is zero because the figure is derived in the equations from the conversion efficiency the rest of the model uses — declaring it here as well would be two copies of one number. The reformer figures come from the constants the cost layer already used and nothing else did: 3.33 t of methane and 9.23 tCO2 per tonne of hydrogen, converted at the lower heating values declared beside them.

Rowmethaneelectricitycarbon_captured
Electrolysis
electrolysis
000
Steam methane reforming
smr
1.390.01740
Autothermal reforming + capture
atr_ccs
1.450.030.94

The land of Spain Provisional

PLACEHOLDER — French areas carried, not Spanish data. The seven class ids are the model's and are fixed; the areas are France's, and they add up to France's territory rather than to Spain's. Nothing reads them: land_module_active is 0. A national land-cover survey with one nomenclature and a published national total is what replaces them, and the areas have to be declared at the survey's own precision because the account's closure is asserted on their sum.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Rowarea_2023soil_carbon_stockpeat_areapeat_ef
Arable land
arable
17.264851.600
Permanent grassland
grassland
9.1385484.600
Vines and orchards
perm_crops
1.2757140.400
Forest
forest
17.52138100
Heath, scrub and bare ground
other_natural
3.444277900
Water and wetlands
water
1.03458000
Artificialised
artificial
5.240063000

Climate cases for the forest Provisional

PLACEHOLDER — French factors carried, not Spanish data. Three cases, mildest first, as factors on the base-year production and mortality at the horizon. A national forest-sector projection with named climate cases is what replaces them; the number of rows may differ, and the forestClimate lever's range follows it automatically. Nothing reads them: land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The land module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Rowpositionproduction_factormortality_factor
C1 — mild
c1
10.991.1
C2 — central
c2
20.881.4
C3 — severe
c3
30.751.6

The herd Provisional

PLACEHOLDER — French values carried, not national data. The six category ids are the model's and are fixed; the herd, the emission factors and the grassland requirement are France's. A national farm survey for the herd and the national inventory's own livestock lines for the factors are what replace them, and the per-head factors have to be re-calibrated on the national total or the base-year check will not close. Nothing reads them: land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Rowspecies_groupheads_2024emission_factorenteric_mitigablemanure_ch4_sharemanure_n_2024grassland_ha_per_head
Dairy cows
dairy_cow
cattle3.0763 69710.2300.390.765333
Suckler cows
suckler_cow
cattle3.6753 12810.06358.890.765333
Other cattle
other_cattle
cattle9.7061 62510.12568.720.4592
Pigs
pig
pig11.902207.52800.95780
Poultry
poultry
poultry272.7240.8433400.6640
Sheep and goats
small_ruminant
small_ruminant7.868551.60100.05920.1148

Animal products, and where they go Provisional

PLACEHOLDER — French values carried, not national data. The five product ids are the model's and are fixed; the consumption, the trade position and the production are France's. A national food balance sheet and farm survey replace them, and the export volumes have to be derived from the other three so the base year closes exactly. Nothing reads them: land_module_active is 0.

  • countries/FR/FR.yaml — French value carried unchanged. The food module is switched off in this edition (`land_module_active` = 0), so nothing reads it.
Rowspeciesconsumption_baseper_capita_2024import_shareexport_baseproduction_2024waste_share
Beef and veal
beef
suckler_cow1 42420.80.255206.121 2670.088
Pork
pork
pig2 11630.60.3617.82 0990.088
Sheep meat
sheep
small_ruminant1452.10.5842.11030.088
Poultry
poultry
poultry2 13330.80.46540.181 6920.191
Cow milk
milk
dairy_cow21 240309.80.3339 432.9223 6000.108

Scoreboard bands Game rule

These set the difficulty of the game. Three of the ten have a published Spanish number behind them; the rest are the French bands transposed by a stated ratio, and the ratio is different for each because what the band should scale with is different for each. Declared here rather than in the interface because the feasibility tool has to score the same scenario the player does. The four emission bands are on the game perimeter — the footprint basis, which counts life-cycle electricity and international bunkers — and not on the inventory figures the sector cards show. Scoring one against the other's band would be meaningless, and it matters more in Spain than in France because Spanish bunkers are much larger relative to everything else. * total — Spain's published 2050 gross target is 29 MtCO₂e (ELP 2050) against France's 63 (SNBC 3), a ratio of 0.4603. The French bands, 15 and 30, scaled by it give 6.9 and 13.8, rounded to 7 and 14. * transport — the ELP's 2050 transport figure is 2 MtCO₂e on the inventory perimeter, which excludes international aviation and shipping, and the game's perimeter does not. That is exactly why the French band (4 / 10) sits far above the French target (0.6). Scaled instead by the two countries' observed 2024 transport emissions, 90.374 / 125.350 = 0.7210, giving 2.9 and 7.2, rounded to 3 and 7. * building — the ELP's 2050 building figure is zero: «el sector de la edificación estará totalmente descarbonizado». A band of zero would make the indicator useless, so it is scaled by the observed 2024 building emissions, 23.504 / 56.073 = 0.4192, giving 1.26 and 2.93, rounded to 1.5 and 3. The band being this tight is the right signal: Spanish buildings emit 42% of what French ones do and the strategy asks for all of it. * industry — the only band with a directly published number. The ELP sets Spanish industry at 7 MtCO₂e in 2050, from 72 in its base year. Target 7, limit 11. * peak — France's 35 / 45 GW scaled by the same 0.2967 ratio of the two stocks' electric peak load that sets building_peak_2020, giving 10.4 and 13.4, widened to 14 and 18 so the band brackets the reference rather than sitting on top of it. And it is a winter band in a country whose peak may become a summer one — see the controversy table. * biogas, biofuel, biomass — the three resource bands, scaled from the French ones by Spain's observed consumption of each: biogas 4.36 TWh against France's, pure biodiesel and biogasoline 20.2 TWh, primary solid biofuels 65.4 TWh. They are not resource assessments; ENSPRESO's Spanish potentials would replace all three with measurements, and that is the single cheapest improvement to this table. * agriculture — declared and not scored. This edition switches the land and food module off (land_module_active: 0), so the three agriculture rows of the post table are empty by construction and the scoreboard leaves the line out instead of printing a free green zero. The band is declared so the table keeps one shape in every edition: good 14 is the ELP 2050 agriculture figure of 14.03 MtCO₂e rounded, warning 21 is 1.5 times it. * sink — the second published number, added in 0.26.0: the ELP's own 2050 absorption of 37 MtCO₂e (official_natural_sink_2050), scored against the land sink as a magnitude. The line exists because the net line is hinged at zero and so stops charging a scenario for leaning on the land the moment it crosses; the French file gives the full argument. With the land module off, what it reads here is the naturalSink slider, whose default is that same 37 — so the reference pays nothing, and pushing the slider to 60 stops being free. warning 60 is the top of that slider, a teaching rule. * techsink — zero, the ELP's own engineered removals, added in 0.31.0. It is scored the way the net line is, against gross emissions: a megatonne of engineered removal beyond the strategy costs exactly what it buys on the net line. A Spanish scenario can still add capture, and see what it does to the account; it cannot win by it, because the strategy it is scored against closes on natural sinks alone. warning 20 is the slider's flag.

Rowgoodwarning
Total emissions, game perimeter
total
714
Transport emissions
transport
37
Building emissions
building
1.53
Industry emissions
industry
711
Agriculture emissions
agriculture
1421
Winter electricity peak
peak
1418
Biogas
biogas
2040
Biofuels
biofuel
2035
Wood energy
biomass
65100
Land sink reliance
sink
3760
Engineered removals
techsink
020

Contested assumptions Game rule

A model that shows its sources still hides which of them are argued over. This table names them. weight is how much the answer moves: high means a reasonable person taking the other side gets a materially different 2050. Four of the eight entries are structural — they are about the model, not about a country — and are carried from the French table with their numbers made Spanish. Four are Spanish: the nuclear axis that does not exist, the technological sink that is not needed, the tertiary floor area that is probably wrong, and the summer peak the model cannot see.

Rowtopicweightpositioncontestedsettles_it
Is burning wood carbon-neutral?
wood_factor
emission factorshigh27 gCO2/kWh in 2050, rather than the zero the biogenic convention gives it — and the 27 is a French figure carried, because no Spanish life-cycle factor for the wood chain was found.The convention books the CO2 against the forest that regrew, not the boiler. Whether that holds depends on the harvest, the rotation and the counterfactual, none of which this model has — and Spanish forestry is not French forestry: drier, slower-growing, and burning. Spain imports a larger share of its pellets than France does, which adds transport the factor does not carry.A carbon-debt payback period for Spanish forestry and a rule for which harvests qualify — and, first, a Spanish life-cycle factor at all.
Spain needs no technological sink, and that is the point
technological_sink
carbon sinkshighZero. The ELP 2050 closes on natural sinks alone — 37 MtCO2e absorbed against 29 emitted, so the strategy is net -8 MtCO2e — and names no technological removals at all. The slider still reaches 30 so a player can add some and see what it costs.The French edition of this game carries 43 MtCO2e a year of capture as a closure residual and calls it, in this same table, the single largest assumption in the model: nothing builds the plant, powers it or pays for it. Spain simply does not need the line. Comparing the two countries here is the clearest way to show a student what that French number is doing.Nothing to settle on the Spanish side. What is worth watching is whether the update of the ELP, in public consultation until January 2025 and not yet approved, introduces one.
Spain's official pathway weakens its own sink
natural_sink
carbon sinkshigh37 MtCO2e absorbed in 2050, the ELP's own figure, adjustable from 15 to 60. The default therefore sits below the 51.9 MtCO2e observed in 2024.Spain's inventory sink is -51.9 MtCO2e in 2024, its 2030 objective -43.6 and its 2050 figure -37: the plan expects the sink to shrink by a third. Drought, fire and an ageing stock make that a forecast rather than a target, and the 2022 and 2023 fire seasons alone moved several MtCO2e. A player who slides this to 60 is assuming a forest growing faster than any Spanish forest has.Forest inventory projections under climate and fire stress. Genuinely hard, and harder in Spain than in France.
A winter peak band in a country heading for a summer peak
peak_limit
system constraintshighTarget 14 GW, limit 18, on the electric-heating contribution alone, and the 11.9 GW anchor behind them is the French anchor rescaled by the ratio of the two stocks, not a Spanish measurement.Two things at once. Red Electrica publishes no decomposition of the Spanish peak by end use, so the anchor is a transposition. And the indicator is the wrong season: Spain's 2024 peninsular maximum was a winter one, 40.5 GW on 11 January, but the summer maximum is close behind, cooling already takes 3.87 TWh of residential and 8.13 TWh of services electricity, and the model has no summer constraint at all. A Spanish player can pass this indicator while building a system that fails in August.A summer peak indicator, and a Spanish adequacy study. The first is a change to the model, not a missing number.
There is no nuclear question in Spain
nuclear_share
electricity supplyhighSix mixes are offered and five of them have no nuclear at all: the ordered closure plan retires all seven Spanish reactors between 2027 and 2035, and the TYNDP's own capacity table gives Spain zero from 2040 in every scenario. The slider is ordered by firm thermal generation instead.The closure calendar itself is politically live and has been argued over since 2024. But the deeper point is what replaces the French argument: with no nuclear axis, the Spanish question is adequacy — storage, firm capacity and interconnection — and this model has no hourly balance, no storage and no adequacy calculation. A 100%-renewable Spanish mix is applied exactly as a gas-backed one is.Hourly dispatch with storage and flexibility, and the 22.5 GW of storage the PNIEC plans for 2030 put into it. Until then the cost shown here is plant only.
Is the Spanish services floor area three times too big?
tertiary_floor_area
building stockmedium2 231 Mm2 of Spanish services floor area, from JRC-IDEES, which is what the cost panel divides its euros by.The same dataset gives 140.0 m2 per service-sector employee for Spain against 43.6 for France and 102.6 for Germany. Those three cannot all be right on one definition. The symptom is visible in the stock table: the Spanish tertiary segments come out at 10.6 to 11.7 kWh per m2 per year of space-heating need, which is not credible for a heated building. The heat is unaffected — surface times need reproduces the measured 24 TWh whatever the area — but every euro per square metre printed for the tertiary sector is understated in the same proportion.The Catastro's built-area statistics by use, or ERESEE 2020. Neither could be downloaded: the Catastro pages are JavaScript-driven and every ERESEE URL returned 403 or 404.
How much of the Spanish 2050 is actually French?
french_assumptions
what is carriedhighNamed rather than hidden. The rest-of-industry table's observed corner is Spanish and every assumption about how it decarbonises is a French ratio; the waste-heat and efficiency ceilings are French studies; the two transport reallocation tables are French conventions; seven other entries carry a French value outright. NOTES.md lists every one of them in a table.A ratio travels better than a stock — the physics of a compressor is not national — but "better" is not "well". What is French in these entries is the starting point: the efficiency already captured, the plant vintage, the fleet-renewal story. Spanish industry is younger in steel and older in ceramics, and its bus fleet already runs on gas where France's does not.Spanish equivalents, one at a time: IDAE's efficiency studies, the sEEnergies excess-heat datasets, the PNIEC's fleet targets. Each is a document, not a research programme.
The gap to the ELP
perimeter_gap
accountingmediumReported as a named reconciliation, never divided away.Arithmetic rather than controversy, and listed so the distinction is visible — but the gap is bigger here than in France. The model counts life-cycle electricity, at 157.5 gCO2/kWh in the Spanish base year against France's 79, and it counts international bunkers, which for Spain are 140 TWh of aviation and marine fuel including the transhipment traffic of Algeciras and Valencia. Neither is in the inventory. Whether a teaching model should charge Spain for the world's container ships is a question worth asking out loud.Nothing to settle on the arithmetic. The bunker question is a convention, and the interface should state it rather than resolve it.

Emissions and energy posts Provisional

One row per sub-sector: the constructive account every sector total is a sum of. The row set and the sector mapping are the model's; what is national is the three ratio columns, and all three are French ratios carried deliberately. ADEME expresses the recoverable waste-heat gisement per unit of fuel burned and RTE, after CEREN, expresses the electricity-efficiency potential as a percentage of consumption. Both are ratios attached to a process, not stocks attached to a country, which is why OTHER_COUNTRIES.md ranks them sixth-hardest to port rather than first: a Spanish cement kiln rejects heat in about the same proportion as a French one. What is French is the branch mix those ratios were averaged over and the vintage of the plant they were measured on. Spanish industry is younger in some branches — steel, largely rebuilt as electric arc — and older in others. And there is a Spanish twist the French ratios cannot express: Spain has no heat networks to deliver recovered heat into, so the waste heat this table finds has nowhere to go, which is a bigger constraint here than the size of the gisement. The named replacement is the sEEnergies family of European industrial excess-heat datasets, which covers Spain and would fix this for every country at once. It has never been explored. Transport and building rows are zero because the ADEME study is industrial, exactly as in France.

Rowsectorkindwaste_heat_sharewaste_heat_hot_shareelec_efficiency_ceiling
Passenger mobility
passenger_mobility
transportmobility000
Freight
freight_mobility
transportmobility000
Residential heating
residential_heating
buildingheat000
Tertiary heating
tertiary_heating
buildingheat000
Residential, other uses
residential_uses
buildingother000
Tertiary, other uses
tertiary_uses
buildingother000
Electricity generation
energy_production
energyother000
Hydrogen production
hydrogen_production
energyother000
Waste to energy
waste_to_energy
energyother000
Steel
steel
industryprocess0.012490.64490.11412
Ammonia
ammonia
industryprocess0.018310.43970.31091
Olefins and plastics
olefins
industryprocess0.018310.43970.31091
Cement
cement
industryprocess0.086760.83540.24128
Food-industry heat
food_heat
industryheat0.016430.32760.25011
Metals and machinery
other_metals
industryother0.061850.5560.15539
Minerals and materials
other_minerals
industryother0.087480.82830.24128
Chemicals, other
other_chemicals
industryother0.018310.43970.31091
Paper and board
other_paper
industryother0.31080.33480.19258
Other industries
other_diverse
industryother0.11130.54120.23636
Livestock
livestock
agricultureprocess000
Crops and soils
crops
agricultureprocess000
Farm and forestry engines
farm_machinery
agricultureother000

Every equation

The complete calculation, in the order it is evaluated. A name in a formula is either a lever, a constant, or another equation in this list; row.x is a field of the row being computed; and sum(table.column, condition) totals a column over the rows that satisfy the condition.

Transport — demand reallocation

Every 2020 service demand is reallocated to the 2050 categories through an explicit matrix. Reading the matrix is the only way to see that, for instance, car demand shifted to rail is then served at the occupancy and unit consumption of a train rather than a car.

NameFormulaUnitNotes and sources
shift_share
per row of passenger_shift
car_to_fuel: carFuel
car_to_gas: carGas
car_to_electric: carElectric
car_to_rail: carRail
aviation_keep: 1 - domesticAviationRail
aviation_to_rail: domesticAviationRail
default: row.share
fraction

Fixed workbook conventions come from the table; the six shares a lever drives are overridden here. The four car shares and the two aviation shares each sum to one by construction of the controls.

aviation_demand_factor(1 + aviationDemandGrowth) ** aviation_demand_horizon_yearsmultiple of 2020 demand

Growth compounded over thirty years. At the default of 0%/year it is exactly 1, which reproduces the workbook: the workbook carries 2020 air traffic straight through to 2050.

demand_2050_before_shift
per row of passenger
row.demand_2020 * (aviation_demand_factor if row.aviation == 1 else 1)Gpkm/y

Only aviation carries a demand trend. Road and rail demand is set by the modal levers, which is where the player's choices act.

passenger_flow
per row of passenger_shift
passenger[row.source].demand_2050_before_shift * (1 - passengerReduction) * row.shift_shareGpkm/y—
passenger_demand
per row of passenger
sum(passenger_shift.passenger_flow, passenger_shift.target == row.id)Gpkm/y—
aviation_efficiency_factor(1 - aviationEfficiency) ** aviation_horizon_yearsfraction of today's consumption

A yearly improvement compounded to 2050. At the default of 0%/year it is exactly 1, which reproduces the workbook: the workbook gives 2050 aviation the same consumption per passenger-kilometre as today.

unit_consumption_2050
per row of passenger
row.unit_consumption * (aviation_efficiency_factor if row.aviation == 1 else 1)MWh per million vehicle-kilometres

Only aviation carries an efficiency trend. Road and rail keep the workbook's 2050 values, in which the shift between vehicle types already does the work.

passenger_energy
per row of passenger
row.passenger_demand * row.unit_consumption_2050 / row.occupancy / 100TWh/y

Unit consumption is per vehicle-kilometre, so dividing by occupancy converts it to passenger-kilometres. The factor 100 carries the unit change from the workbook's mixed units to TWh.

freight_shift_share
per row of freight_shift
truck_to_h2: truckH2
truck_to_thermal: truckThermal
truck_to_electric: truckElectric
truck_to_rail: truckRail
air_to_sea: freightAviationSea
air_keep: 1 - freightAviationSea
default: row.share
fraction—
freight_flow
per row of freight_shift
freight[row.source].demand_2020 * (1 - freightReduction) * row.freight_shift_shareGtkm/y—
freight_demand
per row of freight
sum(freight_shift.freight_flow, freight_shift.target == row.id)Gtkm/y—
freight_energy
per row of freight
row.freight_demand * row.unit_consumption / 100TWh/y—

Transport — energy by vector

Liquid fuel is split between biofuel and e-fuel by the biofuel-share lever, and the e-fuel half is converted back into the electricity needed to make it, at the declared conversion efficiency. Hydrogen is handed on as hydrogen: the posts module converts it through the production mix, like every other consumer's. That is why an electrified transport scenario still shows a large electricity demand even where no vehicle is plugged in.

NameFormulaUnitNotes and sources
passenger_liquidsum(passenger.passenger_energy, passenger.vector == "liquid")TWh/y—
passenger_gassum(passenger.passenger_energy, passenger.vector == "gas")TWh/y—
passenger_electricity_directsum(passenger.passenger_energy, passenger.vector == "electricity")TWh/y—
passenger_hydrogensum(passenger.passenger_energy, passenger.vector == "hydrogen")TWh/y—
freight_liquidsum(freight.freight_energy, freight.vector == "liquid")TWh/y—
freight_gassum(freight.freight_energy, freight.vector == "gas")TWh/y—
freight_electricity_directsum(freight.freight_energy, freight.vector == "electricity")TWh/y—
freight_hydrogensum(freight.freight_energy, freight.vector == "hydrogen")TWh/y—
passenger_biofuelpassenger_liquid * biofuelShareTWh/y—
passenger_electricity_efuelpassenger_liquid * (1 - biofuelShare) / efficiency_electricity_to_efuelTWh/y—
freight_biofuelfreight_liquid * biofuelShareTWh/y—
freight_electricity_efuelfreight_liquid * (1 - biofuelShare) / efficiency_electricity_to_efuelTWh/y—

Building heating

The stock says how much heat the country needs and anchors the winter peak. What covers that heat is set by target: so many TWh of wood, such a share of the need on electricity, and that electric heat split across five technologies with genuinely different efficiencies — in season and, which is what the peak cares about, on the coldest evening. Gas is the residual. It is not a target and has no slider: it absorbs whatever the other choices leave uncovered, which is what makes the account close by construction and what makes the cost of not choosing visible. If the targets over-subscribe the need, gas goes to zero and a surplus is reported rather than silently absorbed.

NameFormulaUnitNotes and sources
need_2020
per row of building_segment
row.surface_2020 * row.surfacic_need / 1000000000 * building_need_calibrationTWh/y

Surface times surfacic need, scaled by the one stock-wide calibration that lands the 2020 account on the observed 359.34 TWh.

need_2050
per row of building_segment
row.need_2020 * (1 - bldgRetrofit) * (1 - bldgSobriety)TWh/y

Retrofit and temperature-related sufficiency act on the need itself, before any heating system sees it, so they benefit every vector alike and they are the only levers that lower the peak without changing a single technology.

building_heat_needsum(building_segment.need_2050)TWh/y—
building_heat_need_residentialsum(building_segment.need_2050, building_segment.building_type != "tertiary")TWh/y

Apartments and houses. The stock carries the building type, so the residential/tertiary split of every vector is counted rather than assumed — the allocation is national, but the need it is applied to is not.

building_residential_sharebuilding_heat_need_residential / building_heat_needfraction—
vector_need_2020
per row of building_vector
sum(building_segment.need_2020, building_segment.system == row.system)TWh/y—
vector_peak_load_2020
per row of building_vector
row.vector_need_2020 * row.unit_2020 / row.peak_efficiency * row.peak_shareTWh/y equivalent

The 2020 stock at its own peak efficiencies. This is the denominator of the peak anchor and the only thing the segment table is still needed for once the allocation is set by target.

building_peak_load_2020sum(building_vector.vector_peak_load_2020, building_vector.vector == "electricity")TWh/y equivalent—
heat_from_biomassbldgBiomassTwh * building_vector["biomass_wood"].seasonal_efficiencyTWh/y

Wood burned times the boiler efficiency gives the heat delivered.

heat_from_electricitybldgElectricShare * building_heat_needTWh/y—
heat_from_district_wooddistrictWoodTwh * building_vector["district_wood"].seasonal_efficiencyTWh/y—
heat_from_district_wastedistrictWasteTwhTWh/y

Recovered heat is delivered as it is found; no conversion, no losses charged.

heat_targetedheat_from_biomass + heat_from_electricity + heat_from_district_wood + heat_from_district_wasteTWh/y—
heat_from_gasmax(0, building_heat_need - heat_targeted)TWh/y

The residual, floored at zero. Gas is the only thing here without a slider, which is the point: it is what a scenario is left burning.

building_heat_surplusmax(0, heat_targeted - building_heat_need)TWh/y

What the targets over-subscribe, once gas has gone to zero. It is reported rather than absorbed, because a scenario that has quietly allocated more heat than the stock needs is a scenario whose numbers should not be trusted, and the interface says so.

electric_split_totalbldgElecAirAir + bldgElecAirWater + bldgElecResistance + bldgElecHybrid + bldgElecDistrictHPfraction

The interface rebalances these five to 100%, but a scenario file is just JSON and can be hand-edited. Normalising here means the electric heat is shared out rather than over- or under-allocated, so the five shares cannot between them invent heat that the target did not grant.

heat_air_airheat_from_electricity * bldgElecAirAir / electric_split_total if electric_split_total > 0 else 0TWh/y—
heat_air_waterheat_from_electricity * bldgElecAirWater / electric_split_total if electric_split_total > 0 else 0TWh/y—
heat_resistanceheat_from_electricity * bldgElecResistance / electric_split_total if electric_split_total > 0 else 0TWh/y—
heat_hybridheat_from_electricity * bldgElecHybrid / electric_split_total if electric_split_total > 0 else 0TWh/y—
heat_district_hpheat_from_electricity * bldgElecDistrictHP / electric_split_total if electric_split_total > 0 else 0TWh/y—
electricity_air_airheat_air_air / building_vector["air_air_electricity"].seasonal_efficiencyTWh/y—
electricity_air_waterheat_air_water / building_vector["air_water_electricity"].seasonal_efficiencyTWh/y—
electricity_resistanceheat_resistance / building_vector["resistance_electricity"].seasonal_efficiencyTWh/y—
electricity_hybridheat_hybrid * building_vector["hybrid_electricity"].unit_2050 / building_vector["hybrid_electricity"].seasonal_efficiencyTWh/y

A hybrid runs 95% of its output on electricity over the year and the rest on gas — and reverses that on the coldest evening, which is what the peak calculation picks up.

gas_hybridheat_hybrid * building_vector["hybrid_gas"].unit_2050 / building_vector["hybrid_gas"].seasonal_efficiencyTWh/y—
electricity_district_hpheat_district_hp / building_vector["district_electricity"].seasonal_efficiencyTWh/y—
building_electricityelectricity_air_air + electricity_air_water + electricity_resistance + electricity_hybrid + electricity_district_hpTWh/y—
building_gasheat_from_gas / building_vector["gas_gas"].seasonal_efficiency + gas_hybridTWh/y

The residual heat at a boiler efficiency, plus the gas a hybrid burns over the year. Network gas is charged the same efficiency as a boiler — the allocation no longer distinguishes a network from an individual installation, which slightly understates distribution losses and is stated rather than hidden.

building_woodbldgBiomassTwh + districtWoodTwhTWh/y—
building_waste_heatdistrictWasteTwhTWh/y—
building_liquid0TWh/y

Zero by construction: fuel oil is not one of the targets and gas is the residual, so no scenario can leave heating oil in 2050. Carried so the account stays constructive and so the post table keeps a line that would reappear the moment fuel became a choice again.

building_coal0TWh/y—
building_electricity_residentialbuilding_electricity * building_residential_shareTWh/y—
building_gas_residentialbuilding_gas * building_residential_shareTWh/y—
building_wood_residentialbuilding_wood * building_residential_shareTWh/y—
building_liquid_residentialbuilding_liquid * building_residential_shareTWh/y—
building_coal_residentialbuilding_coal * building_residential_shareTWh/y—
building_peak_load_2050heat_air_air / building_vector["air_air_electricity"].peak_efficiency + heat_air_water / building_vector["air_water_electricity"].peak_efficiency + heat_resistance / building_vector["resistance_electricity"].peak_efficiency + heat_hybrid * building_vector["hybrid_electricity"].unit_2050 / building_vector["hybrid_electricity"].peak_efficiency * building_vector["hybrid_electricity"].peak_share + heat_district_hp / building_vector["district_electricity"].peak_efficiencyTWh/y equivalent

Each technology at its peak efficiency rather than its seasonal one, and only the share of it actually running on electricity then. Those two things differ by technology in ways a single COP cannot express: air-air and air-water both fall to 2.0, a network heat pump to 1.5, resistance stays at 1, and a hybrid puts 70% of its peak on gas.

building_peakbuilding_peak_2020 * building_peak_load_2050 / building_peak_load_2020GW

The peak-coincident electric load is built for 2020 and for 2050 from the same rule, and the observed 2020 peak scales their ratio, so the anchor checks itself: run the 2020 stock through this and it returns 40 GW exactly. Electric space heating only, as in the source. Transport, industry and electrolysis change annual electricity but never this figure — a real asymmetry of the model, stated rather than silently patched.

building_surface_2020sum(building_segment.surface_2020) / 1000000Mm²—
building_surface_residentialsum(building_segment.surface_2020, building_segment.building_type != "tertiary") / 1000000Mm²—
building_surface_coveragebuilding_surface_2020 / floor_area_totalfraction

What share of France's floor area this stock covers: 3 654.9 Mm² of heated surface against the 4 200 Mm² ADEME reports after CEREN, so 87%. Every €/m² the model prints is per square metre of heated stock.

heat_pump_surface_2050building_surface_2020 * (heat_air_air + heat_air_water + heat_hybrid) / building_heat_needMm²

Surface in proportion to the heat that heat pumps cover. The allocation is national and carries no stock of its own, so this is a conversion rather than a count — enough to price the equipment, not enough to say which buildings got it.

heat_pump_surface_2020sum(building_segment.surface_2020, building_segment.system == "air_air" or building_segment.system == "air_water" or building_segment.system == "hybrid") / 1000000Mm²—
heat_pump_surface_addedmax(0, heat_pump_surface_2050 - heat_pump_surface_2020)Mm²

The surface that gains a heat pump it did not have in 2020 — what the scenario has to buy and install.

What the country builds, and what it takes

Stage A of the construction module. Until v0.20 no square metre was built anywhere in this model. Cement volume was a bare index — a player could remove a third of French cement by moving cementReduction without saying which building was not built — and the materials account knew about wind turbines and cars but not about buildings, which are the largest mineral flow in any industrial country. The chain is short and every step is an observation. Two floor-area levers set how much is built; the construction_use table says how many kilogrammes of cement and of steel a square metre of each destination carries, and how much of the country's cement no square metre reaches; a timber share converts part of that floor area to a frame that carries less of both and more wood. Cement demand then drives cement production, which is the change this stage exists to make. Three things this stage deliberately does not do, each because the evidence says it should not. It does not drive steel. New buildings are roughly a tenth of French steel use and about a sixth of the construction envelope, the rest being civil engineering, renovation and cladding; and construction itself is 43% of a demand whose other 57% is vehicles, machinery, tubes and metalware that nothing here models. Construction steel is computed and put beside production in the materials account, and steelGrowth remains the driver. A model that set steel output from floor area would be wrong by a factor of ten. It does not make the building stock grow. New floor area consumes cement here and heats nothing: building_heat_need still reads a stock frozen at its base-year surface. That is a real and named gap — the land account has been booking artificialised hectares since stage A of the land module while the building account stayed still — and it is stage B. It does not move the harvested-wood-products pool. Construction timber is compared with the long-lived harvest the forest account already computes, and the headroom is reported; the pool's inflow is calibrated on the inventory and is left alone. Making construction demand set the long-lived share is stage C, and it needs a sawn-versus-panel split the base year does not carry.

NameFormulaUnitNotes and sources
construction_floor_housingnewHousingMm²/y—
construction_floor_othernewNonResidentialMm²/y—
construction_floor_totalconstruction_floor_housing + construction_floor_otherMm²/y—
construction_timber_extraconstruction_floor_total * (timberShare - timber_share_base)Mm²/y

The floor area a scenario frames in timber beyond what the country already does. The base year's timber buildings are already inside the observed cement and steel tonnages the table carries, so booking the whole timber share as a saving would count today's timber twice. It can go negative — a scenario is free to build less in timber than the country does now — and then the sign works the other way, which is correct and is the reason it is not clamped.

construction_cement_savedconstruction_timber_extra * timber_cement_savingkt/y

Megagrammes per square metre are kilotonnes per square megametre, so the unit carries itself: Mm² times kg/m² is kt.

construction_steel_savedconstruction_timber_extra * timber_steel_savingkt/y—
construction_use_cement
per row of construction_use
housing_new: construction_floor_housing * row.cement_intensity
other_new: construction_floor_other * row.cement_intensity
civil_works: row.cement_2024 * civilWorksVolume
unattributed: row.cement_2024
kt/y

How much cement each end use asks for at the horizon. The two new-build rows are floor area times an intensity, which is the whole point of the module; civil works are a base-year tonnage times an index, because no square metre drives a road; and the residual row is held where it is, since a slider on a quantity nobody has attributed would be a slider on an accounting gap. An edition that has not been through its own end-use map declares zero intensities and puts all of its cement in the residual row. The arithmetic then returns the base-year tonnage unchanged, which is what the three provisional editions do and why they are unaffected by this module.

construction_use_steel
per row of construction_use
housing_new: construction_floor_housing * row.steel_intensity
other_new: construction_floor_other * row.steel_intensity
civil_works: row.steel_2024
unattributed: row.steel_2024
kt/y—
cement_demandmax(0, sum(construction_use.construction_use_cement) - construction_cement_saved)kt cement/y

The country's cement demand at the horizon, before any change in how much cement a cubic metre of concrete carries. At the reference it is the base-year total to the last digit: the four rows sum to it by construction, every index is 1, and the timber share sits on its own base — which is what lets this stage replace an exogenous volume without moving a single published result.

construction_steel_demandmax(0, sum(construction_use.construction_use_steel) - construction_steel_saved)kt/y

Structural and reinforcing steel for new buildings, computed and never read back: steelGrowth still sets what the country's mills make. The materials account puts the two side by side, which is the honest comparison — and the gap between them is the point. New buildings are a small part of construction steel, construction is 43% of French steel demand, and the rest is transport, machinery and metalware that nothing in this model drives.

construction_timber_floorconstruction_floor_total * timberShareMm²/y—
construction_timber_woodconstruction_timber_floor * timber_wood_intensityMm³/y of sawn product—
construction_timber_roundwoodconstruction_timber_wood * sawnwood_roundwood_factorMm³/y

What the built square metres ask of the forest, in the standing-stock volume the harvest is written in. It is compared with land_harvest_long_lived further down rather than subtracted from it: the long-lived share is a supply decision the player makes with harvestToProducts, and this is the demand that decision has to meet.

Industry — production volumes

NameFormulaUnitNotes and sources
steel_bf_productionsteel_bf_base_production * (1 - steelDRI) * (1 + steelGrowth)kt/y—
steel_dri_productionsteel_bf_base_production * steelDRI * (1 + steelGrowth)kt/y—
steel_eaf_productionsteel_eaf_base_production * (1 + steelGrowth)kt/y—
olefin_productionolefin_base_production * olefinRoute * (1 - plasticReduction)kt/y—
cement_productioncement_demand * clinkerRate * (1 - cementReduction)kt clinker/y

Demand now sets this, and it did not before v0.20. Until then the volume was cement_base_production — a bare base-year tonnage — times a slider, so a scenario could remove a third of the country's cement without naming a building it had not built. It is now the demand the construction module computes from floor area, civil works and the share nothing attributes, times the clinker ratio, times what a cubic metre of concrete still asks of the cement works. cementReduction survives the change and finally has a driver: it is no longer "less cement" but less cement per unit of works — leaner mixes, thinner structures, more supplementary material inside the concrete rather than inside the cement, which is what clinkerRate does. The two are not the same lever and the annex says so. What this equation still does not do is import. About a seventh of French cement consumption is imported, and clinker imports on top of that put roughly a quarter of the clinker behind French cement in a kiln outside France. Demand here drives domestic output one for one, which overstates what a French kiln burns and, in the other direction, quietly leaves the imported quarter's carbon outside the perimeter. Named rather than corrected: a domestic-supply share would be a fifth lever on a chain that already has four.

chain_production
per row of industry_chain
steel_bf: steel_bf_production
steel_dri: steel_dri_production
steel_eaf: steel_eaf_production
ammonia: chain_ammonia_production
olefins: olefin_production
cement: cement_production
kt/y—

Industry — energy and process emissions

Energy is production times unit consumption. Process emissions are the part that no change of fuel can remove: the carbon of the limestone, the carbon locked into the product, and the residue of the blast-furnace route once its coal has been counted as energy.

NameFormulaUnitNotes and sources
chain_electricity
per row of industry_chain
row.chain_production * row.electricity / 1000TWh/y—
chain_gas
per row of industry_chain
row.chain_production * row.gas / 1000TWh/y—
chain_coal
per row of industry_chain
row.chain_production * row.coal / 1000TWh/y—
chain_liquid
per row of industry_chain
row.chain_production * row.liquid / 1000TWh/y

No chain burns liquid fuel since 0.29.0: the cement kiln's 0.358 MWh a tonne of "liquid" was the teaching workbook's, and a French kiln burns petroleum coke, coal and waste instead. Kept so the account stays constructive.

chain_hydrogen
per row of industry_chain
row.chain_production * row.hydrogen / 1000TWh/y—
kiln_heatcement_production * kiln_heat_per_tonne / 1000TWh/y

What the cement kilns burn: clinker times the French fleet's 1.064 MWh a tonne. Split below between what is fossil and what is biomass, because the carriers the model has are fuels and a kiln burns a mix of them that the player chooses with kilnAltFuel.

kiln_fossil_heatkiln_heat * (1 - kilnAltFuel * kiln_waste_biomass_share)TWh/y

Petroleum coke, coal and the fossil half of the waste, all on the coal carrier. At 2020's mix — 43% waste, half of it biomass — this gives 0.281 t of fuel CO₂ a tonne of clinker, against the 0.284 the French kilns were observed at: the fossil half of the waste burns within a few per cent of coal's factor, so one carrier carries both honestly.

kiln_biomass_heatkiln_heat * kilnAltFuel * kiln_waste_biomass_shareTWh/y

The biomass half of the waste — animal meal, wood waste, sludge — on the wood carrier, where it draws on the wood pool the land supplies. Not all of it is wood, and the pool is the nearest one the model has.

kiln_fuel_co2_per_tonnekiln_heat_per_tonne * (1 - kilnAltFuel * kiln_waste_biomass_share) * sum(post.efficiency_fuel_factor, post.id == "cement") * ef_coal / 1000tCO₂ per tonne of clinker

The fossil CO₂ of the kiln fuel per tonne of clinker, after the industrial efficiency lever, so that capture and the carbon price can reach it. The same quantity the coal carrier books for the cement post, read per tonne.

kiln_biomass_co2_per_tonnekiln_heat_per_tonne * kilnAltFuel * kiln_waste_biomass_share * sum(post.efficiency_fuel_factor, post.id == "cement") * kiln_biomass_co2tCO₂ per tonne of clinker

The biogenic CO₂ of the kiln's waste, per tonne of clinker. Never counted as an emission; it goes up the same stack as the fossil, so a capture plant takes it too, and the CO₂ has to be shipped and stored whatever its origin.

cement_captured_fossilcement_production * (cement_process_per_tonne + kiln_fuel_co2_per_tonne) * carbonCapture / 1000MtCO₂/y

What carbonCapture removes from the cement post: its share of the calcination and of the fossil kiln fuel.

cement_captured_biogeniccement_production * kiln_biomass_co2_per_tonne * carbonCapture / 1000MtCO₂/y

Shown, not counted, for the reason wte_biogenic_captured gives; paid for all the same, in transport and storage.

cement_capture_powercement_production * cement_capture_extra_electricity * carbonCapture / cement_capture_reference_rate / 1000TWh/y

The electricity the cement capture plants draw. It is added to the cement post after the industrial efficiency lever, which was sized on the grinding mills and cannot shave a solvent's regeneration heat.

steel_bf_process_residualsteel_bf_direct_intensity - industry_chain["steel_bf"].coal * ef_coal / 1000tCO₂ per tonne of steel

A remainder, not a measurement. The route's direct total, steel_bf_direct_intensity, less the coal the chain row charges at the published coal factor: 1.76 − 5.047 MWh × 340 g = 0.044 tCO₂ per tonne. The coal is counted once, as energy, where the fuel levers can reach it; this keeps the rest. The teaching workbook had charged both, so the coal carbon was counted twice until this line existed. The rest is physically the limestone flux — 0.27 t per tonne of steel, +0.12 tCO₂ — less the carbon that stays in the steel, −0.04, less whatever leaves the site in blast-furnace and coke-oven gas. 0.044 is inside that band, but it is the difference of two numbers of order 1.7, so a 2% revision of either moves it by 78%. Treat it as a closure, and build it from the flux if it ever matters.

chain_process_per_tonne
per row of industry_chain
steel_bf: steel_bf_process_residual
steel_dri: steel_eaf_process_per_tonne
steel_eaf: steel_eaf_process_per_tonne
olefins: -olefin_carbon_per_tonne * biogenicCO2
cement: cement_process_per_tonne * (1 - carbonCapture) - carbonCapture * kiln_fuel_co2_per_tonne
default: 0
tCO₂ per tonne of product

Emissions no change of fuel can remove: the limestone carbon in cement, the carbon locked into synthetic olefins — a credit, hence negative — the blast-furnace residue left once its coal has been counted as energy, and, since 0.27.0, the electrodes and charge carbon of the two electric-furnace routes.

chain_emissions_per_tonne
per row of industry_chain
row.coal * ef_coal / 1000 + row.chain_process_per_tonne + (kiln_fuel_co2_per_tonne if row.id == "cement" else 0)tCO₂ per tonne of product

What the plant emits on site, per tonne of product. The cost model charges the carbon price on exactly this quantity, so the cost and the emissions account can never describe different plants.

chain_process
per row of industry_chain
row.chain_production * row.chain_process_per_tonne / 1000MtCO₂/y—
food_steamfood_steam_demand * (1 - foodEfficiency)TWh/y—
food_direct_heatfood_direct_heat_demand * (1 - foodEfficiency)TWh/y—
food_electricity(food_steam * foodHPSteam + food_direct_heat * foodHPDirect) / food_heat_pump_copTWh/y

Heat delivered by heat pumps, divided by their coefficient of performance.

food_gasfood_steam * (1 - foodHPSteam) + food_direct_heat * (1 - foodHPDirect)TWh/y—

The rest of industry

Seventeen manufacturing branches the game does not model as value chains — metals and machinery, minerals, the rest of chemistry, paper, and a diverse remainder. Together they are about 174 TWh today, 68 of it electricity, more than the five modelled chains use between them. Output and processes move on separate levers because the source scenario mixes the two: it electrifies, and it also multiplies textile output by 8.5.

NameFormulaUnitNotes and sources
other_energy
per row of industry_other
(row.e00 + (row.e10 - row.e00) * otherIndustryVolume + (row.e01 - row.e00) * otherIndustryProcess + (row.e11 - row.e10 - row.e01 + row.e00) * otherIndustryVolume * otherIndustryProcess) * (1 - otherIndustrySobriety)TWh/y, or MtCO₂/y for the process rows

Bilinear interpolation between the four corners. It is exact at all four, so at the default levers the block reproduces the published 2050 processes applied to today's output, and at (100%, 100%) it reproduces the source scenario to the last decimal. Then the whole block is scaled by otherIndustrySobriety, the same share off every branch, carrier and process term.

other_industry_energysum(industry_other.other_energy, industry_other.carrier != "process")TWh/y—
other_industry_electricitysum(industry_other.other_energy, industry_other.carrier == "electricity")TWh/y—

The constructive account — energy and emissions by post

One row per sub-sector, one column per energy carrier. Sector totals are sums of this table and nothing else. Electricity is kept in three columns — used directly, used to make hydrogen, used to make e-fuel — because the three have very different implications for the power system even though they carry the same emission factor.

NameFormulaUnitNotes and sources
energy_electricity_direct_raw
per row of post
passenger_mobility: passenger_electricity_direct
freight_mobility: freight_electricity_direct
residential_heating: building_electricity_residential
tertiary_heating: building_electricity - building_electricity_residential
residential_uses: usages_electricity_residential
tertiary_uses: usages_electricity_tertiary
steel: sum(industry_chain.chain_electricity, industry_chain.subpost == "steel")
ammonia: sum(industry_chain.chain_electricity, industry_chain.subpost == "ammonia")
olefins: sum(industry_chain.chain_electricity, industry_chain.subpost == "olefins")
cement: sum(industry_chain.chain_electricity, industry_chain.subpost == "cement")
food_heat: food_electricity
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "electricity")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "electricity")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "electricity")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "electricity")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "electricity")
energy_production: 0
hydrogen_production: 0
waste_to_energy: 0
livestock: 0
crops: 0
farm_machinery: 0
TWh/y—
energy_hydrogen
per row of post
passenger_mobility: passenger_hydrogen
freight_mobility: freight_hydrogen
steel: sum(industry_chain.chain_hydrogen, industry_chain.subpost == "steel")
ammonia: sum(industry_chain.chain_hydrogen, industry_chain.subpost == "ammonia")
olefins: sum(industry_chain.chain_hydrogen, industry_chain.subpost == "olefins")
food_heat: food_hydrogen
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "hydrogen")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "hydrogen")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "hydrogen")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "hydrogen")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "hydrogen")
default: 0
TWh/y

The hydrogen each post consumes, before anything is said about how it was made. Until v0.12.0 this was converted straight into electricity at the electrolyser efficiency, which hard-coded one production route into every consumer of hydrogen in the model. That release undid it for industry but left the two transport rows pointing at figures the transport module had already divided by that efficiency, so transport hydrogen was converted twice — 2.78 MWh of electricity per MWh of hydrogen instead of 1.67 — until v0.14.3.

hydrogen_mix_totalh2Electrolysis + h2Smr + h2AtrCcs if h2Electrolysis + h2Smr + h2AtrCcs > 0 else 1fraction

Normalised in the model rather than trusted to the interface, like the building and generation mixes. Falls back to one if a scenario zeroes all three, since hydrogen has to come from somewhere.

hydrogen_demand_totalsum(post.energy_hydrogen)TWh/y—
route_share
per row of hydrogen_route
electrolysis: h2Electrolysis / hydrogen_mix_total
smr: h2Smr / hydrogen_mix_total
atr_ccs: h2AtrCcs / hydrogen_mix_total
fraction—
route_hydrogen
per row of hydrogen_route
hydrogen_demand_total * row.route_shareTWh/y—
route_electricity_per_mwh
per row of hydrogen_route
electrolysis: 1 / efficiency_electricity_to_h2
default: row.electricity
MWh of electricity per MWh of hydrogen

The electrolyser's figure is derived from the conversion efficiency the rest of the model already uses, rather than declared again in the table. Two copies of that number would be two numbers.

route_methane
per row of hydrogen_route
row.route_hydrogen * row.methaneTWh/y—
route_captured_methane
per row of hydrogen_route
row.route_methane * row.carbon_capturedTWh/y—
hydrogen_electricity_totalsumproduct(hydrogen_route.route_hydrogen, hydrogen_route.route_electricity_per_mwh)TWh/y—
hydrogen_methane_totalsum(hydrogen_route.route_methane)TWh/y

Feedstock and fuel together. It draws on the same methane the buildings and the power stations want, and the scoreboard counts it there — which is the trade-off a reforming route actually makes.

hydrogen_carbon_capturedsum(hydrogen_route.route_captured_methane) * carbon_in_methane / 1000MtCO₂/y

The carbon in the reformed methane that ends underground. Charged against the physical carbon the methane carries, not against efGas: what a capture plant removes is molecules, and efGas at 25 gCO₂/kWh is a biogenic accounting convention rather than a measurement of what is in the pipe. The consequence is deliberate and contested. On biomethane this makes hydrogen production carbon-negative — the physics of BECCS, and the place where this model will most easily mislead a reader who has not read the controversy tab.

hydrogen_electricity_per_mwhhydrogen_electricity_total / hydrogen_demand_total if hydrogen_demand_total > 0 else 0MWh of electricity per MWh of hydrogen

The mix's average. Each consumer's electricity-for-hydrogen is its own hydrogen times this, so reforming half the country's hydrogen halves the electricity every hydrogen user draws.

energy_electricity_hydrogen
per row of post
row.energy_hydrogen * hydrogen_electricity_per_mwhTWh/y—
energy_electricity_efuel
per row of post
passenger_mobility: passenger_electricity_efuel
freight_mobility: freight_electricity_efuel
default: 0
TWh/y—
energy_gas_raw
per row of post
passenger_mobility: passenger_gas
freight_mobility: freight_gas
residential_heating: building_gas_residential
tertiary_heating: building_gas - building_gas_residential
residential_uses: usages_gas_residential
tertiary_uses: usages_gas_tertiary
energy_production: generation_gas_fuel
hydrogen_production: hydrogen_methane_total
waste_to_energy: 0
steel: sum(industry_chain.chain_gas, industry_chain.subpost == "steel")
ammonia: sum(industry_chain.chain_gas, industry_chain.subpost == "ammonia")
olefins: sum(industry_chain.chain_gas, industry_chain.subpost == "olefins")
cement: sum(industry_chain.chain_gas, industry_chain.subpost == "cement")
food_heat: food_gas
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "gas") + sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "steam")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "gas") + sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "steam")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "gas") + sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "steam")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "gas") + sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "steam")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "gas") + sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "steam")
livestock: 0
crops: 0
farm_machinery: 0
TWh/y

Before any waste heat is recovered against it.

energy_biofuel_raw
per row of post
passenger_mobility: passenger_biofuel
freight_mobility: freight_biofuel
cement: sum(industry_chain.chain_liquid, industry_chain.subpost == "cement")
residential_heating: building_liquid_residential
tertiary_heating: building_liquid - building_liquid_residential
residential_uses: usages_liquid_residential
tertiary_uses: usages_liquid_tertiary
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "oil")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "oil")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "oil")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "oil")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "oil")
default: 0
TWh/y—
energy_wood_raw
per row of post
residential_heating: building_wood_residential
tertiary_heating: building_wood - building_wood_residential
residential_uses: usages_wood_residential
tertiary_uses: usages_wood_tertiary
energy_production: generation_wood_fuel
cement: kiln_biomass_heat
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "biomass")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "biomass")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "biomass")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "biomass")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "biomass")
default: 0
TWh/y—
energy_coal_raw
per row of post
steel: sum(industry_chain.chain_coal, industry_chain.subpost == "steel")
cement: sum(industry_chain.chain_coal, industry_chain.subpost == "cement") + kiln_fossil_heat
residential_heating: building_coal_residential
tertiary_heating: building_coal - building_coal_residential
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "coal")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "coal")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "coal")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "coal")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "coal")
default: 0
TWh/y—
efficiency_elec_factor
per row of post
1 - industryEfficiency * row.elec_efficiency_ceilingfraction of the electricity remaining

The effort lever times this post's own ceiling, so the lever can never buy more efficiency than RTE identified for that branch. Only direct electricity is affected: the electricity that goes into hydrogen and e-fuel is set by conversion efficiencies declared elsewhere.

efficiency_fuel_factor
per row of post
1 - industryEfficiency * (fuel_efficiency_ceiling if row.sector == "industry" else 0)fraction of the fuel remaining

RTE gives no branch breakdown on the fuel side, so one ceiling applies across industry. Transport and buildings are untouched: their own levers already carry demand and equipment efficiency.

energy_electricity_efficient
per row of post
row.energy_electricity_direct_raw * row.efficiency_elec_factorTWh/y—
energy_electricity_added
per row of post
cement: cement_capture_power
waste_to_energy: wte_capture_power + plastic_recycling_power
default: 0
TWh/y

What the two capture levers draw, since 0.32.0, and the plastic recycling lines, since 0.33.0. Outside the efficiency lever and inside the direct demand, so the mix has to produce it.

energy_electricity_direct
per row of post
row.energy_electricity_efficient + row.energy_electricity_addedTWh/y—
energy_gas_gross
per row of post
row.energy_gas_raw * row.efficiency_fuel_factorTWh/y—
energy_coal
per row of post
row.energy_coal_raw * row.efficiency_fuel_factorTWh/y—
energy_biofuel
per row of post
row.energy_biofuel_raw * row.efficiency_fuel_factorTWh/y—
energy_wood
per row of post
row.energy_wood_raw * row.efficiency_fuel_factorTWh/y—
combustion_fuel_gross
per row of post
row.energy_gas_gross + row.energy_coal + row.energy_biofuel + row.energy_woodTWh/y

Everything burned, before recovery. ADEME expresses the waste-heat gisement against exactly this — fossil fuels and biomass together.

waste_heat_potential
per row of post
row.combustion_fuel_gross * row.waste_heat_shareTWh/y

The recoverable gisement of this post, at the fuel it actually burns in this scenario. It is not a fixed reserve: electrify the heat and the gisement goes with it, because there is no combustion left to reject heat from. That is the trade-off the lever exists to show.

waste_heat_recovered
per row of post
min(row.waste_heat_potential * wasteHeatRecovery, row.energy_gas_gross)TWh/y

Recovered heat is assumed to displace gas, the marginal fuel, and cannot displace more gas than the post burns. The second-order feedback — less gas means a slightly smaller gisement — is neglected; at full recovery it is under half a percent.

energy_gas
per row of post
row.energy_gas_gross - row.waste_heat_recoveredTWh/y—
energy_electricity_total
per row of post
row.energy_electricity_direct + row.energy_electricity_hydrogen + row.energy_electricity_efuelTWh/y—
energy_total
per row of post
row.energy_electricity_total + row.energy_gas + row.energy_biofuel + row.energy_wood + row.energy_coalTWh/y—
emissions_electricity
per row of post
0MtCO₂/y

Zero, and that is the accounting scope, not an omission. The model is a scope-1 account: emissions are booked where the combustion happens. A power station's emissions belong to the power station, so they sit on the energy_production post, computed from the fuel the chosen mix actually burns — not spread back over everyone who used a kilowatt-hour. This is the same convention SECTEN and the SNBC use, which is why the national reconciliation no longer needs a life-cycle line to undo it. The consequence a reader should hold onto: electrifying a sector moves its emissions rather than removing them, and where they land depends on the electricity mix, which is a separate choice.

emissions_gas
per row of post
row.energy_gas * efGas / 1000MtCO₂/y—
emissions_biofuel
per row of post
row.energy_biofuel * efLiquid / 1000MtCO₂/y—
emissions_wood
per row of post
row.energy_wood * efWood / 1000MtCO₂/y—
emissions_coal
per row of post
row.energy_coal * ef_coal / 1000MtCO₂/y—
emissions_process
per row of post
steel: sum(industry_chain.chain_process, industry_chain.subpost == "steel")
ammonia: sum(industry_chain.chain_process, industry_chain.subpost == "ammonia")
olefins: sum(industry_chain.chain_process, industry_chain.subpost == "olefins")
cement: sum(industry_chain.chain_process, industry_chain.subpost == "cement")
other_metals: sum(industry_other.other_energy, industry_other.group == "metals_machinery" and industry_other.carrier == "process")
other_minerals: sum(industry_other.other_energy, industry_other.group == "minerals" and industry_other.carrier == "process")
other_chemicals: sum(industry_other.other_energy, industry_other.group == "chemicals_other" and industry_other.carrier == "process")
other_paper: sum(industry_other.other_energy, industry_other.group == "paper" and industry_other.carrier == "process")
other_diverse: sum(industry_other.other_energy, industry_other.group == "other_industries" and industry_other.carrier == "process")
hydrogen_production: -hydrogen_carbon_captured
waste_to_energy: wte_fossil_co2
livestock: agriculture_livestock_post
crops: agriculture_crops_post
farm_machinery: agriculture_fuel_post
default: 0
MtCO₂/y—
emissions_combustion
per row of post
row.emissions_gas + row.emissions_biofuel + row.emissions_wood + row.emissions_coal + row.emissions_processMtCO₂/y

Everything except the electricity, which the inventory attributes elsewhere.

emissions_total
per row of post
row.emissions_electricity + row.emissions_combustionMtCO₂/y—

Waste to energy

The incinerators that turn residual waste into heat and power. The inventory books their fossil CO₂ to the energy sector, not to waste, and until 0.28.0 this model booked it nowhere: national_waste slides between two published waste totals that exclude it by construction, and the power sector here is the electricity mix alone.

NameFormulaUnitNotes and sources
wte_fossil_co2wte_fossil_burned * (1 - wteCapture)MtCO₂/y

The base year's fossil CO₂, of which the plastic share follows plastic demand: plasticReduction at 30% takes 28.5% off it, at 70% two thirds. This is what turns plastic sobriety the right way round. The lever used to scale only the olefins a French plant makes, so a scenario that asked for less plastic lost part of its olefin credit and saw its emissions rise; the plastic it no longer burns now counts, and over the lever's range it is worth ten times the credit. Three things it assumes, and says. The plastic burned is the plastic consumed, wherever it was made, so olefinRoute does not reach it — whether France cracks its ethylene, synthesises it or imports it, the packaging ends in a French furnace. It is all fossil: bio-based plastic is about 1% of the European market, and the IPCC's default for plastics is 100% fossil carbon. And landfill stands still. Since 0.33.0 recycling does not: plasticRecycling takes plastic out of the furnace. Landfill has no variable because the evidence says it does not reach this term: French landfill fell 3.1 Mt between 2020 and 2022 while the incinerators, which are full and already turn waste away, burned no more, and what leaves landfill goes to refuse-derived fuel for kilns and boilers. wteCapture then takes its share of what is left, stack by stack.

wte_fossil_burnedwte_fossil_co2_base * (1 - wte_plastic_fossil_share + wte_plastic_fossil_share * (1 - plasticReduction) * (1 - plasticRecycling))MtCO₂/y

The fossil CO₂ the incinerators release before any capture. The plastic part follows what is consumed, plasticReduction, and then what is recycled of it rather than burned, plasticRecycling; the other 5% — textiles, nappies, leather — follows neither.

plastic_recycledwte_fossil_co2_base * wte_plastic_fossil_share * (1 - plasticReduction) * plasticRecycling / plastic_fossil_co2_per_tonneMt/y

The tonnes of plastic the recycling lever takes away from the incinerators, read back from their CO₂ at 2.75 t a tonne.

plastic_recycling_powerplastic_recycled * plastic_recycling_electricityTWh/y

What the recycling lines draw, booked on the waste-to-energy post for want of a post of their own.

wte_fossil_capturedwte_fossil_burned * wteCaptureMtCO₂/y

The fossil CO₂ the capture plants take, which is what lowers the total.

wte_biogenic_capturedwte_fossil_co2_base * wte_biogenic_share / (1 - wte_biogenic_share) * wteCaptureMtCO₂/y

Shown, not counted. The biogenic CO₂ the same capture plants take with the fossil: 1.5 tonnes for every fossil tonne of the base year in France, one in Germany, and it does not fall with plastic demand, because it is the food, paper and wood in the bin. It would be a removal, and removals are what techSink stands for; adding it here would count one tonne twice.

wte_capture_power(wte_fossil_captured + wte_biogenic_captured) * wte_capture_electricityTWh/y

The electricity the incinerators stop exporting to run their capture plants, booked as a demand on their own post: every tonne captured, fossil or biogenic, at 0.315 MWh. Since 60% of what French plants capture is biogenic, 0.79 MWh of it is spent for each fossil tonne the total loses, and more once plastic sobriety has thinned the fossil part.

Sector and resource totals

NameFormulaUnitNotes and sources
transport_emissionssum(post.emissions_total, post.sector == "transport")MtCO₂/y—
building_emissionssum(post.emissions_total, post.sector == "building")MtCO₂/y—
industry_emissionssum(post.emissions_total, post.sector == "industry")MtCO₂/y—
game_emissionssum(post.emissions_total)MtCO₂/y—
electricity_demand_before_power_hydrogensum(post.energy_electricity_total)TWh/y

Everything the sectors consume, before the power system's own electrolysis.

power_hydrogen_feedbackclamp(sum(generation_technology.generation_share_thermal_gas) * gasPlantHydrogen / efficiency_electricity_to_h2, 0, 0.9)fraction of total demand

The share of total electricity that goes back into making the hydrogen the gas plants burn. It depends on the mix's shares and on two efficiencies, never on the demand itself, which is what makes the loop solvable rather than iterative. Clamped below one: a fleet consuming more electricity than it produces has no solution, and the model says so by refusing to divide rather than by returning a negative demand.

electricity_demandelectricity_demand_before_power_hydrogen / (1 - power_hydrogen_feedback)TWh/y

base / (1 - k). Closing the loop in one line rather than iterating: demand sets the mix, the mix sets the fuel, the fuel sets the electrolysis, and the electrolysis is demand — but k depends only on shares and efficiencies, so the fixed point is linear. It matters. Converting the whole gas fleet adds around a ninth of national demand, and reporting that beside the total instead of inside it would let a scenario buy clean combustion for free.

electricity_direct_demandsum(post.energy_electricity_direct)TWh/y—
electricity_hydrogen_demandsum(post.energy_electricity_hydrogen)TWh/y—
electricity_efuel_demandsum(post.energy_electricity_efuel)TWh/y—
biogas_demandsum(post.energy_gas)TWh/y

The methane resource the scenario needs. It includes about 23 TWh of international air-freight fuel, which the workbook classes as gas — worth knowing before reading this against a biomethane potential.

biofuel_demandsum(post.energy_biofuel)TWh/y—
wood_demandsum(post.energy_wood)TWh/y—
coal_demandsum(post.energy_coal)TWh/y—
efficiency_savingsum(post.energy_electricity_direct_raw) - sum(post.energy_electricity_efficient) + sum(post.energy_gas_raw) - sum(post.energy_gas_gross) + sum(post.energy_coal_raw) - sum(post.energy_coal) + sum(post.energy_biofuel_raw) - sum(post.energy_biofuel) + sum(post.energy_wood_raw) - sum(post.energy_wood)TWh/y

What the effort lever removes from final energy, all carriers together.

efficiency_saving_fuelsum(post.energy_gas_raw) - sum(post.energy_gas_gross) + sum(post.energy_coal_raw) - sum(post.energy_coal) + sum(post.energy_biofuel_raw) - sum(post.energy_biofuel) + sum(post.energy_wood_raw) - sum(post.energy_wood)TWh/y

The fuel part of the saving. It is the part that also removes waste heat, which is why it is reported separately from the electricity.

waste_heat_potential_totalsum(post.waste_heat_potential)TWh/y—
waste_heat_recovered_totalsum(post.waste_heat_recovered)TWh/y—
waste_heat_potential_hotsumproduct(post.waste_heat_potential, post.waste_heat_hot_share)TWh/y

The part of the gisement above 100 °C, which is the part that can displace process heat directly.

total_final_energysum(post.energy_total)TWh/y—
electric_shareelectricity_demand / total_final_energyfraction—

Land, forest and the carbon sink

Stage A of the land module. It replaces a slider that had no driver — a natural sink set by hand, anywhere between 5 and 40 MtCO₂e absorbed — with a physical account: seven land classes that add up to a fixed territory, three flows that move hectares between them, and a forest whose sink is an identity in cubic metres rather than a number somebody chose. Three things are worth understanding before reading the formulas. The account closes by construction, and nothing absorbs a residual. Every flow is a signed transfer with a named source and a named destination, and the destination gains exactly what the source loses, so the seven classes sum to the same territory at every position of every lever. Nothing is clamped: land_clamped_kha reports how much flow a class could not have supplied, and it is zero everywhere inside the declared bounds. Clamping would have been the alternative, and it would have broken the closure it was meant to protect. The forest sink is k · (P·A − M·A − H) and nothing else. Gross production less mortality less removals, in cubic metres, times a carbon coefficient. A harvest lever therefore moves the sink, which is exactly the argument the forestry literature is having, and a wood-heavy scenario no longer gets its biomass for free. What the identity does not book is substitution — the fossil fuel and the concrete that wood displaces — for the reason the whole model is built on: the game already charges fossil fuel where it burns, so a substitution credit here would count it twice. The base year is checked, the horizon is not. A parallel set of *_2024 equations recomputes each pool at the base year, on base-year quantities and with no climate factor, and the tests hold them against the published inventory pool by pool. The 2050 figures are results, and two of them are uncomfortable: under the severe climate case with a hard harvest the forest becomes a net source, which is reachable inside the declared bounds and is reported rather than clamped away. Read the 2050 sink as an endpoint, not as an average — published projections usually quote a 2020–2050 mean, which is higher because the sink is still falling.

NameFormulaUnitNotes and sources
land_setting_artificialisationland_module_active * artificialisationRate + (1 - land_module_active) * artificialisation_rate_basekha/y

The module's switch applied to a lever. Where land_module_active is 0 the whole module is read at its base year, so a package that does not carry it reports no land movement rather than another country's, and a lever hidden in that package cannot move a number. Both sides always evaluate — this is arithmetic and never a branch — so the three back-ends see one expression and cannot take different paths through it.

land_setting_afforestationland_module_active * afforestationRate + (1 - land_module_active) * afforestation_rate_basekha/y—
land_setting_grasslandland_module_active * grasslandConversion + (1 - land_module_active) * grassland_conversion_basekha/y—
land_setting_soil_practicesland_module_active * soilCarbonPractices + (1 - land_module_active) * soil_practice_basefraction of the identified potential—
land_setting_harvestland_module_active * forestHarvest + (1 - land_module_active) * forest_harvest_baseMm³/y—
land_setting_long_livedland_module_active * harvestToProducts + (1 - land_module_active) * hwp_long_lived_share_basefraction of the harvest—
land_setting_peat_rewettingland_module_active * peatRewetting + (1 - land_module_active) * peat_rewetting_basefraction of the drained organic soil

The same switch on the peat lever. It is a share of the drained organic soil rewetted by the horizon, not a rate: rewetting is a one-off change of state, and a country that has already rewetted part of its peat declares that as peat_rewetting_base so the base year reads what it observed rather than a bare zero.

forest_production_factorland_module_active * sum(forest_climate.production_factor, forest_climate.position == forestClimate) + (1 - land_module_active)factor on the base-year production

The climate case, read out of the table by the position the control sits at — a plain filtered column total, the same idiom the electricity mix uses, and no loader change. Switched off, the factor is 1: a forest whose growth has not changed, which is the state the base-year check is written in.

forest_mortality_factorland_module_active * sum(forest_climate.mortality_factor, forest_climate.position == forestClimate) + (1 - land_module_active)factor on the base-year mortality—
land_flow_artificialisedland_setting_artificialisation * land_horizon_years / 1000Mha over the horizon

A rate in thousand hectares a year, sustained over the whole horizon, in million hectares. Artificialisation is measured on the land survey the account is written in, not on the cadastre: the cadastre counts parcels newly built on and the survey counts every garden and verge as well, so the two differ by a factor of two or three, and the emission content of the artificial pool only closes on the survey's rate. The cadastral measure belongs beside the result as a comparison, not inside it as the driver.

land_flow_afforestedland_setting_afforestation * land_horizon_years / 1000Mha over the horizon—
land_flow_grassland_to_arableland_setting_grassland * land_horizon_years / 1000Mha over the horizon

Signed: positive ploughs grassland into arable land, negative puts arable land back to grass. One flow rather than two levers, because the two directions are one decision and a country cannot do both at once.

land_arableland_class["arable"].area_2023 - land_flow_artificialised * artificialisation_to_arable_share + land_flow_grassland_to_arableMha

Land take draws on three named classes and the semi-natural residual, and the four shares are declared rather than assumed. A country whose building spreads onto arable land alone declares 1, 0 and 0 and the other two terms are exactly zero; a country whose forest inventory measures how much woodland the roads and the industrial estates took declares that share too.

land_grasslandland_class["grassland"].area_2023 - land_flow_grassland_to_arable - land_flow_artificialised * artificialisation_to_grassland_shareMha—
land_perm_cropsland_class["perm_crops"].area_2023Mha

Vines and orchards. No lever moves them, and saying so as an equation rather than leaving the class out is what keeps the account a partition of the whole territory.

land_forestland_class["forest"].area_2023 + land_flow_afforested - land_flow_artificialised * artificialisation_to_forest_shareMha

The forest class of the land account, which is not the forest area the sink identity runs on: the identity uses the area available for wood production, a smaller and differently drawn perimeter. The two are kept apart on purpose, and afforestation adds hectares to this one while the identity's area stays where it is — new forest is booked at the expansion storage rate instead, because a young stand does not store like a mature one.

land_other_naturalland_class["other_natural"].area_2023 - land_flow_artificialised * (1 - artificialisation_to_arable_share - artificialisation_to_grassland_share - artificialisation_to_forest_share) - land_flow_afforestedMha

Heath, scrub, copses and bare ground — the class both other flows draw on, and the one that empties first. It is also where the largest unreconciled disagreement in the account sits: a forest inventory sees canopy closing on former heath and calls it new forest, while a land survey still sees heath, and the two published expansion rates differ by a factor of nearly three.

land_waterland_class["water"].area_2023Mha—
land_artificialland_class["artificial"].area_2023 + land_flow_artificialisedMha—
land_area_2023
per row of land_class
row.area_2023Mha

The base-year column, re-emitted as a result so the partition chart reads both of its bars from one place instead of one from the model and one from the raw table.

land_area_2050
per row of land_class
arable: land_arable
grassland: land_grassland
perm_crops: land_perm_crops
forest: land_forest
other_natural: land_other_natural
water: land_water
artificial: land_artificial
Mha

One formula per class, side by side, which is what makes the transfers auditable: every hectare that leaves a class arrives in another, and reading the seven lines together is how you see it. This is also what makes land_class a fixed-row table — the row set is derived from this map, not restated by hand.

land_peat_emission
per row of land_class
row.peat_area * (row.peat_ef - land_setting_peat_rewetting * (row.peat_ef - peat_rewetted_emission))MtCO₂e/y emitted

A drained peat soil is a chimney, and in some countries it is the largest one on the land. Per land class, the area of organic soil the inventory maps under it times the emission factor that class's drained peat carries, with the share the player rewets moved onto the much smaller wet factor. The two are declared in land_class beside the area, because an organic-soil area is a fact about a land class and putting it anywhere else would let the two drift apart. Three things about it are deliberate. The peat area does not follow the class area: a peat deposit is where it is, and ploughing a hectare of grassland does not move the peat under it. The rewetted hectare keeps emitting — peat_rewetted_emission, mostly methane — rather than going to zero, because a wet peatland is not a sink on this timescale. And the factors are the inventory's implied ones, so a country with no mapped organic soil declares zero areas and every term here is exactly zero, which is what keeps this addition inert where it does not apply.

land_peat_emission_2024
per row of land_class
row.peat_area * (row.peat_ef - peat_rewetting_base * (row.peat_ef - peat_rewetted_emission))MtCO₂e/y emitted—
land_peat_arablesum(land_class.land_peat_emission, land_class.id == "arable")MtCO₂e/y emitted—
land_peat_grasslandsum(land_class.land_peat_emission, land_class.id == "grassland")MtCO₂e/y emitted—
land_peat_forestsum(land_class.land_peat_emission, land_class.id == "forest")MtCO₂e/y emitted—
land_peat_watersum(land_class.land_peat_emission, land_class.id == "water")MtCO₂e/y emitted—
land_peat_artificialsum(land_class.land_peat_emission, land_class.id == "artificial")MtCO₂e/y emitted—
land_peat_totalsum(land_class.land_peat_emission)MtCO₂e/y emitted—
land_peat_unbookedland_peat_total - land_peat_arable - land_peat_grassland - land_peat_forest - land_peat_water - land_peat_artificialMtCO₂e/y emitted

Zero, and asserted rather than assumed. Five of the seven classes hand their peat to a named pool of the inventory; the two that do not — permanent crops and semi-natural land — have no pool of their own to book it in, so a country that declared organic soil under them would otherwise lose it silently. This is the line that refuses to.

land_peat_area_totalsum(land_class.peat_area)Mha—
land_peat_rewetted_arealand_peat_area_total * land_setting_peat_rewettingMha

The hectares the lever puts back under water, over the whole horizon. It is reported because it is the quantity a rewetting programme is actually written in — Germany's own targets are in hectares, not in megatonnes — and because it is what the grassland the herd can graze loses.

land_total_2023sum(land_class.area_2023)Mha—
land_total_2050sum(land_class.land_area_2050)Mha—
land_account_residualland_total_2050 - land_total_2023Mha

Zero, at every position of every lever, and a test asserts it over the corners of the three flow levers and a seeded sweep between them. It is emitted rather than assumed because an account that closes by construction is a claim about the algebra, and a claim worth making is worth showing.

land_clamped_kha(max(0, -land_arable) + max(0, -land_grassland) + max(0, -land_perm_crops) + max(0, -land_forest) + max(0, -land_other_natural) + max(0, -land_water) + max(0, -land_artificial)) * 1000 / land_horizon_yearskha/y

How much annual flow would have to be given back for every class to stay non-negative — the answer to the author's own question, "should the extreme corner be clamped, or reported?". It is reported. Inside the declared bounds it is exactly zero, with the smallest margin on the semi-natural class, which both artificialisation and afforestation draw on; a bound loosened without checking this number would silently start taking hectares out of a class that does not have them.

forest_production_2050forest_production * forest_production_factorm³/ha/y—
forest_mortality_2050forest_mortality * forest_mortality_factorm³/ha/y—
forest_volume_balance(forest_production_2050 - forest_mortality_2050) * forest_production_area - land_setting_harvest * forest_harvest_volume_factorMm³/y

Production less mortality less removals — the volume the forest gains in a year. It is the quantity every argument about the forest is really about, and it has roughly halved in a decade as mortality doubled. Negative means the standing stock is falling.

forest_removal_rateland_setting_harvest * forest_harvest_volume_factor / (forest_production_2050 * forest_production_area)fraction of gross production

Removals over gross production, the ratio the forestry debate is usually conducted in. Quote it with its base: the same forest is at 60% on the inventory's production and at 70% on the industry's "availability", and the two numbers are not comparable.

forest_volume_balance_2024(forest_production - forest_mortality) * forest_production_area - forest_harvest_base * forest_harvest_volume_factorMm³/y

The same balance on base-year quantities: no climate factor, and the inventory's own harvest — 19.9 Mm³/y in France, against the +19.5 IGN measures. It is the point the living-biomass line is anchored at: the inventory's pair sets the level there, and the marginal coefficient carries it to 2050. Its quantities are IGN's 2014–2022 means, so the point is the campaign's median year, 2018, under the base year's label: the inventory's 2024, extrapolated on a mortality still rising, splits the same total differently (forest_dead_wood_coefficient).

forest_carbon_growthforest_carbon_k + (forest_carbon_ratio_base - forest_carbon_k) * forest_volume_balance_2024 / (forest_production * forest_production_area)tCO₂/m³

What a cubic metre of gross production stores in the living trees. It is derived, not declared: the marginal forest_carbon_k, which a cubic metre cut or dead takes with it, plus what the inventory's own pair says the living biomass gains beyond that, spread over the base year's gross production. In France that is 1.5 plus 0.11, 1.61 tCO₂/m³. The inventory measures 39 MtCO₂/y for a 19.5 Mm³/y balance, 2.0 per cubic metre of balance, while a cubic metre taken out of the stock moves the sink by 1.5: the two fit only if growth stores more per cubic metre of stem than the trees that leave take with them. A plausible reading is that growth is carried by younger trees, which hold more branch and root per cubic metre of stem, and by the stems that cross the inventory threshold each year. Put on growth, the excess falls with production in the harsher climate cases. Where a package's ratio and its k are the same number, this is k and the line is proportional.

land_sink_forest_biomassforest_carbon_k * forest_volume_balance + (forest_carbon_growth - forest_carbon_k) * forest_production_2050 * forest_production_areaMtCO₂/y absorbed

g·P·A − k·(M·A + H): what grows, less what dies and what is cut. k — forest_carbon_k — is what a cubic metre leaving the living stock takes with it, cut or dead alike, and it is the marginal: the response of this pool to one cubic metre more harvested, or one more killed by the climate. g — forest_carbon_growth — is what a cubic metre of growth stores, derived so that the base year is the inventory's own pair, forest_carbon_ratio_base times the base-year balance, to the bit. The level comes from the inventory and the slope from the projections, and they are declared apart because the evidence for them is not the same. Until stage B one coefficient did both, k · (P·A − M·A − H), and no single number can: in the same document the inventory's ratio of sink to balance is 1.51 over 2005–2013 and 2.00 over 2014–2022. The projections the climate cases come from move this pool by 1.44 to 1.56 tCO₂ per cubic metre harvested, on their 2020–2050 means, and the span they publish between their mildest and their severest case at a constant harvest, about 51 MtCO₂/y in 2045–2050, is what 1.5 gives on this identity's own balance. Two things k is not. It is not the response of the land account: a cubic metre not harvested also never enters the wood-products pool, so the whole sink moves by k less that pool's share. And it is not a price: nothing here says what happens to the wood that is not cut, which the scoreboard answers separately, by charging a scenario that leans on its land for more than its own strategy does.

land_sink_forest_dead_wood_2024forest_dead_wood_coefficient * forest_mortality * forest_production_areaMtCO₂/y absorbed

The dead-wood sink of the base year: what the inventory added to the forest line in its 2025 edition, when it began to model dead wood explicitly from the observed mortality, and what the pool is calibrated on.

forest_dead_wood_retentionland_module_active * 0.5 ** (land_horizon_years / forest_dead_wood_half_life) + (1 - land_module_active)fraction

What is left at the horizon of a tonne of dead wood from the base year: 0.5 ^ (years / half-life), the wood-products idiom with the dead wood's own half-life. At 26 years and a half-life of ten it is 0.165 — five sixths of today's dead wood is gone by 2050. It is 1 where the land module is switched off, so that a package that does not carry the module still reproduces its base year.

land_sink_forest_dead_woodforest_dead_wood_retention * (land_sink_forest_dead_wood_2024 + forest_carbon_k * (forest_mortality_2050 - forest_mortality) * forest_production_area)MtCO₂/y absorbed

Dead wood as a first-order stock, in the closed form of the wood-products pool: with a constant inflow from the base year on, the horizon flux is retention × (base-year flux + change in inflow). The change in inflow is the change in mortality at the living pool's marginal k, so that a tree that dies leaves one pool and enters the other with the same carbon, and the stock itself drops out. Today's sink is a transient. It was about 10 MtCO₂/y at the campaign's median year, 2018, and the inventory puts it at 22.6 in 2024, because mortality doubled in a decade and the dead wood has not caught up. The closed form books the 2050 mortality from 2025, so the central case's step from 16.6 to 23.2 Mm³/y stands in for the rise the inventory already sees by 2024; in 2050 the two readings differ by 0.3. The inventory itself calls it a buffer, which the forest gives back by oxidation as mortality comes down, and the study the climate cases come from decomposes it with a half-life of ten years. At constant mortality the pool fills and stops absorbing; a climate case that kills more trees refills it only by what has not decomposed by 2050 — 2.1, 3.3 or 4.9 MtCO₂/y from the mildest case to the severest, where until stage B this line gave 11, 14 and 18 and never decayed. Harvest residues are not in the inflow: the study counts them, and finds that the management scenario hardly moves this pool.

land_sink_forest_afforestationafforestation_storage_rate * land_setting_afforestation * max(0, land_horizon_years - afforestation_lag) / 1000MtCO₂/y absorbed

New forest, booked at the expansion storage rate on the hectares planted more than the establishment lag before the horizon. Hectares planted later store nothing here — a step where the truth is a curve, and the honest alternative was a curve nobody published.

land_sink_forestland_sink_forest_biomass + land_sink_forest_dead_wood + land_sink_forest_afforestation + forest_litter_soil_sink + forest_overseas_sink - land_peat_forestMtCO₂/y absorbed—
hwp_inflow_2024forest_harvest_base * hwp_long_lived_share_base * hwp_carbon_per_m3MtCO₂/y

The carbon that entered the long-lived wood-products pool in the base year: the base-year harvest, times the share that became sawn timber and panels, times the carbon a cubic metre of that share carries. The coefficient is derived so that this reproduces the national inventory report's own inflow, 10.0 MtCO₂/y, and it lands within half a per cent of the IPCC's default carbon density of sawnwood without having been fitted to it.

hwp_inflowland_harvest_long_lived * hwp_carbon_per_m3MtCO₂/y—
hwp_decay_rateln_two / hwp_half_life1/y—
hwp_stock_2024(hwp_inflow_2024 - hwp_base_sink) / hwp_decay_rateMtCO₂

The stock the pool must hold for the base year to balance: a first-order pool releases k · stock a year, so a pool that takes in 10.0 MtCO₂ and is measured as a source of 0.4 holds (10.0 + 0.4) / k. It is derived from the base-year balance rather than declared, which is what makes the base-year check hold by construction — and it is reported beside the stock the inventory report's own outflows imply, hwp_stock_nir_2021, which is a fifth smaller because the two inventory vintages do not agree on the sign of the 2021 balance.

hwp_retention0.5 ** (land_horizon_years / hwp_half_life)fraction

What is left of a tonne put into the pool at the base year by the horizon: 0.5 ^ (years / half-life), which is e^(−k·T) written with the half-life a reader knows. At 26 years and a half-life of 28.9 it is 0.536 — roughly half of what stands today is still standing in 2050, and roughly half of what is added between now and then.

hwp_stock_2050hwp_stock_2024 * hwp_retention + hwp_inflow / hwp_decay_rate * (1 - hwp_retention)MtCO₂

The first-order-decay stock at the horizon, in closed form for a constant inflow from the base year on: what remains of the base-year stock, plus what the horizon inflow has built towards its own equilibrium inflow / k. A constant inflow is the assumption to name — the lever is a 2050 setting and the model has no trajectory to integrate — and it errs on the side of a larger stock for a rising harvest, because it books the 2050 inflow from 2025.

hwp_decay_2050hwp_decay_rate * hwp_stock_2050MtCO₂/y—
land_sink_hwphwp_inflow - hwp_decay_2050MtCO₂/y absorbed

Harvested wood products as a stock, since stage E: the inflow of long-lived products less the decay of everything already standing, at the horizon. With a constant inflow the closed form collapses to retention × (inflow − base-year inflow + base-year balance), so the stock itself drops out of the flux — which is why the base stock is derived rather than fetched — and the pool responds to the change in what is put in, damped by half over the horizon. That damping is what the flow reading of stage A lacked: at the reference it gives 2.5 MtCO₂/y where the flow gave 3.0, and hwp_flow_reading keeps the old figure beside it. Raising the harvest and the long-lived share together is still the one move that deepens this pool and the wood supply at once.

hwp_flow_readinghwp_coefficient * (land_setting_harvest * land_setting_long_lived - forest_harvest_base * hwp_long_lived_share_base) + hwp_base_sinkMtCO₂/y absorbed

The stage-A flow reading of the same pool — a coefficient on the change in long-lived volume plus the base-year balance — kept as a comparison line and read by nothing else. It overstates the 2050 flux by the decay of what is added, which the stock reading carries.

hwp_stock_checkhwp_stock_2024 - hwp_stock_nir_2021MtCO₂

The derived base-year stock less the stock the inventory report's own 2021 outflows imply. Positive, and not meant to be zero: the balance this model is held to is the 2026 vintage's, which books a source where the 2023 report booked a sink.

land_soil_practice_gain(soil_practice_potential_arable + soil_practice_potential_grassland) * land_setting_soil_practicesMtCO₂/y absorbed

The identified soil-carbon potential, taken at the share the lever asks for, split between the two land uses it sits on. Reduced tillage is deliberately excluded: the study that sizes the potential calls it a redistribution down the soil profile rather than a gain, and including it would add about a seventh. The headline "4 per 1000" figure quoted in public is larger still, because it counts no-till and forest land together; this one is the agricultural part without them, and the split between arable and grassland follows the itemised practices rather than the areas they sit on.

land_soil_conversion_flux(max(0, land_setting_grassland) * soil_carbon_grass_to_crop - max(0, -land_setting_grassland) * soil_carbon_crop_to_grass) * min(land_horizon_years, soil_carbon_conversion_years) / 1000MtCO₂/y emitted

The soil-carbon tail of ploughing grassland, or of putting arable land back to grass. Only the last twenty years of conversions are still in the flux at the horizon, and the two directions carry different coefficients — loss is about twice as fast as gain, so re-grassing repairs more slowly than ploughing broke. Written with two max terms rather than a conditional so that nothing branches: at a conversion of zero both terms are zero, which is where the reference scenario sits. It is booked on top of the per-hectare cropland and grassland coefficients, and only for the change the player makes: those coefficients are calibrated on a base year that already contains the historic conversions, so charging the base year twice would have been the mistake to avoid here.

land_sink_grasslandgrassland_sink_coefficient * land_grassland + soil_practice_potential_grassland * land_setting_soil_practices - land_peat_grasslandMtCO₂/y absorbed

Mineral grassland absorbs; the organic soil under part of it emits ten times as much per hectare, and which of the two wins is a national fact rather than a general one. Splitting the line is what lets the same equation carry a country whose grassland is a sink and a country whose grassland is its second largest source — and it is what stops a herd cut from raising emissions, which is what a single negative per-hectare coefficient would have done.

land_sink_cropland-(cropland_source_coefficient * land_arable) + soil_practice_potential_arable * land_setting_soil_practices - land_soil_conversion_flux - land_peat_arableMtCO₂/y absorbed

A source, not a sink, and it has been one in every year the inventory covers: arable soil loses carbon under crops, and the drained organic soils and the historic conversions are booked here too. Soil practices are what pushes back against it, and the conversion flux of a grassland decision lands here as well, because that is where the inventory puts it.

land_sink_artificial-(artificialisation_carbon_content * land_setting_artificialisation / 1000) - land_peat_artificialMtCO₂/y absorbed

Always a source. A standing emission per unit of annual flow rather than a one-off per hectare, because sealing and the biomass it removes are booked over a twenty-year tail: stop artificialising and this line goes to zero, which is exactly what the net-zero-artificialisation target claims.

land_sink_wetland-wetland_other_source - land_peat_waterMtCO₂/y absorbed—
land_sink_totalland_sink_forest + land_sink_hwp + land_sink_grassland + land_sink_cropland + land_sink_artificial + land_sink_wetlandMtCO₂/y absorbed

The six pools, added up, positive for absorption — the module's own sign, which national_natural_sink then negates once, where the national account needs it. The specification calls this quantity lulucf_absorbed; the name here follows the land_ prefix the rest of the module carries.

land_sink_forest_2024forest_carbon_ratio_base * forest_volume_balance_2024 + land_sink_forest_dead_wood_2024 + forest_litter_soil_sink + forest_overseas_sink - land_peat_forest_2024MtCO₂/y absorbed

The same lines on base-year quantities, with no climate factor and no afforestation term: the living biomass at the inventory's own pair, the dead wood at its base-year flux, and a standing forest that already contains everything planted before the base year, which the inventory's forest line already counts. This and the five pools after it are what the module is calibrated on, and the only numbers in the block that are checked against an observation rather than produced as a result. Two dates under one label, in France. The living biomass and the dead wood are read at the IGN campaign's median year, 2018, because that is where the production, mortality and removals come from; the total they are closed on, and so the litter-and-soil residual and the French Guiana line, is the inventory's 2024. The inventory splits the same total at its own 2024, after six more years of mortality: 25.5 of living biomass and 22.56 of dead wood. Re-anchoring the two pools there was measured in stage C and not taken: it would move the 2050 natural sink by −2.2 to +2.2 MtCO₂e depending on the cubic metre the inventory's mortality is converted at, which no source fixes, against a reference margin of 2.63 under its band and a pinned winner's of 2.04 (docs/forest/stage_b.md).

land_sink_hwp_2024hwp_inflow_2024 - hwp_decay_rate * hwp_stock_2024MtCO₂/y absorbed

The base-year inflow less the decay of the base-year stock, which is the published balance to the bit, because the stock was derived from it. Written out rather than restated as the constant so that the identity the stock rests on is on the page.

land_peat_arable_2024sum(land_class.land_peat_emission_2024, land_class.id == "arable")MtCO₂e/y emitted—
land_peat_grassland_2024sum(land_class.land_peat_emission_2024, land_class.id == "grassland")MtCO₂e/y emitted—
land_peat_forest_2024sum(land_class.land_peat_emission_2024, land_class.id == "forest")MtCO₂e/y emitted—
land_peat_water_2024sum(land_class.land_peat_emission_2024, land_class.id == "water")MtCO₂e/y emitted—
land_peat_artificial_2024sum(land_class.land_peat_emission_2024, land_class.id == "artificial")MtCO₂e/y emitted—
land_peat_total_2024sum(land_class.land_peat_emission_2024)MtCO₂e/y emitted—
land_sink_grassland_2024grassland_sink_coefficient * land_class["grassland"].area_2023 - land_peat_grassland_2024MtCO₂/y absorbed—
land_sink_cropland_2024-(cropland_source_coefficient * land_class["arable"].area_2023) - land_peat_arable_2024MtCO₂/y absorbed—
land_sink_artificial_2024-(artificialisation_carbon_content * artificialisation_rate_base / 1000) - land_peat_artificial_2024MtCO₂/y absorbed—
land_sink_wetland_2024-wetland_other_source - land_peat_water_2024MtCO₂/y absorbed—
land_sink_total_2024land_sink_forest_2024 + land_sink_hwp_2024 + land_sink_grassland_2024 + land_sink_cropland_2024 + land_sink_artificial_2024 + land_sink_wetland_2024MtCO₂/y absorbed—
land_sink_check_2024-land_sink_total_2024 - official_natural_sink_2024MtCO₂e/y

What the module reproduces for the base year, less what the inventory books, in the inventory's sign. It is not zero and is not meant to be: it is the rounding of the published sub-sector lines against their own published total, and a residual that had been tuned away would have told a reader nothing. Watch it after any change to the calibrated coefficients — it is the first place a mis-calibration shows.

land_harvest_long_livedland_setting_harvest * land_setting_long_livedMm³/y—
land_timber_headroomland_harvest_long_lived - construction_timber_roundwoodMm³/y

What the long-lived harvest has left for everything else made of wood — furniture, joinery, panels, packaging — once the built square metres have taken theirs. At the reference construction takes 1.8 of 18.0 Mm³; at the top of the timber slider it takes 12.2, which is two thirds of the pool. It goes negative inside the declared ranges only in one corner — the harvest at its floor and the timber share at its top, −0.2 Mm³, or −6.2 with the long-lived share at its minimum too — and where it is positive that is not reassurance: the binding constraint is not the standing harvest but the sawmill. New-building structure alone asks for 6.1 Mm³ of sawn product at the top of the slider, against a French softwood sawnwood production of about 7.0 Mm³ — and France already imports a quarter of what it uses, while the national forest inventory's own projection finds additional sawlog supply short of additional demand by one to one and a half million cubic metres a year in 2050 even under its increased-harvest cases. And imported timber does not store carbon here. The harvested-wood- products pool is kept on the production approach, so a beam sawn in Finland and bolted into a French building adds nothing to the French inventory's wood pool: the carbon is Finland's. A scenario that builds in timber on imports gets the cement saving and none of the sink. That is also why timberShare leaves the wood-products pool where it is, and a test pins it: the pool follows what French sawmills cut, which harvestToProducts sets, not what French buildings use. The 4.65 MtCO₂/y that looks unbooked at the top of the slider is the flux of a France sawing ten million cubic metres more, and that lever reaches three.

land_harvest_otherland_setting_harvest - land_harvest_long_livedMm³/y

Everything the harvest is not turning into sawn timber and panels: pulp, packaging, fuel and what is burned without being sold. Stage C converts it into a wood supply and puts it beside the game's wood demand; stage A only says how large it is.

forest_material_share_base(forest_harvest_sawlogs + forest_harvest_industrial) / forest_harvest_basefraction of the harvest

Sawlogs and industrial wood over the whole base-year harvest — the share that leaves the forest as material rather than as fuel. It is not the long-lived share: pulp and packaging are material and come back within a few years, which is why the harvested-wood-products pool reads the smaller number.

forest_unutilised_share_baseforest_harvest_unutilised / forest_harvest_basefraction of the harvest

Wood that was felled, left the live stock, and supplies nothing. Windthrow and beetle-killed stems cut and abandoned on the forest floor: the harvest statistic counts them, the forest identity must count them because the tree is no longer growing, and the boiler never sees them. A fifth row rather than a fold into the informal firewood, which was the other option and would have handed the wood supply three million cubic metres of fuel that does not exist. Zero in a country whose statistic does not report the category, and then every term below is unchanged.

land_harvest_checkforest_harvest_sawlogs + forest_harvest_industrial + forest_harvest_energy_commercial + forest_informal_firewood + forest_harvest_unutilised - forest_harvest_baseMm³/y

Zero: the four declared uses of the base-year harvest add up to the harvest. It matters because one of the four — the firewood cut and never sold — is an estimate by difference, so the closure is what makes it visible instead of leaving it inside a larger number. It is about a quarter of the whole harvest and the independent estimates of it span two and a half million cubic metres.

Livestock, crops, nitrogen and diet

Stage B of the land module. It replaces the second of the two sliders that had no driver — an agriculture sector sliding along a published trajectory between the observed year and the strategy's horizon — with a chain that runs from a plate to a herd to a field, and it makes the agriculture sector a sum of the constructive account like every other sector. Four things are worth understanding before reading the formulas. Causality runs demand → production → herd, and trade sits in the middle. What a country eats, times its population, times what it no longer wastes, is a domestic demand; what it imports is subtracted and what it exports is added; the result is production, and production divided by a yield per head is a herd. The export term is indexed on volumes rather than on a share, because a share runs away as it approaches one and because a country that exports two fifths of its milk while importing a third of the dairy it eats has no single share to move. Without it a diet change would move the herd one for one, which is wrong for every exporting country. The dairy herd sells its culls whatever the diet does. Two fifths of French beef is a by-product of the dairy herd, so the suckler herd is the residual: it supplies the beef the dairy herd did not. Cut the milk and beef still reaches the market; cut the beef and the milk decides how much of the cut the suckler herd absorbs. That coupling is in the equations rather than in a footnote, and dairy_beef_coupling_share is the one number it rests on. Nitrogen is one decision with two consequences. The mineral nitrogen the fields receive drives the soil N₂O and the urea and liming CO₂ in agriculture, and it drives the ammonia the industry chain has to make and the hydrogen that ammonia draws. Until this module those were two unconnected numbers — a fertiliser dose nobody chose and an ammonia tonnage nobody explained. They are now one lever and a domestic share. The base year is checked by source, the horizon is not. A parallel set of *_2024 equations recomputes the livestock and the crops blocks on base-year quantities with no lever at all, and the tests hold them against the published inventory line by line. Every figure in this module is traced through docs/agriculture/agriculture_food_fertilisers.md, the sourced study behind it, to the publication named in its own sources; what is cited here is that publication rather than the study, because a citation has to be findable by somebody who does not have this repository. The 2050 figures are results, and the reference scenario's is uncomfortable: at the national strategy's own settings this module lands about three megatonnes above the strategy's own 2050 agriculture figure, because the strategy reaches it through practices it does not fully publish. That gap is information, and closing it by construction would have thrown the information away.

NameFormulaUnitNotes and sources
food_setting_red_meatland_module_active * dietRedMeat + (1 - land_module_active) * diet_red_meat_basekgec/cap/y

The land module's switch applied to a lever, the same arithmetic the seven land levers use. Where land_module_active is 0 the whole food block is read at its base year, so a package that does not carry the module reports its own observed farm projected forward rather than another country's diet, and a lever hidden in that package cannot move a number. Both sides always evaluate — this is arithmetic and never a branch — so the browser engine, the Python evaluator and the solver see one expression and cannot take different paths through it.

food_setting_poultryland_module_active * dietPoultry + (1 - land_module_active) * diet_poultry_basekgec/cap/y—
food_setting_dairyland_module_active * dietDairy + (1 - land_module_active) * diet_dairy_index_baseindex, base year = 1—
food_setting_wasteland_module_active * foodWaste + (1 - land_module_active) * food_waste_cut_basefraction of edible waste removed—
food_setting_exportland_module_active * livestockExport + (1 - land_module_active) * livestock_export_baseindex, base year = 1—
food_setting_nitrogenland_module_active * nIntensity + (1 - land_module_active) * n_intensity_baseindex, base year = 1—
food_setting_legume_arealand_module_active * legumeArea + (1 - land_module_active) * legume_area_baseMha—
food_setting_entericland_module_active * entericMitigation + (1 - land_module_active) * enteric_mitigation_basefraction of cattle—
food_setting_manureland_module_active * manureMethanised + (1 - land_module_active) * manure_methanised_basefraction of manure—
food_setting_farm_fuelland_module_active * agriFuelSwitch + (1 - land_module_active) * agri_fuel_switch_basefraction of farm fuel—
food_setting_ammonia_shareland_module_active * ammoniaDomesticShare + (1 - land_module_active) * ammonia_domestic_share_basefraction—
food_setting_organicland_module_active * organicShare + (1 - land_module_active) * organic_share_basefraction of the arable area—
food_setting_crop_exportland_module_active * cropExport + (1 - land_module_active) * crop_export_baseindex, base year = 1—
plant_food_waste_factor(1 - crop_food_waste_share) / (1 - crop_food_waste_share * (1 - food_setting_waste))factor on demand

Apparent consumption is published on today's losses, so cutting waste does not cut consumption — it cuts the supply the same nutrition needs. (1 − w) / (1 − w·(1 − cut)) is that: at no cut it is one, and at a complete cut it is 1 − w. Since stage E the share w is per product: this one is the plant-food basket's, read from the wheat-to-bread chain, and the animal products carry their own in animal_product.waste_share — a fifth of the poultry that leaves the farm never reaches a plate, a tenth of the milk, a twelfth of the beef and pork. The whole-basket figure the environment statistician publishes, 7% of the supply on the European definition, is a different perimeter and is reported beside these rather than used for them.

product_waste_factor
per row of animal_product
(1 - row.waste_share) / (1 - row.waste_share * (1 - food_setting_waste))factor on demand

The same identity, on each product's own downstream loss share. It is what makes the waste lever a large lever on poultry and a small one on beef — the chain-loss study finds them two and a half times apart — where a single basket share made it the same size on everything.

food_waste_basket_sharesumproduct(animal_product.consumption_base, animal_product.waste_share) / sum(animal_product.consumption_base)fraction of the animal supply

The per-product shares weighted by what the country eats — the animal basket's own downstream loss, about 12% — for comparison with the 7% the environment statistician counts as edible waste on the whole food supply. Not an identity: the two perimeters differ, and the difference is reported rather than reconciled.

population_ratiopopulation_horizon / population_basefactor on demand

Demography is a constant here and not a lever: the module does not offer the size of the population as a choice a player makes. It moves every diet-driven quantity by about a per cent, which is small beside the diet levers and large beside the food-waste one.

demand_index_red_meatfood_setting_red_meat / diet_red_meat_base * population_ratioindex, base year = 1

Diet and population in one multiplier, one for the base year by construction; the waste factor joins it per product, below. Beef, pork and sheep meat share it because every published diet scenario moves the three together and none of them publishes a separate trajectory for sheep.

demand_index_poultryfood_setting_poultry / diet_poultry_base * population_ratioindex, base year = 1—
demand_index_dairyfood_setting_dairy / diet_dairy_index_base * population_ratioindex, base year = 1—
product_demand_index
per row of animal_product
beef: demand_index_red_meat * row.product_waste_factor
pork: demand_index_red_meat * row.product_waste_factor
sheep: demand_index_red_meat * row.product_waste_factor
poultry: demand_index_poultry * row.product_waste_factor
milk: demand_index_dairy * row.product_waste_factor
index, base year = 1

Which diet lever drives which product, written out one line per product rather than hidden in a conditional. This map is also what makes animal_product a fixed-row table: every row has to have a formula, so a country cannot quietly drop a product the account needs.

product_domestic_demand
per row of animal_product
row.consumption_base * row.product_demand_indexkt/y—
product_production
per row of animal_product
row.consumption_base * row.product_demand_index * (1 - row.import_share) + row.export_base * food_setting_exportkt/y

Domestic demand less what is imported, plus what is exported. The import share is held at the base year's — a country that eats less meat is not assumed to import a different fraction of it — while the export volume is the lever. That asymmetry is deliberate: the import share is an observed market position, and the export volume is the policy choice, because it is the one that decides whether a herd exists to feed this country or another.

product_self_sufficiency
per row of animal_product
row.product_production / row.product_domestic_demand if row.product_domestic_demand > 0 else 0fraction

Production over domestic demand. Above one the country is a net exporter of that product, below one a net importer, and the two can coexist inside one product — France exports two fifths of its milk and imports a third of the dairy it eats — which is why the ratio is reported beside the trade terms rather than instead of them.

product_production_2024
per row of animal_product
row.production_2024kt/y—
product_trade_check
per row of animal_product
row.consumption_base * (1 - row.import_share) + row.export_base - row.production_2024kt/y

Zero for every product: consumption net of imports, plus exports, is production. It is the identity the base-year trade position rests on, and it is emitted rather than assumed because the export volumes are derived from it — a country that declared all four numbers independently would find out here, and not in a footnote, that its statistics do not agree.

milk_productionsum(animal_product.product_production, animal_product.id == "milk")kt/y—
beef_productionsum(animal_product.product_production, animal_product.id == "beef")kt/y—
pork_productionsum(animal_product.product_production, animal_product.id == "pork")kt/y—
poultry_productionsum(animal_product.product_production, animal_product.id == "poultry")kt/y—
sheep_productionsum(animal_product.product_production, animal_product.id == "sheep")kt/y—
milk_per_dairy_cowanimal_product["milk"].production_2024 / livestock["dairy_cow"].heads_2024kg/head/y

Derived from the base-year production and the base-year herd rather than declared beside them, because a yield declared next to the two numbers it is the ratio of would be a third copy of the same fact and could drift from them. Every yield in this block is derived the same way.

beef_per_dairy_cowdairy_beef_coupling_share * animal_product["beef"].production_2024 / livestock["dairy_cow"].heads_2024kg/head/y

The beef a dairy cow sends to market anyway — cull cows and the calves the dairy herd does not keep. It is dairy_beef_coupling_share of the whole beef production divided by the dairy herd, so the coupling rests on that one share, which is estimated rather than published: a herd-flow account is what would replace it, and the alternative split, proportional to cow numbers, gives a very different pair of yields.

beef_per_suckler_cow(1 - dairy_beef_coupling_share) * animal_product["beef"].production_2024 / livestock["suckler_cow"].heads_2024kg/head/y—
other_cattle_per_cowlivestock["other_cattle"].heads_2024 / (livestock["dairy_cow"].heads_2024 + livestock["suckler_cow"].heads_2024)head per cow

Heifers, bullocks, calves and everything else in the herd that is neither a dairy cow nor a suckler cow, per cow. The ratio is held at the base year's: the module sizes a herd, not a herd structure, and a changed rearing pattern is a decision the model does not carry.

dairy_cowsmilk_production / milk_per_dairy_cowM head—
suckler_cowsmax(0, (beef_production - dairy_cows * beef_per_dairy_cow) / beef_per_suckler_cow)M head

The residual herd: the beef the market wants, less the beef the dairy herd sells anyway, over what a suckler cow produces. It is the line that makes a dairy-only diet cut still send beef to market, and the line that makes a beef-only cut fall hardest on the suckler herd. Floored at zero rather than allowed to go negative. The floor is reachable: a diet that cuts beef far harder than dairy asks for less beef than the dairy herd already supplies, and the honest answer there is that the suckler herd disappears and the surplus dairy beef is exported or not produced — not that the country keeps a negative number of cows. Where the floor binds, self-sufficiency in beef rises above one and says so.

other_cattle_heads(dairy_cows + suckler_cows) * other_cattle_per_cowM head—
pig_herdlivestock["pig"].heads_2024 * pork_production / animal_product["pork"].production_2024M head—
poultry_headslivestock["poultry"].heads_2024 * poultry_production / animal_product["poultry"].production_2024M head—
small_ruminant_herdlivestock["small_ruminant"].heads_2024 * sheep_production / animal_product["sheep"].production_2024M head—
livestock_heads
per row of livestock
dairy_cow: dairy_cows
suckler_cow: suckler_cows
other_cattle: other_cattle_heads
pig: pig_herd
poultry: poultry_heads
small_ruminant: small_ruminant_herd
M head

One formula per animal category, side by side, which is what makes the chain auditable: a dairy cow is sized by milk, a suckler cow by the beef the dairy herd did not supply, the rest of the cattle by the cows, and a pig, a bird and a ewe by their own product. This map is what makes livestock a fixed-row table.

livestock_heads_2024
per row of livestock
row.heads_2024M head

The base-year column, re-emitted as a result so a chart that compares the herd with the herd it started from reads both from one place instead of one from the model and one from the raw table.

cattle_base_headssum(livestock.heads_2024, livestock.species_group == "cattle")M head—
cattle_headssum(livestock.livestock_heads, livestock.species_group == "cattle")M head—
cattle_indexcattle_heads / cattle_base_headsindex, base year = 1

The cattle herd against the base year's. It is what the manure and grazing nitrogen are scaled by, and using cattle alone for all of it is an approximation: cattle are about five sixths of the nitrogen excreted here, but a scenario that cut pigs and kept cattle would be charged too much organic nitrogen. manure_nitrogen_excreted is the same quantity computed species by species and is reported beside it, so the size of the approximation is visible rather than argued about.

livestock_row_base
per row of livestock
row.livestock_heads * row.emission_factor / 1000 * (1 - food_setting_enteric * enteric_lipid_effect * row.enteric_mitigable)MtCO₂e/y

Heads times a per-head factor, less what a low-methane ration removes where one is fed. The factor covers enteric fermentation and manure management together because that is how the inventory publishes it; manure_ch4_share splits the result below, and the split is the module's, not the inventory's.

livestock_row_enteric
per row of livestock
row.livestock_row_base * (1 - row.manure_ch4_share)MtCO₂e/y—
livestock_row_manure
per row of livestock
row.livestock_row_base * row.manure_ch4_share * (1 - food_setting_manure * methanisation_abatement)MtCO₂e/y

The manure half, and the only half a digester can take. Sending manure to a digester removes methanisation_abatement of the methane the store would have released, on the share that goes there. Both coefficients are provisional, and they are the module's weakest pair: the inventory publishes enteric and manure methane as one number, so the share each species carries is an assumption rather than a measurement, and the detailed reporting tables are what would settle it.

livestock_row_emissions
per row of livestock
row.livestock_row_enteric + row.livestock_row_manureMtCO₂e/y—
livestock_enteric_emissionssum(livestock.livestock_row_enteric)MtCO₂e/y—
livestock_manure_emissionssum(livestock.livestock_row_manure)MtCO₂e/y—
livestock_emissionslivestock_enteric_emissions + livestock_manure_emissions + refrigerants_fixedMtCO₂e/y

The whole livestock block, refrigerant leakage included. The refrigerants are a constant because no lever in this module drives them and because the inventory books them inside the agriculture sector; leaving them out would break the base-year closure by exactly their own size.

livestock_row_manure_n
per row of livestock
row.manure_n_2024 * row.livestock_heads / row.heads_2024kt N/y—
manure_nitrogen_excretedsum(livestock.livestock_row_manure_n)kt N/y

The nitrogen the herd excretes, scaled species by species — the quantity the crops block approximates with a cattle index, reported here so the approximation can be measured instead of taken on trust. It is also the feedstock a digester eats, which is what stage C will read it for.

manure_nitrogen_excreted_2024sum(livestock.manure_n_2024)kt N/y—
livestock_row_grassland
per row of livestock
row.grassland_ha_per_head * row.livestock_headsMha—
grassland_requiredsum(livestock.livestock_row_grassland)Mha

The permanent grassland the herd needs, at per-head requirements calibrated so the base-year herd needs exactly the grassland the base year has. It is grassland only: the fodder maize, the cereals and the imported protein the same herd eats are not in it, and neither is temporary grassland, which the land account books inside arable land.

grassland_availableland_grassland + grassland_rough - land_class["grassland"].peat_area * land_setting_peat_rewettingMha

The land account's permanent grassland plus the rough grazing the farm survey counts and the land survey books under heath. Two statistics, reconciled in the open: the livestock block reads the farm survey's total while the land account still closes on the land survey's.

grassland_releasedgrassland_available - grassland_requiredMha

Grassland available less grassland required. Positive means a shrinking herd has freed hectares; negative means the herd asks for more grass than the land account has, which is a tension the module reports rather than resolves — nothing here plants a forest on freed grassland, and nothing forces a herd onto land that does not exist. Whether freed grassland should afforest automatically is a decision, and it is left to the land levers.

legume_creditlegume_n_credit * (food_setting_legume_area - legume_area_base) / legume_credit_spankt N/y

The mineral nitrogen the rotation no longer needs, read linearly over the span of hectares the study that measured it used. Outside that span the extrapolation belongs to the reader, and the lever's bounds are set so it is not left far outside.

mineral_nitrogenmax(0, mineral_n_base * food_setting_nitrogen * organic_nitrogen_factor - legume_credit)kt N/y

The dose the conventional fields receive, less the hectares gone organic and less the legume credit, floored at zero. It is the module's most consequential single number: it sets the soil N₂O and the urea and liming CO₂ in agriculture, and it sets the ammonia the industry chain has to make and the hydrogen that ammonia draws. Two things that were unconnected — how much nitrogen the fields get and how much hydrogen the country must produce — are one decision here.

organic_nitrogen_factor(1 - food_setting_organic) / (1 - organic_share_base)factor on the mineral dose

(1 − organic share) / (1 − base-year organic share): an organic hectare takes no mineral nitrogen, and the base-year delivery already excludes the hectares that were organic then, so only the change moves the dose. It multiplies nIntensity, which since stage E is the dose on the hectares that stay conventional; at the reference the two together deliver 55% of 2024, the strategy's −54%, without counting the organic extension twice. INRAE books −330 kt N for the same extension; this factor gives −360 at the base-year dose.

nitrogen_manure_spreadmanure_n_spread_base * cattle_indexkt N/y—
nitrogen_manure_grazingmanure_n_grazing_base * cattle_indexkt N/y—
nitrogen_fixationfixation_n_base * (1 + fixation_gain * (food_setting_legume_area - legume_area_base) / legume_credit_span)kt N/y—
nitrogen_input_totalmineral_nitrogen + nitrogen_manure_spread + nitrogen_manure_grazing + nitrogen_fixationkt N/y

Mineral, spread manure, grazing deposits and biological fixation. Atmospheric deposition is not in it — the inventory books it elsewhere — and neither is seed or irrigation nitrogen. Legumes appear twice, on purpose and in opposite directions, and the result is worth stating because it surprises people: they take mineral nitrogen out through legume_credit and put fixed nitrogen in through nitrogen_fixation, and the second is the larger. A hectare of legumes fixes more nitrogen than the mineral fertiliser it saves the next crop, so the total input rises with the legume area even as the mineral dose falls. Emissions still fall, because a tonne of mineral nitrogen is charged at more than twice what a tonne of total input costs on the indirect line — but a scenario that reads the nitrogen balance as a proxy for emissions would get the sign wrong here.

agricultural_arealand_arable + land_perm_crops + grassland_availableMha—
nitrogen_input_per_hectarenitrogen_input_total / agricultural_areakg N/ha/y

Total nitrogen input over the agricultural area — arable, permanent crops and grassland, the farm survey's grassland included. It is an input intensity and not the gross nitrogen surplus the environmental accounts publish: a surplus subtracts the nitrogen the harvest removes, and this model has no crop-offtake account to subtract with. The two are different numbers and the surplus is much the smaller — about 45 kg/ha against an input of 123 in the base year — so read this as a trend against its own base year and not against a published surplus.

crop_soil_n2o(mineral_nitrogen * ef_mineral_n2o + nitrogen_manure_spread * ef_organic_n2o + nitrogen_manure_grazing * ef_grazing_n2o + nitrogen_input_total * ef_other_crop_n2o) / 1000MtCO₂e/y

The four nitrogen sources at their own emission factors. Mineral nitrogen is charged the heaviest one, grazing deposits the next, spread manure the lightest, and the whole input again at the factor that covers residues, mineralisation, leaching and the indirect pathways. That last term is the module's largest approximation: it lumps an area-driven quantity with a nitrogen-driven one, which the inventory's detailed tables separate.

crop_fertiliser_co2mineral_nitrogen * ef_mineral_co2 / 1000MtCO₂/y

Urea hydrolysis and liming, charged on mineral nitrogen. Liming is driven by area and soil pH rather than by nitrogen, so this is a stated approximation and not a measurement of liming; it is kept on the nitrogen because the inventory publishes the two on one line.

peat_agriculture_n2o(land_class["arable"].peat_area + land_class["grassland"].peat_area) * peat_agri_n2o_ef * (1 - land_setting_peat_rewetting)MtCO₂e/y

The nitrous oxide of a drained agricultural peat soil, taken out of the nitrogen dose. The inventory books it in agriculture, not in land use, so it cannot live in the land module's peat term; and it is not a response to fertiliser — it is what a drained organic soil mineralises out of its own carbon and nitrogen — so leaving it inside ef_other_crop_n2o would have let a nitrogen cut switch off a chimney that fertiliser never lit. Rewetting is what stops it, and the whole of it stops: the emission is a drainage emission.

peat_agriculture_n2o_2024(land_class["arable"].peat_area + land_class["grassland"].peat_area) * peat_agri_n2o_ef * (1 - peat_rewetting_base)MtCO₂e/y—
digestate_emissionsbioenergy_setting_energy_maize * energy_maize_digestate_efMtCO₂e/y

The methane and nitrous oxide a digester's own store and its digestate release, per hectare of the main crop grown to feed it. The inventory gives it a line of its own inside agriculture where the practice is large enough to have one, and it is booked on the area rather than on the gas because that is the quantity the lever moves. Zero where no main crop is grown for methane, and then the line is not there.

digestate_emissions_2024energy_maize_area_base * energy_maize_digestate_efMtCO₂e/y—
crop_emissionscrop_soil_n2o + crop_fertiliser_co2 + residue_burning_fixed + crop_carbon_fixed + peat_agriculture_n2o + digestate_emissionsMtCO₂e/y—
arable_committedfood_setting_legume_area + bioenergy_setting_energy_crop + bioenergy_setting_energy_maizeMha

The arable hectares two levers have spoken for by name: the legumes in the rotation and the land growing a first-generation biofuel. Since stage E it is a readout rather than the headroom's numerator — the headroom is now the whole arable area the diet, the herd, the exports and the fuel crops need at the yield the organic share leaves, arable_needed — and it is kept because the two levers still compete for the same hectares and a reader wants to see how many. The cover crops are deliberately not here. A winter intermediate crop occupies the same hectare as the spring crop that follows it, so it commits no land; what limits it is the spring-crop area, and cive_headroom reports that separately.

crop_mineral_input_sharemineral_n_base / (mineral_n_base + manure_n_spread_base + fixation_n_base)fraction of the field nitrogen input

Mineral fertiliser's share of the nitrogen the fields receive in the base year — mineral, spread manure and biological fixation, from the module's own base-year inputs: 0.62 in France, 0.49 in Germany, where manure carries more of the load. These are national totals, grassland included. A cropland-only budget, which takes grassland's share of the fixation and the manure out and adds deposition, puts France at 0.65 to 0.71, and the stockless Seine basin at 0.76: the response here is, if anything, a little gentle — about one point of yield at the reference.

nitrogen_plateau_input1 - crop_mineral_input_share * (1 - n_yield_plateau)fraction of the base-year input

The nitrogen a conventional field receives at the plateau's edge, against the base year: the excess above n_yield_plateau removed, the manure and fixation held. The crop harvests the same there, so the field is more efficient at the edge than in the base year — which is what makes the excess an excess.

nitrogen_useful_dosemin(food_setting_nitrogen, n_yield_plateau)fraction of the base-year dose

The conventional dose, capped at the plateau: above n_yield_plateau the extra nitrogen is what the crop does not take up, and a heavier dose buys nothing — French doses sit at or above the technical optimum, and yields have risen since the 1980s on a flat or falling input.

nitrogen_input_index(1 - crop_mineral_input_share * (1 - nitrogen_useful_dose)) / nitrogen_plateau_inputindex, plateau edge = 1

The nitrogen a conventional field receives against the plateau's edge: one on the plateau, less below it, by the mineral nitrogen cut there.

crop_nue_plateaucrop_nue_base / nitrogen_plateau_inputfraction of the nitrogen input

The cropland's nitrogen use efficiency at the plateau's edge: the same harvest as the base year on less input. It fixes the hyperbola's one free parameter, Ymax = Y/(1 − NUE), at the point the curve starts from.

nitrogen_yield_factornitrogen_input_index / (nitrogen_input_index + crop_nue_plateau * (1 - nitrogen_input_index))index, base year = 1

The yield of a conventional hectare at this dose, against the base year's. Above the plateau, one. Below it, the hyperbola the GRAFS school fits to every country's cropland, Y = Ymax·F/(F + Ymax) (Lassaletta et al. 2014), passed through the plateau's edge and divided by its value there: φ/(φ + NUE·(1 − φ)), with φ the input index and NUE the efficiency at the edge. The yield falls slowly at first and faster as the input shrinks, and never to zero, because manure and fixation still feed the crop. Written so that it is exactly one on the plateau, which keeps the base year and every edition without the module bit-identical. Legumes do not move it: their credit replaces mineral nitrogen with the rotation's own and is taken off mineral_nitrogen, not off the dose.

crop_yield_index((1 - food_setting_organic) * nitrogen_yield_factor + food_setting_organic * organic_yield_ratio) / (1 - organic_share_base + organic_share_base * organic_yield_ratio)index, base year = 1

The average yield of the arable area against the base year's: the conventional hectares at nitrogen_yield_factor, the organic ones at organic_yield_ratio, over the same mix at the base-year organic share. One at the base year by construction; 0.66 with every hectare organic, whatever the dose. Two things move it, the organic share and the mineral dose below its plateau; neither the climate nor the breeding progress the strategy's own modelling assumes at +0.16% a year does, and that is a named gap rather than a number.

organic_areafood_setting_organic * land_arableMha—
crop_food_indexpopulation_ratio * plant_food_waste_factorindex, base year = 1

The plant food people eat, per person held at the base year — the module offers no plant-diet lever, so a shift to pulses and cereals is not in it and is a named gap — times the population, times what is no longer wasted downstream of the farm.

poultry_indexpoultry_heads / livestock["poultry"].heads_2024index, base year = 1—
pig_indexpig_herd / livestock["pig"].heads_2024index, base year = 1—
small_ruminant_indexsmall_ruminant_herd / livestock["small_ruminant"].heads_2024index, base year = 1—
feed_grain_indexcompound_feed_share_poultry * poultry_index + compound_feed_share_cattle * cattle_index + compound_feed_share_pig * pig_index + (1 - compound_feed_share_poultry - compound_feed_share_cattle - compound_feed_share_pig) * small_ruminant_indexindex, base year = 1

The grain the herd eats, weighted by which herd eats it: the compound-feed industry's species mix — poultry two fifths, cattle and pigs a quarter each — with the rest read as the small ruminants. Poultry is the point: a diet that swaps beef for chicken frees grassland and takes arable land, and a feed index that followed the cattle alone would have hidden it.

crop_feed_indexfeed_forage_share * cattle_index + (1 - feed_forage_share) * feed_grain_indexindex, base year = 1—
arable_base_non_energyland_class["arable"].area_2023 - energy_crop_area_base - energy_maize_area_baseMha

The base-year arable area less the base-year fuel crops — the area the four use shares are declared on, because the fuel crops are a lever of their own and enter arable_needed at the player's value.

arable_share_checkarable_share_food + arable_share_feed + arable_share_export + arable_share_other - 1fraction

Zero: the four use shares of the base-year arable area sum to one, so arable_needed equals the base-year arable area at the base-year settings. Emitted because the shares are four numbers from two statistics and the rounding of three of them was put in the fourth.

arable_need_energybioenergy_setting_energy_crop + bioenergy_setting_energy_maizeMha

The arable hectares a digester and a fuel plant take out of the food chain: the first-generation fuel crop, and the main crop grown for methane. The second is separated from the cover crops on purpose — a winter intermediate crop shares its hectare with the spring crop that follows, and a field of silage maize cut for a digester does not share anything. Both are read at the player's value, so a scenario that grows its own gas pays for it in food land here rather than nowhere.

arable_need_foodarable_base_non_energy * arable_share_food * crop_food_index / crop_yield_indexMha—
arable_need_feedarable_base_non_energy * arable_share_feed * crop_feed_index / crop_yield_indexMha—
arable_need_exportarable_base_non_energy * arable_share_export * food_setting_crop_export / crop_yield_indexMha—
arable_need_otherarable_base_non_energy * arable_share_otherMha—
arable_neededarable_need_food + arable_need_feed + arable_need_export + arable_need_other + arable_need_energyMha

The arable land this scenario's plates, herd, exports and fuel crops need, at the yield its organic share leaves — the crop block stage E added, and the module's answer to its own largest simplification, which was an arable area held at the base year while everything on it moved. Demand ÷ yield, use by use: the plant food people eat, scaled by population and waste; the feed the herd eats, scaled by the herd; the exports, scaled by their lever; fallow and seed held; the fuel crops at the player's value. The land account does not resolve the difference with land_arable: arable_headroom reports it, and a negative headroom is a diet, a herd and an export position the country's fields cannot carry at that yield.

arable_headroomland_arable - arable_neededMha

What the land account holds less what the scenario needs. Positive is arable land the fields could spare; negative is the tension the crop block exists to show, reported rather than clamped. At the reference it is 1.5 Mha short: the strategy's organic share costs 7% of the yield, its dose cut below the nitrogen plateau another 8%, and the strategy's herd gives a little of that back in feed.

crop_self_sufficiency(land_arable - arable_need_other - arable_need_energy) * crop_yield_index / (arable_base_non_energy * (arable_share_food * crop_food_index + arable_share_feed * crop_feed_index))fraction

What the arable land the account holds can grow at this yield, over what the country's own plates and herd need of it — fallow, seed and fuel crops set aside on both sides. 1.4 at the base year: France grows two fifths more than it eats, which is the cereal exporter the trade statistics describe. Below one the country would import grain to feed itself, whatever the export lever says.

crop_output_index(land_arable - arable_need_other - arable_need_energy) * crop_yield_index / (arable_base_non_energy * (1 - arable_share_other))index, base year = 1

What the fields the account holds produce, against the base year: the arable area net of fallow and fuel crops, times the yield index. It moves with the land levers and the organic share and with nothing the plates decide, which is the point of showing it beside arable_needed.

farm_fuel_emissionsfarm_fuel_2024 * (1 - food_setting_farm_fuel)MtCO₂e/y

The combustion of tractors, engines and farm boilers, taken to zero by the lever. It is booked as a named process term rather than as energy times a factor, and that is a deliberate departure from the rule the rest of the account follows. The reason is the model's own liquid fuel: efLiquid is a horizon-year assumption of about 25 gCO₂/kWh, because the model's 2050 leaves no fossil liquid, and charging farm diesel at it would put the base-year farm at about one megatonne against an inventory that measures ten and a half. The inventory measures this combustion directly, so the module books the measured quantity and lets the lever remove it. What that costs, stated rather than hidden: the roughly forty terawatt-hours of fuel behind the line are not in the model's carrier pools, so a farm that keeps burning diesel does not show up in the liquid-fuel demand the scoreboard scores. Neither does whatever replaces it — the national strategy sets the target of zero fossil fuel without publishing what carries the tractors afterwards, and inventing an electricity demand for them would be inventing a number. Both are reported as farm_fuel_energy_2024 and are the first thing stage C should close.

farm_fuel_energy_2024farm_fuel_2024 / ef_liquid_fossil_observed * 1000TWh/y

The base-year farm fuel, converted to energy at the observed emission factor of fossil liquid fuel — a diagnostic, and the size of the hole the line above describes. No equation reads it.

agriculture_livestock_postland_module_active * livestock_emissionsMtCO₂e/y

The module's switch again, this time on what reaches the constructive account. Gating the levers is not enough here: a package that does not carry the module would otherwise find three agriculture rows in its post table, computed on placeholder data, adding some seventy megatonnes to a total that is meant not to move. At zero the three rows are present, empty, and visible as such.

agriculture_crops_postland_module_active * crop_emissionsMtCO₂e/y—
agriculture_fuel_postland_module_active * farm_fuel_emissionsMtCO₂e/y—
agriculture_emissionssum(post.emissions_total, post.sector == "agriculture")MtCO₂e/y

A sum of the post table filtered on the sector, exactly as transport, building, industry and energy already are. That is the point of the three new rows: the sector total is now a sum of the constructive account and nothing else, so a missing sub-sector would be visible instead of invisible.

livestock_emissions_2024sumproduct(livestock.heads_2024, livestock.emission_factor) / 1000 + refrigerants_fixedMtCO₂e/y

The same per-head factors on the published base-year herd, with no lever and no diet: this is what the factors are calibrated on, and the only number of the livestock block that is held against an observation rather than produced as a result. It is deliberately not the chain evaluated at base-year lever positions — the chain's own agreement with the published herd is a separate identity, checked separately, and folding the two together would let a demand error hide behind a factor error.

nitrogen_input_2024mineral_n_base + manure_n_spread_base + manure_n_grazing_base + fixation_n_basekt N/y—
crop_emissions_2024(mineral_n_base * (ef_mineral_n2o + ef_mineral_co2) + manure_n_spread_base * ef_organic_n2o + manure_n_grazing_base * ef_grazing_n2o + nitrogen_input_2024 * ef_other_crop_n2o) / 1000 + residue_burning_fixed + crop_carbon_fixed + peat_agriculture_n2o_2024 + digestate_emissions_2024MtCO₂e/y—
agriculture_emissions_2024livestock_emissions_2024 + crop_emissions_2024 + farm_fuel_2024MtCO₂e/y—
livestock_check_2024livestock_emissions_2024 - citepa_livestock_2024MtCO₂e/y—
crops_check_2024crop_emissions_2024 - citepa_crops_2024MtCO₂e/y—
agriculture_check_2024agriculture_emissions_2024 - official_agriculture_2024MtCO₂e/y

What the module reproduces for the base year, less what the inventory books. It is not zero and it is not meant to be: three of the five sources are reproduced from published quantities and published implied factors, and what is left is the rounding of the published lines against their own published total. Watch it after any change to the calibrated factors — it is the first place a mis-calibration shows.

ammonia_productionmineral_nitrogen * food_setting_ammonia_share / nh3_nitrogen_fraction + ammonia_non_fertiliserkt NH₃/y

The nitrogen the fields receive, times the share made at home, divided by the nitrogen fraction of ammonia, plus the ammonia the chemical industry makes for something other than fertiliser. At the base year's nitrogen and the base year's domestic share it reproduces the tonnage the model used to carry as a free-standing lever to within a fraction of a per cent — a cross-check rather than a fit, because the domestic share comes from the fertiliser industry and the nitrogen from the inventory, and neither was chosen to land there. The consequence is that a fertiliser decision is now a hydrogen decision. At the reference nitrogen dose the ammonia demand is little more than half what the lever used to assert, and the hydrogen it draws falls with it.

ammonia_production_2024mineral_n_base * ammonia_domestic_share_base / nh3_nitrogen_fraction + ammonia_non_fertiliserkt NH₃/y—
chain_ammonia_productionland_module_active * ammonia_production + (1 - land_module_active) * ammoniaProductionkt NH₃/y

Which of the two the industry chain reads. Where the module is carried, the ammonia tonnage is derived from the nitrogen the fields ask for and the ammoniaProduction slider is retired and hidden; where it is not, the slider is the model exactly as it was. The switch is arithmetic and not a branch, which is what lets one shared equation serve both and lets the retired slider be provably inert rather than merely invisible. Restructuring the entry itself — moving the lever out of the shared model — would have been a change to the country contract, and this is the same result without one.

Bioenergy — what the land supplies

Stage C of the land module, and the last of the four first-order objects the module replaces. Three threshold rows — biogas 70/150, biofuels 40/50, wood 80/120 — were game rules: numbers the teaching team chose so the game would be playable, declared as such, and argued over in the controversy table because a resource limit that nobody sourced is a resource limit nobody has to believe. They are now computed, from the same land account, the same herd and the same forest the rest of this module already builds. What that changes is not the difficulty but the kind of statement the band makes. A player who breaches the biogas band is no longer over a rule; they are asking the country for more methane than its manure, its cover crops and its straw can make, and the panel can say which of the three would have to move. Push civeArea and the supply rises and so does the band. Push forestHarvest and the wood band rises while the forest sink falls, in the same scenario, from one identity — which is the whole reason the land account was built first. Three things a reader should know before quoting a number from here. The biogas supply carries a calibrated residual, biogas_other, which is 78% of the base year and is the module's largest declared hole; every build prints it. The residue pool is genuinely shared — a tonne of straw is either methane or a second-generation liquid and cannot be both — and residue_to_biogas_share splits it exhaustively, which a test asserts. And the good band is the domestic supply: bioImports moves the warning band and never the target, so a scenario that meets its liquid demand on imports is amber by construction.

NameFormulaUnitNotes and sources
bioenergy_setting_civeland_module_active * civeArea + (1 - land_module_active) * cive_area_baseMha

The switch idiom the whole module uses: where land_module_active is 1 the lever is read, where it is 0 the base-year value is, and both branches always evaluate so nothing about the arithmetic depends on which country is being built.

bioenergy_setting_residuesland_module_active * residueMobilisation + (1 - land_module_active) * residue_mobilisation_basefraction of the residue pool—
bioenergy_setting_energy_cropland_module_active * energyCropArea + (1 - land_module_active) * energy_crop_area_baseMha—
bioenergy_setting_energy_maizeland_module_active * energyMaizeArea + (1 - land_module_active) * energy_maize_area_baseMha

The main crop grown for a digester, on the same switch. It is a separate lever from civeArea because the two are separate facts about the land: a cover crop grows in the gap between two main crops and costs no hectare, while a field of silage maize cut for methane is that field's whole season and is booked in arable_needed as such. Where a country's digesters run on manure and cover crops alone the area is zero and every term it enters is unchanged.

bioenergy_setting_importsland_module_active * bioImports + (1 - land_module_active) * bio_imports_baseTWh/y—
manure_dm_collectablemanure_dm_per_cattle_head * cattle_heads + manure_dm_per_pig_head * pig_herdMt DM/y

The manure a digester could actually take, from the herd the food module sizes. Cattle and pigs only: poultry litter and sheep manure are outside every source's own accounting of the feedstock, and adding them at an invented coefficient would have been inventing a number. Cattle carry about nine tenths of it. A tonne of dry matter times a megawatt-hour per tonne is a terawatt-hour, so the units below need no conversion factor — that is not a coincidence but it is worth stating, because a stray thousand is the easiest error to make here.

biogas_from_manuremanure_dm_collectable * food_setting_manure * biomass_biogas_yieldTWh/y

One lever, two effects. manureMethanised removes part of the methane a manure store would have released — that is livestock_row_manure in the food module — and produces the methane a digester makes, which is this. The abatement is provisional and the supply is not: the yield per tonne is measured, the split between enteric and manure methane that the abatement rests on is not.

biogas_from_civebioenergy_setting_cive * cive_dm_yield * cive_biogas_yieldTWh/y—
biogas_from_energy_maizebioenergy_setting_energy_maize * energy_maize_dm_yield * cive_biogas_yieldTWh/y

Area × dry-matter yield × the same methane yield a tonne of green matter gives a digester. It is the largest single feedstock of the German fleet and the reason the German biogas residual is a sixth of the base year rather than three quarters of it — the feedstock is published as an area and a tonnage, so the module can build it instead of calibrating it away.

residue_dm_poolland_arable * residue_dm_yieldMt DM/y

Straw and stubble the arable area produces, whether or not anybody takes it. It follows land_arable, so ploughing grassland raises it and building on cropland lowers it — the residue supply is a consequence of the land account rather than a parameter beside it.

residue_dm_mobilisedresidue_dm_pool * bioenergy_setting_residuesMt DM/y—
biogas_from_residuesresidue_dm_mobilised * residue_to_biogas_share * biomass_biogas_yieldTWh/y—
biogas_supplybiogas_from_manure + biogas_from_cive + biogas_from_energy_maize + biogas_from_residues + biogas_otherTWh/y

Manure, cover crops, straw and a residual. The residual is 19 TWh and the base year's whole biogas consumption was 24.25, so at the base year this equation is three quarters an admission that the feedstock split is not published. At the reference the three built terms are worth about 51 TWh and the residual is unchanged, which is the right way round — the module grows what it can account for and leaves the hole the size it was.

wood_material_shareforest_material_share_base + land_setting_long_lived - hwp_long_lived_share_basefraction of the harvest

The share of the harvest that leaves the forest as material — sawn timber, panels, pulp, packaging — and therefore does not arrive at a boiler as a log. It starts at the base year's 53.3% and moves one-for-one with harvestToProducts, because a strategy that puts more of the cut into long-lived products is taking it out of the fuel pile and out of nowhere else. It is reported rather than clamped, on the land account's own rule. Inside the declared sliders it stays between 0.458 and 0.658, so neither term below can go negative; a country that widened either lever would see that in the supply before it saw it here.

wood_direct_supplyland_setting_harvest * (1 - wood_material_share - forest_unutilised_share_base) * wood_energy_per_m3TWh/y

The part of the cut that goes straight to energy: commercial fuelwood, and the firewood cut and never sold, which is about a quarter of the French harvest and is estimated by difference.

wood_byproduct_supplywood_byproduct_share * land_setting_harvest * wood_material_share * wood_energy_per_m3TWh/y

What comes back from the material half: sawmill offcuts and bark, panel residues and black liquor. It is 58% of the material harvest and about 35 TWh at the base year — bigger than the direct fuelwood in every scenario where the material share is above a half, which is every scenario the sliders reach.

wood_supplywood_direct_supply + wood_byproduct_supply + non_forest_wood + waste_woodTWh/y

The forest, plus two terms it does not produce: hedges and orchards, and end-of-life wood. Those two are 31.8 TWh and fixed, so a quarter of the wood supply answers to no lever in this game at all. There is no import line. France imports a few terawatt-hours of pellets and chips and exports about half as much again, and both are small enough beside 120 that adding a lever for them would have been decoration.

biofuel_1g_supplybioenergy_setting_energy_crop * biofuel_1g_yieldTWh/y

Area times the mix's average yield. The mix is held fixed while the area moves, which is the simplification worth naming: a sugar-beet hectare yields three times an oilseed hectare, so a scenario that wanted more beet would get a different answer from the same hectares.

biofuel_2g_supplyresidue_dm_mobilised * (1 - residue_to_biogas_share) * residue_liquid_yieldTWh/y

The other half of the residue pool, at the same 2.0 MWh a tonne the digester gets. The two are exclusive and the split is exhaustive: residue_to_biogas_share and its complement are the only claims on residue_dm_mobilised, so raising the mobilisation lever raises both bands together and nothing can be counted twice. A test asserts that the two terms add back to the pool exactly.

biofuel_domestic_supplybiofuel_1g_supply + biofuel_2g_supply + waste_fats_supplyTWh/y

Crops, straw and waste fats — everything the country's own land and bins produce. This is the good band.

biofuel_supplybiofuel_domestic_supply + bioenergy_setting_importsTWh/y

Domestic supply plus the import allowance. This is the warning band, and it is the only place in the three pools where an import appears: wood imports are small and left at zero, and no French study publishes a biomethane import at all.

biogas_headroombiogas_supply - biogas_demandTWh/y

Supply less demand, so a negative number is a scenario asking for more than the country can make. At the reference it is about −238 TWh, and that is the single most important thing this module surfaces: the game's methane demand is 308 TWh against a supply near 70. Part of it is an artefact worth naming — some 23 TWh of international air-freight fuel the source workbook classes as gas — and a large part is the methane a steam reformer turns into hydrogen. Most of it is neither, and is simply a scenario that has not electrified.

biofuel_headroombiofuel_supply - biofuel_demandTWh/y—
biofuel_domestic_headroombiofuel_domestic_supply - biofuel_demandTWh/y

The same against the domestic supply alone, which is the band the score reads. The difference between the two is exactly bioImports.

wood_headroomwood_supply - wood_demandTWh/y—
cive_headroomcive_land_ceiling - bioenergy_setting_civeMha

Cover crops against the land that could carry one. A cover crop occupies the same hectare as the spring crop that follows it, so it takes nothing from the food chain and moves no class of the land account — what limits it is how much spring cropping there is. Reported, never clamped: at the slider's maximum of 3.0 Mha against a ceiling of 4.0 it is a diagnostic and stays positive.

band_biogas_goodland_module_active * biogas_supply + (1 - land_module_active) * threshold["biogas"].goodTWh/y

The domestic biogas supply, and there is no import allowance above it — no French study publishes a biomethane import — so the warning band equals it and a scenario over the supply is straight into the red. That is deliberate: an amber band nothing can buy would be a suggestion that something can.

band_biogas_warningland_module_active * biogas_supply + (1 - land_module_active) * threshold["biogas"].warningTWh/y—
band_biofuel_goodland_module_active * biofuel_domestic_supply + (1 - land_module_active) * threshold["biofuel"].goodTWh/y

The domestic liquid supply — crops, straw and waste fats — and not the imports. This is where bioImports earns its why: it buys the amber band and never the green one.

band_biofuel_warningland_module_active * biofuel_supply + (1 - land_module_active) * threshold["biofuel"].warningTWh/y—
band_wood_goodland_module_active * wood_supply + (1 - land_module_active) * threshold["biomass"].goodTWh/y

The wood supply, and the one band that rises when the forest sink falls. Cutting more wood feeds the boiler and costs the sink, in the same scenario and from the same cubic metres, which is the coupling the whole module was built to show.

band_wood_warningland_module_active * wood_supply + (1 - land_module_active) * threshold["biomass"].warningTWh/y—
manure_dm_collectable_2024manure_dm_per_cattle_head * cattle_base_heads + manure_dm_per_pig_head * livestock["pig"].heads_2024Mt DM/y

The same pool on the published herd rather than on the modelled one. Cattle and pigs, as above.

residue_dm_pool_2024land_class["arable"].area_2023 * residue_dm_yieldMt DM/y

The residue pool on the land account's own base-year arable area. It is 57.0 Mt DM by construction — residue_dm_yield is derived as the published national tonnage over exactly this area — so what the equation shows is that the two definitions were reconciled rather than carried across.

biogas_supply_2024manure_dm_collectable_2024 * manure_methanised_2024 * biomass_biogas_yield + cive_area_base * cive_dm_yield * cive_biogas_yield + energy_maize_area_base * energy_maize_dm_yield * cive_biogas_yield + residue_dm_pool_2024 * residue_mobilisation_base * residue_to_biogas_share * biomass_biogas_yield + biogas_otherTWh/y

The base-year herd, the base-year cover-crop area, the base-year arable and the base-year mobilisation — and biogas_other, which is fitted so this closes. It therefore closes by construction, and the check below is zero by construction, which is worth saying rather than presenting as a result: what this equation demonstrates is the size of the residual, not the quality of the coefficients.

biogas_check_2024biogas_supply_2024 - sdes_biogas_2024TWh/y—
biogas_other_share_2024biogas_other / sdes_biogas_2024fraction of the base-year total

The number gap 3 exists to make impossible to forget. The share of the base year's biogas that this module cannot account for: 78%. The build prints it, the annex carries it in the residual's own why, and a test asserts that the printed figure and the model's are the same.

wood_supply_2024forest_harvest_base * (1 - forest_material_share_base - forest_unutilised_share_base) * wood_energy_per_m3 + wood_byproduct_share * forest_harvest_base * forest_material_share_base * wood_energy_per_m3 + non_forest_wood + waste_woodTWh/y

The base-year harvest at the base-year material share. Unlike the biogas one this is a real check: wood_byproduct_share is the only fitted term in it, and it is fitted on this identity, so what the residual below measures is how much the other four terms — the harvest, the material share, the conversion factor and the two fixed waste terms — miss the observed total by once the fitted one has done its work. It lands at +0.009 TWh.

wood_check_2024wood_supply_2024 - sdes_wood_2024TWh/y—
biofuel_domestic_2024energy_crop_area_base * biofuel_1g_yield + residue_dm_pool_2024 * residue_mobilisation_base * (1 - residue_to_biogas_share) * residue_liquid_yield + waste_fats_supplyTWh/y—
biofuel_supply_2024biofuel_domestic_2024 + bio_imports_baseTWh/y

The only one of the three base-year checks that nothing was fitted to. The 1G yield is the published crop areas times published yields, the 2G term shares the residue pool with the biogas one, the waste fats are observed and the imports are derived from the trade balance. It lands 0.05 TWh under the 41.7 the statistician observes — a tenth of a per cent — which is the closest thing this module has to independent evidence that the liquid coefficients are right.

biofuel_check_2024biofuel_supply_2024 - sdes_biofuel_2024TWh/y—

National reconciliation

Since v0.11.0 the game and the inventory share an accounting scope, and this module has much less to do. Both are scope 1: emissions are booked where the combustion happens, so a power station's emissions belong to the power station and not to everyone who used a kilowatt-hour. One difference remains, and it is real rather than conventional: the game includes international aviation and shipping, which the inventory reports as a memo item outside the national total. That is subtracted as its own named line. What is left is the perimeter the model does not cover at all — refining, fugitive emissions, and the sub-sectors nobody has modelled — and it stays visible rather than being divided away.

NameFormulaUnitNotes and sources
footprint_electricitysum(post.emissions_electricity)MtCO₂/y

Zero since v0.11.0, and kept as a line so the change is visible rather than silent. The game used to charge every sector the life-cycle emissions of its electricity, and this memo undid that to reach the inventory's basis. Now that the game books electricity where it is burned, there is nothing left to undo.

bunker_liquidsum(passenger.passenger_energy, passenger.in_inventory == 0) + sum(freight.freight_energy, freight.in_inventory == 0 and freight.vector == "liquid")TWh/y

International aviation and maritime shipping. Computed from the same rows the game already models, so the exclusion is a consequence of the data rather than an assertion.

bunker_gassum(freight.freight_energy, freight.in_inventory == 0 and freight.vector == "gas")TWh/y—
bunker_emissions_combustion(bunker_liquid * biofuelShare * efLiquid + bunker_gas * efGas) / 1000MtCO₂/y—
transport_combustionsum(post.emissions_combustion, post.sector == "transport")MtCO₂/y—
building_combustionsum(post.emissions_combustion, post.sector == "building")MtCO₂/y—
industry_combustionsum(post.emissions_combustion, post.sector == "industry")MtCO₂/y—
national_transporttransport_combustion - bunker_emissions_combustionMtCO₂e/y

Domestic transport only, on a combustion basis, comparable with SECTEN.

national_buildingbuilding_combustionMtCO₂e/y—
industry_perimeter_differenceofficial_industry_2024 - industry_covered_2020MtCO₂e/y

A diagnostic, not a term of the total. Until the rest of industry was modelled this was a hole in the account and had to be added back; now that all seventeen remaining manufacturing branches are in the model, what is left is a difference of perimeter and of year, and it is shown rather than absorbed. A positive value means the inventory sector is larger than what the model represents — construction and refining sit in SECTEN's industry and not in the manufacturing survey the model is built from, while the survey is a 2019 base compared with a 2024 inventory.

national_industryindustry_combustionMtCO₂e/y

No residual is added any more: every manufacturing branch is in the post table, so the sector total is a sum of the model and nothing else. See industry_perimeter_difference for what still separates it from the inventory sector.

national_agricultureland_module_active * agriculture_emissions + (1 - land_module_active) * (official_agriculture_2024 + (official_agriculture_2050 - official_agriculture_2024) * agriPathway)MtCO₂e/y

Which of the two it reads is land_module_active, the same switch the natural sink is behind. Where the food module is carried, agriculture is a sum of the post table filtered on the sector — three constructive rows, a herd, a nitrogen balance and a fuel line — and the agriPathway slider is retired and hidden; where it is not, the slider is the model exactly as it was, sliding between the observed year and the strategy's horizon. Both sides always evaluate: the switch is arithmetic and never a branch. No perimeter line is needed on either side. Agriculture has no electricity worth the detour and no international bunkers, so the game's basis and the inventory's coincide here — which is why this module lost a line when the food block arrived rather than gaining one.

national_wasteofficial_waste_2024 + (official_waste_2050 - official_waste_2024) * wastePathwayMtCO₂e/y—
national_energysum(post.emissions_combustion, post.sector == "energy")MtCO₂e/y

Computed, not taken from the SNBC. It is what the chosen electricity mix actually burns, at the emission factors the rest of the model uses — so a mix without combustion lands near zero and one leaning on biomass or methane does not. Until v0.11.0 this was a first-order trajectory sliding between two published values, which meant the sector the whole electrification story pushes emissions into was the one sector the player could not affect. What it omits. The inventory's energy branch is power generation plus refining, fugitive emissions and the rest of energy industry transformation; this is power generation and, since 0.28.0, the fossil carbon of the incinerators, because that is all the model has. Expect it to sit below the published figure for that reason and not because the mix is clean.

national_grossnational_transport + national_building + national_industry + national_agriculture + national_waste + national_energyMtCO₂e/y—
national_natural_sink-(land_module_active * land_sink_total + (1 - land_module_active) * naturalSink)MtCO₂e/y

Negated here: both of the things it can read are a magnitude absorbed, so a slider runs the way a reader expects, and the sign is applied once, where the account needs it. Which of the two it reads is land_module_active. Where the land module is carried, the natural sink is computed — seven land classes, six inventory pools and a forest identity in cubic metres — and the naturalSink slider is retired and hidden. Where it is not, the slider is the model, exactly as it was, and the computed side contributes nothing. Both sides always evaluate: the switch is arithmetic and not a branch, so the browser engine, the Python evaluator and the solver see one expression and cannot take different paths through it.

national_technological_sink-techSinkMtCO₂e/y—
national_total_sinknational_natural_sink + national_technological_sinkMtCO₂e/y

The two sinks added up, because what a net-zero claim rests on is the total and not either half. They are very different objects, though, and the dashboard keeps them visible separately: the natural sink is a forest that the official pathway expects to weaken, while the technological one is a closure residual rather than a published target.

sink_reliance-national_natural_sinkMtCO₂e/y absorbed

How much of net zero this scenario buys with the land: the natural sink as a magnitude, so it can be read against the trajectory the country's own strategy publishes for it. Scored on a line of its own, and not only inside the net, for two reasons. The two sinks are different objects — one is a forest, reversible, exposed to drought, fire and pests, and expected by the official pathways themselves to weaken; the other is a closure residual — which is the High Council on Climate's case for budgeting reversible sequestration and permanent removals separately. And the net line is hinged at zero: once a scenario crosses it, it stops reading either sink, so a player could buy the last megatonnes by cutting less wood and see no score move at all. This line has no hinge.

tech_sink_reliance-national_technological_sinkMtCO₂e/y absorbed

The engineered removals a scenario counts on, as a magnitude, so they can be read against the volume the country's own strategy plans. The natural sink has its own line; this is the other half of the High Council on Climate's recommendation to budget the two apart. Scored the way the net line is, against gross emissions and not as a percentage of its band, because the published volumes run from zero to forty-odd megatonnes and a percentage of nothing is undefined.

national_netnational_gross + national_natural_sink + national_technological_sinkMtCO₂e/y—
snbc_gross_gapnational_gross - snbc_gross_2050MtCO₂e/y

The number that matters: how far the scenario sits from the published SNBC 3 gross total. It is not zero by construction, and it is not meant to be — a large gap tells you where the scenario or the model disagrees with the national strategy.

Annualised cost layer

Real euros, no inflation, no subsidy or transfer, at full utilisation of installed capacity. For every asset the annualised cost is CAPEX × CRF(rate, lifetime) + fixed O&M + Σ(input intensity × price) + on-site CO₂ × carbon price. The governing principle is that the cost layer prices the quantities the game already shows: it never substitutes a different intensity, so where the physical description of a chain is incomplete its cost is understated by the same amount.

NameFormulaUnitNotes and sources
route_annuity
per row of cost_route
row.capex * crf(discountIndustry, row.life) + row.fixed€/t of capacity/y—
price_methane_mwhprice_methane_per_tonne / lhv_methane€/MWh—
price_coal_mwhprice_coal_per_tonne / lhv_coal€/MWh—
cost_hydrogen_electrolyticcost_route["electrolyser"].route_annuity / lhv_hydrogen + elecPriceIndustry / efficiency_electricity_to_h2€/MWh

Electrolyser annuity spread over its hydrogen output, plus the electricity it consumes at the workbook's 60% efficiency rather than the 74% POMMES uses. Hydrogen is therefore about 40% dearer here than a POMMES-native calculation gives, and everything hydrogen-based inherits that.

cost_hydrogen_smr(cost_route["smr"].route_annuity + smr_methane_per_tonne_h2 * price_methane_per_tonne + smr_electricity_per_tonne_h2 * elecPriceIndustry + smr_emission_per_tonne_h2 * carbonPrice) / lhv_hydrogen€/MWh—
cost_hydrogen_atr_ccscost_route["smr"].route_annuity / lhv_hydrogen + hydrogen_route["atr_ccs"].methane * price_methane_mwh + hydrogen_route["atr_ccs"].electricity * elecPriceIndustry + carbon_in_methane * hydrogen_route["atr_ccs"].methane * (1 - hydrogen_route["atr_ccs"].carbon_captured) * carbonPrice / 1000000€/MWh

The reformer's own cost plus the capture: no separate plant cost is declared for the capture train, so this uses the SMR annuity and adds the methane an ATR needs, which understates the capital. The carbon price applies only to what escapes.

cost_hydrogen_blendedhydrogen_route["electrolysis"].route_share * cost_hydrogen_electrolytic + hydrogen_route["smr"].route_share * cost_hydrogen_smr + hydrogen_route["atr_ccs"].route_share * cost_hydrogen_atr_ccs€/MWh

What a tonne of hydrogen costs on average, given the mix. Everything that buys hydrogen buys it at this price, which is what makes the route choice show up in the cost of steel and ammonia alike.

chain_cost_capital
per row of industry_chain
steel_bf: cost_route["steel_bf"].route_annuity
steel_dri: cost_route["steel_dri"].route_annuity
steel_eaf: cost_route["steel_eaf"].route_annuity
ammonia: cost_route["haber_bosch"].route_annuity
olefins: cost_route["methanol_to_olefins"].route_annuity + cost_route["methanol"].route_annuity * methanol_per_olefin
cement: cost_route["cement_kiln"].route_annuity * (1 - carbonCapture) + cost_route["cement_kiln_ccs"].route_annuity * carbonCapture
€/t of product—
chain_cost_variable
per row of industry_chain
steel_bf: row.coal * price_coal_mwh + row.gas * price_methane_mwh + row.electricity * elecPriceIndustry + iron_ore_per_steel_bf * price_iron_ore
steel_dri: row.hydrogen * cost_hydrogen_electrolytic + row.gas * price_methane_mwh + row.electricity * elecPriceIndustry + iron_ore_per_steel_dri * price_iron_ore
steel_eaf: row.electricity * elecPriceIndustry + scrap_per_steel_eaf * price_scrap
ammonia: industry_chain["ammonia"].electricity * elecPriceIndustry + industry_chain["ammonia"].hydrogen * cost_hydrogen_blended
olefins: row.electricity * elecPriceIndustry + row.hydrogen * cost_hydrogen_electrolytic
cement: kiln_heat_per_clinker * coal_per_kiln_heat * price_coal_per_tonne + limestone_per_clinker * price_limestone + (row.electricity + cement_capture_extra_electricity * carbonCapture / cement_capture_reference_rate) * elecPriceIndustry + carbonCapture * (cement_process_per_tonne + kiln_fuel_co2_per_tonne + kiln_biomass_co2_per_tonne) * co2_transport_storage_cost
€/t of product

Energy and feedstock. Ammonia buys its hydrogen at the mix's blended price rather than at one route's, because since v0.12.0 it no longer owns a route: the same reformers and electrolysers serve steel and everything else.

chain_cost_carbon
per row of industry_chain
row.chain_emissions_per_tonne * carbonPrice€/t of product—
chain_cost_total
per row of industry_chain
row.chain_cost_capital + row.chain_cost_variable + row.chain_cost_carbon€/t of product—
steel_outputsum(industry_chain.chain_production, industry_chain.subpost == "steel")kt/y—
steel_cost_blendedsumproduct(industry_chain.chain_production, industry_chain.chain_cost_total, industry_chain.subpost == "steel") / max(1, steel_output)€/t—
industry_cost_chainssumproduct(industry_chain.chain_production, industry_chain.chain_cost_total) / 1000M€/y—
industry_cost_food_energyfood_gas * price_methane_mwh + food_electricity * elecPriceIndustryM€/y

Food-industry heat is priced on its energy alone: the workbook does not describe its equipment, so no annuity can be attached to it.

industry_cost_totalindustry_cost_chains + industry_cost_food_energyM€/y—
cement_capture_costcement_production * carbonCapture * (cost_route["cement_kiln_ccs"].route_annuity - cost_route["cement_kiln"].route_annuity + cement_capture_extra_electricity / cement_capture_reference_rate * elecPriceIndustry) / 1000 + (cement_captured_fossil + cement_captured_biogenic) * co2_transport_storage_costM€/y

What carbonCapture adds to the clinker bill, read out of the chain cost so it can be set beside the incinerators': the capture kiln's extra annuity, its electricity, and transport and storage on every tonne it stores. Already inside industry_cost_total.

wte_capture_cost_total(wte_fossil_captured + wte_biogenic_captured) * (wte_capture_cost + co2_transport_storage_cost) + wte_capture_power * elecPriceIndustryM€/y

What wteCapture costs: the capture plants, the electricity the incinerators no longer sell, at the industrial price, and transport and storage — on the biogenic tonnes as much as on the fossil ones that lower the total.

retrofit_deep_equivalentmin(1, bldgRetrofit / deep_retrofit_saving)fraction of the stock

The average stock improvement expressed as an equivalent number of deep renovations, capped at the whole stock.

retrofit_investmentbuilding_surface_2020 * retrofit_deep_equivalent * retrofitCost * renovation_vatM€—
retrofit_annualretrofit_investment * crf(discountResidential, retrofit_life)M€/y—
heat_pump_investmentheat_pump_surface_added * heat_pump_cost_per_m2M€

Priced on the surface that actually gains a heat pump between 2020 and 2050, which the stock model now knows. The aggregate module could only charge the whole electrically heated stock, equipment already installed included.

heat_pump_annualheat_pump_investment * crf(discountResidential, heat_pump_life)M€/y—
building_energy_costbuilding_electricity * price_household_electricity + building_gas * price_household_gas + building_wood * price_woodM€/y—
building_cost_totalretrofit_annual + heat_pump_annual + building_energy_costM€/y—
building_cost_per_m2building_cost_total / building_surface_2020€/m²/y—
residential_areabuilding_surface_residentialMm²

The model's own heated surface, 3 654.9 Mm², rather than the 4 200 Mm² of total floor area ADEME reports after CEREN: the stock segments only what is heated by one of the eight systems. Cost and energy now share one denominator, which they did not before.

tertiary_areabuilding_surface_2020 - building_surface_residentialMm²—
residential_energy_costbuilding_electricity_residential * price_household_electricity + building_gas_residential * price_household_gas + building_wood_residential * price_woodM€/y

The split is now counted, not assumed: every segment carries its building type, so each vector is divided where it is actually used. The residential stock takes most of the wood and about half the gas, and a floor-area split would have misstated both. The retrofit and equipment annuities are still split by area, because one retrofit lever drives the whole stock.

tertiary_energy_costbuilding_energy_cost - residential_energy_costM€/y—
residential_cost_total(retrofit_annual + heat_pump_annual) * residential_area / building_surface_2020 + residential_energy_costM€/y—
tertiary_cost_totalbuilding_cost_total - residential_cost_totalM€/y—
residential_cost_per_m2residential_cost_total / residential_area€/m²/y—
tertiary_cost_per_m2tertiary_cost_total / tertiary_area€/m²/y—
car_vehicle_kmsum(passenger.passenger_demand / passenger.occupancy, passenger.id == "car_fuel" or passenger.id == "car_gas" or passenger.id == "car_electric")Gvkm/y—
car_fleetcar_vehicle_km * 1000000000 / km_per_car_per_yearcars—
car_fleet_ratiocar_fleet / reference_car_fleetratio—
car_ownership_costcar_ownership_reference * car_fleet_ratio€/household/y

Purchase, insurance and maintenance are deliberately technology-neutral: the electric-versus-thermal purchase premium and maintenance saving are not sourced, so they are excluded rather than guessed. Only the size of the fleet moves this block.

car_electricitysum(passenger.passenger_energy, passenger.id == "car_electric")TWh/y—
car_moleculessum(passenger.passenger_energy, passenger.id == "car_fuel" or passenger.id == "car_gas")TWh/y—
car_energy_cost(car_electricity * price_household_electricity + car_molecules * liquidFuelPrice) / households€/household/y—
transport_cost_per_householdcar_ownership_cost + car_energy_cost€/household/y—

Aviation — the price of a ticket

What decarbonised flying costs the passenger. The fuel side is computed from the same energy the emissions account charges, at a synthetic-fuel price the player sets; everything else — aircraft, crew, airport charges, maintenance — is derived from today's ticket through the fuel share of airline operating cost and held constant. That last assumption is the weak one, and it is stated rather than buried: a 2050 airline may have a different cost structure and nothing here models it.

NameFormulaUnitNotes and sources
jet_price_per_mwh_todayjet_fuel_price_2023 / lhv_kerosene€/MWh—
saf_price_per_tonnebiofuelShare * safBioPrice + (1 - biofuelShare) * safEfuelPrice€/t

The same biofuel/e-fuel split the transport module applies to every litre of liquid fuel, so the ticket and the emissions account describe the same fuel.

saf_price_per_mwhsaf_price_per_tonne / lhv_kerosene€/MWh—
flight_distance
per row of flight_type
row.pkt_2023 / row.pax_2023 * 1000km

Passenger-kilometres divided by passengers, one way.

flight_energy_today
per row of flight_type
row.flight_distance * passenger[row.game_row].unit_consumption / passenger[row.game_row].occupancy / 100kWh per passenger—
flight_energy_2050
per row of flight_type
row.flight_distance * passenger[row.game_row].unit_consumption_2050 / passenger[row.game_row].occupancy / 100kWh per passenger—
flight_fuel_cost_today
per row of flight_type
row.flight_energy_today / 1000 * jet_price_per_mwh_today€ per passenger—
flight_ticket_today
per row of flight_type
row.flight_fuel_cost_today / fuelShareOperating€ per passenger

Not an observed fare: the fuel bill grossed up by the fuel share of operating cost. It carries no margin, no tax and no yield management, so it is a cost, not a price, and it will sit below what a traveller actually pays on a route with high margins and above it on a route sold at a loss.

flight_non_fuel_cost
per row of flight_type
row.flight_ticket_today - row.flight_fuel_cost_today€ per passenger—
flight_fuel_cost_2050
per row of flight_type
row.flight_energy_2050 / 1000 * saf_price_per_mwh€ per passenger—
flight_ticket_2050
per row of flight_type
row.flight_non_fuel_cost + row.flight_fuel_cost_2050€ per passenger—
flight_ticket_ratio
per row of flight_type
row.flight_ticket_2050 / row.flight_ticket_today×—
flight_co2_today
per row of flight_type
row.flight_energy_today / 1000 / lhv_kerosene * co2_per_tonne_kerosene * 1000kgCO₂ per passenger

Combustion of the kerosene only. It excludes the upstream fuel chain and the non-CO₂ effects of aviation — contrails and nitrogen oxides — which several studies put at the same order of magnitude again.

flight_co2_2050
per row of flight_type
row.flight_energy_2050 * efLiquid / 1000kgCO₂ per passenger—
aviation_energysum(passenger.passenger_energy, passenger.aviation == 1)TWh/y—
aviation_fuel_billaviation_energy * saf_price_per_mwhM€/y

What the scenario's aviation fuel costs the sector as a whole, at the same price the tickets use.

Building usages other than heating

Space heating is about half of what a building consumes. This is the other half: hot water, cooking, air conditioning, and the specific electrical uses — lighting, appliances, screens, and the servers behind them. It carries no stock and no technology choice; each usage is its observed energy carried to 2050 and moved by an efficiency lever, a growth lever, or both. That is a weaker model than the heating one and deliberately so: the alternative was to leave 240 TWh of building energy out of the account entirely, which is what the model did until 0.8.0.

NameFormulaUnitNotes and sources
usage_factor
per row of building_usage
dhw_residential: 1 - usageDhwEfficiency
dhw_tertiary: 1 - usageDhwEfficiency
cooking_residential: 1 - usageCookingEfficiency
cooking_tertiary: 1 - usageCookingEfficiency
cooling_residential: 1 + usageCoolingGrowth
cooling_tertiary: 1 + usageCoolingGrowth
specific_residential: (1 - usageSpecificEfficiency) * (1 + usageSpecificGrowth)
specific_tertiary: (1 - usageSpecificEfficiency) * (1 + usageSpecificGrowth)
other_tertiary: 1
multiple of the observed year

Efficiency and growth act on the same usage and pull against each other, which is the point of carrying both. Cooking and hot water get efficiency only; cooling gets growth only, because nothing suggests a French air-conditioning stock that shrinks.

usage_electric_efficiency
per row of building_usage
dhw_residential: dhw_efficiency_electric
dhw_tertiary: dhw_efficiency_electric
cooking_residential: cooking_efficiency_electric
cooking_tertiary: cooking_efficiency_electric
default: 1
service per MWh—
usage_fuel_efficiency
per row of building_usage
dhw_residential: dhw_efficiency_fuel
dhw_tertiary: dhw_efficiency_fuel
cooking_residential: cooking_efficiency_fuel
cooking_tertiary: cooking_efficiency_fuel
default: 1
service per MWh—
usage_electric_target
per row of building_usage
dhw_residential: usageDhwElectric
dhw_tertiary: usageDhwElectric
cooking_residential: usageCookingElectric
cooking_tertiary: usageCookingElectric
default: -1
fraction of the service

Only hot water and cooking can be switched. Cooling and the specific electrical uses are already electric, and the tertiary "other" row is too heterogeneous to claim anything about.

usage_fuel_base
per row of building_usage
row.gas + row.heat + row.liquid + row.woodTWh/y—
usage_service
per row of building_usage
(row.electricity * row.usage_electric_efficiency + row.usage_fuel_base * row.usage_fuel_efficiency) * row.usage_factorservice units

What the usage actually delivers — hot water, hot pans — rather than what it consumes. Efficiency and growth act here, before the choice of carrier.

usage_electricity
per row of building_usage
row.usage_service * row.usage_electric_target / row.usage_electric_efficiency if row.usage_electric_target >= 0 else row.electricity * row.usage_factorTWh/y

Where a target exists, the electric share of the service divided by the electric route's efficiency. Where it does not, the observed electricity carried forward.

usage_fuel_energy
per row of building_usage
row.usage_service * (1 - row.usage_electric_target) / row.usage_fuel_efficiency if row.usage_electric_target >= 0 else row.usage_fuel_base * row.usage_factorTWh/y

The service left to the fuels, at the fuel route's efficiency.

usage_fuel_scale
per row of building_usage
row.usage_fuel_energy / row.usage_fuel_base if row.usage_fuel_base > 0 else 0multiple of the observed fuel mix

What is left to the fuels keeps the proportions it has today — gas, oil and LPG in the ratio observed — because nothing here says which of them goes first.

usage_gas
per row of building_usage
(row.gas + row.heat) * row.usage_fuel_scaleTWh/y

District heat is folded in here. The model has no heat carrier outside the heating module, and its networks are majority gas, so this is the least wrong home for 2.8 TWh — stated rather than buried.

usage_liquid
per row of building_usage
row.liquid * row.usage_fuel_scaleTWh/y—
usage_wood
per row of building_usage
row.wood * row.usage_fuel_scaleTWh/y—
usage_energy
per row of building_usage
row.usage_electricity + row.usage_gas + row.usage_liquid + row.usage_woodTWh/y—
usages_electricity_residentialsum(building_usage.usage_electricity, building_usage.segment == "residential")TWh/y—
usages_electricity_tertiarysum(building_usage.usage_electricity, building_usage.segment == "tertiary")TWh/y—
usages_gas_residentialsum(building_usage.usage_gas, building_usage.segment == "residential")TWh/y—
usages_gas_tertiarysum(building_usage.usage_gas, building_usage.segment == "tertiary")TWh/y—
usages_liquid_residentialsum(building_usage.usage_liquid, building_usage.segment == "residential")TWh/y—
usages_liquid_tertiarysum(building_usage.usage_liquid, building_usage.segment == "tertiary")TWh/y—
usages_wood_residentialsum(building_usage.usage_wood, building_usage.segment == "residential")TWh/y—
usages_wood_tertiarysum(building_usage.usage_wood, building_usage.segment == "tertiary")TWh/y—
usages_energy_totalsum(building_usage.usage_energy)TWh/y—
usages_energy_dhwsum(building_usage.usage_energy, building_usage.usage == "dhw")TWh/y—
usages_energy_cookingsum(building_usage.usage_energy, building_usage.usage == "cooking")TWh/y—
usages_energy_coolingsum(building_usage.usage_energy, building_usage.usage == "cooling")TWh/y—
usages_energy_specificsum(building_usage.usage_energy, building_usage.usage == "specific")TWh/y—

Electricity supply

The mix follows the demand rather than standing beside it: whatever electricity the rest of the model turns out to need is served by the share structure of one of RTE's six 2050 scenarios. Choosing a scenario answers "with what", never "how much". Capacity follows from energy through a load factor, and what has to be built each year follows from capacity through a lifetime — a fleet of that size has to be renewed at that rate, and it is the build rate rather than the standing fleet that consumes materials. The result feeds the material account, which is why the seven build-rate sliders it used to carry are gone. This does not check that the mix works. There is no hourly balance, no adequacy calculation and no storage: a 100%-renewable share structure is applied here exactly as a nuclear-heavy one is. The winter peak the building module computes is still a demand-side number that nothing on this side has to meet.

NameFormulaUnitNotes and sources
generation_share
per row of generation_technology
nuclear: sum(rte_scenario.nuclear, rte_scenario.scenario_index == rteScenario)
pv_ground: sum(rte_scenario.pv_ground, rte_scenario.scenario_index == rteScenario)
pv_roof: sum(rte_scenario.pv_roof, rte_scenario.scenario_index == rteScenario)
wind_onshore: sum(rte_scenario.wind_onshore, rte_scenario.scenario_index == rteScenario)
wind_offshore_fixed: sum(rte_scenario.wind_offshore_fixed, rte_scenario.scenario_index == rteScenario)
wind_offshore_floating: sum(rte_scenario.wind_offshore_floating, rte_scenario.scenario_index == rteScenario)
hydro: sum(rte_scenario.hydro, rte_scenario.scenario_index == rteScenario)
bioenergy: sum(rte_scenario.bioenergy, rte_scenario.scenario_index == rteScenario)
gas_turbine: sum(rte_scenario.gas_turbine, rte_scenario.scenario_index == rteScenario)
combined_cycle: sum(rte_scenario.combined_cycle, rte_scenario.scenario_index == rteScenario)
fraction of supply

The selected scenario's row, picked by a filtered sum over the one row whose index matches the lever.

generation_share_totalsum(generation_technology.generation_share)fraction

The declared shares are rounded, so they sum to one only to about six decimals. Dividing by their own total makes supply equal demand exactly rather than nearly, which is the difference between an identity a test can assert and one it can only approximate.

generation_share_thermal_gas
per row of generation_technology
row.generation_share / generation_share_total / row.thermal_efficiency if row.thermal_efficiency > 0 and row.fuel_carrier == "gas" else 0fraction of demand, per unit of fuel

Share of supply divided by thermal efficiency: how much fuel each gas plant needs per unit of national demand. Zero for anything that burns no gas.

generation_energy
per row of generation_technology
electricity_demand * row.generation_share / generation_share_total if generation_share_total > 0 else 0TWh/y—
generation_capacity
per row of generation_technology
row.generation_energy / row.load_factor / 8.76 if row.load_factor > 0 else 0GW

Energy divided by a load factor and by the 8 760 hours in a year. The load factors are RTE's own, read back out of its capacity and generation tables, and they barely move between scenarios — onshore wind 23%, offshore 41%, solar 14%.

generation_build
per row of generation_technology
row.generation_capacity * 1000 / row.lifetimeMW/y

A fleet of this size has to be renewed at this rate. It is the steady-state build, which understates the years when the fleet is still growing and overstates them once it is not — a build rate rather than a build programme, and the material account reads it as such.

generation_fuel
per row of generation_technology
row.generation_energy / row.thermal_efficiency if row.thermal_efficiency > 0 else 0TWh/y

Electricity out divided by thermal efficiency gives fuel in. Zero for everything that burns nothing, which in these scenarios is all of it bar the biomass plants and a sliver of combined cycle.

generation_switchable_fuelsum(generation_technology.generation_fuel, generation_technology.fuel_carrier == "gas")TWh/y

Every gas-fired plant. The model does not distinguish a combined cycle from an open-cycle turbine from a gas engine — RTE's categories are fuels, not machines — so it cannot claim that one of them can burn hydrogen and another cannot. A plant that burns biogas burns it in a turbine, and that turbine is as convertible as any other.

generation_gas_fuelgeneration_switchable_fuel * (1 - gasPlantHydrogen)TWh/y—
generation_hydrogen_fuelgeneration_switchable_fuel * gasPlantHydrogenTWh/y—
generation_hydrogen_electricitygeneration_hydrogen_fuel / efficiency_electricity_to_h2TWh/y

What the electrolysers would draw. It is not added to the electricity the mix has to serve: demand sets the mix and the mix would then set demand, which is a fixed point this compiler cannot express. It is reported rather than hidden. Because the switch reaches the combined cycle alone, and RTE keeps barely a percent of supply there, the number is around one TWh — small enough that leaving it out of the demand changes nothing a reader would notice.

generation_wood_fuelsum(generation_technology.generation_fuel, generation_technology.fuel_carrier == "wood")TWh/y

Biomass electricity at 25% efficiency needs four units of wood for one of power, so this is large — and it competes for the same resource the buildings burn. The scoreboard counts it.

generation_fuel_costgeneration_gas_fuel * price_methane_mwh + generation_hydrogen_fuel * cost_hydrogen_electrolyticM€/y

What the combustion plants burn, priced. Hydrogen is much the dearer of the two and the model charges it at the electrolytic price the industry module already computes — which is the point of the switch being a lever rather than an assumption.

generation_annual_cost
per row of generation_technology
row.generation_capacity * (row.capex_per_kw * crf(discountResidential, row.lifetime) + row.opex_per_kw_year)M€/y

Capital recovered over the technology's own life at the residential discount rate, plus fixed operating cost. No fuel, no carbon, no network, no storage — this is the plant, and it is the floor of what a mix costs rather than its price.

generation_total_capacitysum(generation_technology.generation_capacity)GW—
generation_total_costsum(generation_technology.generation_annual_cost) + generation_fuel_costM€/y

Plant plus fuel. Still no carbon, no network and no storage.

generation_cost_per_mwhgeneration_total_cost / electricity_demand€/MWh—
grid_emission_factornational_energy / electricity_demand * 1000 if electricity_demand > 0 else 0gCO₂/kWh

What a kilowatt-hour actually carries, derived from the fuel the mix burns rather than declared. It replaced a 40 gCO₂/kWh lever in v0.11.0: under a scope-1 account the number is a result of the generation choice, and letting a player set it independently of the mix they had just chosen was the inconsistency that prompted the whole change. It is a combustion figure, not a life-cycle one — no construction, no fuel chain, no decommissioning — which is why it lands near zero for a mix that burns almost nothing, and why it is not comparable with the 80-ish gCO₂/kWh a life-cycle study reports for the same grid.

generation_renewable_sharesum(generation_technology.generation_share, generation_technology.renewable == 1)fraction—

Materials of the transition

A satellite account, and deliberately a one-way one: it reads the scenario, nothing reads it back. The steel a wind farm needs is not charged to the steel industry the model already has, the concrete is not charged to cement, and none of it emits. Wiring it back would double-count against an industry module whose output is set by its own levers, so the honest thing is to compute the demand and put it beside the supply rather than inside it. What it is for: a decarbonisation pathway is usually argued in TWh and MtCO2. This says what the same pathway weighs. Three of the numbers are worth reading against the industry module directly — the transition's steel against French steel output, its concrete against French cement.

NameFormulaUnitNotes and sources
vehicle_electric_share
per row of vehicle_type
car: carElectric
truck: truckElectric
default: row.electric_share
fraction of production

Cars and trucks follow the player's own electrification levers, which is the whole point of a satellite account that reacts to the scenario. The rest keep the share derived from the source's battery-capacity row. Note the levers are shares of demand rather than of production; over a thirty-year horizon the two converge, and the approximation is stated rather than hidden.

vehicle_battery_capacity
per row of vehicle_type
row.production_2050 * row.vehicle_electric_share * row.battery_kwh / 1000000GWh/y—
battery_capacity_vehiclessum(vehicle_type.vehicle_battery_capacity)GWh/y—
battery_capacity_totalbattery_capacity_vehiclesGWh/y

Vehicle batteries only. Grid storage had its own slider until the supply mix started following demand; at the rate the source scenario built it — 1 GWh a year against 159 in vehicles — it was rounding, and carrying a lever for it implied a precision the model does not have.

vehicle_steelsumproduct(vehicle_type.production_2050, vehicle_type.steel) / 1000000kt/y

Kilogrammes per vehicle times units per year, so 10^6 carries kg to kt.

vehicle_aluminiumsumproduct(vehicle_type.production_2050, vehicle_type.aluminium) / 1000000kt/y—
generation_steelsumproduct(generation_technology.generation_build, generation_technology.steel) / 1000kt/y—
generation_concretesumproduct(generation_technology.generation_build, generation_technology.concrete) / 1000kt/y—
generation_aluminiumsumproduct(generation_technology.generation_build, generation_technology.aluminium) / 1000kt/y—
generation_coppersumproduct(generation_technology.generation_build, generation_technology.copper) / 1000kt/y—
generation_lithiumsumproduct(generation_technology.generation_build, generation_technology.lithium) / 1000kt/y—
generation_cobaltsumproduct(generation_technology.generation_build, generation_technology.cobalt) / 1000kt/y—
generation_nickelsumproduct(generation_technology.generation_build, generation_technology.nickel) / 1000kt/y—
generation_rare_earthsumproduct(generation_technology.generation_build, generation_technology.rare_earth) / 1000kt/y—
battery_intensity_steelbattery_chemistry["lfp"].steel * batteryLfpShare + battery_chemistry["nmc_811"].steel * (1 - batteryLfpShare)t per MWh—
battery_intensity_aluminiumbattery_chemistry["lfp"].aluminium * batteryLfpShare + battery_chemistry["nmc_811"].aluminium * (1 - batteryLfpShare)t per MWh—
battery_intensity_copperbattery_chemistry["lfp"].copper * batteryLfpShare + battery_chemistry["nmc_811"].copper * (1 - batteryLfpShare)t per MWh—
battery_intensity_lithiumbattery_chemistry["lfp"].lithium * batteryLfpShare + battery_chemistry["nmc_811"].lithium * (1 - batteryLfpShare)t per MWh—
battery_intensity_cobaltbattery_chemistry["lfp"].cobalt * batteryLfpShare + battery_chemistry["nmc_811"].cobalt * (1 - batteryLfpShare)t per MWh—
battery_intensity_nickelbattery_chemistry["lfp"].nickel * batteryLfpShare + battery_chemistry["nmc_811"].nickel * (1 - batteryLfpShare)t per MWh—
battery_steelbattery_capacity_total * battery_intensity_steelkt/y—
battery_aluminiumbattery_capacity_total * battery_intensity_aluminiumkt/y—
battery_copperbattery_capacity_total * battery_intensity_copperkt/y—
battery_lithiumbattery_capacity_total * battery_intensity_lithiumkt/y—
battery_cobaltbattery_capacity_total * battery_intensity_cobaltkt/y—
battery_nickelbattery_capacity_total * battery_intensity_nickelkt/y—
construction_concrete(sum(construction_use.construction_use_cement, construction_use.cement_intensity > 0) - construction_cement_saved) / cement_per_concrete * concrete_densitykt/y

The concrete of the buildings the scenario puts up, from the cement the construction module says they carry. Converted at the cement content of a cubic metre and the density of concrete rather than at the whole-economy "béton équivalent" bookkeeping factor of 266 kg a cubic metre: that factor already absorbs mortars, renders and bagged cement, and pushing building cement through it inflates the answer by about seven tenths — enough to make a collective dwelling come out as 98% concrete by mass, which it is not.

material_steelgeneration_steel + vehicle_steel + battery_steel + construction_steel_demandkt/y—
material_concretegeneration_concrete + construction_concretekt/y—
material_aluminiumgeneration_aluminium + vehicle_aluminium + battery_aluminiumkt/y—
material_coppergeneration_copper + battery_copperkt/y—
material_lithiumgeneration_lithium + battery_lithiumkt/y—
material_cobaltgeneration_cobalt + battery_cobaltkt/y—
material_nickelgeneration_nickel + battery_nickelkt/y—
material_rare_earthgeneration_rare_earthkt/y—
french_steel_productionsum(industry_chain.chain_production, industry_chain.subpost == "steel")kt/y—
material_steel_share_of_french_steelmaterial_steel / french_steel_productionfraction

The transition's annual steel demand against what the scenario's own steel industry produces. Both move with the player, which is the comparison worth making: electrifying harder raises the steel needed and, if the output levers are left alone, does not raise the steel made.

material_concrete_vs_cementmaterial_concrete / sum(industry_chain.chain_production, industry_chain.subpost == "cement")fraction

Against clinker rather than concrete, because clinker is what the model produces and what carries the process CO2. A ratio above one is not an error: concrete is mostly aggregate, and a tonne of clinker makes several tonnes of concrete.

Cost layer — method and sources

The cost layer prices the physical flows the game already computes. It never uses a different quantity from the one shown in the emissions dashboard: if the physical description of a chain is incomplete, its cost is understated by the same amount, and that is stated rather than patched.

The cost layer is the least Spanish part of this edition. The industrial capital costs, the commodity prices, the retrofit cost, the heat-pump cost and the household car budgets are French or French-derived. Where a Spanish price exists it is used — household electricity and gas are Eurostat's Spanish 2024 tariffs, and the renovation VAT is Spain's own 10% — and where it does not, the entry says so in the sources annex. Read Spanish costs as relative, not absolute.

Convention

Real euros, no inflation, no subsidy or tax transfer. Annualised cost = CAPEX × CRF(rate, lifetime) + fixed O&M + Σ (input × price) + CO₂ × carbon price, with CRF(r, n) = r / (1 − (1+r)−n) and full utilisation of installed capacity. Two discount rates are exposed because an industrial investor and a household do not face the same cost of capital. The industrial rate of 8% is the POMMES France default and a Spanish investor's is not a French one's, which is a national assumption wearing a technology label.

Where the cost numbers come from

ParameterValueProvenanceSource
Industrial CAPEX, lifetime, fixed O&M, feedstock intensitiese.g. BF-BOF 442 €/t over 25 years; electrolyser 1 125 €/t H₂PublishedPOMMES-INDUSTRY, France 2050 — carried unchanged for Spain
Commodity prices 2050: methane 561 €/t, coal 99, iron ore 100, scrap 180, limestone 20 €/tWorld prices in substance, French assumptions in provenance. Spain's gas arrives as LNG from Algeria, the United States and Nigeria rather than by pipeline, and Spain is a net scrap importer on which two thirds of its steel dependsProvisional for SpainPOMMES-INDUSTRY import_hourly.csv
Carbon price, 150 €/tCO₂ by defaultEnd point of a linear trajectoryPublishedPOMMES-INDUSTRY carbon.csv. EU-wide, so genuinely shared
Household energy prices: electricity 242.2 €/MWh, gas 88.0 €/MWh incl. taxMean of the two 2024 semesters. Spanish households pay two thirds of the French gas price, which is one reason gas holds so much of the Spanish heat market and why electrification is a harder sell here on cost alonePublishedEurostat nrg_pc_204 and nrg_pc_202, Spain, bands DC and D2, all taxes included
Wood pellets, 77.5 €/MWhFrench value carried. Spanish pellet prices have run below French ones for a decadePlaceholderPropellet index. AVEBIOM publishes the Spanish equivalent; it was not reachable
Floor area, 4 625 Mm² of which 52% residentialDenominator of the €/m² indicator. The services half is the weakest number in this edition — see the Controversy tabDerivedEurostat census 2021 for dwellings and floor space; JRC-IDEES for services
Household car budget, 3 234 €/y and ownership 2 161 €/yFrench budgets scaled by the ratio of household consumption expenditure, 0.850. This assumes a Spanish household spends the same share of its budget on a car as a French one, which it plainly does notPlaceholderINSEE Première 1855 scaled by JRC-IDEES household expenditure. INE's Encuesta de Presupuestos Familiares would close it
18.873 million households; 11 194 km per car per yearDenominator and fleet conversion. A Spanish household is larger than a French one — 2.49 people against 2.18 — so every per-household cost is spread over fewer, bigger householdsPublishedJRC-IDEES-2021, Spain, 2019
VAT on renovation, 10%Against a standard rate of 21% and against France's 5.5%: a Spanish renovation carries almost twice the tax margin a French one doesProvisionalLey 37/1992 del IVA, art. 91.Uno.2.10º. Not verified against the BOE in this edition
Deep-retrofit cost, 550 €/m²; heat pump 80 €/m²French values carried. Spanish installation labour is cheaper and Spanish dwellings slightly smallerPlaceholderADEME orders of magnitude. IDAE's aid-programme reference costs would close the heat pump
Liquid fuel at the pump, 200 €/MWh by defaultApplied to biofuel, e-fuel and vehicle gas alikeProvisionalNo 2050 source secured, for either country. The weakest number in the layer

Two deliberate inconsistencies with POMMES

Electrolysis efficiency. POMMES uses about 74%; the model uses 60%, and the cost layer follows the model so that the cost and the electricity KPI describe the same hydrogen. This makes hydrogen roughly 40% more expensive than a POMMES-native calculation would give, and for a country whose industrial strategy rests on cheap renewable hydrogen that is not a neutral technology choice.

Grey ammonia. The shared file gives grey ammonia a gas consumption an order of magnitude below a real reforming plant. It is kept in the energy balance for continuity but is not used for cost.

What the cost layer omits

Freight, aviation and public transport; grid reinforcement; CO₂ transport and storage; equipment for food-industry heat; cement kiln-fuel CO₂. Price base years are mixed, with no deflator. Compare deltas across scenarios, not levels across sectors — and in this edition, not levels across countries either.

Build information and model limitations

This page is a self-contained artefact generated by Python: no server, external library or connection is required. The live calculation engine runs in the browser.

Transport and industry reproduce the workbook relationships algebraically. Building heating is an aggregate calibrated model because the workbook computes the stock bottom-up. Reference outputs are covered by automated regression tests.

The calculation is not written in this page. It is compiled from app/model/technology.yaml, app/model/countries/<CC>/<CC>.yaml and app/model/equations.yaml, which also generate the sources annex — so a value shown and a value used are the same value. A Python evaluator runs the same specification, and the test suite fails if the two ever disagree.

Three accounting defects inherited from the workbook have been corrected here and not yet at source, so the Excel edition and this page currently disagree: the blast furnace's coal was counted both as energy and inside its process factor; gas used by steel and grey ammonia was counted as a resource but charged no emissions; and two legacy transport aggregations (Transport parc 2050!J40 and General hypotheses!F22) added subtotals already counted elsewhere, inventing about 32 TWh of electricity.